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:
commit
99a0d9f5e8
@ -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>;
|
||||
};
|
||||
|
||||
|
||||
...
|
50
Documentation/devicetree/bindings/gpio/gpio-rda.yaml
Normal file
50
Documentation/devicetree/bindings/gpio/gpio-rda.yaml
Normal 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
|
||||
|
||||
...
|
@ -8,6 +8,7 @@ Required Properties:
|
||||
- "renesas,gpio-r8a7745": for R8A7745 (RZ/G1E) compatible GPIO controller.
|
||||
- "renesas,gpio-r8a77470": for R8A77470 (RZ/G1C) compatible GPIO controller.
|
||||
- "renesas,gpio-r8a774a1": for R8A774A1 (RZ/G2M) compatible GPIO controller.
|
||||
- "renesas,gpio-r8a774b1": for R8A774B1 (RZ/G2N) compatible GPIO controller.
|
||||
- "renesas,gpio-r8a774c0": for R8A774C0 (RZ/G2E) compatible GPIO controller.
|
||||
- "renesas,gpio-r8a7778": for R8A7778 (R-Car M1) compatible GPIO controller.
|
||||
- "renesas,gpio-r8a7779": for R8A7779 (R-Car H1) compatible GPIO controller.
|
||||
|
@ -2,7 +2,7 @@
|
||||
A driver for a selfmade cheap BT8xx based PCI GPIO-card (bt8xxgpio)
|
||||
===================================================================
|
||||
|
||||
For advanced documentation, see http://www.bu3sch.de/btgpio.php
|
||||
For advanced documentation, see https://bues.ch/cms/unmaintained/btgpio.html
|
||||
|
||||
A generic digital 24-port PCI GPIO card can be built out of an ordinary
|
||||
Brooktree bt848, bt849, bt878 or bt879 based analog TV tuner card. The
|
@ -5,7 +5,7 @@ GPIO Driver Interface
|
||||
This document serves as a guide for writers of GPIO chip drivers.
|
||||
|
||||
Each GPIO controller driver needs to include the following header, which defines
|
||||
the structures used to define a GPIO driver:
|
||||
the structures used to define a GPIO driver::
|
||||
|
||||
#include <linux/gpio/driver.h>
|
||||
|
||||
@ -398,12 +398,15 @@ provided. A big portion of overhead code will be managed by gpiolib,
|
||||
under the assumption that your interrupts are 1-to-1-mapped to the
|
||||
GPIO line index:
|
||||
|
||||
GPIO line offset Hardware IRQ
|
||||
0 0
|
||||
1 1
|
||||
2 2
|
||||
... ...
|
||||
ngpio-1 ngpio-1
|
||||
.. csv-table::
|
||||
:header: GPIO line offset, Hardware IRQ
|
||||
|
||||
0,0
|
||||
1,1
|
||||
2,2
|
||||
...,...
|
||||
ngpio-1, ngpio-1
|
||||
|
||||
|
||||
If some GPIO lines do not have corresponding IRQs, the bitmask valid_mask
|
||||
and the flag need_valid_mask in gpio_irq_chip can be used to mask off some
|
||||
@ -413,7 +416,9 @@ The preferred way to set up the helpers is to fill in the
|
||||
struct gpio_irq_chip inside struct gpio_chip before adding the gpio_chip.
|
||||
If you do this, the additional irq_chip will be set up by gpiolib at the
|
||||
same time as setting up the rest of the GPIO functionality. The following
|
||||
is a typical example of a cascaded interrupt handler using gpio_irq_chip:
|
||||
is a typical example of a cascaded interrupt handler using gpio_irq_chip::
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
/* Typical state container with dynamic irqchip */
|
||||
struct my_gpio {
|
||||
@ -448,7 +453,9 @@ is a typical example of a cascaded interrupt handler using gpio_irq_chip:
|
||||
return devm_gpiochip_add_data(dev, &g->gc, g);
|
||||
|
||||
The helper support using hierarchical interrupt controllers as well.
|
||||
In this case the typical set-up will look like this:
|
||||
In this case the typical set-up will look like this::
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
/* Typical state container with dynamic irqchip */
|
||||
struct my_gpio {
|
||||
|
@ -13,6 +13,7 @@ Contents:
|
||||
board
|
||||
drivers-on-gpio
|
||||
legacy
|
||||
bt8xxgpio
|
||||
|
||||
Core
|
||||
====
|
||||
|
@ -70,7 +70,6 @@ available subsections can be seen below.
|
||||
fpga/index
|
||||
acpi/index
|
||||
backlight/lp855x-driver.rst
|
||||
bt8xxgpio
|
||||
connector
|
||||
console
|
||||
dcdbas
|
||||
|
@ -2183,9 +2183,11 @@ L: linux-unisoc@lists.infradead.org (moderated for non-subscribers)
|
||||
S: Maintained
|
||||
F: arch/arm/boot/dts/rda8810pl-*
|
||||
F: drivers/clocksource/timer-rda.c
|
||||
F: drivers/gpio/gpio-rda.c
|
||||
F: drivers/irqchip/irq-rda-intc.c
|
||||
F: drivers/tty/serial/rda-uart.c
|
||||
F: Documentation/devicetree/bindings/arm/rda.yaml
|
||||
F: Documentation/devicetree/bindings/gpio/gpio-rda.yaml
|
||||
F: Documentation/devicetree/bindings/interrupt-controller/rda,8810pl-intc.txt
|
||||
F: Documentation/devicetree/bindings/serial/rda,8810pl-uart.txt
|
||||
F: Documentation/devicetree/bindings/timer/rda,8810pl-timer.txt
|
||||
@ -8329,7 +8331,7 @@ F: Documentation/fb/intelfb.rst
|
||||
F: drivers/video/fbdev/intelfb/
|
||||
|
||||
INTEL GPIO DRIVERS
|
||||
M: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
|
||||
M: Andy Shevchenko <andy@kernel.org>
|
||||
L: linux-gpio@vger.kernel.org
|
||||
S: Maintained
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/andy/linux-gpio-intel.git
|
||||
@ -8483,7 +8485,7 @@ F: arch/x86/include/asm/intel_pmc_ipc.h
|
||||
F: arch/x86/include/asm/intel_punit_ipc.h
|
||||
|
||||
INTEL PMIC GPIO DRIVERS
|
||||
M: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
|
||||
M: Andy Shevchenko <andy@kernel.org>
|
||||
S: Maintained
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/andy/linux-gpio-intel.git
|
||||
F: drivers/gpio/gpio-*cove.c
|
||||
|
@ -11,8 +11,8 @@
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/ahci_platform.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/of_gpio.h>
|
||||
#include <linux/mfd/syscon.h>
|
||||
#include <linux/mfd/syscon/imx6q-iomuxc-gpr.h>
|
||||
#include <linux/libata.h>
|
||||
@ -100,7 +100,7 @@ struct imx_ahci_priv {
|
||||
struct clk *phy_pclk0;
|
||||
struct clk *phy_pclk1;
|
||||
void __iomem *phy_base;
|
||||
int clkreq_gpio;
|
||||
struct gpio_desc *clkreq_gpiod;
|
||||
struct regmap *gpr;
|
||||
bool no_device;
|
||||
bool first_time;
|
||||
@ -980,7 +980,6 @@ static struct scsi_host_template ahci_platform_sht = {
|
||||
|
||||
static int imx8_sata_probe(struct device *dev, struct imx_ahci_priv *imxpriv)
|
||||
{
|
||||
int ret;
|
||||
struct resource *phy_res;
|
||||
struct platform_device *pdev = imxpriv->ahci_pdev;
|
||||
struct device_node *np = dev->of_node;
|
||||
@ -1033,20 +1032,12 @@ static int imx8_sata_probe(struct device *dev, struct imx_ahci_priv *imxpriv)
|
||||
}
|
||||
|
||||
/* Fetch GPIO, then enable the external OSC */
|
||||
imxpriv->clkreq_gpio = of_get_named_gpio(np, "clkreq-gpio", 0);
|
||||
if (gpio_is_valid(imxpriv->clkreq_gpio)) {
|
||||
ret = devm_gpio_request_one(dev, imxpriv->clkreq_gpio,
|
||||
GPIOF_OUT_INIT_LOW,
|
||||
"SATA CLKREQ");
|
||||
if (ret == -EBUSY) {
|
||||
dev_info(dev, "clkreq had been initialized.\n");
|
||||
} else if (ret) {
|
||||
dev_err(dev, "%d unable to get clkreq.\n", ret);
|
||||
return ret;
|
||||
}
|
||||
} else if (imxpriv->clkreq_gpio == -EPROBE_DEFER) {
|
||||
return imxpriv->clkreq_gpio;
|
||||
}
|
||||
imxpriv->clkreq_gpiod = devm_gpiod_get_optional(dev, "clkreq",
|
||||
GPIOD_OUT_LOW | GPIOD_FLAGS_BIT_NONEXCLUSIVE);
|
||||
if (IS_ERR(imxpriv->clkreq_gpiod))
|
||||
return PTR_ERR(imxpriv->clkreq_gpiod);
|
||||
if (imxpriv->clkreq_gpiod)
|
||||
gpiod_set_consumer_name(imxpriv->clkreq_gpiod, "SATA CLKREQ");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -120,6 +120,14 @@ config GPIO_ASPEED
|
||||
help
|
||||
Say Y here to support Aspeed AST2400 and AST2500 GPIO controllers.
|
||||
|
||||
config GPIO_ASPEED_SGPIO
|
||||
bool "Aspeed SGPIO support"
|
||||
depends on (ARCH_ASPEED || COMPILE_TEST) && OF_GPIO
|
||||
select GPIO_GENERIC
|
||||
select GPIOLIB_IRQCHIP
|
||||
help
|
||||
Say Y here to support Aspeed AST2500 SGPIO functionality.
|
||||
|
||||
config GPIO_ATH79
|
||||
tristate "Atheros AR71XX/AR724X/AR913X GPIO support"
|
||||
default y if ATH79
|
||||
@ -147,6 +155,15 @@ config GPIO_BCM_KONA
|
||||
help
|
||||
Turn on GPIO support for Broadcom "Kona" chips.
|
||||
|
||||
config GPIO_BCM_XGS_IPROC
|
||||
tristate "BRCM XGS iProc GPIO support"
|
||||
depends on OF_GPIO && (ARCH_BCM_IPROC || COMPILE_TEST)
|
||||
select GPIO_GENERIC
|
||||
select GPIOLIB_IRQCHIP
|
||||
default ARCH_BCM_IPROC
|
||||
help
|
||||
Say yes here to enable GPIO support for Broadcom XGS iProc SoCs.
|
||||
|
||||
config GPIO_BRCMSTB
|
||||
tristate "BRCMSTB GPIO support"
|
||||
default y if (ARCH_BRCMSTB || BMIPS_GENERIC)
|
||||
@ -435,6 +452,15 @@ config GPIO_RCAR
|
||||
help
|
||||
Say yes here to support GPIO on Renesas R-Car SoCs.
|
||||
|
||||
config GPIO_RDA
|
||||
bool "RDA Micro GPIO controller support"
|
||||
depends on ARCH_RDA || COMPILE_TEST
|
||||
depends on OF_GPIO
|
||||
select GPIO_GENERIC
|
||||
select GPIOLIB_IRQCHIP
|
||||
help
|
||||
Say Y here to support RDA Micro GPIO controller.
|
||||
|
||||
config GPIO_REG
|
||||
bool
|
||||
help
|
||||
@ -531,6 +557,7 @@ config GPIO_TEGRA186
|
||||
depends on ARCH_TEGRA_186_SOC || COMPILE_TEST
|
||||
depends on OF_GPIO
|
||||
select GPIOLIB_IRQCHIP
|
||||
select IRQ_DOMAIN_HIERARCHY
|
||||
help
|
||||
Say yes here to support GPIO pins on NVIDIA Tegra186 SoCs.
|
||||
|
||||
@ -1320,7 +1347,7 @@ config GPIO_BT8XX
|
||||
The card needs to be physically altered for using it as a
|
||||
GPIO card. For more information on how to build a GPIO card
|
||||
from a BT8xx TV card, see the documentation file at
|
||||
Documentation/driver-api/bt8xxgpio.rst
|
||||
Documentation/driver-api/gpio/bt8xxgpio.rst
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
|
@ -32,8 +32,10 @@ obj-$(CONFIG_GPIO_AMD_FCH) += gpio-amd-fch.o
|
||||
obj-$(CONFIG_GPIO_AMDPT) += gpio-amdpt.o
|
||||
obj-$(CONFIG_GPIO_ARIZONA) += gpio-arizona.o
|
||||
obj-$(CONFIG_GPIO_ASPEED) += gpio-aspeed.o
|
||||
obj-$(CONFIG_GPIO_ASPEED_SGPIO) += gpio-aspeed-sgpio.o
|
||||
obj-$(CONFIG_GPIO_ATH79) += gpio-ath79.o
|
||||
obj-$(CONFIG_GPIO_BCM_KONA) += gpio-bcm-kona.o
|
||||
obj-$(CONFIG_GPIO_BCM_XGS_IPROC) += gpio-xgs-iproc.o
|
||||
obj-$(CONFIG_GPIO_BD70528) += gpio-bd70528.o
|
||||
obj-$(CONFIG_GPIO_BD9571MWV) += gpio-bd9571mwv.o
|
||||
obj-$(CONFIG_GPIO_BRCMSTB) += gpio-brcmstb.o
|
||||
@ -115,6 +117,7 @@ obj-$(CONFIG_GPIO_PXA) += gpio-pxa.o
|
||||
obj-$(CONFIG_GPIO_RASPBERRYPI_EXP) += gpio-raspberrypi-exp.o
|
||||
obj-$(CONFIG_GPIO_RC5T583) += gpio-rc5t583.o
|
||||
obj-$(CONFIG_GPIO_RCAR) += gpio-rcar.o
|
||||
obj-$(CONFIG_GPIO_RDA) += gpio-rda.o
|
||||
obj-$(CONFIG_GPIO_RDC321X) += gpio-rdc321x.o
|
||||
obj-$(CONFIG_GPIO_REG) += gpio-reg.o
|
||||
obj-$(CONFIG_ARCH_SA1100) += gpio-sa1100.o
|
||||
|
@ -80,6 +80,10 @@ Work items:
|
||||
- Look over and identify any remaining easily converted drivers and
|
||||
dry-code conversions to MMIO GPIO for maintainers to test
|
||||
|
||||
- Expand the MMIO GPIO or write a new library for regmap-based I/O
|
||||
helpers for GPIO drivers on regmap that simply use offsets
|
||||
0..n in some register to drive GPIO lines
|
||||
|
||||
- Expand the MMIO GPIO or write a new library for port-mapped I/O
|
||||
helpers (x86 inb()/outb()) and convert port-mapped I/O drivers to use
|
||||
this with dry-coding and sending to maintainers to test
|
||||
|
@ -59,7 +59,10 @@ static int dio48e_gpio_get_direction(struct gpio_chip *chip, unsigned offset)
|
||||
const unsigned port = offset / 8;
|
||||
const unsigned mask = BIT(offset % 8);
|
||||
|
||||
return !!(dio48egpio->io_state[port] & mask);
|
||||
if (dio48egpio->io_state[port] & mask)
|
||||
return GPIO_LINE_DIRECTION_IN;
|
||||
|
||||
return GPIO_LINE_DIRECTION_OUT;
|
||||
}
|
||||
|
||||
static int dio48e_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
|
||||
|
@ -53,7 +53,7 @@ struct idi_48_gpio {
|
||||
|
||||
static int idi_48_gpio_get_direction(struct gpio_chip *chip, unsigned offset)
|
||||
{
|
||||
return 1;
|
||||
return GPIO_LINE_DIRECTION_IN;
|
||||
}
|
||||
|
||||
static int idi_48_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
|
||||
@ -65,7 +65,7 @@ static int idi_48_gpio_get(struct gpio_chip *chip, unsigned offset)
|
||||
{
|
||||
struct idi_48_gpio *const idi48gpio = gpiochip_get_data(chip);
|
||||
unsigned i;
|
||||
const unsigned register_offset[6] = { 0, 1, 2, 4, 5, 6 };
|
||||
static const unsigned int register_offset[6] = { 0, 1, 2, 4, 5, 6 };
|
||||
unsigned base_offset;
|
||||
unsigned mask;
|
||||
|
||||
|
@ -51,9 +51,9 @@ struct idio_16_gpio {
|
||||
static int idio_16_gpio_get_direction(struct gpio_chip *chip, unsigned offset)
|
||||
{
|
||||
if (offset > 15)
|
||||
return 1;
|
||||
return GPIO_LINE_DIRECTION_IN;
|
||||
|
||||
return 0;
|
||||
return GPIO_LINE_DIRECTION_OUT;
|
||||
}
|
||||
|
||||
static int idio_16_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
|
||||
|
@ -77,7 +77,10 @@ static int mmio_74xx_get_direction(struct gpio_chip *gc, unsigned offset)
|
||||
{
|
||||
struct mmio_74xx_gpio_priv *priv = gpiochip_get_data(gc);
|
||||
|
||||
return !(priv->flags & MMIO_74XX_DIR_OUT);
|
||||
if (priv->flags & MMIO_74XX_DIR_OUT)
|
||||
return GPIO_LINE_DIRECTION_OUT;
|
||||
|
||||
return GPIO_LINE_DIRECTION_IN;
|
||||
}
|
||||
|
||||
static int mmio_74xx_dir_in(struct gpio_chip *gc, unsigned int gpio)
|
||||
|
@ -92,7 +92,7 @@ static int amd_fch_gpio_get_direction(struct gpio_chip *gc, unsigned int gpio)
|
||||
ret = (readl_relaxed(ptr) & AMD_FCH_GPIO_FLAG_DIRECTION);
|
||||
spin_unlock_irqrestore(&priv->lock, flags);
|
||||
|
||||
return ret;
|
||||
return ret ? GPIO_LINE_DIRECTION_IN : GPIO_LINE_DIRECTION_OUT;
|
||||
}
|
||||
|
||||
static void amd_fch_gpio_set(struct gpio_chip *gc,
|
||||
|
@ -487,10 +487,10 @@ static int aspeed_gpio_get_direction(struct gpio_chip *gc, unsigned int offset)
|
||||
u32 val;
|
||||
|
||||
if (!have_input(gpio, offset))
|
||||
return 0;
|
||||
return GPIO_LINE_DIRECTION_OUT;
|
||||
|
||||
if (!have_output(gpio, offset))
|
||||
return 1;
|
||||
return GPIO_LINE_DIRECTION_IN;
|
||||
|
||||
spin_lock_irqsave(&gpio->lock, flags);
|
||||
|
||||
@ -498,8 +498,7 @@ static int aspeed_gpio_get_direction(struct gpio_chip *gc, unsigned int offset)
|
||||
|
||||
spin_unlock_irqrestore(&gpio->lock, flags);
|
||||
|
||||
return !val;
|
||||
|
||||
return val ? GPIO_LINE_DIRECTION_OUT : GPIO_LINE_DIRECTION_IN;
|
||||
}
|
||||
|
||||
static inline int irqd_to_aspeed_gpio_data(struct irq_data *d,
|
||||
|
@ -226,7 +226,6 @@ static int ath79_gpio_probe(struct platform_device *pdev)
|
||||
struct device_node *np = dev->of_node;
|
||||
struct ath79_gpio_ctrl *ctrl;
|
||||
struct gpio_irq_chip *girq;
|
||||
struct resource *res;
|
||||
u32 ath79_gpio_count;
|
||||
bool oe_inverted;
|
||||
int err;
|
||||
@ -256,12 +255,9 @@ static int ath79_gpio_probe(struct platform_device *pdev)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!res)
|
||||
return -EINVAL;
|
||||
ctrl->base = devm_ioremap_nocache(dev, res->start, resource_size(res));
|
||||
if (!ctrl->base)
|
||||
return -ENOMEM;
|
||||
ctrl->base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(ctrl->base))
|
||||
return PTR_ERR(ctrl->base);
|
||||
|
||||
raw_spin_lock_init(&ctrl->lock);
|
||||
err = bgpio_init(&ctrl->gc, dev, 4,
|
||||
|
@ -127,7 +127,7 @@ static int bcm_kona_gpio_get_dir(struct gpio_chip *chip, unsigned gpio)
|
||||
u32 val;
|
||||
|
||||
val = readl(reg_base + GPIO_CONTROL(gpio)) & GPIO_GPCTR0_IOTR_MASK;
|
||||
return !!val;
|
||||
return val ? GPIO_LINE_DIRECTION_IN : GPIO_LINE_DIRECTION_OUT;
|
||||
}
|
||||
|
||||
static void bcm_kona_gpio_set(struct gpio_chip *chip, unsigned gpio, int value)
|
||||
@ -144,7 +144,7 @@ static void bcm_kona_gpio_set(struct gpio_chip *chip, unsigned gpio, int value)
|
||||
raw_spin_lock_irqsave(&kona_gpio->lock, flags);
|
||||
|
||||
/* this function only applies to output pin */
|
||||
if (bcm_kona_gpio_get_dir(chip, gpio) == 1)
|
||||
if (bcm_kona_gpio_get_dir(chip, gpio) == GPIO_LINE_DIRECTION_IN)
|
||||
goto out;
|
||||
|
||||
reg_offset = value ? GPIO_OUT_SET(bank_id) : GPIO_OUT_CLEAR(bank_id);
|
||||
@ -170,7 +170,7 @@ static int bcm_kona_gpio_get(struct gpio_chip *chip, unsigned gpio)
|
||||
reg_base = kona_gpio->reg_base;
|
||||
raw_spin_lock_irqsave(&kona_gpio->lock, flags);
|
||||
|
||||
if (bcm_kona_gpio_get_dir(chip, gpio) == 1)
|
||||
if (bcm_kona_gpio_get_dir(chip, gpio) == GPIO_LINE_DIRECTION_IN)
|
||||
reg_offset = GPIO_IN_STATUS(bank_id);
|
||||
else
|
||||
reg_offset = GPIO_OUT_STATUS(bank_id);
|
||||
|
@ -54,8 +54,10 @@ static int bd70528_get_direction(struct gpio_chip *chip, unsigned int offset)
|
||||
dev_err(bdgpio->chip.dev, "Could not read gpio direction\n");
|
||||
return ret;
|
||||
}
|
||||
if (val & BD70528_GPIO_OUT_EN_MASK)
|
||||
return GPIO_LINE_DIRECTION_OUT;
|
||||
|
||||
return !(val & BD70528_GPIO_OUT_EN_MASK);
|
||||
return GPIO_LINE_DIRECTION_IN;
|
||||
}
|
||||
|
||||
static int bd70528_gpio_set_config(struct gpio_chip *chip, unsigned int offset,
|
||||
@ -166,9 +168,9 @@ static int bd70528_gpio_get(struct gpio_chip *chip, unsigned int offset)
|
||||
* locking would make no sense.
|
||||
*/
|
||||
ret = bd70528_get_direction(chip, offset);
|
||||
if (ret == 0)
|
||||
if (ret == GPIO_LINE_DIRECTION_OUT)
|
||||
ret = bd70528_gpio_get_o(bdgpio, offset);
|
||||
else if (ret == 1)
|
||||
else if (ret == GPIO_LINE_DIRECTION_IN)
|
||||
ret = bd70528_gpio_get_i(bdgpio, offset);
|
||||
else
|
||||
dev_err(bdgpio->chip.dev, "failed to read GPIO direction\n");
|
||||
@ -230,3 +232,4 @@ module_platform_driver(bd70528_gpio);
|
||||
MODULE_AUTHOR("Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>");
|
||||
MODULE_DESCRIPTION("BD70528 voltage regulator driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_ALIAS("platform:bd70528-gpio");
|
||||
|
@ -37,8 +37,10 @@ static int bd9571mwv_gpio_get_direction(struct gpio_chip *chip,
|
||||
ret = regmap_read(gpio->bd->regmap, BD9571MWV_GPIO_DIR, &val);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
if (val & BIT(offset))
|
||||
return GPIO_LINE_DIRECTION_IN;
|
||||
|
||||
return val & BIT(offset);
|
||||
return GPIO_LINE_DIRECTION_OUT;
|
||||
}
|
||||
|
||||
static int bd9571mwv_gpio_direction_input(struct gpio_chip *chip,
|
||||
|
@ -200,9 +200,9 @@ static int dln2_gpio_get_direction(struct gpio_chip *chip, unsigned offset)
|
||||
struct dln2_gpio *dln2 = gpiochip_get_data(chip);
|
||||
|
||||
if (test_bit(offset, dln2->output_enabled))
|
||||
return 0;
|
||||
return GPIO_LINE_DIRECTION_OUT;
|
||||
|
||||
return 1;
|
||||
return GPIO_LINE_DIRECTION_IN;
|
||||
}
|
||||
|
||||
static int dln2_gpio_get(struct gpio_chip *chip, unsigned int offset)
|
||||
@ -214,7 +214,7 @@ static int dln2_gpio_get(struct gpio_chip *chip, unsigned int offset)
|
||||
if (dir < 0)
|
||||
return dir;
|
||||
|
||||
if (dir == 1)
|
||||
if (dir == GPIO_LINE_DIRECTION_IN)
|
||||
return dln2_gpio_pin_get_in_val(dln2, offset);
|
||||
|
||||
return dln2_gpio_pin_get_out_val(dln2, offset);
|
||||
|
@ -269,13 +269,12 @@ static void em_gio_irq_domain_remove(void *data)
|
||||
static int em_gio_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct em_gio_priv *p;
|
||||
struct resource *io[2], *irq[2];
|
||||
struct gpio_chip *gpio_chip;
|
||||
struct irq_chip *irq_chip;
|
||||
struct device *dev = &pdev->dev;
|
||||
const char *name = dev_name(dev);
|
||||
unsigned int ngpios;
|
||||
int ret;
|
||||
int irq[2], ret;
|
||||
|
||||
p = devm_kzalloc(dev, sizeof(*p), GFP_KERNEL);
|
||||
if (!p)
|
||||
@ -285,25 +284,21 @@ static int em_gio_probe(struct platform_device *pdev)
|
||||
platform_set_drvdata(pdev, p);
|
||||
spin_lock_init(&p->sense_lock);
|
||||
|
||||
io[0] = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
io[1] = platform_get_resource(pdev, IORESOURCE_MEM, 1);
|
||||
irq[0] = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
|
||||
irq[1] = platform_get_resource(pdev, IORESOURCE_IRQ, 1);
|
||||
irq[0] = platform_get_irq(pdev, 0);
|
||||
if (irq[0] < 0)
|
||||
return irq[0];
|
||||
|
||||
if (!io[0] || !io[1] || !irq[0] || !irq[1]) {
|
||||
dev_err(dev, "missing IRQ or IOMEM\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
irq[1] = platform_get_irq(pdev, 1);
|
||||
if (irq[1] < 0)
|
||||
return irq[1];
|
||||
|
||||
p->base0 = devm_ioremap_nocache(dev, io[0]->start,
|
||||
resource_size(io[0]));
|
||||
if (!p->base0)
|
||||
return -ENOMEM;
|
||||
p->base0 = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(p->base0))
|
||||
return PTR_ERR(p->base0);
|
||||
|
||||
p->base1 = devm_ioremap_nocache(dev, io[1]->start,
|
||||
resource_size(io[1]));
|
||||
if (!p->base1)
|
||||
return -ENOMEM;
|
||||
p->base1 = devm_platform_ioremap_resource(pdev, 1);
|
||||
if (IS_ERR(p->base1))
|
||||
return PTR_ERR(p->base1);
|
||||
|
||||
if (of_property_read_u32(dev->of_node, "ngpios", &ngpios)) {
|
||||
dev_err(dev, "Missing ngpios OF property\n");
|
||||
@ -326,7 +321,7 @@ static int em_gio_probe(struct platform_device *pdev)
|
||||
gpio_chip->ngpio = ngpios;
|
||||
|
||||
irq_chip = &p->irq_chip;
|
||||
irq_chip->name = name;
|
||||
irq_chip->name = "gpio-em";
|
||||
irq_chip->irq_mask = em_gio_irq_disable;
|
||||
irq_chip->irq_unmask = em_gio_irq_enable;
|
||||
irq_chip->irq_set_type = em_gio_irq_set_type;
|
||||
@ -346,14 +341,12 @@ static int em_gio_probe(struct platform_device *pdev)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (devm_request_irq(dev, irq[0]->start,
|
||||
em_gio_irq_handler, 0, name, p)) {
|
||||
if (devm_request_irq(dev, irq[0], em_gio_irq_handler, 0, name, p)) {
|
||||
dev_err(dev, "failed to request low IRQ\n");
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
if (devm_request_irq(dev, irq[1]->start,
|
||||
em_gio_irq_handler, 0, name, p)) {
|
||||
if (devm_request_irq(dev, irq[1], em_gio_irq_handler, 0, name, p)) {
|
||||
dev_err(dev, "failed to request high IRQ\n");
|
||||
return -ENOENT;
|
||||
}
|
||||
|
@ -77,7 +77,10 @@ static int exar_get_direction(struct gpio_chip *chip, unsigned int offset)
|
||||
EXAR_OFFSET_MPIOSEL_HI : EXAR_OFFSET_MPIOSEL_LO;
|
||||
unsigned int bit = (offset + exar_gpio->first_pin) % 8;
|
||||
|
||||
return !!(exar_get(chip, addr) & BIT(bit));
|
||||
if (exar_get(chip, addr) & BIT(bit))
|
||||
return GPIO_LINE_DIRECTION_IN;
|
||||
|
||||
return GPIO_LINE_DIRECTION_OUT;
|
||||
}
|
||||
|
||||
static int exar_get_value(struct gpio_chip *chip, unsigned int offset)
|
||||
|
@ -250,7 +250,10 @@ static int f7188x_gpio_get_direction(struct gpio_chip *chip, unsigned offset)
|
||||
|
||||
superio_exit(sio->addr);
|
||||
|
||||
return !(dir & 1 << offset);
|
||||
if (dir & 1 << offset)
|
||||
return GPIO_LINE_DIRECTION_OUT;
|
||||
|
||||
return GPIO_LINE_DIRECTION_IN;
|
||||
}
|
||||
|
||||
static int f7188x_gpio_direction_in(struct gpio_chip *chip, unsigned offset)
|
||||
|
@ -52,7 +52,10 @@ static int gpiomm_gpio_get_direction(struct gpio_chip *chip,
|
||||
const unsigned int port = offset / 8;
|
||||
const unsigned int mask = BIT(offset % 8);
|
||||
|
||||
return !!(gpiommgpio->io_state[port] & mask);
|
||||
if (gpiommgpio->io_state[port] & mask)
|
||||
return GPIO_LINE_DIRECTION_IN;
|
||||
|
||||
return GPIO_LINE_DIRECTION_OUT;
|
||||
}
|
||||
|
||||
static int gpiomm_gpio_direction_input(struct gpio_chip *chip,
|
||||
|
@ -220,7 +220,10 @@ static int egpio_get_direction(struct gpio_chip *chip, unsigned offset)
|
||||
|
||||
egpio = gpiochip_get_data(chip);
|
||||
|
||||
return !test_bit(offset, &egpio->is_out);
|
||||
if (test_bit(offset, &egpio->is_out))
|
||||
return GPIO_LINE_DIRECTION_OUT;
|
||||
|
||||
return GPIO_LINE_DIRECTION_IN;
|
||||
}
|
||||
|
||||
static void egpio_write_cache(struct egpio_info *ei)
|
||||
@ -265,7 +268,6 @@ static int __init egpio_probe(struct platform_device *pdev)
|
||||
struct gpio_chip *chip;
|
||||
unsigned int irq, irq_end;
|
||||
int i;
|
||||
int ret;
|
||||
|
||||
/* Initialize ei data structure. */
|
||||
ei = devm_kzalloc(&pdev->dev, sizeof(*ei), GFP_KERNEL);
|
||||
@ -275,28 +277,24 @@ static int __init egpio_probe(struct platform_device *pdev)
|
||||
spin_lock_init(&ei->lock);
|
||||
|
||||
/* Find chained irq */
|
||||
ret = -EINVAL;
|
||||
res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
|
||||
if (res)
|
||||
ei->chained_irq = res->start;
|
||||
|
||||
/* Map egpio chip into virtual address space. */
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!res)
|
||||
goto fail;
|
||||
ei->base_addr = devm_ioremap_nocache(&pdev->dev, res->start,
|
||||
resource_size(res));
|
||||
if (!ei->base_addr)
|
||||
goto fail;
|
||||
pr_debug("EGPIO phys=%08x virt=%p\n", (u32)res->start, ei->base_addr);
|
||||
ei->base_addr = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(ei->base_addr))
|
||||
return PTR_ERR(ei->base_addr);
|
||||
|
||||
if ((pdata->bus_width != 16) && (pdata->bus_width != 32))
|
||||
goto fail;
|
||||
return -EINVAL;
|
||||
|
||||
ei->bus_shift = fls(pdata->bus_width - 1) - 3;
|
||||
pr_debug("bus_shift = %d\n", ei->bus_shift);
|
||||
|
||||
if ((pdata->reg_width != 8) && (pdata->reg_width != 16))
|
||||
goto fail;
|
||||
return -EINVAL;
|
||||
|
||||
ei->reg_shift = fls(pdata->reg_width - 1);
|
||||
pr_debug("reg_shift = %d\n", ei->reg_shift);
|
||||
|
||||
@ -308,10 +306,9 @@ static int __init egpio_probe(struct platform_device *pdev)
|
||||
ei->chip = devm_kcalloc(&pdev->dev,
|
||||
ei->nchips, sizeof(struct egpio_chip),
|
||||
GFP_KERNEL);
|
||||
if (!ei->chip) {
|
||||
ret = -ENOMEM;
|
||||
goto fail;
|
||||
}
|
||||
if (!ei->chip)
|
||||
return -ENOMEM;
|
||||
|
||||
for (i = 0; i < ei->nchips; i++) {
|
||||
ei->chip[i].reg_start = pdata->chip[i].reg_start;
|
||||
ei->chip[i].cached_values = pdata->chip[i].initial_values;
|
||||
@ -321,10 +318,9 @@ static int __init egpio_probe(struct platform_device *pdev)
|
||||
chip->label = devm_kasprintf(&pdev->dev, GFP_KERNEL,
|
||||
"htc-egpio-%d",
|
||||
i);
|
||||
if (!chip->label) {
|
||||
ret = -ENOMEM;
|
||||
goto fail;
|
||||
}
|
||||
if (!chip->label)
|
||||
return -ENOMEM;
|
||||
|
||||
chip->parent = &pdev->dev;
|
||||
chip->owner = THIS_MODULE;
|
||||
chip->get = egpio_get;
|
||||
@ -366,10 +362,6 @@ static int __init egpio_probe(struct platform_device *pdev)
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
printk(KERN_ERR "EGPIO failed to setup\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
|
@ -159,7 +159,10 @@ static bool ichx_gpio_check_available(struct gpio_chip *gpio, unsigned nr)
|
||||
|
||||
static int ichx_gpio_get_direction(struct gpio_chip *gpio, unsigned nr)
|
||||
{
|
||||
return ichx_read_bit(GPIO_IO_SEL, nr);
|
||||
if (ichx_read_bit(GPIO_IO_SEL, nr))
|
||||
return GPIO_LINE_DIRECTION_IN;
|
||||
|
||||
return GPIO_LINE_DIRECTION_OUT;
|
||||
}
|
||||
|
||||
static int ichx_gpio_direction_input(struct gpio_chip *gpio, unsigned nr)
|
||||
|
@ -104,7 +104,10 @@ static int kempld_gpio_get_direction(struct gpio_chip *chip, unsigned offset)
|
||||
struct kempld_gpio_data *gpio = gpiochip_get_data(chip);
|
||||
struct kempld_device_data *pld = gpio->pld;
|
||||
|
||||
return !kempld_gpio_get_bit(pld, KEMPLD_GPIO_DIR_NUM(offset), offset);
|
||||
if (kempld_gpio_get_bit(pld, KEMPLD_GPIO_DIR_NUM(offset), offset))
|
||||
return GPIO_LINE_DIRECTION_OUT;
|
||||
|
||||
return GPIO_LINE_DIRECTION_IN;
|
||||
}
|
||||
|
||||
static int kempld_gpio_pincount(struct kempld_device_data *pld)
|
||||
|
@ -33,7 +33,7 @@ static int lp873x_gpio_get_direction(struct gpio_chip *chip,
|
||||
unsigned int offset)
|
||||
{
|
||||
/* This device is output only */
|
||||
return 0;
|
||||
return GPIO_LINE_DIRECTION_OUT;
|
||||
}
|
||||
|
||||
static int lp873x_gpio_direction_input(struct gpio_chip *chip,
|
||||
|
@ -57,7 +57,10 @@ static int lp87565_gpio_get_direction(struct gpio_chip *chip,
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return !(val & BIT(offset));
|
||||
if (val & BIT(offset))
|
||||
return GPIO_LINE_DIRECTION_OUT;
|
||||
|
||||
return GPIO_LINE_DIRECTION_IN;
|
||||
}
|
||||
|
||||
static int lp87565_gpio_direction_input(struct gpio_chip *chip,
|
||||
|
@ -164,6 +164,12 @@ static int lp_irq_type(struct irq_data *d, unsigned type)
|
||||
value |= TRIG_SEL_BIT | INT_INV_BIT;
|
||||
|
||||
outl(value, reg);
|
||||
|
||||
if (type & IRQ_TYPE_EDGE_BOTH)
|
||||
irq_set_handler_locked(d, handle_edge_irq);
|
||||
else if (type & IRQ_TYPE_LEVEL_MASK)
|
||||
irq_set_handler_locked(d, handle_level_irq);
|
||||
|
||||
spin_unlock_irqrestore(&lg->lock, flags);
|
||||
|
||||
return 0;
|
||||
|
@ -34,7 +34,10 @@ static int madera_gpio_get_direction(struct gpio_chip *chip,
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return !!(val & MADERA_GP1_DIR_MASK);
|
||||
if (val & MADERA_GP1_DIR_MASK)
|
||||
return GPIO_LINE_DIRECTION_IN;
|
||||
|
||||
return GPIO_LINE_DIRECTION_OUT;
|
||||
}
|
||||
|
||||
static int madera_gpio_direction_in(struct gpio_chip *chip, unsigned int offset)
|
||||
|
@ -94,7 +94,7 @@ DECLARE_CRC8_TABLE(max3191x_crc8);
|
||||
|
||||
static int max3191x_get_direction(struct gpio_chip *gpio, unsigned int offset)
|
||||
{
|
||||
return 1; /* always in */
|
||||
return GPIO_LINE_DIRECTION_IN; /* always in */
|
||||
}
|
||||
|
||||
static int max3191x_direction_input(struct gpio_chip *gpio, unsigned int offset)
|
||||
|
@ -18,109 +18,115 @@ struct max77620_gpio {
|
||||
struct gpio_chip gpio_chip;
|
||||
struct regmap *rmap;
|
||||
struct device *dev;
|
||||
struct mutex buslock; /* irq_bus_lock */
|
||||
unsigned int irq_type[8];
|
||||
bool irq_enabled[8];
|
||||
};
|
||||
|
||||
static const struct regmap_irq max77620_gpio_irqs[] = {
|
||||
[0] = {
|
||||
.reg_offset = 0,
|
||||
.mask = MAX77620_IRQ_LVL2_GPIO_EDGE0,
|
||||
.type = {
|
||||
.type_rising_val = MAX77620_CNFG_GPIO_INT_RISING,
|
||||
.type_falling_val = MAX77620_CNFG_GPIO_INT_FALLING,
|
||||
.type_reg_mask = MAX77620_CNFG_GPIO_INT_MASK,
|
||||
.type_reg_offset = 0,
|
||||
.types_supported = IRQ_TYPE_EDGE_BOTH,
|
||||
},
|
||||
},
|
||||
[1] = {
|
||||
.reg_offset = 0,
|
||||
.mask = MAX77620_IRQ_LVL2_GPIO_EDGE1,
|
||||
.type = {
|
||||
.type_rising_val = MAX77620_CNFG_GPIO_INT_RISING,
|
||||
.type_falling_val = MAX77620_CNFG_GPIO_INT_FALLING,
|
||||
.type_reg_mask = MAX77620_CNFG_GPIO_INT_MASK,
|
||||
.type_reg_offset = 1,
|
||||
.types_supported = IRQ_TYPE_EDGE_BOTH,
|
||||
},
|
||||
},
|
||||
[2] = {
|
||||
.reg_offset = 0,
|
||||
.mask = MAX77620_IRQ_LVL2_GPIO_EDGE2,
|
||||
.type = {
|
||||
.type_rising_val = MAX77620_CNFG_GPIO_INT_RISING,
|
||||
.type_falling_val = MAX77620_CNFG_GPIO_INT_FALLING,
|
||||
.type_reg_mask = MAX77620_CNFG_GPIO_INT_MASK,
|
||||
.type_reg_offset = 2,
|
||||
.types_supported = IRQ_TYPE_EDGE_BOTH,
|
||||
},
|
||||
},
|
||||
[3] = {
|
||||
.reg_offset = 0,
|
||||
.mask = MAX77620_IRQ_LVL2_GPIO_EDGE3,
|
||||
.type = {
|
||||
.type_rising_val = MAX77620_CNFG_GPIO_INT_RISING,
|
||||
.type_falling_val = MAX77620_CNFG_GPIO_INT_FALLING,
|
||||
.type_reg_mask = MAX77620_CNFG_GPIO_INT_MASK,
|
||||
.type_reg_offset = 3,
|
||||
.types_supported = IRQ_TYPE_EDGE_BOTH,
|
||||
},
|
||||
},
|
||||
[4] = {
|
||||
.reg_offset = 0,
|
||||
.mask = MAX77620_IRQ_LVL2_GPIO_EDGE4,
|
||||
.type = {
|
||||
.type_rising_val = MAX77620_CNFG_GPIO_INT_RISING,
|
||||
.type_falling_val = MAX77620_CNFG_GPIO_INT_FALLING,
|
||||
.type_reg_mask = MAX77620_CNFG_GPIO_INT_MASK,
|
||||
.type_reg_offset = 4,
|
||||
.types_supported = IRQ_TYPE_EDGE_BOTH,
|
||||
},
|
||||
},
|
||||
[5] = {
|
||||
.reg_offset = 0,
|
||||
.mask = MAX77620_IRQ_LVL2_GPIO_EDGE5,
|
||||
.type = {
|
||||
.type_rising_val = MAX77620_CNFG_GPIO_INT_RISING,
|
||||
.type_falling_val = MAX77620_CNFG_GPIO_INT_FALLING,
|
||||
.type_reg_mask = MAX77620_CNFG_GPIO_INT_MASK,
|
||||
.type_reg_offset = 5,
|
||||
.types_supported = IRQ_TYPE_EDGE_BOTH,
|
||||
},
|
||||
},
|
||||
[6] = {
|
||||
.reg_offset = 0,
|
||||
.mask = MAX77620_IRQ_LVL2_GPIO_EDGE6,
|
||||
.type = {
|
||||
.type_rising_val = MAX77620_CNFG_GPIO_INT_RISING,
|
||||
.type_falling_val = MAX77620_CNFG_GPIO_INT_FALLING,
|
||||
.type_reg_mask = MAX77620_CNFG_GPIO_INT_MASK,
|
||||
.type_reg_offset = 6,
|
||||
.types_supported = IRQ_TYPE_EDGE_BOTH,
|
||||
},
|
||||
},
|
||||
[7] = {
|
||||
.reg_offset = 0,
|
||||
.mask = MAX77620_IRQ_LVL2_GPIO_EDGE7,
|
||||
.type = {
|
||||
.type_rising_val = MAX77620_CNFG_GPIO_INT_RISING,
|
||||
.type_falling_val = MAX77620_CNFG_GPIO_INT_FALLING,
|
||||
.type_reg_mask = MAX77620_CNFG_GPIO_INT_MASK,
|
||||
.type_reg_offset = 7,
|
||||
.types_supported = IRQ_TYPE_EDGE_BOTH,
|
||||
},
|
||||
},
|
||||
};
|
||||
static irqreturn_t max77620_gpio_irqhandler(int irq, void *data)
|
||||
{
|
||||
struct max77620_gpio *gpio = data;
|
||||
unsigned int value, offset;
|
||||
unsigned long pending;
|
||||
int err;
|
||||
|
||||
static const struct regmap_irq_chip max77620_gpio_irq_chip = {
|
||||
.name = "max77620-gpio",
|
||||
.irqs = max77620_gpio_irqs,
|
||||
.num_irqs = ARRAY_SIZE(max77620_gpio_irqs),
|
||||
.num_regs = 1,
|
||||
.num_type_reg = 8,
|
||||
.irq_reg_stride = 1,
|
||||
.type_reg_stride = 1,
|
||||
.status_base = MAX77620_REG_IRQ_LVL2_GPIO,
|
||||
.type_base = MAX77620_REG_GPIO0,
|
||||
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",
|
||||
.irq_mask = max77620_gpio_irq_mask,
|
||||
.irq_unmask = max77620_gpio_irq_unmask,
|
||||
.irq_set_type = max77620_gpio_set_irq_type,
|
||||
.irq_bus_lock = max77620_gpio_bus_lock,
|
||||
.irq_bus_sync_unlock = max77620_gpio_bus_sync_unlock,
|
||||
.flags = IRQCHIP_MASK_ON_SUSPEND,
|
||||
};
|
||||
|
||||
static int max77620_gpio_dir_input(struct gpio_chip *gc, unsigned int offset)
|
||||
@ -254,14 +260,6 @@ static int max77620_gpio_set_config(struct gpio_chip *gc, unsigned int offset,
|
||||
return -ENOTSUPP;
|
||||
}
|
||||
|
||||
static int max77620_gpio_to_irq(struct gpio_chip *gc, unsigned int offset)
|
||||
{
|
||||
struct max77620_gpio *mgpio = gpiochip_get_data(gc);
|
||||
struct max77620_chip *chip = dev_get_drvdata(mgpio->dev->parent);
|
||||
|
||||
return regmap_irq_get_virq(chip->gpio_irq_data, offset);
|
||||
}
|
||||
|
||||
static int max77620_gpio_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct max77620_chip *chip = dev_get_drvdata(pdev->dev.parent);
|
||||
@ -287,7 +285,6 @@ static int max77620_gpio_probe(struct platform_device *pdev)
|
||||
mgpio->gpio_chip.direction_output = max77620_gpio_dir_output;
|
||||
mgpio->gpio_chip.set = max77620_gpio_set;
|
||||
mgpio->gpio_chip.set_config = max77620_gpio_set_config;
|
||||
mgpio->gpio_chip.to_irq = max77620_gpio_to_irq;
|
||||
mgpio->gpio_chip.ngpio = MAX77620_GPIO_NR;
|
||||
mgpio->gpio_chip.can_sleep = 1;
|
||||
mgpio->gpio_chip.base = -1;
|
||||
@ -303,15 +300,21 @@ static int max77620_gpio_probe(struct platform_device *pdev)
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = devm_regmap_add_irq_chip(&pdev->dev, chip->rmap, gpio_irq,
|
||||
IRQF_ONESHOT, -1,
|
||||
&max77620_gpio_irq_chip,
|
||||
&chip->gpio_irq_data);
|
||||
mutex_init(&mgpio->buslock);
|
||||
|
||||
gpiochip_irqchip_add_nested(&mgpio->gpio_chip, &max77620_gpio_irqchip,
|
||||
0, handle_edge_irq, IRQ_TYPE_NONE);
|
||||
|
||||
ret = request_threaded_irq(gpio_irq, NULL, max77620_gpio_irqhandler,
|
||||
IRQF_ONESHOT, "max77620-gpio", mgpio);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "Failed to add gpio irq_chip %d\n", ret);
|
||||
dev_err(&pdev->dev, "failed to request IRQ: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
gpiochip_set_nested_irqchip(&mgpio->gpio_chip, &max77620_gpio_irqchip,
|
||||
gpio_irq);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -162,7 +162,10 @@ static int mrfld_gpio_get_direction(struct gpio_chip *chip, unsigned int offset)
|
||||
{
|
||||
void __iomem *gpdr = gpio_reg(chip, offset, GPDR);
|
||||
|
||||
return !(readl(gpdr) & BIT(offset % 32));
|
||||
if (readl(gpdr) & BIT(offset % 32))
|
||||
return GPIO_LINE_DIRECTION_OUT;
|
||||
|
||||
return GPIO_LINE_DIRECTION_IN;
|
||||
}
|
||||
|
||||
static int mrfld_gpio_set_debounce(struct gpio_chip *chip, unsigned int offset,
|
||||
@ -362,8 +365,9 @@ static void mrfld_irq_handler(struct irq_desc *desc)
|
||||
chained_irq_exit(irqchip, desc);
|
||||
}
|
||||
|
||||
static void mrfld_irq_init_hw(struct mrfld_gpio *priv)
|
||||
static int mrfld_irq_init_hw(struct gpio_chip *chip)
|
||||
{
|
||||
struct mrfld_gpio *priv = gpiochip_get_data(chip);
|
||||
void __iomem *reg;
|
||||
unsigned int base;
|
||||
|
||||
@ -375,6 +379,8 @@ static void mrfld_irq_init_hw(struct mrfld_gpio *priv)
|
||||
reg = gpio_reg(&priv->chip, base, GFER);
|
||||
writel(0, reg);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const char *mrfld_gpio_get_pinctrl_dev_name(struct mrfld_gpio *priv)
|
||||
@ -393,14 +399,36 @@ static const char *mrfld_gpio_get_pinctrl_dev_name(struct mrfld_gpio *priv)
|
||||
return name;
|
||||
}
|
||||
|
||||
static int mrfld_gpio_probe(struct pci_dev *pdev, const struct pci_device_id *id)
|
||||
static int mrfld_gpio_add_pin_ranges(struct gpio_chip *chip)
|
||||
{
|
||||
struct mrfld_gpio *priv = gpiochip_get_data(chip);
|
||||
const struct mrfld_gpio_pinrange *range;
|
||||
const char *pinctrl_dev_name;
|
||||
unsigned int i;
|
||||
int retval;
|
||||
|
||||
pinctrl_dev_name = mrfld_gpio_get_pinctrl_dev_name(priv);
|
||||
for (i = 0; i < ARRAY_SIZE(mrfld_gpio_ranges); i++) {
|
||||
range = &mrfld_gpio_ranges[i];
|
||||
retval = gpiochip_add_pin_range(&priv->chip, pinctrl_dev_name,
|
||||
range->gpio_base,
|
||||
range->pin_base,
|
||||
range->npins);
|
||||
if (retval) {
|
||||
dev_err(priv->dev, "failed to add GPIO pin range\n");
|
||||
return retval;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mrfld_gpio_probe(struct pci_dev *pdev, const struct pci_device_id *id)
|
||||
{
|
||||
struct gpio_irq_chip *girq;
|
||||
struct mrfld_gpio *priv;
|
||||
u32 gpio_base, irq_base;
|
||||
void __iomem *base;
|
||||
unsigned int i;
|
||||
int retval;
|
||||
|
||||
retval = pcim_enable_device(pdev);
|
||||
@ -441,42 +469,31 @@ static int mrfld_gpio_probe(struct pci_dev *pdev, const struct pci_device_id *id
|
||||
priv->chip.base = gpio_base;
|
||||
priv->chip.ngpio = MRFLD_NGPIO;
|
||||
priv->chip.can_sleep = false;
|
||||
priv->chip.add_pin_ranges = mrfld_gpio_add_pin_ranges;
|
||||
|
||||
raw_spin_lock_init(&priv->lock);
|
||||
|
||||
pci_set_drvdata(pdev, priv);
|
||||
girq = &priv->chip.irq;
|
||||
girq->chip = &mrfld_irqchip;
|
||||
girq->init_hw = mrfld_irq_init_hw;
|
||||
girq->parent_handler = mrfld_irq_handler;
|
||||
girq->num_parents = 1;
|
||||
girq->parents = devm_kcalloc(&pdev->dev, girq->num_parents,
|
||||
sizeof(*girq->parents), GFP_KERNEL);
|
||||
if (!girq->parents)
|
||||
return -ENOMEM;
|
||||
girq->parents[0] = pdev->irq;
|
||||
girq->first = irq_base;
|
||||
girq->default_type = IRQ_TYPE_NONE;
|
||||
girq->handler = handle_bad_irq;
|
||||
|
||||
retval = devm_gpiochip_add_data(&pdev->dev, &priv->chip, priv);
|
||||
if (retval) {
|
||||
dev_err(&pdev->dev, "gpiochip_add error %d\n", retval);
|
||||
return retval;
|
||||
}
|
||||
|
||||
pinctrl_dev_name = mrfld_gpio_get_pinctrl_dev_name(priv);
|
||||
for (i = 0; i < ARRAY_SIZE(mrfld_gpio_ranges); i++) {
|
||||
range = &mrfld_gpio_ranges[i];
|
||||
retval = gpiochip_add_pin_range(&priv->chip,
|
||||
pinctrl_dev_name,
|
||||
range->gpio_base,
|
||||
range->pin_base,
|
||||
range->npins);
|
||||
if (retval) {
|
||||
dev_err(&pdev->dev, "failed to add GPIO pin range\n");
|
||||
return retval;
|
||||
}
|
||||
}
|
||||
|
||||
retval = gpiochip_irqchip_add(&priv->chip, &mrfld_irqchip, irq_base,
|
||||
handle_bad_irq, IRQ_TYPE_NONE);
|
||||
if (retval) {
|
||||
dev_err(&pdev->dev, "could not connect irqchip to gpiochip\n");
|
||||
return retval;
|
||||
}
|
||||
|
||||
mrfld_irq_init_hw(priv);
|
||||
|
||||
gpiochip_set_chained_irqchip(&priv->chip, &mrfld_irqchip, pdev->irq,
|
||||
mrfld_irq_handler);
|
||||
|
||||
pci_set_drvdata(pdev, priv);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -370,15 +370,23 @@ static int bgpio_dir_in(struct gpio_chip *gc, unsigned int gpio)
|
||||
static int bgpio_get_dir(struct gpio_chip *gc, unsigned int gpio)
|
||||
{
|
||||
/* Return 0 if output, 1 if input */
|
||||
if (gc->bgpio_dir_unreadable)
|
||||
return !(gc->bgpio_dir & bgpio_line2mask(gc, gpio));
|
||||
if (gc->reg_dir_out)
|
||||
return !(gc->read_reg(gc->reg_dir_out) & bgpio_line2mask(gc, gpio));
|
||||
if (gc->reg_dir_in)
|
||||
return !!(gc->read_reg(gc->reg_dir_in) & bgpio_line2mask(gc, gpio));
|
||||
if (gc->bgpio_dir_unreadable) {
|
||||
if (gc->bgpio_dir & bgpio_line2mask(gc, gpio))
|
||||
return GPIO_LINE_DIRECTION_OUT;
|
||||
return GPIO_LINE_DIRECTION_IN;
|
||||
}
|
||||
|
||||
/* This should not happen */
|
||||
return 1;
|
||||
if (gc->reg_dir_out) {
|
||||
if (gc->read_reg(gc->reg_dir_out) & bgpio_line2mask(gc, gpio))
|
||||
return GPIO_LINE_DIRECTION_OUT;
|
||||
return GPIO_LINE_DIRECTION_IN;
|
||||
}
|
||||
|
||||
if (gc->reg_dir_in)
|
||||
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)
|
||||
|
@ -34,14 +34,9 @@
|
||||
|
||||
#define gpio_mockup_err(...) pr_err(GPIO_MOCKUP_NAME ": " __VA_ARGS__)
|
||||
|
||||
enum {
|
||||
GPIO_MOCKUP_DIR_IN = 0,
|
||||
GPIO_MOCKUP_DIR_OUT = 1,
|
||||
};
|
||||
|
||||
/*
|
||||
* struct gpio_pin_status - structure describing a GPIO status
|
||||
* @dir: Configures direction of gpio as "in" or "out", 0=in, 1=out
|
||||
* @dir: Configures direction of gpio as "in" or "out"
|
||||
* @value: Configures status of the gpio as 0(low) or 1(high)
|
||||
*/
|
||||
struct gpio_mockup_line_status {
|
||||
@ -146,13 +141,68 @@ static void gpio_mockup_set_multiple(struct gpio_chip *gc,
|
||||
mutex_unlock(&chip->lock);
|
||||
}
|
||||
|
||||
static int gpio_mockup_apply_pull(struct gpio_mockup_chip *chip,
|
||||
unsigned int offset, int value)
|
||||
{
|
||||
struct gpio_desc *desc;
|
||||
struct gpio_chip *gc;
|
||||
struct irq_sim *sim;
|
||||
int curr, irq, irq_type;
|
||||
|
||||
gc = &chip->gc;
|
||||
desc = &gc->gpiodev->descs[offset];
|
||||
sim = &chip->irqsim;
|
||||
|
||||
mutex_lock(&chip->lock);
|
||||
|
||||
if (test_bit(FLAG_REQUESTED, &desc->flags) &&
|
||||
!test_bit(FLAG_IS_OUT, &desc->flags)) {
|
||||
curr = __gpio_mockup_get(chip, offset);
|
||||
if (curr == value)
|
||||
goto out;
|
||||
|
||||
irq = irq_sim_irqnum(sim, offset);
|
||||
irq_type = irq_get_trigger_type(irq);
|
||||
|
||||
if ((value == 1 && (irq_type & IRQ_TYPE_EDGE_RISING)) ||
|
||||
(value == 0 && (irq_type & IRQ_TYPE_EDGE_FALLING)))
|
||||
irq_sim_fire(sim, offset);
|
||||
}
|
||||
|
||||
/* Change the value unless we're actively driving the line. */
|
||||
if (!test_bit(FLAG_REQUESTED, &desc->flags) ||
|
||||
!test_bit(FLAG_IS_OUT, &desc->flags))
|
||||
__gpio_mockup_set(chip, offset, value);
|
||||
|
||||
out:
|
||||
chip->lines[offset].pull = value;
|
||||
mutex_unlock(&chip->lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gpio_mockup_set_config(struct gpio_chip *gc,
|
||||
unsigned int offset, unsigned long config)
|
||||
{
|
||||
struct gpio_mockup_chip *chip = gpiochip_get_data(gc);
|
||||
|
||||
switch (pinconf_to_config_param(config)) {
|
||||
case PIN_CONFIG_BIAS_PULL_UP:
|
||||
return gpio_mockup_apply_pull(chip, offset, 1);
|
||||
case PIN_CONFIG_BIAS_PULL_DOWN:
|
||||
return gpio_mockup_apply_pull(chip, offset, 0);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return -ENOTSUPP;
|
||||
}
|
||||
|
||||
static int gpio_mockup_dirout(struct gpio_chip *gc,
|
||||
unsigned int offset, int value)
|
||||
{
|
||||
struct gpio_mockup_chip *chip = gpiochip_get_data(gc);
|
||||
|
||||
mutex_lock(&chip->lock);
|
||||
chip->lines[offset].dir = GPIO_MOCKUP_DIR_OUT;
|
||||
chip->lines[offset].dir = GPIO_LINE_DIRECTION_OUT;
|
||||
__gpio_mockup_set(chip, offset, value);
|
||||
mutex_unlock(&chip->lock);
|
||||
|
||||
@ -164,7 +214,7 @@ static int gpio_mockup_dirin(struct gpio_chip *gc, unsigned int offset)
|
||||
struct gpio_mockup_chip *chip = gpiochip_get_data(gc);
|
||||
|
||||
mutex_lock(&chip->lock);
|
||||
chip->lines[offset].dir = GPIO_MOCKUP_DIR_IN;
|
||||
chip->lines[offset].dir = GPIO_LINE_DIRECTION_IN;
|
||||
mutex_unlock(&chip->lock);
|
||||
|
||||
return 0;
|
||||
@ -226,12 +276,8 @@ static ssize_t gpio_mockup_debugfs_write(struct file *file,
|
||||
size_t size, loff_t *ppos)
|
||||
{
|
||||
struct gpio_mockup_dbgfs_private *priv;
|
||||
int rv, val, curr, irq, irq_type;
|
||||
struct gpio_mockup_chip *chip;
|
||||
int rv, val;
|
||||
struct seq_file *sfile;
|
||||
struct gpio_desc *desc;
|
||||
struct gpio_chip *gc;
|
||||
struct irq_sim *sim;
|
||||
|
||||
if (*ppos != 0)
|
||||
return -EINVAL;
|
||||
@ -244,35 +290,9 @@ static ssize_t gpio_mockup_debugfs_write(struct file *file,
|
||||
|
||||
sfile = file->private_data;
|
||||
priv = sfile->private;
|
||||
chip = priv->chip;
|
||||
gc = &chip->gc;
|
||||
desc = &gc->gpiodev->descs[priv->offset];
|
||||
sim = &chip->irqsim;
|
||||
|
||||
mutex_lock(&chip->lock);
|
||||
|
||||
if (test_bit(FLAG_REQUESTED, &desc->flags) &&
|
||||
!test_bit(FLAG_IS_OUT, &desc->flags)) {
|
||||
curr = __gpio_mockup_get(chip, priv->offset);
|
||||
if (curr == val)
|
||||
goto out;
|
||||
|
||||
irq = irq_sim_irqnum(sim, priv->offset);
|
||||
irq_type = irq_get_trigger_type(irq);
|
||||
|
||||
if ((val == 1 && (irq_type & IRQ_TYPE_EDGE_RISING)) ||
|
||||
(val == 0 && (irq_type & IRQ_TYPE_EDGE_FALLING)))
|
||||
irq_sim_fire(sim, priv->offset);
|
||||
}
|
||||
|
||||
/* Change the value unless we're actively driving the line. */
|
||||
if (!test_bit(FLAG_REQUESTED, &desc->flags) ||
|
||||
!test_bit(FLAG_IS_OUT, &desc->flags))
|
||||
__gpio_mockup_set(chip, priv->offset, val);
|
||||
|
||||
out:
|
||||
chip->lines[priv->offset].pull = val;
|
||||
mutex_unlock(&chip->lock);
|
||||
rv = gpio_mockup_apply_pull(priv->chip, priv->offset, val);
|
||||
if (rv)
|
||||
return rv;
|
||||
|
||||
return size;
|
||||
}
|
||||
@ -418,6 +438,7 @@ static int gpio_mockup_probe(struct platform_device *pdev)
|
||||
gc->direction_output = gpio_mockup_dirout;
|
||||
gc->direction_input = gpio_mockup_dirin;
|
||||
gc->get_direction = gpio_mockup_get_direction;
|
||||
gc->set_config = gpio_mockup_set_config;
|
||||
gc->to_irq = gpio_mockup_to_irq;
|
||||
gc->free = gpio_mockup_free;
|
||||
|
||||
|
@ -78,9 +78,9 @@ static int moxtet_gpio_get_direction(struct gpio_chip *gc, unsigned int offset)
|
||||
|
||||
/* All lines are hard wired to be either input or output, not both. */
|
||||
if (chip->desc->in_mask & BIT(offset))
|
||||
return 1;
|
||||
return GPIO_LINE_DIRECTION_IN;
|
||||
else if (chip->desc->out_mask & BIT(offset))
|
||||
return 0;
|
||||
return GPIO_LINE_DIRECTION_OUT;
|
||||
else
|
||||
return -EINVAL;
|
||||
}
|
||||
|
@ -22,6 +22,7 @@
|
||||
#include <linux/irq.h>
|
||||
#include <linux/gpio/driver.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/interrupt.h>
|
||||
|
||||
#define MPC8XXX_GPIO_PINS 32
|
||||
|
||||
@ -127,20 +128,19 @@ static int mpc8xxx_gpio_to_irq(struct gpio_chip *gc, unsigned offset)
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
static void mpc8xxx_gpio_irq_cascade(struct irq_desc *desc)
|
||||
static irqreturn_t mpc8xxx_gpio_irq_cascade(int irq, void *data)
|
||||
{
|
||||
struct mpc8xxx_gpio_chip *mpc8xxx_gc = irq_desc_get_handler_data(desc);
|
||||
struct irq_chip *chip = irq_desc_get_chip(desc);
|
||||
struct mpc8xxx_gpio_chip *mpc8xxx_gc = data;
|
||||
struct gpio_chip *gc = &mpc8xxx_gc->gc;
|
||||
unsigned int mask;
|
||||
unsigned long mask;
|
||||
int i;
|
||||
|
||||
mask = gc->read_reg(mpc8xxx_gc->regs + GPIO_IER)
|
||||
& gc->read_reg(mpc8xxx_gc->regs + GPIO_IMR);
|
||||
if (mask)
|
||||
generic_handle_irq(irq_linear_revmap(mpc8xxx_gc->irq,
|
||||
32 - ffs(mask)));
|
||||
if (chip->irq_eoi)
|
||||
chip->irq_eoi(&desc->irq_data);
|
||||
for_each_set_bit(i, &mask, 32)
|
||||
generic_handle_irq(irq_linear_revmap(mpc8xxx_gc->irq, 31 - i));
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static void mpc8xxx_irq_unmask(struct irq_data *d)
|
||||
@ -377,7 +377,8 @@ static int mpc8xxx_probe(struct platform_device *pdev)
|
||||
* It's assumed that only a single type of gpio controller is available
|
||||
* on the current machine, so overwriting global data is fine.
|
||||
*/
|
||||
mpc8xxx_irq_chip.irq_set_type = devtype->irq_set_type;
|
||||
if (devtype->irq_set_type)
|
||||
mpc8xxx_irq_chip.irq_set_type = devtype->irq_set_type;
|
||||
|
||||
if (devtype->gpio_dir_out)
|
||||
gc->direction_output = devtype->gpio_dir_out;
|
||||
@ -386,6 +387,9 @@ static int mpc8xxx_probe(struct platform_device *pdev)
|
||||
|
||||
gc->to_irq = mpc8xxx_gpio_to_irq;
|
||||
|
||||
if (of_device_is_compatible(np, "fsl,qoriq-gpio"))
|
||||
gc->write_reg(mpc8xxx_gc->regs + GPIO_IBE, 0xffffffff);
|
||||
|
||||
ret = gpiochip_add_data(gc, mpc8xxx_gc);
|
||||
if (ret) {
|
||||
pr_err("%pOF: GPIO chip registration failed with status %d\n",
|
||||
@ -409,8 +413,16 @@ static int mpc8xxx_probe(struct platform_device *pdev)
|
||||
if (devtype->gpio_dir_in_init)
|
||||
devtype->gpio_dir_in_init(gc);
|
||||
|
||||
irq_set_chained_handler_and_data(mpc8xxx_gc->irqn,
|
||||
mpc8xxx_gpio_irq_cascade, mpc8xxx_gc);
|
||||
ret = devm_request_irq(&pdev->dev, mpc8xxx_gc->irqn,
|
||||
mpc8xxx_gpio_irq_cascade,
|
||||
IRQF_NO_THREAD | IRQF_SHARED, "gpio-cascade",
|
||||
mpc8xxx_gc);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "%s: failed to devm_request_irq(%d), ret = %d\n",
|
||||
np->full_name, mpc8xxx_gc->irqn, ret);
|
||||
goto err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
err:
|
||||
iounmap(mpc8xxx_gc->regs);
|
||||
|
@ -384,7 +384,10 @@ static int mvebu_gpio_get_direction(struct gpio_chip *chip, unsigned int pin)
|
||||
|
||||
regmap_read(mvchip->regs, GPIO_IO_CONF_OFF + mvchip->offset, &u);
|
||||
|
||||
return !!(u & BIT(pin));
|
||||
if (u & BIT(pin))
|
||||
return GPIO_LINE_DIRECTION_IN;
|
||||
|
||||
return GPIO_LINE_DIRECTION_OUT;
|
||||
}
|
||||
|
||||
static int mvebu_gpio_to_irq(struct gpio_chip *chip, unsigned int pin)
|
||||
|
@ -411,6 +411,7 @@ static int mxc_gpio_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
struct mxc_gpio_port *port;
|
||||
int irq_count;
|
||||
int irq_base;
|
||||
int err;
|
||||
|
||||
@ -426,9 +427,15 @@ static int mxc_gpio_probe(struct platform_device *pdev)
|
||||
if (IS_ERR(port->base))
|
||||
return PTR_ERR(port->base);
|
||||
|
||||
port->irq_high = platform_get_irq(pdev, 1);
|
||||
if (port->irq_high < 0)
|
||||
port->irq_high = 0;
|
||||
irq_count = platform_irq_count(pdev);
|
||||
if (irq_count < 0)
|
||||
return irq_count;
|
||||
|
||||
if (irq_count > 1) {
|
||||
port->irq_high = platform_get_irq(pdev, 1);
|
||||
if (port->irq_high < 0)
|
||||
port->irq_high = 0;
|
||||
}
|
||||
|
||||
port->irq = platform_get_irq(pdev, 0);
|
||||
if (port->irq < 0)
|
||||
|
@ -248,7 +248,10 @@ static int mxs_gpio_get_direction(struct gpio_chip *gc, unsigned offset)
|
||||
u32 dir;
|
||||
|
||||
dir = readl(port->base + PINCTRL_DOE(port));
|
||||
return !(dir & mask);
|
||||
if (dir & mask)
|
||||
return GPIO_LINE_DIRECTION_OUT;
|
||||
|
||||
return GPIO_LINE_DIRECTION_IN;
|
||||
}
|
||||
|
||||
static const struct platform_device_id mxs_gpio_ids[] = {
|
||||
|
@ -805,8 +805,10 @@ static int omap_gpio_get_direction(struct gpio_chip *chip, unsigned offset)
|
||||
{
|
||||
struct gpio_bank *bank = gpiochip_get_data(chip);
|
||||
|
||||
return !!(readl_relaxed(bank->base + bank->regs->direction) &
|
||||
BIT(offset));
|
||||
if (readl_relaxed(bank->base + bank->regs->direction) & BIT(offset))
|
||||
return GPIO_LINE_DIRECTION_IN;
|
||||
|
||||
return GPIO_LINE_DIRECTION_OUT;
|
||||
}
|
||||
|
||||
static int omap_gpio_input(struct gpio_chip *chip, unsigned offset)
|
||||
|
@ -449,7 +449,10 @@ static int pca953x_gpio_get_direction(struct gpio_chip *gc, unsigned off)
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return !!(reg_val & bit);
|
||||
if (reg_val & bit)
|
||||
return GPIO_LINE_DIRECTION_IN;
|
||||
|
||||
return GPIO_LINE_DIRECTION_OUT;
|
||||
}
|
||||
|
||||
static void pca953x_gpio_set_multiple(struct gpio_chip *gc,
|
||||
|
@ -61,9 +61,9 @@ static int idio_16_gpio_get_direction(struct gpio_chip *chip,
|
||||
unsigned int offset)
|
||||
{
|
||||
if (offset > 15)
|
||||
return 1;
|
||||
return GPIO_LINE_DIRECTION_IN;
|
||||
|
||||
return 0;
|
||||
return GPIO_LINE_DIRECTION_OUT;
|
||||
}
|
||||
|
||||
static int idio_16_gpio_direction_input(struct gpio_chip *chip,
|
||||
|
@ -104,15 +104,18 @@ static int idio_24_gpio_get_direction(struct gpio_chip *chip,
|
||||
|
||||
/* FET Outputs */
|
||||
if (offset < 24)
|
||||
return 0;
|
||||
return GPIO_LINE_DIRECTION_OUT;
|
||||
|
||||
/* Isolated Inputs */
|
||||
if (offset < 48)
|
||||
return 1;
|
||||
return GPIO_LINE_DIRECTION_IN;
|
||||
|
||||
/* TTL/CMOS I/O */
|
||||
/* OUT MODE = 1 when TTL/CMOS Output Mode is set */
|
||||
return !(ioread8(&idio24gpio->reg->ctl) & out_mode_mask);
|
||||
if (ioread8(&idio24gpio->reg->ctl) & out_mode_mask)
|
||||
return GPIO_LINE_DIRECTION_OUT;
|
||||
|
||||
return GPIO_LINE_DIRECTION_IN;
|
||||
}
|
||||
|
||||
static int idio_24_gpio_direction_input(struct gpio_chip *chip,
|
||||
|
@ -65,7 +65,7 @@ static int pisosr_gpio_get_direction(struct gpio_chip *chip,
|
||||
unsigned offset)
|
||||
{
|
||||
/* This device always input */
|
||||
return 1;
|
||||
return GPIO_LINE_DIRECTION_IN;
|
||||
}
|
||||
|
||||
static int pisosr_gpio_direction_input(struct gpio_chip *chip,
|
||||
|
@ -63,7 +63,10 @@ static int pl061_get_direction(struct gpio_chip *gc, unsigned offset)
|
||||
{
|
||||
struct pl061 *pl061 = gpiochip_get_data(gc);
|
||||
|
||||
return !(readb(pl061->base + GPIODIR) & BIT(offset));
|
||||
if (readb(pl061->base + GPIODIR) & BIT(offset))
|
||||
return GPIO_LINE_DIRECTION_OUT;
|
||||
|
||||
return GPIO_LINE_DIRECTION_IN;
|
||||
}
|
||||
|
||||
static int pl061_direction_input(struct gpio_chip *gc, unsigned offset)
|
||||
|
@ -147,7 +147,10 @@ static int rpi_exp_gpio_get_direction(struct gpio_chip *gc, unsigned int off)
|
||||
get.gpio);
|
||||
return ret ? ret : -EIO;
|
||||
}
|
||||
return !get.direction;
|
||||
if (get.direction)
|
||||
return GPIO_LINE_DIRECTION_OUT;
|
||||
|
||||
return GPIO_LINE_DIRECTION_IN;
|
||||
}
|
||||
|
||||
static int rpi_exp_gpio_get(struct gpio_chip *gc, unsigned int off)
|
||||
|
@ -279,7 +279,10 @@ static int gpio_rcar_get_direction(struct gpio_chip *chip, unsigned int offset)
|
||||
{
|
||||
struct gpio_rcar_priv *p = gpiochip_get_data(chip);
|
||||
|
||||
return !(gpio_rcar_read(p, INOUTSEL) & BIT(offset));
|
||||
if (gpio_rcar_read(p, INOUTSEL) & BIT(offset))
|
||||
return GPIO_LINE_DIRECTION_OUT;
|
||||
|
||||
return GPIO_LINE_DIRECTION_IN;
|
||||
}
|
||||
|
||||
static int gpio_rcar_direction_input(struct gpio_chip *chip, unsigned offset)
|
||||
@ -483,7 +486,7 @@ static int gpio_rcar_probe(struct platform_device *pdev)
|
||||
gpio_chip->ngpio = npins;
|
||||
|
||||
irq_chip = &p->irq_chip;
|
||||
irq_chip->name = name;
|
||||
irq_chip->name = "gpio-rcar";
|
||||
irq_chip->parent_device = dev;
|
||||
irq_chip->irq_mask = gpio_rcar_irq_disable;
|
||||
irq_chip->irq_unmask = gpio_rcar_irq_enable;
|
||||
|
294
drivers/gpio/gpio-rda.c
Normal file
294
drivers/gpio/gpio-rda.c
Normal 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");
|
@ -26,7 +26,8 @@ static int gpio_reg_get_direction(struct gpio_chip *gc, unsigned offset)
|
||||
{
|
||||
struct gpio_reg *r = to_gpio_reg(gc);
|
||||
|
||||
return r->direction & BIT(offset) ? 1 : 0;
|
||||
return r->direction & BIT(offset) ? GPIO_LINE_DIRECTION_IN :
|
||||
GPIO_LINE_DIRECTION_OUT;
|
||||
}
|
||||
|
||||
static int gpio_reg_direction_output(struct gpio_chip *gc, unsigned offset,
|
||||
|
@ -53,7 +53,10 @@ static int sa1100_get_direction(struct gpio_chip *chip, unsigned offset)
|
||||
{
|
||||
void __iomem *gpdr = sa1100_gpio_chip(chip)->membase + R_GPDR;
|
||||
|
||||
return !(readl_relaxed(gpdr) & BIT(offset));
|
||||
if (readl_relaxed(gpdr) & BIT(offset))
|
||||
return GPIO_LINE_DIRECTION_OUT;
|
||||
|
||||
return GPIO_LINE_DIRECTION_IN;
|
||||
}
|
||||
|
||||
static int sa1100_direction_input(struct gpio_chip *chip, unsigned offset)
|
||||
|
@ -119,7 +119,8 @@ static int sama5d2_piobu_get_direction(struct gpio_chip *chip,
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return (ret == PIOBU_IN) ? 1 : 0;
|
||||
return (ret == PIOBU_IN) ? GPIO_LINE_DIRECTION_IN :
|
||||
GPIO_LINE_DIRECTION_OUT;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -154,9 +155,9 @@ static int sama5d2_piobu_get(struct gpio_chip *chip, unsigned int pin)
|
||||
/* if pin is input, read value from PDS else read from SOD */
|
||||
int ret = sama5d2_piobu_get_direction(chip, pin);
|
||||
|
||||
if (ret == 1)
|
||||
if (ret == GPIO_LINE_DIRECTION_IN)
|
||||
ret = sama5d2_piobu_read_value(chip, pin, PIOBU_PDS);
|
||||
else if (!ret)
|
||||
else if (ret == GPIO_LINE_DIRECTION_OUT)
|
||||
ret = sama5d2_piobu_read_value(chip, pin, PIOBU_SOD);
|
||||
|
||||
if (ret < 0)
|
||||
|
@ -127,7 +127,10 @@ static int sch_gpio_get_direction(struct gpio_chip *gc, unsigned gpio_num)
|
||||
{
|
||||
struct sch_gpio *sch = gpiochip_get_data(gc);
|
||||
|
||||
return sch_gpio_reg_get(sch, gpio_num, GIO);
|
||||
if (sch_gpio_reg_get(sch, gpio_num, GIO))
|
||||
return GPIO_LINE_DIRECTION_IN;
|
||||
|
||||
return GPIO_LINE_DIRECTION_OUT;
|
||||
}
|
||||
|
||||
static const struct gpio_chip sch_gpio_chip = {
|
||||
|
@ -228,7 +228,10 @@ static int sch311x_gpio_get_direction(struct gpio_chip *chip, unsigned offset)
|
||||
data = inb(block->runtime_reg + block->config_regs[offset]);
|
||||
spin_unlock(&block->lock);
|
||||
|
||||
return !!(data & SCH311X_GPIO_CONF_DIR);
|
||||
if (data & SCH311X_GPIO_CONF_DIR)
|
||||
return GPIO_LINE_DIRECTION_IN;
|
||||
|
||||
return GPIO_LINE_DIRECTION_OUT;
|
||||
}
|
||||
|
||||
static int sch311x_gpio_set_config(struct gpio_chip *chip, unsigned offset,
|
||||
|
@ -203,9 +203,9 @@ static int gpio_siox_direction_output(struct gpio_chip *chip,
|
||||
static int gpio_siox_get_direction(struct gpio_chip *chip, unsigned int offset)
|
||||
{
|
||||
if (offset < 12)
|
||||
return 1; /* input */
|
||||
return GPIO_LINE_DIRECTION_IN;
|
||||
else
|
||||
return 0; /* output */
|
||||
return GPIO_LINE_DIRECTION_OUT;
|
||||
}
|
||||
|
||||
static int gpio_siox_probe(struct siox_device *sdevice)
|
||||
|
@ -84,7 +84,10 @@ static int stmpe_gpio_get_direction(struct gpio_chip *chip,
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return !(ret & mask);
|
||||
if (ret & mask)
|
||||
return GPIO_LINE_DIRECTION_OUT;
|
||||
|
||||
return GPIO_LINE_DIRECTION_IN;
|
||||
}
|
||||
|
||||
static int stmpe_gpio_direction_output(struct gpio_chip *chip,
|
||||
|
@ -97,7 +97,10 @@ static int tc3589x_gpio_get_direction(struct gpio_chip *chip,
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return !(ret & BIT(pos));
|
||||
if (ret & BIT(pos))
|
||||
return GPIO_LINE_DIRECTION_OUT;
|
||||
|
||||
return GPIO_LINE_DIRECTION_IN;
|
||||
}
|
||||
|
||||
static int tc3589x_gpio_set_config(struct gpio_chip *chip, unsigned int offset,
|
||||
|
@ -215,7 +215,10 @@ static int tegra_gpio_get_direction(struct gpio_chip *chip,
|
||||
|
||||
oe = tegra_gpio_readl(tgi, GPIO_OE(tgi, offset));
|
||||
|
||||
return !(oe & pin_mask);
|
||||
if (oe & pin_mask)
|
||||
return GPIO_LINE_DIRECTION_OUT;
|
||||
|
||||
return GPIO_LINE_DIRECTION_IN;
|
||||
}
|
||||
|
||||
static int tegra_gpio_set_debounce(struct gpio_chip *chip, unsigned int offset,
|
||||
|
@ -15,6 +15,14 @@
|
||||
#include <dt-bindings/gpio/tegra186-gpio.h>
|
||||
#include <dt-bindings/gpio/tegra194-gpio.h>
|
||||
|
||||
/* security registers */
|
||||
#define TEGRA186_GPIO_CTL_SCR 0x0c
|
||||
#define TEGRA186_GPIO_CTL_SCR_SEC_WEN BIT(28)
|
||||
#define TEGRA186_GPIO_CTL_SCR_SEC_REN BIT(27)
|
||||
|
||||
#define TEGRA186_GPIO_INT_ROUTE_MAPPING(p, x) (0x14 + (p) * 0x20 + (x) * 4)
|
||||
|
||||
/* control registers */
|
||||
#define TEGRA186_GPIO_ENABLE_CONFIG 0x00
|
||||
#define TEGRA186_GPIO_ENABLE_CONFIG_ENABLE BIT(0)
|
||||
#define TEGRA186_GPIO_ENABLE_CONFIG_OUT BIT(1)
|
||||
@ -24,6 +32,7 @@
|
||||
#define TEGRA186_GPIO_ENABLE_CONFIG_TRIGGER_TYPE_DOUBLE_EDGE (0x3 << 2)
|
||||
#define TEGRA186_GPIO_ENABLE_CONFIG_TRIGGER_TYPE_MASK (0x3 << 2)
|
||||
#define TEGRA186_GPIO_ENABLE_CONFIG_TRIGGER_LEVEL BIT(4)
|
||||
#define TEGRA186_GPIO_ENABLE_CONFIG_DEBOUNCE BIT(5)
|
||||
#define TEGRA186_GPIO_ENABLE_CONFIG_INTERRUPT BIT(6)
|
||||
|
||||
#define TEGRA186_GPIO_DEBOUNCE_CONTROL 0x04
|
||||
@ -44,15 +53,16 @@
|
||||
|
||||
struct tegra_gpio_port {
|
||||
const char *name;
|
||||
unsigned int offset;
|
||||
unsigned int bank;
|
||||
unsigned int port;
|
||||
unsigned int pins;
|
||||
unsigned int irq;
|
||||
};
|
||||
|
||||
struct tegra_gpio_soc {
|
||||
const struct tegra_gpio_port *ports;
|
||||
unsigned int num_ports;
|
||||
const char *name;
|
||||
unsigned int instance;
|
||||
};
|
||||
|
||||
struct tegra_gpio {
|
||||
@ -63,6 +73,7 @@ struct tegra_gpio {
|
||||
|
||||
const struct tegra_gpio_soc *soc;
|
||||
|
||||
void __iomem *secure;
|
||||
void __iomem *base;
|
||||
};
|
||||
|
||||
@ -89,12 +100,15 @@ static void __iomem *tegra186_gpio_get_base(struct tegra_gpio *gpio,
|
||||
unsigned int pin)
|
||||
{
|
||||
const struct tegra_gpio_port *port;
|
||||
unsigned int offset;
|
||||
|
||||
port = tegra186_gpio_get_port(gpio, &pin);
|
||||
if (!port)
|
||||
return NULL;
|
||||
|
||||
return gpio->base + port->offset + pin * 0x20;
|
||||
offset = port->bank * 0x1000 + port->port * 0x200;
|
||||
|
||||
return gpio->base + offset + pin * 0x20;
|
||||
}
|
||||
|
||||
static int tegra186_gpio_get_direction(struct gpio_chip *chip,
|
||||
@ -110,9 +124,9 @@ static int tegra186_gpio_get_direction(struct gpio_chip *chip,
|
||||
|
||||
value = readl(base + TEGRA186_GPIO_ENABLE_CONFIG);
|
||||
if (value & TEGRA186_GPIO_ENABLE_CONFIG_OUT)
|
||||
return 0;
|
||||
return GPIO_LINE_DIRECTION_OUT;
|
||||
|
||||
return 1;
|
||||
return GPIO_LINE_DIRECTION_IN;
|
||||
}
|
||||
|
||||
static int tegra186_gpio_direction_input(struct gpio_chip *chip,
|
||||
@ -204,6 +218,42 @@ static void tegra186_gpio_set(struct gpio_chip *chip, unsigned int offset,
|
||||
writel(value, base + TEGRA186_GPIO_OUTPUT_VALUE);
|
||||
}
|
||||
|
||||
static int tegra186_gpio_set_config(struct gpio_chip *chip,
|
||||
unsigned int offset,
|
||||
unsigned long config)
|
||||
{
|
||||
struct tegra_gpio *gpio = gpiochip_get_data(chip);
|
||||
u32 debounce, value;
|
||||
void __iomem *base;
|
||||
|
||||
base = tegra186_gpio_get_base(gpio, offset);
|
||||
if (base == NULL)
|
||||
return -ENXIO;
|
||||
|
||||
if (pinconf_to_config_param(config) != PIN_CONFIG_INPUT_DEBOUNCE)
|
||||
return -ENOTSUPP;
|
||||
|
||||
debounce = pinconf_to_config_argument(config);
|
||||
|
||||
/*
|
||||
* The Tegra186 GPIO controller supports a maximum of 255 ms debounce
|
||||
* time.
|
||||
*/
|
||||
if (debounce > 255000)
|
||||
return -EINVAL;
|
||||
|
||||
debounce = DIV_ROUND_UP(debounce, USEC_PER_MSEC);
|
||||
|
||||
value = TEGRA186_GPIO_DEBOUNCE_CONTROL_THRESHOLD(debounce);
|
||||
writel(value, base + TEGRA186_GPIO_DEBOUNCE_CONTROL);
|
||||
|
||||
value = readl(base + TEGRA186_GPIO_ENABLE_CONFIG);
|
||||
value |= TEGRA186_GPIO_ENABLE_CONFIG_DEBOUNCE;
|
||||
writel(value, base + TEGRA186_GPIO_ENABLE_CONFIG);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tegra186_gpio_of_xlate(struct gpio_chip *chip,
|
||||
const struct of_phandle_args *spec,
|
||||
u32 *flags)
|
||||
@ -327,7 +377,7 @@ static int tegra186_irq_set_type(struct irq_data *data, unsigned int type)
|
||||
else
|
||||
irq_set_handler_locked(data, handle_edge_irq);
|
||||
|
||||
return 0;
|
||||
return irq_chip_set_type_parent(data, type);
|
||||
}
|
||||
|
||||
static void tegra186_gpio_irq(struct irq_desc *desc)
|
||||
@ -342,12 +392,14 @@ static void tegra186_gpio_irq(struct irq_desc *desc)
|
||||
|
||||
for (i = 0; i < gpio->soc->num_ports; i++) {
|
||||
const struct tegra_gpio_port *port = &gpio->soc->ports[i];
|
||||
void __iomem *base = gpio->base + port->offset;
|
||||
unsigned int pin, irq;
|
||||
unsigned long value;
|
||||
void __iomem *base;
|
||||
|
||||
/* skip ports that are not associated with this controller */
|
||||
if (parent != gpio->irq[port->irq])
|
||||
base = gpio->base + port->bank * 0x1000 + port->port * 0x200;
|
||||
|
||||
/* skip ports that are not associated with this bank */
|
||||
if (parent != gpio->irq[port->bank])
|
||||
goto skip;
|
||||
|
||||
value = readl(base + TEGRA186_GPIO_INTERRUPT_STATUS(1));
|
||||
@ -367,46 +419,119 @@ skip:
|
||||
chained_irq_exit(chip, desc);
|
||||
}
|
||||
|
||||
static int tegra186_gpio_irq_domain_xlate(struct irq_domain *domain,
|
||||
struct device_node *np,
|
||||
const u32 *spec, unsigned int size,
|
||||
unsigned long *hwirq,
|
||||
unsigned int *type)
|
||||
static int tegra186_gpio_irq_domain_translate(struct irq_domain *domain,
|
||||
struct irq_fwspec *fwspec,
|
||||
unsigned long *hwirq,
|
||||
unsigned int *type)
|
||||
{
|
||||
struct tegra_gpio *gpio = gpiochip_get_data(domain->host_data);
|
||||
unsigned int port, pin, i, offset = 0;
|
||||
|
||||
if (size < 2)
|
||||
if (WARN_ON(gpio->gpio.of_gpio_n_cells < 2))
|
||||
return -EINVAL;
|
||||
|
||||
port = spec[0] / 8;
|
||||
pin = spec[0] % 8;
|
||||
|
||||
if (port >= gpio->soc->num_ports) {
|
||||
dev_err(gpio->gpio.parent, "invalid port number: %u\n", port);
|
||||
if (WARN_ON(fwspec->param_count < gpio->gpio.of_gpio_n_cells))
|
||||
return -EINVAL;
|
||||
|
||||
port = fwspec->param[0] / 8;
|
||||
pin = fwspec->param[0] % 8;
|
||||
|
||||
if (port >= gpio->soc->num_ports)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
for (i = 0; i < port; i++)
|
||||
offset += gpio->soc->ports[i].pins;
|
||||
|
||||
*type = spec[1] & IRQ_TYPE_SENSE_MASK;
|
||||
*type = fwspec->param[1] & IRQ_TYPE_SENSE_MASK;
|
||||
*hwirq = offset + pin;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct irq_domain_ops tegra186_gpio_irq_domain_ops = {
|
||||
.map = gpiochip_irq_map,
|
||||
.unmap = gpiochip_irq_unmap,
|
||||
.xlate = tegra186_gpio_irq_domain_xlate,
|
||||
static void tegra186_gpio_populate_parent_fwspec(struct gpio_chip *chip,
|
||||
struct irq_fwspec *fwspec,
|
||||
unsigned int parent_hwirq,
|
||||
unsigned int parent_type)
|
||||
{
|
||||
struct tegra_gpio *gpio = gpiochip_get_data(chip);
|
||||
|
||||
fwspec->param_count = 3;
|
||||
fwspec->param[0] = gpio->soc->instance;
|
||||
fwspec->param[1] = parent_hwirq;
|
||||
fwspec->param[2] = parent_type;
|
||||
}
|
||||
|
||||
static int tegra186_gpio_child_to_parent_hwirq(struct gpio_chip *chip,
|
||||
unsigned int hwirq,
|
||||
unsigned int type,
|
||||
unsigned int *parent_hwirq,
|
||||
unsigned int *parent_type)
|
||||
{
|
||||
*parent_hwirq = chip->irq.child_offset_to_irq(chip, hwirq);
|
||||
*parent_type = type;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static unsigned int tegra186_gpio_child_offset_to_irq(struct gpio_chip *chip,
|
||||
unsigned int offset)
|
||||
{
|
||||
struct tegra_gpio *gpio = gpiochip_get_data(chip);
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < gpio->soc->num_ports; i++) {
|
||||
if (offset < gpio->soc->ports[i].pins)
|
||||
break;
|
||||
|
||||
offset -= gpio->soc->ports[i].pins;
|
||||
}
|
||||
|
||||
return offset + i * 8;
|
||||
}
|
||||
|
||||
static const struct of_device_id tegra186_pmc_of_match[] = {
|
||||
{ .compatible = "nvidia,tegra186-pmc" },
|
||||
{ .compatible = "nvidia,tegra194-pmc" },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
|
||||
static void tegra186_gpio_init_route_mapping(struct tegra_gpio *gpio)
|
||||
{
|
||||
unsigned int i, j;
|
||||
u32 value;
|
||||
|
||||
for (i = 0; i < gpio->soc->num_ports; i++) {
|
||||
const struct tegra_gpio_port *port = &gpio->soc->ports[i];
|
||||
unsigned int offset, p = port->port;
|
||||
void __iomem *base;
|
||||
|
||||
base = gpio->secure + port->bank * 0x1000 + 0x800;
|
||||
|
||||
value = readl(base + TEGRA186_GPIO_CTL_SCR);
|
||||
|
||||
/*
|
||||
* For controllers that haven't been locked down yet, make
|
||||
* sure to program the default interrupt route mapping.
|
||||
*/
|
||||
if ((value & TEGRA186_GPIO_CTL_SCR_SEC_REN) == 0 &&
|
||||
(value & TEGRA186_GPIO_CTL_SCR_SEC_WEN) == 0) {
|
||||
for (j = 0; j < 8; j++) {
|
||||
offset = TEGRA186_GPIO_INT_ROUTE_MAPPING(p, j);
|
||||
|
||||
value = readl(base + offset);
|
||||
value = BIT(port->pins) - 1;
|
||||
writel(value, base + offset);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int tegra186_gpio_probe(struct platform_device *pdev)
|
||||
{
|
||||
unsigned int i, j, offset;
|
||||
struct gpio_irq_chip *irq;
|
||||
struct tegra_gpio *gpio;
|
||||
struct device_node *np;
|
||||
char **names;
|
||||
int err;
|
||||
|
||||
@ -416,6 +541,10 @@ static int tegra186_gpio_probe(struct platform_device *pdev)
|
||||
|
||||
gpio->soc = of_device_get_match_data(&pdev->dev);
|
||||
|
||||
gpio->secure = devm_platform_ioremap_resource_byname(pdev, "security");
|
||||
if (IS_ERR(gpio->secure))
|
||||
return PTR_ERR(gpio->secure);
|
||||
|
||||
gpio->base = devm_platform_ioremap_resource_byname(pdev, "gpio");
|
||||
if (IS_ERR(gpio->base))
|
||||
return PTR_ERR(gpio->base);
|
||||
@ -447,6 +576,7 @@ static int tegra186_gpio_probe(struct platform_device *pdev)
|
||||
gpio->gpio.direction_output = tegra186_gpio_direction_output;
|
||||
gpio->gpio.get = tegra186_gpio_get,
|
||||
gpio->gpio.set = tegra186_gpio_set;
|
||||
gpio->gpio.set_config = tegra186_gpio_set_config;
|
||||
|
||||
gpio->gpio.base = -1;
|
||||
|
||||
@ -485,10 +615,15 @@ static int tegra186_gpio_probe(struct platform_device *pdev)
|
||||
gpio->intc.irq_mask = tegra186_irq_mask;
|
||||
gpio->intc.irq_unmask = tegra186_irq_unmask;
|
||||
gpio->intc.irq_set_type = tegra186_irq_set_type;
|
||||
gpio->intc.irq_set_wake = irq_chip_set_wake_parent;
|
||||
|
||||
irq = &gpio->gpio.irq;
|
||||
irq->chip = &gpio->intc;
|
||||
irq->domain_ops = &tegra186_gpio_irq_domain_ops;
|
||||
irq->fwnode = of_node_to_fwnode(pdev->dev.of_node);
|
||||
irq->child_to_parent_hwirq = tegra186_gpio_child_to_parent_hwirq;
|
||||
irq->populate_parent_fwspec = tegra186_gpio_populate_parent_fwspec;
|
||||
irq->child_offset_to_irq = tegra186_gpio_child_offset_to_irq;
|
||||
irq->child_irq_domain_ops.translate = tegra186_gpio_irq_domain_translate;
|
||||
irq->handler = handle_simple_irq;
|
||||
irq->default_type = IRQ_TYPE_NONE;
|
||||
irq->parent_handler = tegra186_gpio_irq;
|
||||
@ -496,6 +631,17 @@ static int tegra186_gpio_probe(struct platform_device *pdev)
|
||||
irq->num_parents = gpio->num_irq;
|
||||
irq->parents = gpio->irq;
|
||||
|
||||
np = of_find_matching_node(NULL, tegra186_pmc_of_match);
|
||||
if (np) {
|
||||
irq->parent_domain = irq_find_host(np);
|
||||
of_node_put(np);
|
||||
|
||||
if (!irq->parent_domain)
|
||||
return -EPROBE_DEFER;
|
||||
}
|
||||
|
||||
tegra186_gpio_init_route_mapping(gpio);
|
||||
|
||||
irq->map = devm_kcalloc(&pdev->dev, gpio->gpio.ngpio,
|
||||
sizeof(*irq->map), GFP_KERNEL);
|
||||
if (!irq->map)
|
||||
@ -505,7 +651,7 @@ static int tegra186_gpio_probe(struct platform_device *pdev)
|
||||
const struct tegra_gpio_port *port = &gpio->soc->ports[i];
|
||||
|
||||
for (j = 0; j < port->pins; j++)
|
||||
irq->map[offset + j] = irq->parents[port->irq];
|
||||
irq->map[offset + j] = irq->parents[port->bank];
|
||||
|
||||
offset += port->pins;
|
||||
}
|
||||
@ -524,136 +670,140 @@ static int tegra186_gpio_remove(struct platform_device *pdev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define TEGRA186_MAIN_GPIO_PORT(port, base, count, controller) \
|
||||
[TEGRA186_MAIN_GPIO_PORT_##port] = { \
|
||||
.name = #port, \
|
||||
.offset = base, \
|
||||
.pins = count, \
|
||||
.irq = controller, \
|
||||
#define TEGRA186_MAIN_GPIO_PORT(_name, _bank, _port, _pins) \
|
||||
[TEGRA186_MAIN_GPIO_PORT_##_name] = { \
|
||||
.name = #_name, \
|
||||
.bank = _bank, \
|
||||
.port = _port, \
|
||||
.pins = _pins, \
|
||||
}
|
||||
|
||||
static const struct tegra_gpio_port tegra186_main_ports[] = {
|
||||
TEGRA186_MAIN_GPIO_PORT( A, 0x2000, 7, 2),
|
||||
TEGRA186_MAIN_GPIO_PORT( B, 0x3000, 7, 3),
|
||||
TEGRA186_MAIN_GPIO_PORT( C, 0x3200, 7, 3),
|
||||
TEGRA186_MAIN_GPIO_PORT( D, 0x3400, 6, 3),
|
||||
TEGRA186_MAIN_GPIO_PORT( E, 0x2200, 8, 2),
|
||||
TEGRA186_MAIN_GPIO_PORT( F, 0x2400, 6, 2),
|
||||
TEGRA186_MAIN_GPIO_PORT( G, 0x4200, 6, 4),
|
||||
TEGRA186_MAIN_GPIO_PORT( H, 0x1000, 7, 1),
|
||||
TEGRA186_MAIN_GPIO_PORT( I, 0x0800, 8, 0),
|
||||
TEGRA186_MAIN_GPIO_PORT( J, 0x5000, 8, 5),
|
||||
TEGRA186_MAIN_GPIO_PORT( K, 0x5200, 1, 5),
|
||||
TEGRA186_MAIN_GPIO_PORT( L, 0x1200, 8, 1),
|
||||
TEGRA186_MAIN_GPIO_PORT( M, 0x5600, 6, 5),
|
||||
TEGRA186_MAIN_GPIO_PORT( N, 0x0000, 7, 0),
|
||||
TEGRA186_MAIN_GPIO_PORT( O, 0x0200, 4, 0),
|
||||
TEGRA186_MAIN_GPIO_PORT( P, 0x4000, 7, 4),
|
||||
TEGRA186_MAIN_GPIO_PORT( Q, 0x0400, 6, 0),
|
||||
TEGRA186_MAIN_GPIO_PORT( R, 0x0a00, 6, 0),
|
||||
TEGRA186_MAIN_GPIO_PORT( T, 0x0600, 4, 0),
|
||||
TEGRA186_MAIN_GPIO_PORT( X, 0x1400, 8, 1),
|
||||
TEGRA186_MAIN_GPIO_PORT( Y, 0x1600, 7, 1),
|
||||
TEGRA186_MAIN_GPIO_PORT(BB, 0x2600, 2, 2),
|
||||
TEGRA186_MAIN_GPIO_PORT(CC, 0x5400, 4, 5),
|
||||
TEGRA186_MAIN_GPIO_PORT( A, 2, 0, 7),
|
||||
TEGRA186_MAIN_GPIO_PORT( B, 3, 0, 7),
|
||||
TEGRA186_MAIN_GPIO_PORT( C, 3, 1, 7),
|
||||
TEGRA186_MAIN_GPIO_PORT( D, 3, 2, 6),
|
||||
TEGRA186_MAIN_GPIO_PORT( E, 2, 1, 8),
|
||||
TEGRA186_MAIN_GPIO_PORT( F, 2, 2, 6),
|
||||
TEGRA186_MAIN_GPIO_PORT( G, 4, 1, 6),
|
||||
TEGRA186_MAIN_GPIO_PORT( H, 1, 0, 7),
|
||||
TEGRA186_MAIN_GPIO_PORT( I, 0, 4, 8),
|
||||
TEGRA186_MAIN_GPIO_PORT( J, 5, 0, 8),
|
||||
TEGRA186_MAIN_GPIO_PORT( K, 5, 1, 1),
|
||||
TEGRA186_MAIN_GPIO_PORT( L, 1, 1, 8),
|
||||
TEGRA186_MAIN_GPIO_PORT( M, 5, 3, 6),
|
||||
TEGRA186_MAIN_GPIO_PORT( N, 0, 0, 7),
|
||||
TEGRA186_MAIN_GPIO_PORT( O, 0, 1, 4),
|
||||
TEGRA186_MAIN_GPIO_PORT( P, 4, 0, 7),
|
||||
TEGRA186_MAIN_GPIO_PORT( Q, 0, 2, 6),
|
||||
TEGRA186_MAIN_GPIO_PORT( R, 0, 5, 6),
|
||||
TEGRA186_MAIN_GPIO_PORT( T, 0, 3, 4),
|
||||
TEGRA186_MAIN_GPIO_PORT( X, 1, 2, 8),
|
||||
TEGRA186_MAIN_GPIO_PORT( Y, 1, 3, 7),
|
||||
TEGRA186_MAIN_GPIO_PORT(BB, 2, 3, 2),
|
||||
TEGRA186_MAIN_GPIO_PORT(CC, 5, 2, 4),
|
||||
};
|
||||
|
||||
static const struct tegra_gpio_soc tegra186_main_soc = {
|
||||
.num_ports = ARRAY_SIZE(tegra186_main_ports),
|
||||
.ports = tegra186_main_ports,
|
||||
.name = "tegra186-gpio",
|
||||
.instance = 0,
|
||||
};
|
||||
|
||||
#define TEGRA186_AON_GPIO_PORT(port, base, count, controller) \
|
||||
[TEGRA186_AON_GPIO_PORT_##port] = { \
|
||||
.name = #port, \
|
||||
.offset = base, \
|
||||
.pins = count, \
|
||||
.irq = controller, \
|
||||
#define TEGRA186_AON_GPIO_PORT(_name, _bank, _port, _pins) \
|
||||
[TEGRA186_AON_GPIO_PORT_##_name] = { \
|
||||
.name = #_name, \
|
||||
.bank = _bank, \
|
||||
.port = _port, \
|
||||
.pins = _pins, \
|
||||
}
|
||||
|
||||
static const struct tegra_gpio_port tegra186_aon_ports[] = {
|
||||
TEGRA186_AON_GPIO_PORT( S, 0x0200, 5, 0),
|
||||
TEGRA186_AON_GPIO_PORT( U, 0x0400, 6, 0),
|
||||
TEGRA186_AON_GPIO_PORT( V, 0x0800, 8, 0),
|
||||
TEGRA186_AON_GPIO_PORT( W, 0x0a00, 8, 0),
|
||||
TEGRA186_AON_GPIO_PORT( Z, 0x0e00, 4, 0),
|
||||
TEGRA186_AON_GPIO_PORT(AA, 0x0c00, 8, 0),
|
||||
TEGRA186_AON_GPIO_PORT(EE, 0x0600, 3, 0),
|
||||
TEGRA186_AON_GPIO_PORT(FF, 0x0000, 5, 0),
|
||||
TEGRA186_AON_GPIO_PORT( S, 0, 1, 5),
|
||||
TEGRA186_AON_GPIO_PORT( U, 0, 2, 6),
|
||||
TEGRA186_AON_GPIO_PORT( V, 0, 4, 8),
|
||||
TEGRA186_AON_GPIO_PORT( W, 0, 5, 8),
|
||||
TEGRA186_AON_GPIO_PORT( Z, 0, 7, 4),
|
||||
TEGRA186_AON_GPIO_PORT(AA, 0, 6, 8),
|
||||
TEGRA186_AON_GPIO_PORT(EE, 0, 3, 3),
|
||||
TEGRA186_AON_GPIO_PORT(FF, 0, 0, 5),
|
||||
};
|
||||
|
||||
static const struct tegra_gpio_soc tegra186_aon_soc = {
|
||||
.num_ports = ARRAY_SIZE(tegra186_aon_ports),
|
||||
.ports = tegra186_aon_ports,
|
||||
.name = "tegra186-gpio-aon",
|
||||
.instance = 1,
|
||||
};
|
||||
|
||||
#define TEGRA194_MAIN_GPIO_PORT(port, base, count, controller) \
|
||||
[TEGRA194_MAIN_GPIO_PORT_##port] = { \
|
||||
.name = #port, \
|
||||
.offset = base, \
|
||||
.pins = count, \
|
||||
.irq = controller, \
|
||||
#define TEGRA194_MAIN_GPIO_PORT(_name, _bank, _port, _pins) \
|
||||
[TEGRA194_MAIN_GPIO_PORT_##_name] = { \
|
||||
.name = #_name, \
|
||||
.bank = _bank, \
|
||||
.port = _port, \
|
||||
.pins = _pins, \
|
||||
}
|
||||
|
||||
static const struct tegra_gpio_port tegra194_main_ports[] = {
|
||||
TEGRA194_MAIN_GPIO_PORT( A, 0x1400, 8, 1),
|
||||
TEGRA194_MAIN_GPIO_PORT( B, 0x4e00, 2, 4),
|
||||
TEGRA194_MAIN_GPIO_PORT( C, 0x4600, 8, 4),
|
||||
TEGRA194_MAIN_GPIO_PORT( D, 0x4800, 4, 4),
|
||||
TEGRA194_MAIN_GPIO_PORT( E, 0x4a00, 8, 4),
|
||||
TEGRA194_MAIN_GPIO_PORT( F, 0x4c00, 6, 4),
|
||||
TEGRA194_MAIN_GPIO_PORT( G, 0x4000, 8, 4),
|
||||
TEGRA194_MAIN_GPIO_PORT( H, 0x4200, 8, 4),
|
||||
TEGRA194_MAIN_GPIO_PORT( I, 0x4400, 5, 4),
|
||||
TEGRA194_MAIN_GPIO_PORT( J, 0x5200, 6, 5),
|
||||
TEGRA194_MAIN_GPIO_PORT( K, 0x3000, 8, 3),
|
||||
TEGRA194_MAIN_GPIO_PORT( L, 0x3200, 4, 3),
|
||||
TEGRA194_MAIN_GPIO_PORT( M, 0x2600, 8, 2),
|
||||
TEGRA194_MAIN_GPIO_PORT( N, 0x2800, 3, 2),
|
||||
TEGRA194_MAIN_GPIO_PORT( O, 0x5000, 6, 5),
|
||||
TEGRA194_MAIN_GPIO_PORT( P, 0x2a00, 8, 2),
|
||||
TEGRA194_MAIN_GPIO_PORT( Q, 0x2c00, 8, 2),
|
||||
TEGRA194_MAIN_GPIO_PORT( R, 0x2e00, 6, 2),
|
||||
TEGRA194_MAIN_GPIO_PORT( S, 0x3600, 8, 3),
|
||||
TEGRA194_MAIN_GPIO_PORT( T, 0x3800, 8, 3),
|
||||
TEGRA194_MAIN_GPIO_PORT( U, 0x3a00, 1, 3),
|
||||
TEGRA194_MAIN_GPIO_PORT( V, 0x1000, 8, 1),
|
||||
TEGRA194_MAIN_GPIO_PORT( W, 0x1200, 2, 1),
|
||||
TEGRA194_MAIN_GPIO_PORT( X, 0x2000, 8, 2),
|
||||
TEGRA194_MAIN_GPIO_PORT( Y, 0x2200, 8, 2),
|
||||
TEGRA194_MAIN_GPIO_PORT( Z, 0x2400, 8, 2),
|
||||
TEGRA194_MAIN_GPIO_PORT(FF, 0x3400, 2, 3),
|
||||
TEGRA194_MAIN_GPIO_PORT(GG, 0x0000, 2, 0)
|
||||
TEGRA194_MAIN_GPIO_PORT( A, 1, 2, 8),
|
||||
TEGRA194_MAIN_GPIO_PORT( B, 4, 7, 2),
|
||||
TEGRA194_MAIN_GPIO_PORT( C, 4, 3, 8),
|
||||
TEGRA194_MAIN_GPIO_PORT( D, 4, 4, 4),
|
||||
TEGRA194_MAIN_GPIO_PORT( E, 4, 5, 8),
|
||||
TEGRA194_MAIN_GPIO_PORT( F, 4, 6, 6),
|
||||
TEGRA194_MAIN_GPIO_PORT( G, 4, 0, 8),
|
||||
TEGRA194_MAIN_GPIO_PORT( H, 4, 1, 8),
|
||||
TEGRA194_MAIN_GPIO_PORT( I, 4, 2, 5),
|
||||
TEGRA194_MAIN_GPIO_PORT( J, 5, 1, 6),
|
||||
TEGRA194_MAIN_GPIO_PORT( K, 3, 0, 8),
|
||||
TEGRA194_MAIN_GPIO_PORT( L, 3, 1, 4),
|
||||
TEGRA194_MAIN_GPIO_PORT( M, 2, 3, 8),
|
||||
TEGRA194_MAIN_GPIO_PORT( N, 2, 4, 3),
|
||||
TEGRA194_MAIN_GPIO_PORT( O, 5, 0, 6),
|
||||
TEGRA194_MAIN_GPIO_PORT( P, 2, 5, 8),
|
||||
TEGRA194_MAIN_GPIO_PORT( Q, 2, 6, 8),
|
||||
TEGRA194_MAIN_GPIO_PORT( R, 2, 7, 6),
|
||||
TEGRA194_MAIN_GPIO_PORT( S, 3, 3, 8),
|
||||
TEGRA194_MAIN_GPIO_PORT( T, 3, 4, 8),
|
||||
TEGRA194_MAIN_GPIO_PORT( U, 3, 5, 1),
|
||||
TEGRA194_MAIN_GPIO_PORT( V, 1, 0, 8),
|
||||
TEGRA194_MAIN_GPIO_PORT( W, 1, 1, 2),
|
||||
TEGRA194_MAIN_GPIO_PORT( X, 2, 0, 8),
|
||||
TEGRA194_MAIN_GPIO_PORT( Y, 2, 1, 8),
|
||||
TEGRA194_MAIN_GPIO_PORT( Z, 2, 2, 8),
|
||||
TEGRA194_MAIN_GPIO_PORT(FF, 3, 2, 2),
|
||||
TEGRA194_MAIN_GPIO_PORT(GG, 0, 0, 2)
|
||||
};
|
||||
|
||||
static const struct tegra_gpio_soc tegra194_main_soc = {
|
||||
.num_ports = ARRAY_SIZE(tegra194_main_ports),
|
||||
.ports = tegra194_main_ports,
|
||||
.name = "tegra194-gpio",
|
||||
.instance = 0,
|
||||
};
|
||||
|
||||
#define TEGRA194_AON_GPIO_PORT(port, base, count, controller) \
|
||||
[TEGRA194_AON_GPIO_PORT_##port] = { \
|
||||
.name = #port, \
|
||||
.offset = base, \
|
||||
.pins = count, \
|
||||
.irq = controller, \
|
||||
#define TEGRA194_AON_GPIO_PORT(_name, _bank, _port, _pins) \
|
||||
[TEGRA194_AON_GPIO_PORT_##_name] = { \
|
||||
.name = #_name, \
|
||||
.bank = _bank, \
|
||||
.port = _port, \
|
||||
.pins = _pins, \
|
||||
}
|
||||
|
||||
static const struct tegra_gpio_port tegra194_aon_ports[] = {
|
||||
TEGRA194_AON_GPIO_PORT(AA, 0x0600, 8, 0),
|
||||
TEGRA194_AON_GPIO_PORT(BB, 0x0800, 4, 0),
|
||||
TEGRA194_AON_GPIO_PORT(CC, 0x0200, 8, 0),
|
||||
TEGRA194_AON_GPIO_PORT(DD, 0x0400, 3, 0),
|
||||
TEGRA194_AON_GPIO_PORT(EE, 0x0000, 7, 0)
|
||||
TEGRA194_AON_GPIO_PORT(AA, 0, 3, 8),
|
||||
TEGRA194_AON_GPIO_PORT(BB, 0, 4, 4),
|
||||
TEGRA194_AON_GPIO_PORT(CC, 0, 1, 8),
|
||||
TEGRA194_AON_GPIO_PORT(DD, 0, 2, 3),
|
||||
TEGRA194_AON_GPIO_PORT(EE, 0, 0, 7)
|
||||
};
|
||||
|
||||
static const struct tegra_gpio_soc tegra194_aon_soc = {
|
||||
.num_ports = ARRAY_SIZE(tegra194_aon_ports),
|
||||
.ports = tegra194_aon_ports,
|
||||
.name = "tegra194-gpio-aon",
|
||||
.instance = 1,
|
||||
};
|
||||
|
||||
static const struct of_device_id tegra186_gpio_of_match[] = {
|
||||
|
@ -169,7 +169,10 @@ static int thunderx_gpio_get_direction(struct gpio_chip *chip, unsigned int line
|
||||
|
||||
bit_cfg = readq(txgpio->register_base + bit_cfg_reg(line));
|
||||
|
||||
return !(bit_cfg & GPIO_BIT_CFG_TX_OE);
|
||||
if (bit_cfg & GPIO_BIT_CFG_TX_OE)
|
||||
return GPIO_LINE_DIRECTION_OUT;
|
||||
|
||||
return GPIO_LINE_DIRECTION_IN;
|
||||
}
|
||||
|
||||
static int thunderx_gpio_set_config(struct gpio_chip *chip,
|
||||
|
@ -39,7 +39,7 @@ static int tpic2810_get_direction(struct gpio_chip *chip,
|
||||
unsigned offset)
|
||||
{
|
||||
/* This device always output */
|
||||
return 0;
|
||||
return GPIO_LINE_DIRECTION_OUT;
|
||||
}
|
||||
|
||||
static int tpic2810_direction_input(struct gpio_chip *chip,
|
||||
|
@ -21,7 +21,7 @@ static int tps65086_gpio_get_direction(struct gpio_chip *chip,
|
||||
unsigned offset)
|
||||
{
|
||||
/* This device is output only */
|
||||
return 0;
|
||||
return GPIO_LINE_DIRECTION_OUT;
|
||||
}
|
||||
|
||||
static int tps65086_gpio_direction_input(struct gpio_chip *chip,
|
||||
|
@ -32,9 +32,9 @@ static int tps65912_gpio_get_direction(struct gpio_chip *gc,
|
||||
return ret;
|
||||
|
||||
if (val & GPIO_CFG_MASK)
|
||||
return 0;
|
||||
return GPIO_LINE_DIRECTION_OUT;
|
||||
else
|
||||
return 1;
|
||||
return GPIO_LINE_DIRECTION_IN;
|
||||
}
|
||||
|
||||
static int tps65912_gpio_direction_input(struct gpio_chip *gc, unsigned offset)
|
||||
|
@ -47,7 +47,6 @@ static int tps68470_gpio_get(struct gpio_chip *gc, unsigned int offset)
|
||||
return !!(val & BIT(offset));
|
||||
}
|
||||
|
||||
/* Return 0 if output, 1 if input */
|
||||
static int tps68470_gpio_get_direction(struct gpio_chip *gc,
|
||||
unsigned int offset)
|
||||
{
|
||||
@ -57,7 +56,7 @@ static int tps68470_gpio_get_direction(struct gpio_chip *gc,
|
||||
|
||||
/* rest are always outputs */
|
||||
if (offset >= TPS68470_N_REGULAR_GPIO)
|
||||
return 0;
|
||||
return GPIO_LINE_DIRECTION_OUT;
|
||||
|
||||
ret = regmap_read(regmap, TPS68470_GPIO_CTL_REG_A(offset), &val);
|
||||
if (ret) {
|
||||
@ -67,7 +66,8 @@ static int tps68470_gpio_get_direction(struct gpio_chip *gc,
|
||||
}
|
||||
|
||||
val &= TPS68470_GPIO_MODE_MASK;
|
||||
return val >= TPS68470_GPIO_MODE_OUT_CMOS ? 0 : 1;
|
||||
return val >= TPS68470_GPIO_MODE_OUT_CMOS ? GPIO_LINE_DIRECTION_OUT :
|
||||
GPIO_LINE_DIRECTION_IN;
|
||||
}
|
||||
|
||||
static void tps68470_gpio_set(struct gpio_chip *gc, unsigned int offset,
|
||||
|
@ -101,7 +101,10 @@ static int tqmx86_gpio_direction_output(struct gpio_chip *chip,
|
||||
static int tqmx86_gpio_get_direction(struct gpio_chip *chip,
|
||||
unsigned int offset)
|
||||
{
|
||||
return !!(TQMX86_DIR_INPUT_MASK & BIT(offset));
|
||||
if (TQMX86_DIR_INPUT_MASK & BIT(offset))
|
||||
return GPIO_LINE_DIRECTION_IN;
|
||||
|
||||
return GPIO_LINE_DIRECTION_OUT;
|
||||
}
|
||||
|
||||
static void tqmx86_gpio_irq_mask(struct irq_data *data)
|
||||
|
@ -44,7 +44,10 @@ static int ts4900_gpio_get_direction(struct gpio_chip *chip,
|
||||
|
||||
regmap_read(priv->regmap, offset, ®);
|
||||
|
||||
return !(reg & TS4900_GPIO_OE);
|
||||
if (reg & TS4900_GPIO_OE)
|
||||
return GPIO_LINE_DIRECTION_OUT;
|
||||
|
||||
return GPIO_LINE_DIRECTION_IN;
|
||||
}
|
||||
|
||||
static int ts4900_gpio_direction_input(struct gpio_chip *chip,
|
||||
|
@ -165,10 +165,10 @@ static int twl4030_get_gpio_direction(int gpio)
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* 1 = output, but gpiolib semantics are inverse so invert */
|
||||
ret = !(ret & d_msk);
|
||||
if (ret & d_msk)
|
||||
return GPIO_LINE_DIRECTION_OUT;
|
||||
|
||||
return ret;
|
||||
return GPIO_LINE_DIRECTION_IN;
|
||||
}
|
||||
|
||||
static int twl4030_set_gpio_dataout(int gpio, int enable)
|
||||
@ -380,10 +380,10 @@ static int twl_get_direction(struct gpio_chip *chip, unsigned offset)
|
||||
{
|
||||
struct gpio_twl4030_priv *priv = gpiochip_get_data(chip);
|
||||
/*
|
||||
* Default 0 = output
|
||||
* Default GPIO_LINE_DIRECTION_OUT
|
||||
* LED GPIOs >= TWL4030_GPIO_MAX are always output
|
||||
*/
|
||||
int ret = 0;
|
||||
int ret = GPIO_LINE_DIRECTION_OUT;
|
||||
|
||||
mutex_lock(&priv->mutex);
|
||||
if (offset < TWL4030_GPIO_MAX) {
|
||||
|
@ -34,8 +34,7 @@ static int twl6040gpo_get(struct gpio_chip *chip, unsigned offset)
|
||||
|
||||
static int twl6040gpo_get_direction(struct gpio_chip *chip, unsigned offset)
|
||||
{
|
||||
/* This means "out" */
|
||||
return 0;
|
||||
return GPIO_LINE_DIRECTION_OUT;
|
||||
}
|
||||
|
||||
static int twl6040gpo_direction_out(struct gpio_chip *chip, unsigned offset,
|
||||
|
@ -113,7 +113,10 @@ static int uniphier_gpio_offset_read(struct gpio_chip *chip,
|
||||
static int uniphier_gpio_get_direction(struct gpio_chip *chip,
|
||||
unsigned int offset)
|
||||
{
|
||||
return uniphier_gpio_offset_read(chip, offset, UNIPHIER_GPIO_PORT_DIR);
|
||||
if (uniphier_gpio_offset_read(chip, offset, UNIPHIER_GPIO_PORT_DIR))
|
||||
return GPIO_LINE_DIRECTION_IN;
|
||||
|
||||
return GPIO_LINE_DIRECTION_OUT;
|
||||
}
|
||||
|
||||
static int uniphier_gpio_direction_input(struct gpio_chip *chip,
|
||||
|
@ -170,13 +170,16 @@ static int wcove_gpio_get_direction(struct gpio_chip *chip, unsigned int gpio)
|
||||
int ret, reg = to_reg(gpio, CTRL_OUT);
|
||||
|
||||
if (reg < 0)
|
||||
return 0;
|
||||
return GPIO_LINE_DIRECTION_OUT;
|
||||
|
||||
ret = regmap_read(wg->regmap, reg, &val);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return !(val & CTLO_DIR_OUT);
|
||||
if (val & CTLO_DIR_OUT)
|
||||
return GPIO_LINE_DIRECTION_OUT;
|
||||
|
||||
return GPIO_LINE_DIRECTION_IN;
|
||||
}
|
||||
|
||||
static int wcove_gpio_get(struct gpio_chip *chip, unsigned int gpio)
|
||||
|
@ -56,7 +56,10 @@ static int ws16c48_gpio_get_direction(struct gpio_chip *chip, unsigned offset)
|
||||
const unsigned port = offset / 8;
|
||||
const unsigned mask = BIT(offset % 8);
|
||||
|
||||
return !!(ws16c48gpio->io_state[port] & mask);
|
||||
if (ws16c48gpio->io_state[port] & mask)
|
||||
return GPIO_LINE_DIRECTION_IN;
|
||||
|
||||
return GPIO_LINE_DIRECTION_OUT;
|
||||
}
|
||||
|
||||
static int ws16c48_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
|
||||
|
@ -80,7 +80,10 @@ static int xgene_gpio_get_direction(struct gpio_chip *gc, unsigned int offset)
|
||||
bank_offset = GPIO_SET_DR_OFFSET + GPIO_BANK_OFFSET(offset);
|
||||
bit_offset = GPIO_BIT_OFFSET(offset);
|
||||
|
||||
return !!(ioread32(chip->base + bank_offset) & BIT(bit_offset));
|
||||
if (ioread32(chip->base + bank_offset) & BIT(bit_offset))
|
||||
return GPIO_LINE_DIRECTION_IN;
|
||||
|
||||
return GPIO_LINE_DIRECTION_OUT;
|
||||
}
|
||||
|
||||
static int xgene_gpio_dir_in(struct gpio_chip *gc, unsigned int offset)
|
||||
@ -155,28 +158,16 @@ static SIMPLE_DEV_PM_OPS(xgene_gpio_pm, xgene_gpio_suspend, xgene_gpio_resume);
|
||||
|
||||
static int xgene_gpio_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct resource *res;
|
||||
struct xgene_gpio *gpio;
|
||||
int err = 0;
|
||||
|
||||
gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL);
|
||||
if (!gpio) {
|
||||
err = -ENOMEM;
|
||||
goto err;
|
||||
}
|
||||
if (!gpio)
|
||||
return -ENOMEM;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!res) {
|
||||
err = -EINVAL;
|
||||
goto err;
|
||||
}
|
||||
|
||||
gpio->base = devm_ioremap_nocache(&pdev->dev, res->start,
|
||||
resource_size(res));
|
||||
if (!gpio->base) {
|
||||
err = -ENOMEM;
|
||||
goto err;
|
||||
}
|
||||
gpio->base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(gpio->base))
|
||||
return PTR_ERR(gpio->base);
|
||||
|
||||
gpio->chip.ngpio = XGENE_MAX_GPIOS;
|
||||
|
||||
@ -196,14 +187,11 @@ static int xgene_gpio_probe(struct platform_device *pdev)
|
||||
if (err) {
|
||||
dev_err(&pdev->dev,
|
||||
"failed to register gpiochip.\n");
|
||||
goto err;
|
||||
return err;
|
||||
}
|
||||
|
||||
dev_info(&pdev->dev, "X-Gene GPIO driver registered.\n");
|
||||
return 0;
|
||||
err:
|
||||
dev_err(&pdev->dev, "X-Gene GPIO driver registration failed.\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
static const struct of_device_id xgene_gpio_of_match[] = {
|
||||
|
320
drivers/gpio/gpio-xgs-iproc.c
Normal file
320
drivers/gpio/gpio-xgs-iproc.c
Normal 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");
|
@ -83,7 +83,10 @@ static int xra1403_get_direction(struct gpio_chip *chip, unsigned int offset)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return !!(val & BIT(offset % 8));
|
||||
if (val & BIT(offset % 8))
|
||||
return GPIO_LINE_DIRECTION_IN;
|
||||
|
||||
return GPIO_LINE_DIRECTION_OUT;
|
||||
}
|
||||
|
||||
static int xra1403_get(struct gpio_chip *chip, unsigned int offset)
|
||||
|
@ -72,7 +72,7 @@ static inline void disable_cp(unsigned long flags, unsigned long cpenable)
|
||||
|
||||
static int xtensa_impwire_get_direction(struct gpio_chip *gc, unsigned offset)
|
||||
{
|
||||
return 1; /* input only */
|
||||
return GPIO_LINE_DIRECTION_IN; /* input only */
|
||||
}
|
||||
|
||||
static int xtensa_impwire_get_value(struct gpio_chip *gc, unsigned offset)
|
||||
@ -95,7 +95,7 @@ static void xtensa_impwire_set_value(struct gpio_chip *gc, unsigned offset,
|
||||
|
||||
static int xtensa_expstate_get_direction(struct gpio_chip *gc, unsigned offset)
|
||||
{
|
||||
return 0; /* output only */
|
||||
return GPIO_LINE_DIRECTION_OUT; /* output only */
|
||||
}
|
||||
|
||||
static int xtensa_expstate_get_value(struct gpio_chip *gc, unsigned offset)
|
||||
|
@ -360,7 +360,7 @@ static int zynq_gpio_dir_out(struct gpio_chip *chip, unsigned int pin,
|
||||
*
|
||||
* This function returns the direction of the specified GPIO.
|
||||
*
|
||||
* Return: 0 for output, 1 for input
|
||||
* Return: GPIO_LINE_DIRECTION_OUT or GPIO_LINE_DIRECTION_IN
|
||||
*/
|
||||
static int zynq_gpio_get_direction(struct gpio_chip *chip, unsigned int pin)
|
||||
{
|
||||
@ -372,7 +372,10 @@ static int zynq_gpio_get_direction(struct gpio_chip *chip, unsigned int pin)
|
||||
|
||||
reg = readl_relaxed(gpio->base_addr + ZYNQ_GPIO_DIRM_OFFSET(bank_num));
|
||||
|
||||
return !(reg & BIT(bank_pin_num));
|
||||
if (reg & BIT(bank_pin_num))
|
||||
return GPIO_LINE_DIRECTION_OUT;
|
||||
|
||||
return GPIO_LINE_DIRECTION_IN;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -194,6 +194,7 @@ static void acpi_gpiochip_request_irqs(struct acpi_gpio_chip *acpi_gpio)
|
||||
acpi_gpiochip_request_irq(acpi_gpio, event);
|
||||
}
|
||||
|
||||
/* Always returns AE_OK so that we keep looping over the resources */
|
||||
static acpi_status acpi_gpiochip_alloc_event(struct acpi_resource *ares,
|
||||
void *context)
|
||||
{
|
||||
@ -230,19 +231,25 @@ static acpi_status acpi_gpiochip_alloc_event(struct acpi_resource *ares,
|
||||
desc = gpiochip_request_own_desc(chip, pin, "ACPI:Event",
|
||||
GPIO_ACTIVE_HIGH, GPIOD_IN);
|
||||
if (IS_ERR(desc)) {
|
||||
dev_err(chip->parent, "Failed to request GPIO\n");
|
||||
return AE_ERROR;
|
||||
dev_err(chip->parent,
|
||||
"Failed to request GPIO for pin 0x%04X, err %ld\n",
|
||||
pin, PTR_ERR(desc));
|
||||
return AE_OK;
|
||||
}
|
||||
|
||||
ret = gpiochip_lock_as_irq(chip, pin);
|
||||
if (ret) {
|
||||
dev_err(chip->parent, "Failed to lock GPIO as interrupt\n");
|
||||
dev_err(chip->parent,
|
||||
"Failed to lock GPIO pin 0x%04X as interrupt, err %d\n",
|
||||
pin, ret);
|
||||
goto fail_free_desc;
|
||||
}
|
||||
|
||||
irq = gpiod_to_irq(desc);
|
||||
if (irq < 0) {
|
||||
dev_err(chip->parent, "Failed to translate GPIO to IRQ\n");
|
||||
dev_err(chip->parent,
|
||||
"Failed to translate GPIO pin 0x%04X to IRQ, err %d\n",
|
||||
pin, irq);
|
||||
goto fail_unlock_irq;
|
||||
}
|
||||
|
||||
@ -287,7 +294,7 @@ fail_unlock_irq:
|
||||
fail_free_desc:
|
||||
gpiochip_free_own_desc(desc);
|
||||
|
||||
return AE_ERROR;
|
||||
return AE_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -27,7 +27,7 @@
|
||||
* This is used by external users of of_gpio_count() from <linux/of_gpio.h>
|
||||
*
|
||||
* FIXME: get rid of those external users by converting them to GPIO
|
||||
* descriptors and let them all use gpiod_get_count()
|
||||
* descriptors and let them all use gpiod_count()
|
||||
*/
|
||||
int of_gpio_get_count(struct device *dev, const char *con_id)
|
||||
{
|
||||
@ -84,8 +84,9 @@ static struct gpio_desc *of_xlate_and_get_gpiod_flags(struct gpio_chip *chip,
|
||||
/**
|
||||
* of_gpio_need_valid_mask() - figure out if the OF GPIO driver needs
|
||||
* to set the .valid_mask
|
||||
* @dev: the device for the GPIO provider
|
||||
* @return: true if the valid mask needs to be set
|
||||
* @gc: the target gpio_chip
|
||||
*
|
||||
* Return: true if the valid mask needs to be set
|
||||
*/
|
||||
bool of_gpio_need_valid_mask(const struct gpio_chip *gc)
|
||||
{
|
||||
@ -134,18 +135,20 @@ static void of_gpio_flags_quirks(struct device_node *np,
|
||||
(!(strcmp(propname, "enable-gpio") &&
|
||||
strcmp(propname, "enable-gpios")) &&
|
||||
of_device_is_compatible(np, "regulator-gpio")))) {
|
||||
bool active_low = !of_property_read_bool(np,
|
||||
"enable-active-high");
|
||||
/*
|
||||
* The regulator GPIO handles are specified such that the
|
||||
* presence or absence of "enable-active-high" solely controls
|
||||
* the polarity of the GPIO line. Any phandle flags must
|
||||
* be actively ignored.
|
||||
*/
|
||||
if (*flags & OF_GPIO_ACTIVE_LOW) {
|
||||
if ((*flags & OF_GPIO_ACTIVE_LOW) && !active_low) {
|
||||
pr_warn("%s GPIO handle specifies active low - ignored\n",
|
||||
of_node_full_name(np));
|
||||
*flags &= ~OF_GPIO_ACTIVE_LOW;
|
||||
}
|
||||
if (!of_property_read_bool(np, "enable-active-high"))
|
||||
if (active_low)
|
||||
*flags |= OF_GPIO_ACTIVE_LOW;
|
||||
}
|
||||
/*
|
||||
@ -882,16 +885,13 @@ int of_gpiochip_add(struct gpio_chip *chip)
|
||||
of_node_get(chip->of_node);
|
||||
|
||||
ret = of_gpiochip_scan_gpios(chip);
|
||||
if (ret) {
|
||||
if (ret)
|
||||
of_node_put(chip->of_node);
|
||||
gpiochip_remove_pin_ranges(chip);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void of_gpiochip_remove(struct gpio_chip *chip)
|
||||
{
|
||||
gpiochip_remove_pin_ranges(chip);
|
||||
of_node_put(chip->of_node);
|
||||
}
|
||||
|
@ -390,6 +390,14 @@ static void gpiochip_free_valid_mask(struct gpio_chip *gpiochip)
|
||||
gpiochip->valid_mask = NULL;
|
||||
}
|
||||
|
||||
static int gpiochip_add_pin_ranges(struct gpio_chip *gc)
|
||||
{
|
||||
if (gc->add_pin_ranges)
|
||||
return gc->add_pin_ranges(gc);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool gpiochip_line_is_valid(const struct gpio_chip *gpiochip,
|
||||
unsigned int offset)
|
||||
{
|
||||
@ -422,9 +430,127 @@ struct linehandle_state {
|
||||
(GPIOHANDLE_REQUEST_INPUT | \
|
||||
GPIOHANDLE_REQUEST_OUTPUT | \
|
||||
GPIOHANDLE_REQUEST_ACTIVE_LOW | \
|
||||
GPIOHANDLE_REQUEST_BIAS_PULL_UP | \
|
||||
GPIOHANDLE_REQUEST_BIAS_PULL_DOWN | \
|
||||
GPIOHANDLE_REQUEST_BIAS_DISABLE | \
|
||||
GPIOHANDLE_REQUEST_OPEN_DRAIN | \
|
||||
GPIOHANDLE_REQUEST_OPEN_SOURCE)
|
||||
|
||||
static int linehandle_validate_flags(u32 flags)
|
||||
{
|
||||
/* Return an error if an unknown flag is set */
|
||||
if (flags & ~GPIOHANDLE_REQUEST_VALID_FLAGS)
|
||||
return -EINVAL;
|
||||
|
||||
/*
|
||||
* Do not allow both INPUT & OUTPUT flags to be set as they are
|
||||
* contradictory.
|
||||
*/
|
||||
if ((flags & GPIOHANDLE_REQUEST_INPUT) &&
|
||||
(flags & GPIOHANDLE_REQUEST_OUTPUT))
|
||||
return -EINVAL;
|
||||
|
||||
/*
|
||||
* Do not allow OPEN_SOURCE & OPEN_DRAIN flags in a single request. If
|
||||
* the hardware actually supports enabling both at the same time the
|
||||
* electrical result would be disastrous.
|
||||
*/
|
||||
if ((flags & GPIOHANDLE_REQUEST_OPEN_DRAIN) &&
|
||||
(flags & GPIOHANDLE_REQUEST_OPEN_SOURCE))
|
||||
return -EINVAL;
|
||||
|
||||
/* OPEN_DRAIN and OPEN_SOURCE flags only make sense for output mode. */
|
||||
if (!(flags & GPIOHANDLE_REQUEST_OUTPUT) &&
|
||||
((flags & GPIOHANDLE_REQUEST_OPEN_DRAIN) ||
|
||||
(flags & GPIOHANDLE_REQUEST_OPEN_SOURCE)))
|
||||
return -EINVAL;
|
||||
|
||||
/* Bias flags only allowed for input or output mode. */
|
||||
if (!((flags & GPIOHANDLE_REQUEST_INPUT) ||
|
||||
(flags & GPIOHANDLE_REQUEST_OUTPUT)) &&
|
||||
((flags & GPIOHANDLE_REQUEST_BIAS_DISABLE) ||
|
||||
(flags & GPIOHANDLE_REQUEST_BIAS_PULL_UP) ||
|
||||
(flags & GPIOHANDLE_REQUEST_BIAS_PULL_DOWN)))
|
||||
return -EINVAL;
|
||||
|
||||
/* Only one bias flag can be set. */
|
||||
if (((flags & GPIOHANDLE_REQUEST_BIAS_DISABLE) &&
|
||||
(flags & (GPIOHANDLE_REQUEST_BIAS_PULL_DOWN |
|
||||
GPIOHANDLE_REQUEST_BIAS_PULL_UP))) ||
|
||||
((flags & GPIOHANDLE_REQUEST_BIAS_PULL_DOWN) &&
|
||||
(flags & GPIOHANDLE_REQUEST_BIAS_PULL_UP)))
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void linehandle_configure_flag(unsigned long *flagsp,
|
||||
u32 bit, bool active)
|
||||
{
|
||||
if (active)
|
||||
set_bit(bit, flagsp);
|
||||
else
|
||||
clear_bit(bit, flagsp);
|
||||
}
|
||||
|
||||
static long linehandle_set_config(struct linehandle_state *lh,
|
||||
void __user *ip)
|
||||
{
|
||||
struct gpiohandle_config gcnf;
|
||||
struct gpio_desc *desc;
|
||||
int i, ret;
|
||||
u32 lflags;
|
||||
unsigned long *flagsp;
|
||||
|
||||
if (copy_from_user(&gcnf, ip, sizeof(gcnf)))
|
||||
return -EFAULT;
|
||||
|
||||
lflags = gcnf.flags;
|
||||
ret = linehandle_validate_flags(lflags);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
for (i = 0; i < lh->numdescs; i++) {
|
||||
desc = lh->descs[i];
|
||||
flagsp = &desc->flags;
|
||||
|
||||
linehandle_configure_flag(flagsp, FLAG_ACTIVE_LOW,
|
||||
lflags & GPIOHANDLE_REQUEST_ACTIVE_LOW);
|
||||
|
||||
linehandle_configure_flag(flagsp, FLAG_OPEN_DRAIN,
|
||||
lflags & GPIOHANDLE_REQUEST_OPEN_DRAIN);
|
||||
|
||||
linehandle_configure_flag(flagsp, FLAG_OPEN_SOURCE,
|
||||
lflags & GPIOHANDLE_REQUEST_OPEN_SOURCE);
|
||||
|
||||
linehandle_configure_flag(flagsp, FLAG_PULL_UP,
|
||||
lflags & GPIOHANDLE_REQUEST_BIAS_PULL_UP);
|
||||
|
||||
linehandle_configure_flag(flagsp, FLAG_PULL_DOWN,
|
||||
lflags & GPIOHANDLE_REQUEST_BIAS_PULL_DOWN);
|
||||
|
||||
linehandle_configure_flag(flagsp, FLAG_BIAS_DISABLE,
|
||||
lflags & GPIOHANDLE_REQUEST_BIAS_DISABLE);
|
||||
|
||||
/*
|
||||
* Lines have to be requested explicitly for input
|
||||
* or output, else the line will be treated "as is".
|
||||
*/
|
||||
if (lflags & GPIOHANDLE_REQUEST_OUTPUT) {
|
||||
int val = !!gcnf.default_values[i];
|
||||
|
||||
ret = gpiod_direction_output(desc, val);
|
||||
if (ret)
|
||||
return ret;
|
||||
} else if (lflags & GPIOHANDLE_REQUEST_INPUT) {
|
||||
ret = gpiod_direction_input(desc);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static long linehandle_ioctl(struct file *filep, unsigned int cmd,
|
||||
unsigned long arg)
|
||||
{
|
||||
@ -475,6 +601,8 @@ static long linehandle_ioctl(struct file *filep, unsigned int cmd,
|
||||
lh->descs,
|
||||
NULL,
|
||||
vals);
|
||||
} else if (cmd == GPIOHANDLE_SET_CONFIG_IOCTL) {
|
||||
return linehandle_set_config(lh, ip);
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
@ -526,32 +654,9 @@ static int linehandle_create(struct gpio_device *gdev, void __user *ip)
|
||||
|
||||
lflags = handlereq.flags;
|
||||
|
||||
/* Return an error if an unknown flag is set */
|
||||
if (lflags & ~GPIOHANDLE_REQUEST_VALID_FLAGS)
|
||||
return -EINVAL;
|
||||
|
||||
/*
|
||||
* Do not allow both INPUT & OUTPUT flags to be set as they are
|
||||
* contradictory.
|
||||
*/
|
||||
if ((lflags & GPIOHANDLE_REQUEST_INPUT) &&
|
||||
(lflags & GPIOHANDLE_REQUEST_OUTPUT))
|
||||
return -EINVAL;
|
||||
|
||||
/*
|
||||
* Do not allow OPEN_SOURCE & OPEN_DRAIN flags in a single request. If
|
||||
* the hardware actually supports enabling both at the same time the
|
||||
* electrical result would be disastrous.
|
||||
*/
|
||||
if ((lflags & GPIOHANDLE_REQUEST_OPEN_DRAIN) &&
|
||||
(lflags & GPIOHANDLE_REQUEST_OPEN_SOURCE))
|
||||
return -EINVAL;
|
||||
|
||||
/* OPEN_DRAIN and OPEN_SOURCE flags only make sense for output mode. */
|
||||
if (!(lflags & GPIOHANDLE_REQUEST_OUTPUT) &&
|
||||
((lflags & GPIOHANDLE_REQUEST_OPEN_DRAIN) ||
|
||||
(lflags & GPIOHANDLE_REQUEST_OPEN_SOURCE)))
|
||||
return -EINVAL;
|
||||
ret = linehandle_validate_flags(lflags);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
lh = kzalloc(sizeof(*lh), GFP_KERNEL);
|
||||
if (!lh)
|
||||
@ -593,6 +698,12 @@ static int linehandle_create(struct gpio_device *gdev, void __user *ip)
|
||||
set_bit(FLAG_OPEN_DRAIN, &desc->flags);
|
||||
if (lflags & GPIOHANDLE_REQUEST_OPEN_SOURCE)
|
||||
set_bit(FLAG_OPEN_SOURCE, &desc->flags);
|
||||
if (lflags & GPIOHANDLE_REQUEST_BIAS_DISABLE)
|
||||
set_bit(FLAG_BIAS_DISABLE, &desc->flags);
|
||||
if (lflags & GPIOHANDLE_REQUEST_BIAS_PULL_DOWN)
|
||||
set_bit(FLAG_PULL_DOWN, &desc->flags);
|
||||
if (lflags & GPIOHANDLE_REQUEST_BIAS_PULL_UP)
|
||||
set_bit(FLAG_PULL_UP, &desc->flags);
|
||||
|
||||
ret = gpiod_set_transitory(desc, false);
|
||||
if (ret < 0)
|
||||
@ -895,6 +1006,32 @@ static int lineevent_create(struct gpio_device *gdev, void __user *ip)
|
||||
if (copy_from_user(&eventreq, ip, sizeof(eventreq)))
|
||||
return -EFAULT;
|
||||
|
||||
offset = eventreq.lineoffset;
|
||||
lflags = eventreq.handleflags;
|
||||
eflags = eventreq.eventflags;
|
||||
|
||||
if (offset >= gdev->ngpio)
|
||||
return -EINVAL;
|
||||
|
||||
/* Return an error if a unknown flag is set */
|
||||
if ((lflags & ~GPIOHANDLE_REQUEST_VALID_FLAGS) ||
|
||||
(eflags & ~GPIOEVENT_REQUEST_VALID_FLAGS))
|
||||
return -EINVAL;
|
||||
|
||||
/* This is just wrong: we don't look for events on output lines */
|
||||
if ((lflags & GPIOHANDLE_REQUEST_OUTPUT) ||
|
||||
(lflags & GPIOHANDLE_REQUEST_OPEN_DRAIN) ||
|
||||
(lflags & GPIOHANDLE_REQUEST_OPEN_SOURCE))
|
||||
return -EINVAL;
|
||||
|
||||
/* Only one bias flag can be set. */
|
||||
if (((lflags & GPIOHANDLE_REQUEST_BIAS_DISABLE) &&
|
||||
(lflags & (GPIOHANDLE_REQUEST_BIAS_PULL_DOWN |
|
||||
GPIOHANDLE_REQUEST_BIAS_PULL_UP))) ||
|
||||
((lflags & GPIOHANDLE_REQUEST_BIAS_PULL_DOWN) &&
|
||||
(lflags & GPIOHANDLE_REQUEST_BIAS_PULL_UP)))
|
||||
return -EINVAL;
|
||||
|
||||
le = kzalloc(sizeof(*le), GFP_KERNEL);
|
||||
if (!le)
|
||||
return -ENOMEM;
|
||||
@ -912,30 +1049,6 @@ static int lineevent_create(struct gpio_device *gdev, void __user *ip)
|
||||
}
|
||||
}
|
||||
|
||||
offset = eventreq.lineoffset;
|
||||
lflags = eventreq.handleflags;
|
||||
eflags = eventreq.eventflags;
|
||||
|
||||
if (offset >= gdev->ngpio) {
|
||||
ret = -EINVAL;
|
||||
goto out_free_label;
|
||||
}
|
||||
|
||||
/* Return an error if a unknown flag is set */
|
||||
if ((lflags & ~GPIOHANDLE_REQUEST_VALID_FLAGS) ||
|
||||
(eflags & ~GPIOEVENT_REQUEST_VALID_FLAGS)) {
|
||||
ret = -EINVAL;
|
||||
goto out_free_label;
|
||||
}
|
||||
|
||||
/* This is just wrong: we don't look for events on output lines */
|
||||
if ((lflags & GPIOHANDLE_REQUEST_OUTPUT) ||
|
||||
(lflags & GPIOHANDLE_REQUEST_OPEN_DRAIN) ||
|
||||
(lflags & GPIOHANDLE_REQUEST_OPEN_SOURCE)) {
|
||||
ret = -EINVAL;
|
||||
goto out_free_label;
|
||||
}
|
||||
|
||||
desc = &gdev->descs[offset];
|
||||
ret = gpiod_request(desc, le->label);
|
||||
if (ret)
|
||||
@ -945,6 +1058,12 @@ static int lineevent_create(struct gpio_device *gdev, void __user *ip)
|
||||
|
||||
if (lflags & GPIOHANDLE_REQUEST_ACTIVE_LOW)
|
||||
set_bit(FLAG_ACTIVE_LOW, &desc->flags);
|
||||
if (lflags & GPIOHANDLE_REQUEST_BIAS_DISABLE)
|
||||
set_bit(FLAG_BIAS_DISABLE, &desc->flags);
|
||||
if (lflags & GPIOHANDLE_REQUEST_BIAS_PULL_DOWN)
|
||||
set_bit(FLAG_PULL_DOWN, &desc->flags);
|
||||
if (lflags & GPIOHANDLE_REQUEST_BIAS_PULL_UP)
|
||||
set_bit(FLAG_PULL_UP, &desc->flags);
|
||||
|
||||
ret = gpiod_direction_input(desc);
|
||||
if (ret)
|
||||
@ -1098,6 +1217,12 @@ static long gpio_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
|
||||
if (test_bit(FLAG_OPEN_SOURCE, &desc->flags))
|
||||
lineinfo.flags |= (GPIOLINE_FLAG_OPEN_SOURCE |
|
||||
GPIOLINE_FLAG_IS_OUT);
|
||||
if (test_bit(FLAG_BIAS_DISABLE, &desc->flags))
|
||||
lineinfo.flags |= GPIOLINE_FLAG_BIAS_DISABLE;
|
||||
if (test_bit(FLAG_PULL_DOWN, &desc->flags))
|
||||
lineinfo.flags |= GPIOLINE_FLAG_BIAS_PULL_DOWN;
|
||||
if (test_bit(FLAG_PULL_UP, &desc->flags))
|
||||
lineinfo.flags |= GPIOLINE_FLAG_BIAS_PULL_UP;
|
||||
|
||||
if (copy_to_user(ip, &lineinfo, sizeof(lineinfo)))
|
||||
return -EFAULT;
|
||||
@ -1403,15 +1528,19 @@ int gpiochip_add_data_with_key(struct gpio_chip *chip, void *data,
|
||||
}
|
||||
}
|
||||
|
||||
ret = gpiochip_add_pin_ranges(chip);
|
||||
if (ret)
|
||||
goto err_remove_of_chip;
|
||||
|
||||
acpi_gpiochip_add(chip);
|
||||
|
||||
machine_gpiochip_add(chip);
|
||||
|
||||
ret = gpiochip_irqchip_init_hw(chip);
|
||||
ret = gpiochip_irqchip_init_valid_mask(chip);
|
||||
if (ret)
|
||||
goto err_remove_acpi_chip;
|
||||
|
||||
ret = gpiochip_irqchip_init_valid_mask(chip);
|
||||
ret = gpiochip_irqchip_init_hw(chip);
|
||||
if (ret)
|
||||
goto err_remove_acpi_chip;
|
||||
|
||||
@ -1444,6 +1573,7 @@ err_remove_of_chip:
|
||||
gpiochip_free_hogs(chip);
|
||||
of_gpiochip_remove(chip);
|
||||
err_free_gpiochip_mask:
|
||||
gpiochip_remove_pin_ranges(chip);
|
||||
gpiochip_free_valid_mask(chip);
|
||||
err_remove_from_list:
|
||||
spin_lock_irqsave(&gpio_lock, flags);
|
||||
@ -1499,8 +1629,8 @@ void gpiochip_remove(struct gpio_chip *chip)
|
||||
gdev->chip = NULL;
|
||||
gpiochip_irqchip_remove(chip);
|
||||
acpi_gpiochip_remove(chip);
|
||||
gpiochip_remove_pin_ranges(chip);
|
||||
of_gpiochip_remove(chip);
|
||||
gpiochip_remove_pin_ranges(chip);
|
||||
gpiochip_free_valid_mask(chip);
|
||||
/*
|
||||
* We accept no more calls into the driver from this point, so
|
||||
@ -1539,7 +1669,7 @@ static void devm_gpio_chip_release(struct device *dev, void *res)
|
||||
}
|
||||
|
||||
/**
|
||||
* devm_gpiochip_add_data() - Resource manager gpiochip_add_data()
|
||||
* devm_gpiochip_add_data() - Resource managed gpiochip_add_data()
|
||||
* @dev: pointer to the device that gpio_chip belongs to.
|
||||
* @chip: the chip to register, with chip->base initialized
|
||||
* @data: driver-private data associated with this chip
|
||||
@ -2790,6 +2920,9 @@ static bool gpiod_free_commit(struct gpio_desc *desc)
|
||||
clear_bit(FLAG_REQUESTED, &desc->flags);
|
||||
clear_bit(FLAG_OPEN_DRAIN, &desc->flags);
|
||||
clear_bit(FLAG_OPEN_SOURCE, &desc->flags);
|
||||
clear_bit(FLAG_PULL_UP, &desc->flags);
|
||||
clear_bit(FLAG_PULL_DOWN, &desc->flags);
|
||||
clear_bit(FLAG_BIAS_DISABLE, &desc->flags);
|
||||
clear_bit(FLAG_IS_HOGGED, &desc->flags);
|
||||
ret = true;
|
||||
}
|
||||
@ -2916,6 +3049,7 @@ static int gpio_set_config(struct gpio_chip *gc, unsigned offset,
|
||||
unsigned arg;
|
||||
|
||||
switch (mode) {
|
||||
case PIN_CONFIG_BIAS_DISABLE:
|
||||
case PIN_CONFIG_BIAS_PULL_DOWN:
|
||||
case PIN_CONFIG_BIAS_PULL_UP:
|
||||
arg = 1;
|
||||
@ -2929,6 +3063,26 @@ static int gpio_set_config(struct gpio_chip *gc, unsigned offset,
|
||||
return gc->set_config ? gc->set_config(gc, offset, config) : -ENOTSUPP;
|
||||
}
|
||||
|
||||
static int gpio_set_bias(struct gpio_chip *chip, struct gpio_desc *desc)
|
||||
{
|
||||
int bias = 0;
|
||||
int ret = 0;
|
||||
|
||||
if (test_bit(FLAG_BIAS_DISABLE, &desc->flags))
|
||||
bias = PIN_CONFIG_BIAS_DISABLE;
|
||||
else if (test_bit(FLAG_PULL_UP, &desc->flags))
|
||||
bias = PIN_CONFIG_BIAS_PULL_UP;
|
||||
else if (test_bit(FLAG_PULL_DOWN, &desc->flags))
|
||||
bias = PIN_CONFIG_BIAS_PULL_DOWN;
|
||||
|
||||
if (bias) {
|
||||
ret = gpio_set_config(chip, gpio_chip_hwgpio(desc), bias);
|
||||
if (ret != -ENOTSUPP)
|
||||
return ret;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* gpiod_direction_input - set the GPIO direction to input
|
||||
* @desc: GPIO to set to input
|
||||
@ -2973,15 +3127,10 @@ int gpiod_direction_input(struct gpio_desc *desc)
|
||||
__func__);
|
||||
return -EIO;
|
||||
}
|
||||
if (ret == 0)
|
||||
if (ret == 0) {
|
||||
clear_bit(FLAG_IS_OUT, &desc->flags);
|
||||
|
||||
if (test_bit(FLAG_PULL_UP, &desc->flags))
|
||||
gpio_set_config(chip, gpio_chip_hwgpio(desc),
|
||||
PIN_CONFIG_BIAS_PULL_UP);
|
||||
else if (test_bit(FLAG_PULL_DOWN, &desc->flags))
|
||||
gpio_set_config(chip, gpio_chip_hwgpio(desc),
|
||||
PIN_CONFIG_BIAS_PULL_DOWN);
|
||||
ret = gpio_set_bias(chip, desc);
|
||||
}
|
||||
|
||||
trace_gpio_direction(desc_to_gpio(desc), 1, ret);
|
||||
|
||||
@ -3111,6 +3260,9 @@ int gpiod_direction_output(struct gpio_desc *desc, int value)
|
||||
}
|
||||
|
||||
set_output_value:
|
||||
ret = gpio_set_bias(gc, desc);
|
||||
if (ret)
|
||||
return ret;
|
||||
return gpiod_direction_output_raw_commit(desc, value);
|
||||
|
||||
set_output_flag:
|
||||
@ -4742,9 +4894,9 @@ int gpiod_hog(struct gpio_desc *desc, const char *name,
|
||||
|
||||
pr_info("GPIO line %d (%s) hogged as %s%s\n",
|
||||
desc_to_gpio(desc), name,
|
||||
(dflags&GPIOD_FLAGS_BIT_DIR_OUT) ? "output" : "input",
|
||||
(dflags&GPIOD_FLAGS_BIT_DIR_OUT) ?
|
||||
(dflags&GPIOD_FLAGS_BIT_DIR_VAL) ? "/high" : "/low":"");
|
||||
(dflags & GPIOD_FLAGS_BIT_DIR_OUT) ? "output" : "input",
|
||||
(dflags & GPIOD_FLAGS_BIT_DIR_OUT) ?
|
||||
(dflags & GPIOD_FLAGS_BIT_DIR_VAL) ? "/high" : "/low" : "");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -110,6 +110,7 @@ struct gpio_desc {
|
||||
#define FLAG_TRANSITORY 12 /* GPIO may lose value in sleep or reset */
|
||||
#define FLAG_PULL_UP 13 /* GPIO has pull up enabled */
|
||||
#define FLAG_PULL_DOWN 14 /* GPIO has pull down enabled */
|
||||
#define FLAG_BIAS_DISABLE 15 /* GPIO has pull disabled */
|
||||
|
||||
/* Connection label */
|
||||
const char *label;
|
||||
|
@ -285,8 +285,8 @@ static int tfp410_get_connector_properties(struct tfp410 *dvi)
|
||||
else
|
||||
dvi->connector_type = DRM_MODE_CONNECTOR_DVID;
|
||||
|
||||
dvi->hpd = fwnode_get_named_gpiod(&connector_node->fwnode,
|
||||
"hpd-gpios", 0, GPIOD_IN, "hpd");
|
||||
dvi->hpd = fwnode_gpiod_get_index(&connector_node->fwnode,
|
||||
"hpd", 0, GPIOD_IN, "hpd");
|
||||
if (IS_ERR(dvi->hpd)) {
|
||||
ret = PTR_ERR(dvi->hpd);
|
||||
dvi->hpd = NULL;
|
||||
|
@ -22,6 +22,9 @@ enum gpio_lookup_flags;
|
||||
|
||||
struct gpio_chip;
|
||||
|
||||
#define GPIO_LINE_DIRECTION_IN 1
|
||||
#define GPIO_LINE_DIRECTION_OUT 0
|
||||
|
||||
/**
|
||||
* struct gpio_irq_chip - GPIO interrupt controller
|
||||
*/
|
||||
@ -286,6 +289,9 @@ struct gpio_irq_chip {
|
||||
* state (such as pullup/pulldown configuration).
|
||||
* @init_valid_mask: optional routine to initialize @valid_mask, to be used if
|
||||
* not all GPIOs are valid.
|
||||
* @add_pin_ranges: optional routine to initialize pin ranges, to be used when
|
||||
* requires special mapping of the pins that provides GPIO functionality.
|
||||
* It is called after adding GPIO chip and before adding IRQ chip.
|
||||
* @base: identifies the first GPIO number handled by this chip;
|
||||
* or, if negative during registration, requests dynamic ID allocation.
|
||||
* DEPRECATION: providing anything non-negative and nailing the base
|
||||
@ -376,6 +382,8 @@ struct gpio_chip {
|
||||
unsigned long *valid_mask,
|
||||
unsigned int ngpios);
|
||||
|
||||
int (*add_pin_ranges)(struct gpio_chip *chip);
|
||||
|
||||
int base;
|
||||
u16 ngpio;
|
||||
const char *const *names;
|
||||
|
@ -33,6 +33,9 @@ struct gpiochip_info {
|
||||
#define GPIOLINE_FLAG_ACTIVE_LOW (1UL << 2)
|
||||
#define GPIOLINE_FLAG_OPEN_DRAIN (1UL << 3)
|
||||
#define GPIOLINE_FLAG_OPEN_SOURCE (1UL << 4)
|
||||
#define GPIOLINE_FLAG_BIAS_PULL_UP (1UL << 5)
|
||||
#define GPIOLINE_FLAG_BIAS_PULL_DOWN (1UL << 6)
|
||||
#define GPIOLINE_FLAG_BIAS_DISABLE (1UL << 7)
|
||||
|
||||
/**
|
||||
* struct gpioline_info - Information about a certain GPIO line
|
||||
@ -62,6 +65,9 @@ struct gpioline_info {
|
||||
#define GPIOHANDLE_REQUEST_ACTIVE_LOW (1UL << 2)
|
||||
#define GPIOHANDLE_REQUEST_OPEN_DRAIN (1UL << 3)
|
||||
#define GPIOHANDLE_REQUEST_OPEN_SOURCE (1UL << 4)
|
||||
#define GPIOHANDLE_REQUEST_BIAS_PULL_UP (1UL << 5)
|
||||
#define GPIOHANDLE_REQUEST_BIAS_PULL_DOWN (1UL << 6)
|
||||
#define GPIOHANDLE_REQUEST_BIAS_DISABLE (1UL << 7)
|
||||
|
||||
/**
|
||||
* struct gpiohandle_request - Information about a GPIO handle request
|
||||
@ -94,6 +100,24 @@ struct gpiohandle_request {
|
||||
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
|
||||
* @values: when getting the state of lines this contains the current
|
||||
|
Loading…
Reference in New Issue
Block a user