forked from Minki/linux
Merge branch 'gpio-irqchip-rework' of /home/linus/linux-gpio into devel
This commit is contained in:
commit
bee67c7c9d
@ -11,7 +11,7 @@ Description:
|
||||
Kernel code may export it for complete or partial access.
|
||||
|
||||
GPIOs are identified as they are inside the kernel, using integers in
|
||||
the range 0..INT_MAX. See Documentation/gpio.txt for more information.
|
||||
the range 0..INT_MAX. See Documentation/gpio/gpio.txt for more information.
|
||||
|
||||
/sys/class/gpio
|
||||
/export ... asks the kernel to export a GPIO to userspace
|
||||
|
@ -1,4 +1,8 @@
|
||||
Common properties
|
||||
=================
|
||||
|
||||
Endianness
|
||||
----------
|
||||
|
||||
The Devicetree Specification does not define any properties related to hardware
|
||||
byteswapping, but endianness issues show up frequently in porting Linux to
|
||||
@ -58,3 +62,25 @@ dev: dev@40031000 {
|
||||
...
|
||||
little-endian;
|
||||
};
|
||||
|
||||
Daisy-chained devices
|
||||
---------------------
|
||||
|
||||
Many serially-attached GPIO and IIO devices are daisy-chainable. To the
|
||||
host controller, a daisy-chain appears as a single device, but the number
|
||||
of inputs and outputs it provides is the sum of inputs and outputs provided
|
||||
by all of its devices. The driver needs to know how many devices the
|
||||
daisy-chain comprises to determine the amount of data exchanged, how many
|
||||
inputs and outputs to register and so on.
|
||||
|
||||
Optional properties:
|
||||
- #daisy-chained-devices: Number of devices in the daisy-chain (default is 1).
|
||||
|
||||
Example:
|
||||
gpio@0 {
|
||||
compatible = "name";
|
||||
reg = <0>;
|
||||
gpio-controller;
|
||||
#gpio-cells = <2>;
|
||||
#daisy-chained-devices = <3>;
|
||||
};
|
||||
|
59
Documentation/devicetree/bindings/gpio/gpio-max3191x.txt
Normal file
59
Documentation/devicetree/bindings/gpio/gpio-max3191x.txt
Normal file
@ -0,0 +1,59 @@
|
||||
GPIO driver for Maxim MAX3191x industrial serializer
|
||||
|
||||
Required properties:
|
||||
- compatible: Must be one of:
|
||||
"maxim,max31910"
|
||||
"maxim,max31911"
|
||||
"maxim,max31912"
|
||||
"maxim,max31913"
|
||||
"maxim,max31953"
|
||||
"maxim,max31963"
|
||||
- reg: Chip select number.
|
||||
- gpio-controller: Marks the device node as a GPIO controller.
|
||||
- #gpio-cells: Should be two. For consumer use see gpio.txt.
|
||||
|
||||
Optional properties:
|
||||
- #daisy-chained-devices:
|
||||
Number of chips in the daisy-chain (default is 1).
|
||||
- maxim,modesel-gpios: GPIO pins to configure modesel of each chip.
|
||||
The number of GPIOs must equal "#daisy-chained-devices"
|
||||
(if each chip is driven by a separate pin) or 1
|
||||
(if all chips are wired to the same pin).
|
||||
- maxim,fault-gpios: GPIO pins to read fault of each chip.
|
||||
The number of GPIOs must equal "#daisy-chained-devices"
|
||||
or 1.
|
||||
- maxim,db0-gpios: GPIO pins to configure debounce of each chip.
|
||||
The number of GPIOs must equal "#daisy-chained-devices"
|
||||
or 1.
|
||||
- maxim,db1-gpios: GPIO pins to configure debounce of each chip.
|
||||
The number of GPIOs must equal "maxim,db0-gpios".
|
||||
- maxim,modesel-8bit: Boolean whether the modesel pin of the chips is
|
||||
pulled high (8-bit mode). Use this if the modesel pin
|
||||
is hardwired and consequently "maxim,modesel-gpios"
|
||||
cannot be specified. By default if neither this nor
|
||||
"maxim,modesel-gpios" is given, the driver assumes
|
||||
that modesel is pulled low (16-bit mode).
|
||||
- maxim,ignore-undervoltage:
|
||||
Boolean whether to ignore undervoltage alarms signaled
|
||||
by the "maxim,fault-gpios" or by the status byte
|
||||
(in 16-bit mode). Use this if the chips are powered
|
||||
through 5VOUT instead of VCC24V, in which case they
|
||||
will constantly signal undervoltage.
|
||||
|
||||
For other required and optional properties of SPI slave nodes please refer to
|
||||
../spi/spi-bus.txt.
|
||||
|
||||
Example:
|
||||
gpio@0 {
|
||||
compatible = "maxim,max31913";
|
||||
reg = <0>;
|
||||
gpio-controller;
|
||||
#gpio-cells = <2>;
|
||||
|
||||
maxim,modesel-gpios = <&gpio2 23>;
|
||||
maxim,fault-gpios = <&gpio2 24 GPIO_ACTIVE_LOW>;
|
||||
maxim,db0-gpios = <&gpio2 25>;
|
||||
maxim,db1-gpios = <&gpio2 26>;
|
||||
|
||||
spi-max-frequency = <25000000>;
|
||||
};
|
52
Documentation/devicetree/bindings/gpio/gpio-uniphier.txt
Normal file
52
Documentation/devicetree/bindings/gpio/gpio-uniphier.txt
Normal file
@ -0,0 +1,52 @@
|
||||
UniPhier GPIO controller
|
||||
|
||||
Required properties:
|
||||
- compatible: Should be "socionext,uniphier-gpio".
|
||||
- reg: Specifies offset and length of the register set for the device.
|
||||
- gpio-controller: Marks the device node as a GPIO controller.
|
||||
- #gpio-cells: Should be 2. The first cell is the pin number and the second
|
||||
cell is used to specify optional parameters.
|
||||
- interrupt-parent: Specifies the parent interrupt controller.
|
||||
- interrupt-controller: Marks the device node as an interrupt controller.
|
||||
- #interrupt-cells: Should be 2. The first cell defines the interrupt number.
|
||||
The second cell bits[3:0] is used to specify trigger type as follows:
|
||||
1 = low-to-high edge triggered
|
||||
2 = high-to-low edge triggered
|
||||
4 = active high level-sensitive
|
||||
8 = active low level-sensitive
|
||||
Valid combinations are 1, 2, 3, 4, 8.
|
||||
- ngpios: Specifies the number of GPIO lines.
|
||||
- gpio-ranges: Mapping to pin controller pins (as described in gpio.txt)
|
||||
- socionext,interrupt-ranges: Specifies an interrupt number mapping between
|
||||
this GPIO controller and its interrupt parent, in the form of arbitrary
|
||||
number of <child-interrupt-base parent-interrupt-base length> triplets.
|
||||
|
||||
Optional properties:
|
||||
- gpio-ranges-group-names: Used for named gpio ranges (as described in gpio.txt)
|
||||
|
||||
Example:
|
||||
gpio: gpio@55000000 {
|
||||
compatible = "socionext,uniphier-gpio";
|
||||
reg = <0x55000000 0x200>;
|
||||
interrupt-parent = <&aidet>;
|
||||
interrupt-controller;
|
||||
#interrupt-cells = <2>;
|
||||
gpio-controller;
|
||||
#gpio-cells = <2>;
|
||||
gpio-ranges = <&pinctrl 0 0 0>;
|
||||
gpio-ranges-group-names = "gpio_range";
|
||||
ngpios = <248>;
|
||||
socionext,interrupt-ranges = <0 48 16>, <16 154 5>, <21 217 3>;
|
||||
};
|
||||
|
||||
Consumer Example:
|
||||
|
||||
sdhci0_pwrseq {
|
||||
compatible = "mmc-pwrseq-emmc";
|
||||
reset-gpios = <&gpio UNIPHIER_GPIO_PORT(29, 4) GPIO_ACTIVE_LOW>;
|
||||
};
|
||||
|
||||
Please note UNIPHIER_GPIO_PORT(29, 4) represents PORT294 in the SoC document.
|
||||
Unfortunately, only the one's place is octal in the port numbering. (That is,
|
||||
PORT 8, 9, 18, 19, 28, 29, ... are missing.) UNIPHIER_GPIO_PORT() is a helper
|
||||
macro to calculate 29 * 8 + 4.
|
@ -14,6 +14,7 @@ Required Properties:
|
||||
- "renesas,gpio-r8a7794": for R8A7794 (R-Car E2) compatible GPIO controller.
|
||||
- "renesas,gpio-r8a7795": for R8A7795 (R-Car H3) compatible GPIO controller.
|
||||
- "renesas,gpio-r8a7796": for R8A7796 (R-Car M3-W) compatible GPIO controller.
|
||||
- "renesas,gpio-r8a77970": for R8A77970 (R-Car V3M) compatible GPIO controller.
|
||||
- "renesas,rcar-gen1-gpio": for a generic R-Car Gen1 GPIO controller.
|
||||
- "renesas,rcar-gen2-gpio": for a generic R-Car Gen2 or RZ/G1 GPIO controller.
|
||||
- "renesas,rcar-gen3-gpio": for a generic R-Car Gen3 GPIO controller.
|
||||
|
@ -29,6 +29,7 @@ controller.
|
||||
- interrupts : The interrupt to the parent controller raised when GPIOs
|
||||
generate the interrupts.
|
||||
- snps,nr-gpios : The number of pins in the port, a single cell.
|
||||
- resets : Reset line for the controller.
|
||||
|
||||
Example:
|
||||
|
||||
|
@ -10,14 +10,30 @@ Guidelines for GPIOs consumers
|
||||
==============================
|
||||
|
||||
Drivers that can't work without standard GPIO calls should have Kconfig entries
|
||||
that depend on GPIOLIB. The functions that allow a driver to obtain and use
|
||||
GPIOs are available by including the following file:
|
||||
that depend on GPIOLIB or select GPIOLIB. The functions that allow a driver to
|
||||
obtain and use GPIOs are available by including the following file:
|
||||
|
||||
#include <linux/gpio/consumer.h>
|
||||
|
||||
There are static inline stubs for all functions in the header file in the case
|
||||
where GPIOLIB is disabled. When these stubs are called they will emit
|
||||
warnings. These stubs are used for two use cases:
|
||||
|
||||
- Simple compile coverage with e.g. COMPILE_TEST - it does not matter that
|
||||
the current platform does not enable or select GPIOLIB because we are not
|
||||
going to execute the system anyway.
|
||||
|
||||
- Truly optional GPIOLIB support - where the driver does not really make use
|
||||
of the GPIOs on certain compile-time configurations for certain systems, but
|
||||
will use it under other compile-time configurations. In this case the
|
||||
consumer must make sure not to call into these functions, or the user will
|
||||
be met with console warnings that may be perceived as intimidating.
|
||||
|
||||
All the functions that work with the descriptor-based GPIO interface are
|
||||
prefixed with gpiod_. The gpio_ prefix is used for the legacy interface. No
|
||||
other function in the kernel should use these prefixes.
|
||||
other function in the kernel should use these prefixes. The use of the legacy
|
||||
functions is strongly discouraged, new code should use <linux/gpio/consumer.h>
|
||||
and descriptors exclusively.
|
||||
|
||||
|
||||
Obtaining and Disposing GPIOs
|
||||
@ -279,9 +295,22 @@ as possible, especially by drivers which should not care about the actual
|
||||
physical line level and worry about the logical value instead.
|
||||
|
||||
|
||||
Set multiple GPIO outputs with a single function call
|
||||
-----------------------------------------------------
|
||||
The following functions set the output values of an array of GPIOs:
|
||||
Access multiple GPIOs with a single function call
|
||||
-------------------------------------------------
|
||||
The following functions get or set the values of an array of GPIOs:
|
||||
|
||||
int gpiod_get_array_value(unsigned int array_size,
|
||||
struct gpio_desc **desc_array,
|
||||
int *value_array);
|
||||
int gpiod_get_raw_array_value(unsigned int array_size,
|
||||
struct gpio_desc **desc_array,
|
||||
int *value_array);
|
||||
int gpiod_get_array_value_cansleep(unsigned int array_size,
|
||||
struct gpio_desc **desc_array,
|
||||
int *value_array);
|
||||
int gpiod_get_raw_array_value_cansleep(unsigned int array_size,
|
||||
struct gpio_desc **desc_array,
|
||||
int *value_array);
|
||||
|
||||
void gpiod_set_array_value(unsigned int array_size,
|
||||
struct gpio_desc **desc_array,
|
||||
@ -296,34 +325,40 @@ The following functions set the output values of an array of GPIOs:
|
||||
struct gpio_desc **desc_array,
|
||||
int *value_array)
|
||||
|
||||
The array can be an arbitrary set of GPIOs. The functions will try to set
|
||||
The array can be an arbitrary set of GPIOs. The functions will try to access
|
||||
GPIOs belonging to the same bank or chip simultaneously if supported by the
|
||||
corresponding chip driver. In that case a significantly improved performance
|
||||
can be expected. If simultaneous setting is not possible the GPIOs will be set
|
||||
sequentially.
|
||||
can be expected. If simultaneous access is not possible the GPIOs will be
|
||||
accessed sequentially.
|
||||
|
||||
The gpiod_set_array() functions take three arguments:
|
||||
The functions take three arguments:
|
||||
* array_size - the number of array elements
|
||||
* desc_array - an array of GPIO descriptors
|
||||
* value_array - an array of values to assign to the GPIOs
|
||||
* value_array - an array to store the GPIOs' values (get) or
|
||||
an array of values to assign to the GPIOs (set)
|
||||
|
||||
The descriptor array can be obtained using the gpiod_get_array() function
|
||||
or one of its variants. If the group of descriptors returned by that function
|
||||
matches the desired group of GPIOs, those GPIOs can be set by simply using
|
||||
matches the desired group of GPIOs, those GPIOs can be accessed by simply using
|
||||
the struct gpio_descs returned by gpiod_get_array():
|
||||
|
||||
struct gpio_descs *my_gpio_descs = gpiod_get_array(...);
|
||||
gpiod_set_array_value(my_gpio_descs->ndescs, my_gpio_descs->desc,
|
||||
my_gpio_values);
|
||||
|
||||
It is also possible to set a completely arbitrary array of descriptors. The
|
||||
It is also possible to access a completely arbitrary array of descriptors. The
|
||||
descriptors may be obtained using any combination of gpiod_get() and
|
||||
gpiod_get_array(). Afterwards the array of descriptors has to be setup
|
||||
manually before it can be used with gpiod_set_array().
|
||||
manually before it can be passed to one of the above functions.
|
||||
|
||||
Note that for optimal performance GPIOs belonging to the same chip should be
|
||||
contiguous within the array of descriptors.
|
||||
|
||||
The return value of gpiod_get_array_value() and its variants is 0 on success
|
||||
or negative on error. Note the difference to gpiod_get_value(), which returns
|
||||
0 or 1 on success to convey the GPIO value. With the array functions, the GPIO
|
||||
values are stored in value_array rather than passed back as return value.
|
||||
|
||||
|
||||
GPIOs mapped to IRQs
|
||||
--------------------
|
||||
|
@ -254,7 +254,7 @@ GPIO irqchips usually fall in one of two categories:
|
||||
static irqreturn_t omap_gpio_irq_handler(int irq, void *gpiobank)
|
||||
unsigned long wa_lock_flags;
|
||||
raw_spin_lock_irqsave(&bank->wa_lock, wa_lock_flags);
|
||||
generic_handle_irq(irq_find_mapping(bank->chip.irqdomain, bit));
|
||||
generic_handle_irq(irq_find_mapping(bank->chip.irq.domain, bit));
|
||||
raw_spin_unlock_irqrestore(&bank->wa_lock, wa_lock_flags);
|
||||
|
||||
* GENERIC CHAINED GPIO irqchips: these are the same as "CHAINED GPIO irqchips",
|
||||
@ -313,8 +313,8 @@ symbol:
|
||||
mark all the child IRQs as having the other IRQ as parent.
|
||||
|
||||
If there is a need to exclude certain GPIOs from the IRQ domain, you can
|
||||
set .irq_need_valid_mask of the gpiochip before gpiochip_add_data() is
|
||||
called. This allocates an .irq_valid_mask with as many bits set as there
|
||||
set .irq.need_valid_mask of the gpiochip before gpiochip_add_data() is
|
||||
called. This allocates an .irq.valid_mask with as many bits set as there
|
||||
are GPIOs in the chip. Drivers can exclude GPIOs by clearing bits from this
|
||||
mask. The mask must be filled in before gpiochip_irqchip_add() or
|
||||
gpiochip_irqchip_add_nested() is called.
|
||||
|
@ -2017,6 +2017,7 @@ M: Masahiro Yamada <yamada.masahiro@socionext.com>
|
||||
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/masahiroy/linux-uniphier.git
|
||||
S: Maintained
|
||||
F: Documentation/devicetree/bindings/gpio/gpio-uniphier.txt
|
||||
F: arch/arm/boot/dts/uniphier*
|
||||
F: arch/arm/include/asm/hardware/cache-uniphier.h
|
||||
F: arch/arm/mach-uniphier/
|
||||
@ -2024,6 +2025,7 @@ F: arch/arm/mm/cache-uniphier.c
|
||||
F: arch/arm64/boot/dts/socionext/
|
||||
F: drivers/bus/uniphier-system-bus.c
|
||||
F: drivers/clk/uniphier/
|
||||
F: drivers/gpio/gpio-uniphier.c
|
||||
F: drivers/i2c/busses/i2c-uniphier*
|
||||
F: drivers/irqchip/irq-uniphier-aidet.c
|
||||
F: drivers/pinctrl/uniphier/
|
||||
@ -12884,6 +12886,13 @@ F: arch/arc/plat-axs10x
|
||||
F: arch/arc/boot/dts/ax*
|
||||
F: Documentation/devicetree/bindings/arc/axs10*
|
||||
|
||||
SYNOPSYS DESIGNWARE APB GPIO DRIVER
|
||||
M: Hoan Tran <hotran@apm.com>
|
||||
L: linux-gpio@vger.kernel.org
|
||||
S: Maintained
|
||||
F: drivers/gpio/gpio-dwapb.c
|
||||
F: Documentation/devicetree/bindings/gpio/snps-dwapb-gpio.txt
|
||||
|
||||
SYNOPSYS DESIGNWARE DMAC DRIVER
|
||||
M: Viresh Kumar <vireshk@kernel.org>
|
||||
M: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
|
||||
|
@ -113,7 +113,7 @@ static irqreturn_t bcma_gpio_irq_handler(int irq, void *dev_id)
|
||||
return IRQ_NONE;
|
||||
|
||||
for_each_set_bit(gpio, &irqs, gc->ngpio)
|
||||
generic_handle_irq(irq_find_mapping(gc->irqdomain, gpio));
|
||||
generic_handle_irq(irq_find_mapping(gc->irq.domain, gpio));
|
||||
bcma_chipco_gpio_polarity(cc, irqs, val & irqs);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
|
@ -139,7 +139,7 @@ config GPIO_BRCMSTB
|
||||
default y if (ARCH_BRCMSTB || BMIPS_GENERIC)
|
||||
depends on OF_GPIO && (ARCH_BRCMSTB || BMIPS_GENERIC || COMPILE_TEST)
|
||||
select GPIO_GENERIC
|
||||
select GPIOLIB_IRQCHIP
|
||||
select IRQ_DOMAIN
|
||||
help
|
||||
Say yes here to enable GPIO support for Broadcom STB (BCM7XXX) SoCs.
|
||||
|
||||
@ -286,8 +286,7 @@ config GPIO_LYNXPOINT
|
||||
Requires ACPI device enumeration code to set up a platform device.
|
||||
|
||||
config GPIO_MB86S7X
|
||||
bool "GPIO support for Fujitsu MB86S7x Platforms"
|
||||
depends on ARCH_MB86S7X || COMPILE_TEST
|
||||
tristate "GPIO support for Fujitsu MB86S7x Platforms"
|
||||
help
|
||||
Say yes here to support the GPIO controller in Fujitsu MB86S70 SoCs.
|
||||
|
||||
@ -442,6 +441,15 @@ config GPIO_TEGRA
|
||||
help
|
||||
Say yes here to support GPIO pins on NVIDIA Tegra SoCs.
|
||||
|
||||
config GPIO_TEGRA186
|
||||
tristate "NVIDIA Tegra186 GPIO support"
|
||||
default ARCH_TEGRA_186_SOC
|
||||
depends on ARCH_TEGRA_186_SOC || COMPILE_TEST
|
||||
depends on OF_GPIO
|
||||
select GPIOLIB_IRQCHIP
|
||||
help
|
||||
Say yes here to support GPIO pins on NVIDIA Tegra186 SoCs.
|
||||
|
||||
config GPIO_TS4800
|
||||
tristate "TS-4800 DIO blocks and compatibles"
|
||||
depends on OF_GPIO
|
||||
@ -474,6 +482,14 @@ config GPIO_TZ1090_PDC
|
||||
help
|
||||
Say yes here to support Toumaz Xenif TZ1090 PDC GPIOs.
|
||||
|
||||
config GPIO_UNIPHIER
|
||||
tristate "UniPhier GPIO support"
|
||||
depends on ARCH_UNIPHIER || COMPILE_TEST
|
||||
depends on OF_GPIO
|
||||
select IRQ_DOMAIN_HIERARCHY
|
||||
help
|
||||
Say yes here to support UniPhier GPIOs.
|
||||
|
||||
config GPIO_VF610
|
||||
def_bool y
|
||||
depends on ARCH_MXC && SOC_VF610
|
||||
@ -1246,6 +1262,16 @@ config GPIO_74X164
|
||||
shift registers. This driver can be used to provide access
|
||||
to more gpio outputs.
|
||||
|
||||
config GPIO_MAX3191X
|
||||
tristate "Maxim MAX3191x industrial serializer"
|
||||
select CRC8
|
||||
help
|
||||
GPIO driver for Maxim MAX31910, MAX31911, MAX31912, MAX31913,
|
||||
MAX31953 and MAX31963 industrial serializer, a daisy-chainable
|
||||
chip to make 8 digital 24V inputs available via SPI. Supports
|
||||
CRC checksums to guard against electromagnetic interference,
|
||||
as well as undervoltage and overtemperature detection.
|
||||
|
||||
config GPIO_MAX7301
|
||||
tristate "Maxim MAX7301 GPIO expander"
|
||||
select GPIO_MAX730X
|
||||
|
@ -69,6 +69,7 @@ obj-$(CONFIG_ARCH_LPC32XX) += gpio-lpc32xx.o
|
||||
obj-$(CONFIG_GPIO_LP873X) += gpio-lp873x.o
|
||||
obj-$(CONFIG_GPIO_LP87565) += gpio-lp87565.o
|
||||
obj-$(CONFIG_GPIO_LYNXPOINT) += gpio-lynxpoint.o
|
||||
obj-$(CONFIG_GPIO_MAX3191X) += gpio-max3191x.o
|
||||
obj-$(CONFIG_GPIO_MAX730X) += gpio-max730x.o
|
||||
obj-$(CONFIG_GPIO_MAX7300) += gpio-max7300.o
|
||||
obj-$(CONFIG_GPIO_MAX7301) += gpio-max7301.o
|
||||
@ -113,6 +114,7 @@ obj-$(CONFIG_GPIO_SYSCON) += gpio-syscon.o
|
||||
obj-$(CONFIG_GPIO_TB10X) += gpio-tb10x.o
|
||||
obj-$(CONFIG_GPIO_TC3589X) += gpio-tc3589x.o
|
||||
obj-$(CONFIG_GPIO_TEGRA) += gpio-tegra.o
|
||||
obj-$(CONFIG_GPIO_TEGRA186) += gpio-tegra186.o
|
||||
obj-$(CONFIG_GPIO_THUNDERX) += gpio-thunderx.o
|
||||
obj-$(CONFIG_GPIO_TIMBERDALE) += gpio-timberdale.o
|
||||
obj-$(CONFIG_GPIO_PALMAS) += gpio-palmas.o
|
||||
@ -131,6 +133,7 @@ obj-$(CONFIG_GPIO_TWL6040) += gpio-twl6040.o
|
||||
obj-$(CONFIG_GPIO_TZ1090) += gpio-tz1090.o
|
||||
obj-$(CONFIG_GPIO_TZ1090_PDC) += gpio-tz1090-pdc.o
|
||||
obj-$(CONFIG_GPIO_UCB1400) += gpio-ucb1400.o
|
||||
obj-$(CONFIG_GPIO_UNIPHIER) += gpio-uniphier.o
|
||||
obj-$(CONFIG_GPIO_VF610) += gpio-vf610.o
|
||||
obj-$(CONFIG_GPIO_VIPERBOARD) += gpio-viperboard.o
|
||||
obj-$(CONFIG_GPIO_VR41XX) += gpio-vr41xx.o
|
||||
|
@ -326,7 +326,7 @@ static irqreturn_t dio48e_irq_handler(int irq, void *dev_id)
|
||||
unsigned long gpio;
|
||||
|
||||
for_each_set_bit(gpio, &irq_mask, 2)
|
||||
generic_handle_irq(irq_find_mapping(chip->irqdomain,
|
||||
generic_handle_irq(irq_find_mapping(chip->irq.domain,
|
||||
19 + gpio*24));
|
||||
|
||||
raw_spin_lock(&dio48egpio->lock);
|
||||
|
@ -209,7 +209,7 @@ static irqreturn_t idi_48_irq_handler(int irq, void *dev_id)
|
||||
for_each_set_bit(bit_num, &irq_mask, 8) {
|
||||
gpio = bit_num + boundary * 8;
|
||||
|
||||
generic_handle_irq(irq_find_mapping(chip->irqdomain,
|
||||
generic_handle_irq(irq_find_mapping(chip->irq.domain,
|
||||
gpio));
|
||||
}
|
||||
}
|
||||
|
@ -199,7 +199,7 @@ static irqreturn_t idio_16_irq_handler(int irq, void *dev_id)
|
||||
int gpio;
|
||||
|
||||
for_each_set_bit(gpio, &idio16gpio->irq_mask, chip->ngpio)
|
||||
generic_handle_irq(irq_find_mapping(chip->irqdomain, gpio));
|
||||
generic_handle_irq(irq_find_mapping(chip->irq.domain, gpio));
|
||||
|
||||
raw_spin_lock(&idio16gpio->lock);
|
||||
|
||||
|
@ -192,28 +192,20 @@ static void adnp_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
|
||||
mutex_lock(&adnp->i2c_lock);
|
||||
|
||||
err = adnp_read(adnp, GPIO_DDR(adnp) + i, &ddr);
|
||||
if (err < 0) {
|
||||
mutex_unlock(&adnp->i2c_lock);
|
||||
return;
|
||||
}
|
||||
if (err < 0)
|
||||
goto unlock;
|
||||
|
||||
err = adnp_read(adnp, GPIO_PLR(adnp) + i, &plr);
|
||||
if (err < 0) {
|
||||
mutex_unlock(&adnp->i2c_lock);
|
||||
return;
|
||||
}
|
||||
if (err < 0)
|
||||
goto unlock;
|
||||
|
||||
err = adnp_read(adnp, GPIO_IER(adnp) + i, &ier);
|
||||
if (err < 0) {
|
||||
mutex_unlock(&adnp->i2c_lock);
|
||||
return;
|
||||
}
|
||||
if (err < 0)
|
||||
goto unlock;
|
||||
|
||||
err = adnp_read(adnp, GPIO_ISR(adnp) + i, &isr);
|
||||
if (err < 0) {
|
||||
mutex_unlock(&adnp->i2c_lock);
|
||||
return;
|
||||
}
|
||||
if (err < 0)
|
||||
goto unlock;
|
||||
|
||||
mutex_unlock(&adnp->i2c_lock);
|
||||
|
||||
@ -240,6 +232,11 @@ static void adnp_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
|
||||
direction, level, interrupt, pending);
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
unlock:
|
||||
mutex_unlock(&adnp->i2c_lock);
|
||||
}
|
||||
|
||||
static int adnp_gpio_setup(struct adnp *adnp, unsigned int num_gpios)
|
||||
@ -323,7 +320,7 @@ static irqreturn_t adnp_irq(int irq, void *data)
|
||||
|
||||
for_each_set_bit(bit, &pending, 8) {
|
||||
unsigned int child_irq;
|
||||
child_irq = irq_find_mapping(adnp->gpio.irqdomain,
|
||||
child_irq = irq_find_mapping(adnp->gpio.irq.domain,
|
||||
base + bit);
|
||||
handle_nested_irq(child_irq);
|
||||
}
|
||||
|
@ -211,7 +211,7 @@ static void altera_gpio_irq_edge_handler(struct irq_desc *desc)
|
||||
altera_gc = gpiochip_get_data(irq_desc_get_handler_data(desc));
|
||||
chip = irq_desc_get_chip(desc);
|
||||
mm_gc = &altera_gc->mmchip;
|
||||
irqdomain = altera_gc->mmchip.gc.irqdomain;
|
||||
irqdomain = altera_gc->mmchip.gc.irq.domain;
|
||||
|
||||
chained_irq_enter(chip, desc);
|
||||
|
||||
@ -239,7 +239,7 @@ static void altera_gpio_irq_leveL_high_handler(struct irq_desc *desc)
|
||||
altera_gc = gpiochip_get_data(irq_desc_get_handler_data(desc));
|
||||
chip = irq_desc_get_chip(desc);
|
||||
mm_gc = &altera_gc->mmchip;
|
||||
irqdomain = altera_gc->mmchip.gc.irqdomain;
|
||||
irqdomain = altera_gc->mmchip.gc.irq.domain;
|
||||
|
||||
chained_irq_enter(chip, desc);
|
||||
|
||||
|
@ -411,13 +411,16 @@ static int aspeed_gpio_set_type(struct irq_data *d, unsigned int type)
|
||||
switch (type & IRQ_TYPE_SENSE_MASK) {
|
||||
case IRQ_TYPE_EDGE_BOTH:
|
||||
type2 |= bit;
|
||||
/* fall through */
|
||||
case IRQ_TYPE_EDGE_RISING:
|
||||
type0 |= bit;
|
||||
/* fall through */
|
||||
case IRQ_TYPE_EDGE_FALLING:
|
||||
handler = handle_edge_irq;
|
||||
break;
|
||||
case IRQ_TYPE_LEVEL_HIGH:
|
||||
type0 |= bit;
|
||||
/* fall through */
|
||||
case IRQ_TYPE_LEVEL_LOW:
|
||||
type1 |= bit;
|
||||
handler = handle_level_irq;
|
||||
@ -466,7 +469,7 @@ static void aspeed_gpio_irq_handler(struct irq_desc *desc)
|
||||
reg = ioread32(bank_irq_reg(data, bank, GPIO_IRQ_STATUS));
|
||||
|
||||
for_each_set_bit(p, ®, 32) {
|
||||
girq = irq_find_mapping(gc->irqdomain, i * 32 + p);
|
||||
girq = irq_find_mapping(gc->irq.domain, i * 32 + p);
|
||||
generic_handle_irq(girq);
|
||||
}
|
||||
|
||||
@ -498,7 +501,7 @@ static void set_irq_valid_mask(struct aspeed_gpio *gpio)
|
||||
if (i >= gpio->config->nr_gpios)
|
||||
break;
|
||||
|
||||
clear_bit(i, gpio->chip.irq_valid_mask);
|
||||
clear_bit(i, gpio->chip.irq.valid_mask);
|
||||
}
|
||||
|
||||
props++;
|
||||
@ -853,7 +856,7 @@ static int __init aspeed_gpio_probe(struct platform_device *pdev)
|
||||
gpio->chip.set_config = aspeed_gpio_set_config;
|
||||
gpio->chip.label = dev_name(&pdev->dev);
|
||||
gpio->chip.base = -1;
|
||||
gpio->chip.irq_need_valid_mask = true;
|
||||
gpio->chip.irq.need_valid_mask = true;
|
||||
|
||||
rc = devm_gpiochip_add_data(&pdev->dev, &gpio->chip, gpio);
|
||||
if (rc < 0)
|
||||
|
@ -132,6 +132,7 @@ static int ath79_gpio_irq_set_type(struct irq_data *data,
|
||||
|
||||
case IRQ_TYPE_LEVEL_HIGH:
|
||||
polarity |= mask;
|
||||
/* fall through */
|
||||
case IRQ_TYPE_LEVEL_LOW:
|
||||
type |= mask;
|
||||
break;
|
||||
@ -208,7 +209,7 @@ static void ath79_gpio_irq_handler(struct irq_desc *desc)
|
||||
if (pending) {
|
||||
for_each_set_bit(irq, &pending, gc->ngpio)
|
||||
generic_handle_irq(
|
||||
irq_linear_revmap(gc->irqdomain, irq));
|
||||
irq_linear_revmap(gc->irq.domain, irq));
|
||||
}
|
||||
|
||||
chained_irq_exit(irqchip, desc);
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Broadcom Corporation
|
||||
* Copyright (C) 2015-2017 Broadcom
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
@ -19,17 +19,30 @@
|
||||
#include <linux/irqdomain.h>
|
||||
#include <linux/irqchip/chained_irq.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/reboot.h>
|
||||
#include <linux/bitops.h>
|
||||
|
||||
#define GIO_BANK_SIZE 0x20
|
||||
#define GIO_ODEN(bank) (((bank) * GIO_BANK_SIZE) + 0x00)
|
||||
#define GIO_DATA(bank) (((bank) * GIO_BANK_SIZE) + 0x04)
|
||||
#define GIO_IODIR(bank) (((bank) * GIO_BANK_SIZE) + 0x08)
|
||||
#define GIO_EC(bank) (((bank) * GIO_BANK_SIZE) + 0x0c)
|
||||
#define GIO_EI(bank) (((bank) * GIO_BANK_SIZE) + 0x10)
|
||||
#define GIO_MASK(bank) (((bank) * GIO_BANK_SIZE) + 0x14)
|
||||
#define GIO_LEVEL(bank) (((bank) * GIO_BANK_SIZE) + 0x18)
|
||||
#define GIO_STAT(bank) (((bank) * GIO_BANK_SIZE) + 0x1c)
|
||||
enum gio_reg_index {
|
||||
GIO_REG_ODEN = 0,
|
||||
GIO_REG_DATA,
|
||||
GIO_REG_IODIR,
|
||||
GIO_REG_EC,
|
||||
GIO_REG_EI,
|
||||
GIO_REG_MASK,
|
||||
GIO_REG_LEVEL,
|
||||
GIO_REG_STAT,
|
||||
NUMBER_OF_GIO_REGISTERS
|
||||
};
|
||||
|
||||
#define GIO_BANK_SIZE (NUMBER_OF_GIO_REGISTERS * sizeof(u32))
|
||||
#define GIO_BANK_OFF(bank, off) (((bank) * GIO_BANK_SIZE) + (off * sizeof(u32)))
|
||||
#define GIO_ODEN(bank) GIO_BANK_OFF(bank, GIO_REG_ODEN)
|
||||
#define GIO_DATA(bank) GIO_BANK_OFF(bank, GIO_REG_DATA)
|
||||
#define GIO_IODIR(bank) GIO_BANK_OFF(bank, GIO_REG_IODIR)
|
||||
#define GIO_EC(bank) GIO_BANK_OFF(bank, GIO_REG_EC)
|
||||
#define GIO_EI(bank) GIO_BANK_OFF(bank, GIO_REG_EI)
|
||||
#define GIO_MASK(bank) GIO_BANK_OFF(bank, GIO_REG_MASK)
|
||||
#define GIO_LEVEL(bank) GIO_BANK_OFF(bank, GIO_REG_LEVEL)
|
||||
#define GIO_STAT(bank) GIO_BANK_OFF(bank, GIO_REG_STAT)
|
||||
|
||||
struct brcmstb_gpio_bank {
|
||||
struct list_head node;
|
||||
@ -37,21 +50,23 @@ struct brcmstb_gpio_bank {
|
||||
struct gpio_chip gc;
|
||||
struct brcmstb_gpio_priv *parent_priv;
|
||||
u32 width;
|
||||
struct irq_chip irq_chip;
|
||||
u32 wake_active;
|
||||
u32 saved_regs[GIO_REG_STAT]; /* Don't save and restore GIO_REG_STAT */
|
||||
};
|
||||
|
||||
struct brcmstb_gpio_priv {
|
||||
struct list_head bank_list;
|
||||
void __iomem *reg_base;
|
||||
struct platform_device *pdev;
|
||||
struct irq_domain *irq_domain;
|
||||
struct irq_chip irq_chip;
|
||||
int parent_irq;
|
||||
int gpio_base;
|
||||
bool can_wake;
|
||||
int num_gpios;
|
||||
int parent_wake_irq;
|
||||
struct notifier_block reboot_notifier;
|
||||
};
|
||||
|
||||
#define MAX_GPIO_PER_BANK 32
|
||||
#define MAX_GPIO_PER_BANK 32
|
||||
#define GPIO_BANK(gpio) ((gpio) >> 5)
|
||||
/* assumes MAX_GPIO_PER_BANK is a multiple of 2 */
|
||||
#define GPIO_BIT(gpio) ((gpio) & (MAX_GPIO_PER_BANK - 1))
|
||||
@ -63,12 +78,40 @@ brcmstb_gpio_gc_to_priv(struct gpio_chip *gc)
|
||||
return bank->parent_priv;
|
||||
}
|
||||
|
||||
static unsigned long
|
||||
__brcmstb_gpio_get_active_irqs(struct brcmstb_gpio_bank *bank)
|
||||
{
|
||||
void __iomem *reg_base = bank->parent_priv->reg_base;
|
||||
|
||||
return bank->gc.read_reg(reg_base + GIO_STAT(bank->id)) &
|
||||
bank->gc.read_reg(reg_base + GIO_MASK(bank->id));
|
||||
}
|
||||
|
||||
static unsigned long
|
||||
brcmstb_gpio_get_active_irqs(struct brcmstb_gpio_bank *bank)
|
||||
{
|
||||
unsigned long status;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&bank->gc.bgpio_lock, flags);
|
||||
status = __brcmstb_gpio_get_active_irqs(bank);
|
||||
spin_unlock_irqrestore(&bank->gc.bgpio_lock, flags);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static int brcmstb_gpio_hwirq_to_offset(irq_hw_number_t hwirq,
|
||||
struct brcmstb_gpio_bank *bank)
|
||||
{
|
||||
return hwirq - (bank->gc.base - bank->parent_priv->gpio_base);
|
||||
}
|
||||
|
||||
static void brcmstb_gpio_set_imask(struct brcmstb_gpio_bank *bank,
|
||||
unsigned int offset, bool enable)
|
||||
unsigned int hwirq, bool enable)
|
||||
{
|
||||
struct gpio_chip *gc = &bank->gc;
|
||||
struct brcmstb_gpio_priv *priv = bank->parent_priv;
|
||||
u32 mask = gc->pin2mask(gc, offset);
|
||||
u32 mask = BIT(brcmstb_gpio_hwirq_to_offset(hwirq, bank));
|
||||
u32 imask;
|
||||
unsigned long flags;
|
||||
|
||||
@ -82,6 +125,17 @@ static void brcmstb_gpio_set_imask(struct brcmstb_gpio_bank *bank,
|
||||
spin_unlock_irqrestore(&gc->bgpio_lock, flags);
|
||||
}
|
||||
|
||||
static int brcmstb_gpio_to_irq(struct gpio_chip *gc, unsigned offset)
|
||||
{
|
||||
struct brcmstb_gpio_priv *priv = brcmstb_gpio_gc_to_priv(gc);
|
||||
/* gc_offset is relative to this gpio_chip; want real offset */
|
||||
int hwirq = offset + (gc->base - priv->gpio_base);
|
||||
|
||||
if (hwirq >= priv->num_gpios)
|
||||
return -ENXIO;
|
||||
return irq_create_mapping(priv->irq_domain, hwirq);
|
||||
}
|
||||
|
||||
/* -------------------- IRQ chip functions -------------------- */
|
||||
|
||||
static void brcmstb_gpio_irq_mask(struct irq_data *d)
|
||||
@ -100,12 +154,22 @@ static void brcmstb_gpio_irq_unmask(struct irq_data *d)
|
||||
brcmstb_gpio_set_imask(bank, d->hwirq, true);
|
||||
}
|
||||
|
||||
static void brcmstb_gpio_irq_ack(struct irq_data *d)
|
||||
{
|
||||
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
|
||||
struct brcmstb_gpio_bank *bank = gpiochip_get_data(gc);
|
||||
struct brcmstb_gpio_priv *priv = bank->parent_priv;
|
||||
u32 mask = BIT(brcmstb_gpio_hwirq_to_offset(d->hwirq, bank));
|
||||
|
||||
gc->write_reg(priv->reg_base + GIO_STAT(bank->id), mask);
|
||||
}
|
||||
|
||||
static int brcmstb_gpio_irq_set_type(struct irq_data *d, unsigned int type)
|
||||
{
|
||||
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
|
||||
struct brcmstb_gpio_bank *bank = gpiochip_get_data(gc);
|
||||
struct brcmstb_gpio_priv *priv = bank->parent_priv;
|
||||
u32 mask = BIT(d->hwirq);
|
||||
u32 mask = BIT(brcmstb_gpio_hwirq_to_offset(d->hwirq, bank));
|
||||
u32 edge_insensitive, iedge_insensitive;
|
||||
u32 edge_config, iedge_config;
|
||||
u32 level, ilevel;
|
||||
@ -113,13 +177,13 @@ static int brcmstb_gpio_irq_set_type(struct irq_data *d, unsigned int type)
|
||||
|
||||
switch (type) {
|
||||
case IRQ_TYPE_LEVEL_LOW:
|
||||
level = 0;
|
||||
level = mask;
|
||||
edge_config = 0;
|
||||
edge_insensitive = 0;
|
||||
break;
|
||||
case IRQ_TYPE_LEVEL_HIGH:
|
||||
level = mask;
|
||||
edge_config = 0;
|
||||
edge_config = mask;
|
||||
edge_insensitive = 0;
|
||||
break;
|
||||
case IRQ_TYPE_EDGE_FALLING:
|
||||
@ -166,11 +230,6 @@ static int brcmstb_gpio_priv_set_wake(struct brcmstb_gpio_priv *priv,
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
/*
|
||||
* Only enable wake IRQ once for however many hwirqs can wake
|
||||
* since they all use the same wake IRQ. Mask will be set
|
||||
* up appropriately thanks to IRQCHIP_MASK_ON_SUSPEND flag.
|
||||
*/
|
||||
if (enable)
|
||||
ret = enable_irq_wake(priv->parent_wake_irq);
|
||||
else
|
||||
@ -184,7 +243,18 @@ static int brcmstb_gpio_priv_set_wake(struct brcmstb_gpio_priv *priv,
|
||||
static int brcmstb_gpio_irq_set_wake(struct irq_data *d, unsigned int enable)
|
||||
{
|
||||
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
|
||||
struct brcmstb_gpio_priv *priv = brcmstb_gpio_gc_to_priv(gc);
|
||||
struct brcmstb_gpio_bank *bank = gpiochip_get_data(gc);
|
||||
struct brcmstb_gpio_priv *priv = bank->parent_priv;
|
||||
u32 mask = BIT(brcmstb_gpio_hwirq_to_offset(d->hwirq, bank));
|
||||
|
||||
/*
|
||||
* Do not do anything specific for now, suspend/resume callbacks will
|
||||
* configure the interrupt mask appropriately
|
||||
*/
|
||||
if (enable)
|
||||
bank->wake_active |= mask;
|
||||
else
|
||||
bank->wake_active &= ~mask;
|
||||
|
||||
return brcmstb_gpio_priv_set_wake(priv, enable);
|
||||
}
|
||||
@ -195,43 +265,36 @@ static irqreturn_t brcmstb_gpio_wake_irq_handler(int irq, void *data)
|
||||
|
||||
if (!priv || irq != priv->parent_wake_irq)
|
||||
return IRQ_NONE;
|
||||
pm_wakeup_event(&priv->pdev->dev, 0);
|
||||
|
||||
/* Nothing to do */
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static void brcmstb_gpio_irq_bank_handler(struct brcmstb_gpio_bank *bank)
|
||||
{
|
||||
struct brcmstb_gpio_priv *priv = bank->parent_priv;
|
||||
struct irq_domain *irq_domain = bank->gc.irqdomain;
|
||||
void __iomem *reg_base = priv->reg_base;
|
||||
struct irq_domain *domain = priv->irq_domain;
|
||||
int hwbase = bank->gc.base - priv->gpio_base;
|
||||
unsigned long status;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&bank->gc.bgpio_lock, flags);
|
||||
while ((status = bank->gc.read_reg(reg_base + GIO_STAT(bank->id)) &
|
||||
bank->gc.read_reg(reg_base + GIO_MASK(bank->id)))) {
|
||||
int bit;
|
||||
while ((status = brcmstb_gpio_get_active_irqs(bank))) {
|
||||
unsigned int irq, offset;
|
||||
|
||||
for_each_set_bit(bit, &status, 32) {
|
||||
u32 stat = bank->gc.read_reg(reg_base +
|
||||
GIO_STAT(bank->id));
|
||||
if (bit >= bank->width)
|
||||
for_each_set_bit(offset, &status, 32) {
|
||||
if (offset >= bank->width)
|
||||
dev_warn(&priv->pdev->dev,
|
||||
"IRQ for invalid GPIO (bank=%d, offset=%d)\n",
|
||||
bank->id, bit);
|
||||
bank->gc.write_reg(reg_base + GIO_STAT(bank->id),
|
||||
stat | BIT(bit));
|
||||
generic_handle_irq(irq_find_mapping(irq_domain, bit));
|
||||
bank->id, offset);
|
||||
irq = irq_linear_revmap(domain, hwbase + offset);
|
||||
generic_handle_irq(irq);
|
||||
}
|
||||
}
|
||||
spin_unlock_irqrestore(&bank->gc.bgpio_lock, flags);
|
||||
}
|
||||
|
||||
/* Each UPG GIO block has one IRQ for all banks */
|
||||
static void brcmstb_gpio_irq_handler(struct irq_desc *desc)
|
||||
{
|
||||
struct gpio_chip *gc = irq_desc_get_handler_data(desc);
|
||||
struct brcmstb_gpio_priv *priv = brcmstb_gpio_gc_to_priv(gc);
|
||||
struct brcmstb_gpio_priv *priv = irq_desc_get_handler_data(desc);
|
||||
struct irq_chip *chip = irq_desc_get_chip(desc);
|
||||
struct brcmstb_gpio_bank *bank;
|
||||
|
||||
@ -244,19 +307,63 @@ static void brcmstb_gpio_irq_handler(struct irq_desc *desc)
|
||||
chained_irq_exit(chip, desc);
|
||||
}
|
||||
|
||||
static int brcmstb_gpio_reboot(struct notifier_block *nb,
|
||||
unsigned long action, void *data)
|
||||
static struct brcmstb_gpio_bank *brcmstb_gpio_hwirq_to_bank(
|
||||
struct brcmstb_gpio_priv *priv, irq_hw_number_t hwirq)
|
||||
{
|
||||
struct brcmstb_gpio_priv *priv =
|
||||
container_of(nb, struct brcmstb_gpio_priv, reboot_notifier);
|
||||
struct brcmstb_gpio_bank *bank;
|
||||
int i = 0;
|
||||
|
||||
/* Enable GPIO for S5 cold boot */
|
||||
if (action == SYS_POWER_OFF)
|
||||
brcmstb_gpio_priv_set_wake(priv, 1);
|
||||
|
||||
return NOTIFY_DONE;
|
||||
/* banks are in descending order */
|
||||
list_for_each_entry_reverse(bank, &priv->bank_list, node) {
|
||||
i += bank->gc.ngpio;
|
||||
if (hwirq < i)
|
||||
return bank;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* This lock class tells lockdep that GPIO irqs are in a different
|
||||
* category than their parents, so it won't report false recursion.
|
||||
*/
|
||||
static struct lock_class_key brcmstb_gpio_irq_lock_class;
|
||||
|
||||
|
||||
static int brcmstb_gpio_irq_map(struct irq_domain *d, unsigned int irq,
|
||||
irq_hw_number_t hwirq)
|
||||
{
|
||||
struct brcmstb_gpio_priv *priv = d->host_data;
|
||||
struct brcmstb_gpio_bank *bank =
|
||||
brcmstb_gpio_hwirq_to_bank(priv, hwirq);
|
||||
struct platform_device *pdev = priv->pdev;
|
||||
int ret;
|
||||
|
||||
if (!bank)
|
||||
return -EINVAL;
|
||||
|
||||
dev_dbg(&pdev->dev, "Mapping irq %d for gpio line %d (bank %d)\n",
|
||||
irq, (int)hwirq, bank->id);
|
||||
ret = irq_set_chip_data(irq, &bank->gc);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
irq_set_lockdep_class(irq, &brcmstb_gpio_irq_lock_class);
|
||||
irq_set_chip_and_handler(irq, &priv->irq_chip, handle_level_irq);
|
||||
irq_set_noprobe(irq);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void brcmstb_gpio_irq_unmap(struct irq_domain *d, unsigned int irq)
|
||||
{
|
||||
irq_set_chip_and_handler(irq, NULL, NULL);
|
||||
irq_set_chip_data(irq, NULL);
|
||||
}
|
||||
|
||||
static const struct irq_domain_ops brcmstb_gpio_irq_domain_ops = {
|
||||
.map = brcmstb_gpio_irq_map,
|
||||
.unmap = brcmstb_gpio_irq_unmap,
|
||||
.xlate = irq_domain_xlate_twocell,
|
||||
};
|
||||
|
||||
/* Make sure that the number of banks matches up between properties */
|
||||
static int brcmstb_gpio_sanity_check_banks(struct device *dev,
|
||||
struct device_node *np, struct resource *res)
|
||||
@ -278,13 +385,25 @@ static int brcmstb_gpio_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct brcmstb_gpio_priv *priv = platform_get_drvdata(pdev);
|
||||
struct brcmstb_gpio_bank *bank;
|
||||
int ret = 0;
|
||||
int offset, ret = 0, virq;
|
||||
|
||||
if (!priv) {
|
||||
dev_err(&pdev->dev, "called %s without drvdata!\n", __func__);
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
if (priv->parent_irq > 0)
|
||||
irq_set_chained_handler_and_data(priv->parent_irq, NULL, NULL);
|
||||
|
||||
/* Remove all IRQ mappings and delete the domain */
|
||||
if (priv->irq_domain) {
|
||||
for (offset = 0; offset < priv->num_gpios; offset++) {
|
||||
virq = irq_find_mapping(priv->irq_domain, offset);
|
||||
irq_dispose_mapping(virq);
|
||||
}
|
||||
irq_domain_remove(priv->irq_domain);
|
||||
}
|
||||
|
||||
/*
|
||||
* You can lose return values below, but we report all errors, and it's
|
||||
* more important to actually perform all of the steps.
|
||||
@ -292,12 +411,6 @@ static int brcmstb_gpio_remove(struct platform_device *pdev)
|
||||
list_for_each_entry(bank, &priv->bank_list, node)
|
||||
gpiochip_remove(&bank->gc);
|
||||
|
||||
if (priv->reboot_notifier.notifier_call) {
|
||||
ret = unregister_reboot_notifier(&priv->reboot_notifier);
|
||||
if (ret)
|
||||
dev_err(&pdev->dev,
|
||||
"failed to unregister reboot notifier\n");
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -332,66 +445,163 @@ static int brcmstb_gpio_of_xlate(struct gpio_chip *gc,
|
||||
return offset;
|
||||
}
|
||||
|
||||
/* Before calling, must have bank->parent_irq set and gpiochip registered */
|
||||
/* priv->parent_irq and priv->num_gpios must be set before calling */
|
||||
static int brcmstb_gpio_irq_setup(struct platform_device *pdev,
|
||||
struct brcmstb_gpio_bank *bank)
|
||||
struct brcmstb_gpio_priv *priv)
|
||||
{
|
||||
struct brcmstb_gpio_priv *priv = bank->parent_priv;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct device_node *np = dev->of_node;
|
||||
int err;
|
||||
|
||||
bank->irq_chip.name = dev_name(dev);
|
||||
bank->irq_chip.irq_mask = brcmstb_gpio_irq_mask;
|
||||
bank->irq_chip.irq_unmask = brcmstb_gpio_irq_unmask;
|
||||
bank->irq_chip.irq_set_type = brcmstb_gpio_irq_set_type;
|
||||
priv->irq_domain =
|
||||
irq_domain_add_linear(np, priv->num_gpios,
|
||||
&brcmstb_gpio_irq_domain_ops,
|
||||
priv);
|
||||
if (!priv->irq_domain) {
|
||||
dev_err(dev, "Couldn't allocate IRQ domain\n");
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
/* Ensures that all non-wakeup IRQs are disabled at suspend */
|
||||
bank->irq_chip.flags = IRQCHIP_MASK_ON_SUSPEND;
|
||||
|
||||
if (IS_ENABLED(CONFIG_PM_SLEEP) && !priv->can_wake &&
|
||||
of_property_read_bool(np, "wakeup-source")) {
|
||||
if (of_property_read_bool(np, "wakeup-source")) {
|
||||
priv->parent_wake_irq = platform_get_irq(pdev, 1);
|
||||
if (priv->parent_wake_irq < 0) {
|
||||
priv->parent_wake_irq = 0;
|
||||
dev_warn(dev,
|
||||
"Couldn't get wake IRQ - GPIOs will not be able to wake from sleep");
|
||||
} else {
|
||||
/*
|
||||
* Set wakeup capability before requesting wakeup
|
||||
* interrupt, so we can process boot-time "wakeups"
|
||||
* (e.g., from S5 cold boot)
|
||||
* Set wakeup capability so we can process boot-time
|
||||
* "wakeups" (e.g., from S5 cold boot)
|
||||
*/
|
||||
device_set_wakeup_capable(dev, true);
|
||||
device_wakeup_enable(dev);
|
||||
err = devm_request_irq(dev, priv->parent_wake_irq,
|
||||
brcmstb_gpio_wake_irq_handler, 0,
|
||||
"brcmstb-gpio-wake", priv);
|
||||
brcmstb_gpio_wake_irq_handler,
|
||||
IRQF_SHARED,
|
||||
"brcmstb-gpio-wake", priv);
|
||||
|
||||
if (err < 0) {
|
||||
dev_err(dev, "Couldn't request wake IRQ");
|
||||
return err;
|
||||
goto out_free_domain;
|
||||
}
|
||||
|
||||
priv->reboot_notifier.notifier_call =
|
||||
brcmstb_gpio_reboot;
|
||||
register_reboot_notifier(&priv->reboot_notifier);
|
||||
priv->can_wake = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (priv->can_wake)
|
||||
bank->irq_chip.irq_set_wake = brcmstb_gpio_irq_set_wake;
|
||||
priv->irq_chip.name = dev_name(dev);
|
||||
priv->irq_chip.irq_disable = brcmstb_gpio_irq_mask;
|
||||
priv->irq_chip.irq_mask = brcmstb_gpio_irq_mask;
|
||||
priv->irq_chip.irq_unmask = brcmstb_gpio_irq_unmask;
|
||||
priv->irq_chip.irq_ack = brcmstb_gpio_irq_ack;
|
||||
priv->irq_chip.irq_set_type = brcmstb_gpio_irq_set_type;
|
||||
|
||||
err = gpiochip_irqchip_add(&bank->gc, &bank->irq_chip, 0,
|
||||
handle_simple_irq, IRQ_TYPE_NONE);
|
||||
if (err)
|
||||
return err;
|
||||
gpiochip_set_chained_irqchip(&bank->gc, &bank->irq_chip,
|
||||
priv->parent_irq, brcmstb_gpio_irq_handler);
|
||||
if (priv->parent_wake_irq)
|
||||
priv->irq_chip.irq_set_wake = brcmstb_gpio_irq_set_wake;
|
||||
|
||||
irq_set_chained_handler_and_data(priv->parent_irq,
|
||||
brcmstb_gpio_irq_handler, priv);
|
||||
irq_set_status_flags(priv->parent_irq, IRQ_DISABLE_UNLAZY);
|
||||
|
||||
return 0;
|
||||
|
||||
out_free_domain:
|
||||
irq_domain_remove(priv->irq_domain);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static void brcmstb_gpio_bank_save(struct brcmstb_gpio_priv *priv,
|
||||
struct brcmstb_gpio_bank *bank)
|
||||
{
|
||||
struct gpio_chip *gc = &bank->gc;
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < GIO_REG_STAT; i++)
|
||||
bank->saved_regs[i] = gc->read_reg(priv->reg_base +
|
||||
GIO_BANK_OFF(bank->id, i));
|
||||
}
|
||||
|
||||
static void brcmstb_gpio_quiesce(struct device *dev, bool save)
|
||||
{
|
||||
struct brcmstb_gpio_priv *priv = dev_get_drvdata(dev);
|
||||
struct brcmstb_gpio_bank *bank;
|
||||
struct gpio_chip *gc;
|
||||
u32 imask;
|
||||
|
||||
/* disable non-wake interrupt */
|
||||
if (priv->parent_irq >= 0)
|
||||
disable_irq(priv->parent_irq);
|
||||
|
||||
list_for_each_entry(bank, &priv->bank_list, node) {
|
||||
gc = &bank->gc;
|
||||
|
||||
if (save)
|
||||
brcmstb_gpio_bank_save(priv, bank);
|
||||
|
||||
/* Unmask GPIOs which have been flagged as wake-up sources */
|
||||
if (priv->parent_wake_irq)
|
||||
imask = bank->wake_active;
|
||||
else
|
||||
imask = 0;
|
||||
gc->write_reg(priv->reg_base + GIO_MASK(bank->id),
|
||||
imask);
|
||||
}
|
||||
}
|
||||
|
||||
static void brcmstb_gpio_shutdown(struct platform_device *pdev)
|
||||
{
|
||||
/* Enable GPIO for S5 cold boot */
|
||||
brcmstb_gpio_quiesce(&pdev->dev, false);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static void brcmstb_gpio_bank_restore(struct brcmstb_gpio_priv *priv,
|
||||
struct brcmstb_gpio_bank *bank)
|
||||
{
|
||||
struct gpio_chip *gc = &bank->gc;
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < GIO_REG_STAT; i++)
|
||||
gc->write_reg(priv->reg_base + GIO_BANK_OFF(bank->id, i),
|
||||
bank->saved_regs[i]);
|
||||
}
|
||||
|
||||
static int brcmstb_gpio_suspend(struct device *dev)
|
||||
{
|
||||
brcmstb_gpio_quiesce(dev, true);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int brcmstb_gpio_resume(struct device *dev)
|
||||
{
|
||||
struct brcmstb_gpio_priv *priv = dev_get_drvdata(dev);
|
||||
struct brcmstb_gpio_bank *bank;
|
||||
bool need_wakeup_event = false;
|
||||
|
||||
list_for_each_entry(bank, &priv->bank_list, node) {
|
||||
need_wakeup_event |= !!__brcmstb_gpio_get_active_irqs(bank);
|
||||
brcmstb_gpio_bank_restore(priv, bank);
|
||||
}
|
||||
|
||||
if (priv->parent_wake_irq && need_wakeup_event)
|
||||
pm_wakeup_event(dev, 0);
|
||||
|
||||
/* enable non-wake interrupt */
|
||||
if (priv->parent_irq >= 0)
|
||||
enable_irq(priv->parent_irq);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else
|
||||
#define brcmstb_gpio_suspend NULL
|
||||
#define brcmstb_gpio_resume NULL
|
||||
#endif /* CONFIG_PM_SLEEP */
|
||||
|
||||
static const struct dev_pm_ops brcmstb_gpio_pm_ops = {
|
||||
.suspend_noirq = brcmstb_gpio_suspend,
|
||||
.resume_noirq = brcmstb_gpio_resume,
|
||||
};
|
||||
|
||||
static int brcmstb_gpio_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
@ -406,6 +616,7 @@ static int brcmstb_gpio_probe(struct platform_device *pdev)
|
||||
int err;
|
||||
static int gpio_base;
|
||||
unsigned long flags = 0;
|
||||
bool need_wakeup_event = false;
|
||||
|
||||
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
|
||||
if (!priv)
|
||||
@ -485,16 +696,23 @@ static int brcmstb_gpio_probe(struct platform_device *pdev)
|
||||
gc->of_node = np;
|
||||
gc->owner = THIS_MODULE;
|
||||
gc->label = devm_kasprintf(dev, GFP_KERNEL, "%pOF", dev->of_node);
|
||||
if (!gc->label) {
|
||||
err = -ENOMEM;
|
||||
goto fail;
|
||||
}
|
||||
gc->base = gpio_base;
|
||||
gc->of_gpio_n_cells = 2;
|
||||
gc->of_xlate = brcmstb_gpio_of_xlate;
|
||||
/* not all ngpio lines are valid, will use bank width later */
|
||||
gc->ngpio = MAX_GPIO_PER_BANK;
|
||||
if (priv->parent_irq > 0)
|
||||
gc->to_irq = brcmstb_gpio_to_irq;
|
||||
|
||||
/*
|
||||
* Mask all interrupts by default, since wakeup interrupts may
|
||||
* be retained from S5 cold boot
|
||||
*/
|
||||
need_wakeup_event |= !!__brcmstb_gpio_get_active_irqs(bank);
|
||||
gc->write_reg(reg_base + GIO_MASK(bank->id), 0);
|
||||
|
||||
err = gpiochip_add_data(gc, bank);
|
||||
@ -505,12 +723,6 @@ static int brcmstb_gpio_probe(struct platform_device *pdev)
|
||||
}
|
||||
gpio_base += gc->ngpio;
|
||||
|
||||
if (priv->parent_irq > 0) {
|
||||
err = brcmstb_gpio_irq_setup(pdev, bank);
|
||||
if (err)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
dev_dbg(dev, "bank=%d, base=%d, ngpio=%d, width=%d\n", bank->id,
|
||||
gc->base, gc->ngpio, bank->width);
|
||||
|
||||
@ -520,9 +732,19 @@ static int brcmstb_gpio_probe(struct platform_device *pdev)
|
||||
num_banks++;
|
||||
}
|
||||
|
||||
priv->num_gpios = gpio_base - priv->gpio_base;
|
||||
if (priv->parent_irq > 0) {
|
||||
err = brcmstb_gpio_irq_setup(pdev, priv);
|
||||
if (err)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
dev_info(dev, "Registered %d banks (GPIO(s): %d-%d)\n",
|
||||
num_banks, priv->gpio_base, gpio_base - 1);
|
||||
|
||||
if (priv->parent_wake_irq && need_wakeup_event)
|
||||
pm_wakeup_event(dev, 0);
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
@ -541,9 +763,11 @@ static struct platform_driver brcmstb_gpio_driver = {
|
||||
.driver = {
|
||||
.name = "brcmstb-gpio",
|
||||
.of_match_table = brcmstb_gpio_of_match,
|
||||
.pm = &brcmstb_gpio_pm_ops,
|
||||
},
|
||||
.probe = brcmstb_gpio_probe,
|
||||
.remove = brcmstb_gpio_remove,
|
||||
.shutdown = brcmstb_gpio_shutdown,
|
||||
};
|
||||
module_platform_driver(brcmstb_gpio_driver);
|
||||
|
||||
|
@ -295,7 +295,7 @@ static irqreturn_t crystalcove_gpio_irq_handler(int irq, void *data)
|
||||
|
||||
for (gpio = 0; gpio < CRYSTALCOVE_GPIO_NUM; gpio++) {
|
||||
if (pending & BIT(gpio)) {
|
||||
virq = irq_find_mapping(cg->chip.irqdomain, gpio);
|
||||
virq = irq_find_mapping(cg->chip.irq.domain, gpio);
|
||||
handle_nested_irq(virq);
|
||||
}
|
||||
}
|
||||
|
@ -420,7 +420,7 @@ static void dln2_gpio_event(struct platform_device *pdev, u16 echo,
|
||||
return;
|
||||
}
|
||||
|
||||
irq = irq_find_mapping(dln2->gpio.irqdomain, pin);
|
||||
irq = irq_find_mapping(dln2->gpio.irq.domain, pin);
|
||||
if (!irq) {
|
||||
dev_err(dln2->gpio.parent, "pin %d not mapped to IRQ\n", pin);
|
||||
return;
|
||||
|
@ -25,6 +25,7 @@
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/property.h>
|
||||
#include <linux/reset.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/platform_data/gpio-dwapb.h>
|
||||
#include <linux/slab.h>
|
||||
@ -77,6 +78,7 @@ struct dwapb_context {
|
||||
u32 int_type;
|
||||
u32 int_pol;
|
||||
u32 int_deb;
|
||||
u32 wake_en;
|
||||
};
|
||||
#endif
|
||||
|
||||
@ -97,6 +99,7 @@ struct dwapb_gpio {
|
||||
unsigned int nr_ports;
|
||||
struct irq_domain *domain;
|
||||
unsigned int flags;
|
||||
struct reset_control *rst;
|
||||
};
|
||||
|
||||
static inline u32 gpio_reg_v2_convert(unsigned int offset)
|
||||
@ -295,13 +298,29 @@ static int dwapb_irq_set_type(struct irq_data *d, u32 type)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int dwapb_irq_set_wake(struct irq_data *d, unsigned int enable)
|
||||
{
|
||||
struct irq_chip_generic *igc = irq_data_get_irq_chip_data(d);
|
||||
struct dwapb_gpio *gpio = igc->private;
|
||||
struct dwapb_context *ctx = gpio->ports[0].ctx;
|
||||
|
||||
if (enable)
|
||||
ctx->wake_en |= BIT(d->hwirq);
|
||||
else
|
||||
ctx->wake_en &= ~BIT(d->hwirq);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int dwapb_gpio_set_debounce(struct gpio_chip *gc,
|
||||
unsigned offset, unsigned debounce)
|
||||
{
|
||||
struct dwapb_gpio_port *port = gpiochip_get_data(gc);
|
||||
struct dwapb_gpio *gpio = port->gpio;
|
||||
unsigned long flags, val_deb;
|
||||
unsigned long mask = gc->pin2mask(gc, offset);
|
||||
unsigned long mask = BIT(offset);
|
||||
|
||||
spin_lock_irqsave(&gc->bgpio_lock, flags);
|
||||
|
||||
@ -385,6 +404,9 @@ static void dwapb_configure_irqs(struct dwapb_gpio *gpio,
|
||||
ct->chip.irq_disable = dwapb_irq_disable;
|
||||
ct->chip.irq_request_resources = dwapb_irq_reqres;
|
||||
ct->chip.irq_release_resources = dwapb_irq_relres;
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
ct->chip.irq_set_wake = dwapb_irq_set_wake;
|
||||
#endif
|
||||
ct->regs.ack = gpio_reg_convert(gpio, GPIO_PORTA_EOI);
|
||||
ct->regs.mask = gpio_reg_convert(gpio, GPIO_INTMASK);
|
||||
ct->type = IRQ_TYPE_LEVEL_MASK;
|
||||
@ -460,7 +482,7 @@ static int dwapb_gpio_add_port(struct dwapb_gpio *gpio,
|
||||
(pp->idx * GPIO_SWPORT_DDR_SIZE);
|
||||
|
||||
err = bgpio_init(&port->gc, gpio->dev, 4, dat, set, NULL, dirout,
|
||||
NULL, false);
|
||||
NULL, 0);
|
||||
if (err) {
|
||||
dev_err(gpio->dev, "failed to init gpio chip for port%d\n",
|
||||
port->idx);
|
||||
@ -609,6 +631,12 @@ static int dwapb_gpio_probe(struct platform_device *pdev)
|
||||
gpio->dev = &pdev->dev;
|
||||
gpio->nr_ports = pdata->nports;
|
||||
|
||||
gpio->rst = devm_reset_control_get_optional_shared(dev, NULL);
|
||||
if (IS_ERR(gpio->rst))
|
||||
return PTR_ERR(gpio->rst);
|
||||
|
||||
reset_control_deassert(gpio->rst);
|
||||
|
||||
gpio->ports = devm_kcalloc(&pdev->dev, gpio->nr_ports,
|
||||
sizeof(*gpio->ports), GFP_KERNEL);
|
||||
if (!gpio->ports)
|
||||
@ -660,6 +688,7 @@ static int dwapb_gpio_remove(struct platform_device *pdev)
|
||||
|
||||
dwapb_gpio_unregister(gpio);
|
||||
dwapb_irq_teardown(gpio);
|
||||
reset_control_assert(gpio->rst);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -699,7 +728,8 @@ static int dwapb_gpio_suspend(struct device *dev)
|
||||
ctx->int_deb = dwapb_read(gpio, GPIO_PORTA_DEBOUNCE);
|
||||
|
||||
/* Mask out interrupts */
|
||||
dwapb_write(gpio, GPIO_INTMASK, 0xffffffff);
|
||||
dwapb_write(gpio, GPIO_INTMASK,
|
||||
0xffffffff & ~ctx->wake_en);
|
||||
}
|
||||
}
|
||||
spin_unlock_irqrestore(&gc->bgpio_lock, flags);
|
||||
|
@ -149,7 +149,7 @@ static void ftgpio_gpio_irq_handler(struct irq_desc *desc)
|
||||
stat = readl(g->base + GPIO_INT_STAT);
|
||||
if (stat)
|
||||
for_each_set_bit(offset, &stat, gc->ngpio)
|
||||
generic_handle_irq(irq_find_mapping(gc->irqdomain,
|
||||
generic_handle_irq(irq_find_mapping(gc->irq.domain,
|
||||
offset));
|
||||
|
||||
chained_irq_exit(irqchip, desc);
|
||||
|
@ -35,6 +35,7 @@
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/irqdomain.h>
|
||||
#include <linux/bitops.h>
|
||||
|
||||
#define GRGPIO_MAX_NGPIO 32
|
||||
|
||||
@ -96,12 +97,11 @@ static void grgpio_set_imask(struct grgpio_priv *priv, unsigned int offset,
|
||||
int val)
|
||||
{
|
||||
struct gpio_chip *gc = &priv->gc;
|
||||
unsigned long mask = gc->pin2mask(gc, offset);
|
||||
|
||||
if (val)
|
||||
priv->imask |= mask;
|
||||
priv->imask |= BIT(offset);
|
||||
else
|
||||
priv->imask &= ~mask;
|
||||
priv->imask &= ~BIT(offset);
|
||||
gc->write_reg(priv->regs + GRGPIO_IMASK, priv->imask);
|
||||
}
|
||||
|
||||
|
@ -242,7 +242,7 @@ static void ingenic_gpio_irq_handler(struct irq_desc *desc)
|
||||
flag = gpio_ingenic_read_reg(jzgc, JZ4740_GPIO_FLAG);
|
||||
|
||||
for_each_set_bit(i, &flag, 32)
|
||||
generic_handle_irq(irq_linear_revmap(gc->irqdomain, i));
|
||||
generic_handle_irq(irq_linear_revmap(gc->irq.domain, i));
|
||||
chained_irq_exit(irq_chip, desc);
|
||||
}
|
||||
|
||||
|
@ -295,7 +295,7 @@ static void intel_mid_irq_handler(struct irq_desc *desc)
|
||||
mask = BIT(gpio);
|
||||
/* Clear before handling so we can't lose an edge */
|
||||
writel(mask, gedr);
|
||||
generic_handle_irq(irq_find_mapping(gc->irqdomain,
|
||||
generic_handle_irq(irq_find_mapping(gc->irq.domain,
|
||||
base + gpio));
|
||||
}
|
||||
}
|
||||
|
@ -11,6 +11,7 @@
|
||||
#include <linux/module.h>
|
||||
#include <linux/gpio/driver.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/bitops.h>
|
||||
|
||||
/* Loongson 1 GPIO Register Definitions */
|
||||
#define GPIO_CFG 0x0
|
||||
@ -22,11 +23,10 @@ static void __iomem *gpio_reg_base;
|
||||
|
||||
static int ls1x_gpio_request(struct gpio_chip *gc, unsigned int offset)
|
||||
{
|
||||
unsigned long pinmask = gc->pin2mask(gc, offset);
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&gc->bgpio_lock, flags);
|
||||
__raw_writel(__raw_readl(gpio_reg_base + GPIO_CFG) | pinmask,
|
||||
__raw_writel(__raw_readl(gpio_reg_base + GPIO_CFG) | BIT(offset),
|
||||
gpio_reg_base + GPIO_CFG);
|
||||
spin_unlock_irqrestore(&gc->bgpio_lock, flags);
|
||||
|
||||
@ -35,11 +35,10 @@ static int ls1x_gpio_request(struct gpio_chip *gc, unsigned int offset)
|
||||
|
||||
static void ls1x_gpio_free(struct gpio_chip *gc, unsigned int offset)
|
||||
{
|
||||
unsigned long pinmask = gc->pin2mask(gc, offset);
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&gc->bgpio_lock, flags);
|
||||
__raw_writel(__raw_readl(gpio_reg_base + GPIO_CFG) & ~pinmask,
|
||||
__raw_writel(__raw_readl(gpio_reg_base + GPIO_CFG) & ~BIT(offset),
|
||||
gpio_reg_base + GPIO_CFG);
|
||||
spin_unlock_irqrestore(&gc->bgpio_lock, flags);
|
||||
}
|
||||
|
@ -255,7 +255,7 @@ static void lp_gpio_irq_handler(struct irq_desc *desc)
|
||||
mask = BIT(pin);
|
||||
/* Clear before handling so we don't lose an edge */
|
||||
outl(mask, reg);
|
||||
irq = irq_find_mapping(lg->chip.irqdomain, base + pin);
|
||||
irq = irq_find_mapping(lg->chip.irq.domain, base + pin);
|
||||
generic_handle_irq(irq);
|
||||
}
|
||||
}
|
||||
|
492
drivers/gpio/gpio-max3191x.c
Normal file
492
drivers/gpio/gpio-max3191x.c
Normal file
@ -0,0 +1,492 @@
|
||||
/*
|
||||
* gpio-max3191x.c - GPIO driver for Maxim MAX3191x industrial serializer
|
||||
*
|
||||
* Copyright (C) 2017 KUNBUS GmbH
|
||||
*
|
||||
* The MAX3191x makes 8 digital 24V inputs available via SPI.
|
||||
* Multiple chips can be daisy-chained, the spec does not impose
|
||||
* a limit on the number of chips and neither does this driver.
|
||||
*
|
||||
* Either of two modes is selectable: In 8-bit mode, only the state
|
||||
* of the inputs is clocked out to achieve high readout speeds;
|
||||
* In 16-bit mode, an additional status byte is clocked out with
|
||||
* a CRC and indicator bits for undervoltage and overtemperature.
|
||||
* The driver returns an error instead of potentially bogus data
|
||||
* if any of these fault conditions occur. However it does allow
|
||||
* readout of non-faulting chips in the same daisy-chain.
|
||||
*
|
||||
* MAX3191x supports four debounce settings and the driver is
|
||||
* capable of configuring these differently for each chip in the
|
||||
* daisy-chain.
|
||||
*
|
||||
* If the chips are hardwired to 8-bit mode ("modesel" pulled high),
|
||||
* gpio-pisosr.c can be used alternatively to this driver.
|
||||
*
|
||||
* https://datasheets.maximintegrated.com/en/ds/MAX31910.pdf
|
||||
* https://datasheets.maximintegrated.com/en/ds/MAX31911.pdf
|
||||
* https://datasheets.maximintegrated.com/en/ds/MAX31912.pdf
|
||||
* https://datasheets.maximintegrated.com/en/ds/MAX31913.pdf
|
||||
* https://datasheets.maximintegrated.com/en/ds/MAX31953-MAX31963.pdf
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License (version 2) as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/bitmap.h>
|
||||
#include <linux/crc8.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/gpio/driver.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/spi/spi.h>
|
||||
|
||||
enum max3191x_mode {
|
||||
STATUS_BYTE_ENABLED,
|
||||
STATUS_BYTE_DISABLED,
|
||||
};
|
||||
|
||||
/**
|
||||
* struct max3191x_chip - max3191x daisy-chain
|
||||
* @gpio: GPIO controller struct
|
||||
* @lock: protects read sequences
|
||||
* @nchips: number of chips in the daisy-chain
|
||||
* @mode: current mode, 0 for 16-bit, 1 for 8-bit;
|
||||
* for simplicity, all chips in the daisy-chain are assumed
|
||||
* to use the same mode
|
||||
* @modesel_pins: GPIO pins to configure modesel of each chip
|
||||
* @fault_pins: GPIO pins to detect fault of each chip
|
||||
* @db0_pins: GPIO pins to configure debounce of each chip
|
||||
* @db1_pins: GPIO pins to configure debounce of each chip
|
||||
* @mesg: SPI message to perform a readout
|
||||
* @xfer: SPI transfer used by @mesg
|
||||
* @crc_error: bitmap signaling CRC error for each chip
|
||||
* @overtemp: bitmap signaling overtemperature alarm for each chip
|
||||
* @undervolt1: bitmap signaling undervoltage alarm for each chip
|
||||
* @undervolt2: bitmap signaling undervoltage warning for each chip
|
||||
* @fault: bitmap signaling assertion of @fault_pins for each chip
|
||||
* @ignore_uv: whether to ignore undervoltage alarms;
|
||||
* set by a device property if the chips are powered through
|
||||
* 5VOUT instead of VCC24V, in which case they will constantly
|
||||
* signal undervoltage;
|
||||
* for simplicity, all chips in the daisy-chain are assumed
|
||||
* to be powered the same way
|
||||
*/
|
||||
struct max3191x_chip {
|
||||
struct gpio_chip gpio;
|
||||
struct mutex lock;
|
||||
u32 nchips;
|
||||
enum max3191x_mode mode;
|
||||
struct gpio_descs *modesel_pins;
|
||||
struct gpio_descs *fault_pins;
|
||||
struct gpio_descs *db0_pins;
|
||||
struct gpio_descs *db1_pins;
|
||||
struct spi_message mesg;
|
||||
struct spi_transfer xfer;
|
||||
unsigned long *crc_error;
|
||||
unsigned long *overtemp;
|
||||
unsigned long *undervolt1;
|
||||
unsigned long *undervolt2;
|
||||
unsigned long *fault;
|
||||
bool ignore_uv;
|
||||
};
|
||||
|
||||
#define MAX3191X_NGPIO 8
|
||||
#define MAX3191X_CRC8_POLYNOMIAL 0xa8 /* (x^5) + x^4 + x^2 + x^0 */
|
||||
|
||||
DECLARE_CRC8_TABLE(max3191x_crc8);
|
||||
|
||||
static int max3191x_get_direction(struct gpio_chip *gpio, unsigned int offset)
|
||||
{
|
||||
return 1; /* always in */
|
||||
}
|
||||
|
||||
static int max3191x_direction_input(struct gpio_chip *gpio, unsigned int offset)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int max3191x_direction_output(struct gpio_chip *gpio,
|
||||
unsigned int offset, int value)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static void max3191x_set(struct gpio_chip *gpio, unsigned int offset, int value)
|
||||
{ }
|
||||
|
||||
static void max3191x_set_multiple(struct gpio_chip *gpio, unsigned long *mask,
|
||||
unsigned long *bits)
|
||||
{ }
|
||||
|
||||
static unsigned int max3191x_wordlen(struct max3191x_chip *max3191x)
|
||||
{
|
||||
return max3191x->mode == STATUS_BYTE_ENABLED ? 2 : 1;
|
||||
}
|
||||
|
||||
static int max3191x_readout_locked(struct max3191x_chip *max3191x)
|
||||
{
|
||||
struct device *dev = max3191x->gpio.parent;
|
||||
struct spi_device *spi = to_spi_device(dev);
|
||||
int val, i, ot = 0, uv1 = 0;
|
||||
|
||||
val = spi_sync(spi, &max3191x->mesg);
|
||||
if (val) {
|
||||
dev_err_ratelimited(dev, "SPI receive error %d\n", val);
|
||||
return val;
|
||||
}
|
||||
|
||||
for (i = 0; i < max3191x->nchips; i++) {
|
||||
if (max3191x->mode == STATUS_BYTE_ENABLED) {
|
||||
u8 in = ((u8 *)max3191x->xfer.rx_buf)[i * 2];
|
||||
u8 status = ((u8 *)max3191x->xfer.rx_buf)[i * 2 + 1];
|
||||
|
||||
val = (status & 0xf8) != crc8(max3191x_crc8, &in, 1, 0);
|
||||
__assign_bit(i, max3191x->crc_error, val);
|
||||
if (val)
|
||||
dev_err_ratelimited(dev,
|
||||
"chip %d: CRC error\n", i);
|
||||
|
||||
ot = (status >> 1) & 1;
|
||||
__assign_bit(i, max3191x->overtemp, ot);
|
||||
if (ot)
|
||||
dev_err_ratelimited(dev,
|
||||
"chip %d: overtemperature\n", i);
|
||||
|
||||
if (!max3191x->ignore_uv) {
|
||||
uv1 = !((status >> 2) & 1);
|
||||
__assign_bit(i, max3191x->undervolt1, uv1);
|
||||
if (uv1)
|
||||
dev_err_ratelimited(dev,
|
||||
"chip %d: undervoltage\n", i);
|
||||
|
||||
val = !(status & 1);
|
||||
__assign_bit(i, max3191x->undervolt2, val);
|
||||
if (val && !uv1)
|
||||
dev_warn_ratelimited(dev,
|
||||
"chip %d: voltage warn\n", i);
|
||||
}
|
||||
}
|
||||
|
||||
if (max3191x->fault_pins && !max3191x->ignore_uv) {
|
||||
/* fault pin shared by all chips or per chip */
|
||||
struct gpio_desc *fault_pin =
|
||||
(max3191x->fault_pins->ndescs == 1)
|
||||
? max3191x->fault_pins->desc[0]
|
||||
: max3191x->fault_pins->desc[i];
|
||||
|
||||
val = gpiod_get_value_cansleep(fault_pin);
|
||||
if (val < 0) {
|
||||
dev_err_ratelimited(dev,
|
||||
"GPIO read error %d\n", val);
|
||||
return val;
|
||||
}
|
||||
__assign_bit(i, max3191x->fault, val);
|
||||
if (val && !uv1 && !ot)
|
||||
dev_err_ratelimited(dev,
|
||||
"chip %d: fault\n", i);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool max3191x_chip_is_faulting(struct max3191x_chip *max3191x,
|
||||
unsigned int chipnum)
|
||||
{
|
||||
/* without status byte the only diagnostic is the fault pin */
|
||||
if (!max3191x->ignore_uv && test_bit(chipnum, max3191x->fault))
|
||||
return true;
|
||||
|
||||
if (max3191x->mode == STATUS_BYTE_DISABLED)
|
||||
return false;
|
||||
|
||||
return test_bit(chipnum, max3191x->crc_error) ||
|
||||
test_bit(chipnum, max3191x->overtemp) ||
|
||||
(!max3191x->ignore_uv &&
|
||||
test_bit(chipnum, max3191x->undervolt1));
|
||||
}
|
||||
|
||||
static int max3191x_get(struct gpio_chip *gpio, unsigned int offset)
|
||||
{
|
||||
struct max3191x_chip *max3191x = gpiochip_get_data(gpio);
|
||||
int ret, chipnum, wordlen = max3191x_wordlen(max3191x);
|
||||
u8 in;
|
||||
|
||||
mutex_lock(&max3191x->lock);
|
||||
ret = max3191x_readout_locked(max3191x);
|
||||
if (ret)
|
||||
goto out_unlock;
|
||||
|
||||
chipnum = offset / MAX3191X_NGPIO;
|
||||
if (max3191x_chip_is_faulting(max3191x, chipnum)) {
|
||||
ret = -EIO;
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
in = ((u8 *)max3191x->xfer.rx_buf)[chipnum * wordlen];
|
||||
ret = (in >> (offset % MAX3191X_NGPIO)) & 1;
|
||||
|
||||
out_unlock:
|
||||
mutex_unlock(&max3191x->lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int max3191x_get_multiple(struct gpio_chip *gpio, unsigned long *mask,
|
||||
unsigned long *bits)
|
||||
{
|
||||
struct max3191x_chip *max3191x = gpiochip_get_data(gpio);
|
||||
int ret, bit = 0, wordlen = max3191x_wordlen(max3191x);
|
||||
|
||||
mutex_lock(&max3191x->lock);
|
||||
ret = max3191x_readout_locked(max3191x);
|
||||
if (ret)
|
||||
goto out_unlock;
|
||||
|
||||
while ((bit = find_next_bit(mask, gpio->ngpio, bit)) != gpio->ngpio) {
|
||||
unsigned int chipnum = bit / MAX3191X_NGPIO;
|
||||
unsigned long in, shift, index;
|
||||
|
||||
if (max3191x_chip_is_faulting(max3191x, chipnum)) {
|
||||
ret = -EIO;
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
in = ((u8 *)max3191x->xfer.rx_buf)[chipnum * wordlen];
|
||||
shift = round_down(bit % BITS_PER_LONG, MAX3191X_NGPIO);
|
||||
index = bit / BITS_PER_LONG;
|
||||
bits[index] &= ~(mask[index] & (0xff << shift));
|
||||
bits[index] |= mask[index] & (in << shift); /* copy bits */
|
||||
|
||||
bit = (chipnum + 1) * MAX3191X_NGPIO; /* go to next chip */
|
||||
}
|
||||
|
||||
out_unlock:
|
||||
mutex_unlock(&max3191x->lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int max3191x_set_config(struct gpio_chip *gpio, unsigned int offset,
|
||||
unsigned long config)
|
||||
{
|
||||
struct max3191x_chip *max3191x = gpiochip_get_data(gpio);
|
||||
u32 debounce, chipnum, db0_val, db1_val;
|
||||
|
||||
if (pinconf_to_config_param(config) != PIN_CONFIG_INPUT_DEBOUNCE)
|
||||
return -ENOTSUPP;
|
||||
|
||||
if (!max3191x->db0_pins || !max3191x->db1_pins)
|
||||
return -EINVAL;
|
||||
|
||||
debounce = pinconf_to_config_argument(config);
|
||||
switch (debounce) {
|
||||
case 0:
|
||||
db0_val = 0;
|
||||
db1_val = 0;
|
||||
break;
|
||||
case 1 ... 25:
|
||||
db0_val = 0;
|
||||
db1_val = 1;
|
||||
break;
|
||||
case 26 ... 750:
|
||||
db0_val = 1;
|
||||
db1_val = 0;
|
||||
break;
|
||||
case 751 ... 3000:
|
||||
db0_val = 1;
|
||||
db1_val = 1;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (max3191x->db0_pins->ndescs == 1)
|
||||
chipnum = 0; /* all chips use the same pair of debounce pins */
|
||||
else
|
||||
chipnum = offset / MAX3191X_NGPIO; /* per chip debounce pins */
|
||||
|
||||
mutex_lock(&max3191x->lock);
|
||||
gpiod_set_value_cansleep(max3191x->db0_pins->desc[chipnum], db0_val);
|
||||
gpiod_set_value_cansleep(max3191x->db1_pins->desc[chipnum], db1_val);
|
||||
mutex_unlock(&max3191x->lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void gpiod_set_array_single_value_cansleep(unsigned int ndescs,
|
||||
struct gpio_desc **desc,
|
||||
int value)
|
||||
{
|
||||
int i, values[ndescs];
|
||||
|
||||
for (i = 0; i < ndescs; i++)
|
||||
values[i] = value;
|
||||
|
||||
gpiod_set_array_value_cansleep(ndescs, desc, values);
|
||||
}
|
||||
|
||||
static struct gpio_descs *devm_gpiod_get_array_optional_count(
|
||||
struct device *dev, const char *con_id,
|
||||
enum gpiod_flags flags, unsigned int expected)
|
||||
{
|
||||
struct gpio_descs *descs;
|
||||
int found = gpiod_count(dev, con_id);
|
||||
|
||||
if (found == -ENOENT)
|
||||
return NULL;
|
||||
|
||||
if (found != expected && found != 1) {
|
||||
dev_err(dev, "ignoring %s-gpios: found %d, expected %u or 1\n",
|
||||
con_id, found, expected);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
descs = devm_gpiod_get_array_optional(dev, con_id, flags);
|
||||
|
||||
if (IS_ERR(descs)) {
|
||||
dev_err(dev, "failed to get %s-gpios: %ld\n",
|
||||
con_id, PTR_ERR(descs));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return descs;
|
||||
}
|
||||
|
||||
static int max3191x_probe(struct spi_device *spi)
|
||||
{
|
||||
struct device *dev = &spi->dev;
|
||||
struct max3191x_chip *max3191x;
|
||||
int n, ret;
|
||||
|
||||
max3191x = devm_kzalloc(dev, sizeof(*max3191x), GFP_KERNEL);
|
||||
if (!max3191x)
|
||||
return -ENOMEM;
|
||||
spi_set_drvdata(spi, max3191x);
|
||||
|
||||
max3191x->nchips = 1;
|
||||
device_property_read_u32(dev, "#daisy-chained-devices",
|
||||
&max3191x->nchips);
|
||||
|
||||
n = BITS_TO_LONGS(max3191x->nchips);
|
||||
max3191x->crc_error = devm_kcalloc(dev, n, sizeof(long), GFP_KERNEL);
|
||||
max3191x->undervolt1 = devm_kcalloc(dev, n, sizeof(long), GFP_KERNEL);
|
||||
max3191x->undervolt2 = devm_kcalloc(dev, n, sizeof(long), GFP_KERNEL);
|
||||
max3191x->overtemp = devm_kcalloc(dev, n, sizeof(long), GFP_KERNEL);
|
||||
max3191x->fault = devm_kcalloc(dev, n, sizeof(long), GFP_KERNEL);
|
||||
max3191x->xfer.rx_buf = devm_kcalloc(dev, max3191x->nchips,
|
||||
2, GFP_KERNEL);
|
||||
if (!max3191x->crc_error || !max3191x->undervolt1 ||
|
||||
!max3191x->overtemp || !max3191x->undervolt2 ||
|
||||
!max3191x->fault || !max3191x->xfer.rx_buf)
|
||||
return -ENOMEM;
|
||||
|
||||
max3191x->modesel_pins = devm_gpiod_get_array_optional_count(dev,
|
||||
"maxim,modesel", GPIOD_ASIS, max3191x->nchips);
|
||||
max3191x->fault_pins = devm_gpiod_get_array_optional_count(dev,
|
||||
"maxim,fault", GPIOD_IN, max3191x->nchips);
|
||||
max3191x->db0_pins = devm_gpiod_get_array_optional_count(dev,
|
||||
"maxim,db0", GPIOD_OUT_LOW, max3191x->nchips);
|
||||
max3191x->db1_pins = devm_gpiod_get_array_optional_count(dev,
|
||||
"maxim,db1", GPIOD_OUT_LOW, max3191x->nchips);
|
||||
|
||||
max3191x->mode = device_property_read_bool(dev, "maxim,modesel-8bit")
|
||||
? STATUS_BYTE_DISABLED : STATUS_BYTE_ENABLED;
|
||||
if (max3191x->modesel_pins)
|
||||
gpiod_set_array_single_value_cansleep(
|
||||
max3191x->modesel_pins->ndescs,
|
||||
max3191x->modesel_pins->desc, max3191x->mode);
|
||||
|
||||
max3191x->ignore_uv = device_property_read_bool(dev,
|
||||
"maxim,ignore-undervoltage");
|
||||
|
||||
if (max3191x->db0_pins && max3191x->db1_pins &&
|
||||
max3191x->db0_pins->ndescs != max3191x->db1_pins->ndescs) {
|
||||
dev_err(dev, "ignoring maxim,db*-gpios: array len mismatch\n");
|
||||
devm_gpiod_put_array(dev, max3191x->db0_pins);
|
||||
devm_gpiod_put_array(dev, max3191x->db1_pins);
|
||||
max3191x->db0_pins = NULL;
|
||||
max3191x->db1_pins = NULL;
|
||||
}
|
||||
|
||||
max3191x->xfer.len = max3191x->nchips * max3191x_wordlen(max3191x);
|
||||
spi_message_init_with_transfers(&max3191x->mesg, &max3191x->xfer, 1);
|
||||
|
||||
max3191x->gpio.label = spi->modalias;
|
||||
max3191x->gpio.owner = THIS_MODULE;
|
||||
max3191x->gpio.parent = dev;
|
||||
max3191x->gpio.base = -1;
|
||||
max3191x->gpio.ngpio = max3191x->nchips * MAX3191X_NGPIO;
|
||||
max3191x->gpio.can_sleep = true;
|
||||
|
||||
max3191x->gpio.get_direction = max3191x_get_direction;
|
||||
max3191x->gpio.direction_input = max3191x_direction_input;
|
||||
max3191x->gpio.direction_output = max3191x_direction_output;
|
||||
max3191x->gpio.set = max3191x_set;
|
||||
max3191x->gpio.set_multiple = max3191x_set_multiple;
|
||||
max3191x->gpio.get = max3191x_get;
|
||||
max3191x->gpio.get_multiple = max3191x_get_multiple;
|
||||
max3191x->gpio.set_config = max3191x_set_config;
|
||||
|
||||
mutex_init(&max3191x->lock);
|
||||
|
||||
ret = gpiochip_add_data(&max3191x->gpio, max3191x);
|
||||
if (ret) {
|
||||
mutex_destroy(&max3191x->lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int max3191x_remove(struct spi_device *spi)
|
||||
{
|
||||
struct max3191x_chip *max3191x = spi_get_drvdata(spi);
|
||||
|
||||
gpiochip_remove(&max3191x->gpio);
|
||||
mutex_destroy(&max3191x->lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __init max3191x_register_driver(struct spi_driver *sdrv)
|
||||
{
|
||||
crc8_populate_msb(max3191x_crc8, MAX3191X_CRC8_POLYNOMIAL);
|
||||
return spi_register_driver(sdrv);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static const struct of_device_id max3191x_of_id[] = {
|
||||
{ .compatible = "maxim,max31910" },
|
||||
{ .compatible = "maxim,max31911" },
|
||||
{ .compatible = "maxim,max31912" },
|
||||
{ .compatible = "maxim,max31913" },
|
||||
{ .compatible = "maxim,max31953" },
|
||||
{ .compatible = "maxim,max31963" },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, max3191x_of_id);
|
||||
#endif
|
||||
|
||||
static const struct spi_device_id max3191x_spi_id[] = {
|
||||
{ "max31910" },
|
||||
{ "max31911" },
|
||||
{ "max31912" },
|
||||
{ "max31913" },
|
||||
{ "max31953" },
|
||||
{ "max31963" },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(spi, max3191x_spi_id);
|
||||
|
||||
static struct spi_driver max3191x_driver = {
|
||||
.driver = {
|
||||
.name = "max3191x",
|
||||
.of_match_table = of_match_ptr(max3191x_of_id),
|
||||
},
|
||||
.probe = max3191x_probe,
|
||||
.remove = max3191x_remove,
|
||||
.id_table = max3191x_spi_id,
|
||||
};
|
||||
module_driver(max3191x_driver, max3191x_register_driver, spi_unregister_driver);
|
||||
|
||||
MODULE_AUTHOR("Lukas Wunner <lukas@wunner.de>");
|
||||
MODULE_DESCRIPTION("GPIO driver for Maxim MAX3191x industrial serializer");
|
||||
MODULE_LICENSE("GPL v2");
|
@ -486,7 +486,7 @@ static irqreturn_t max732x_irq_handler(int irq, void *devid)
|
||||
|
||||
do {
|
||||
level = __ffs(pending);
|
||||
handle_nested_irq(irq_find_mapping(chip->gpio_chip.irqdomain,
|
||||
handle_nested_irq(irq_find_mapping(chip->gpio_chip.irq.domain,
|
||||
level));
|
||||
|
||||
pending &= ~(1 << level);
|
||||
|
@ -17,6 +17,7 @@
|
||||
#include <linux/io.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/ioport.h>
|
||||
@ -52,11 +53,6 @@ static int mb86s70_gpio_request(struct gpio_chip *gc, unsigned gpio)
|
||||
spin_lock_irqsave(&gchip->lock, flags);
|
||||
|
||||
val = readl(gchip->base + PFR(gpio));
|
||||
if (!(val & OFFSET(gpio))) {
|
||||
spin_unlock_irqrestore(&gchip->lock, flags);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
val &= ~OFFSET(gpio);
|
||||
writel(val, gchip->base + PFR(gpio));
|
||||
|
||||
@ -209,6 +205,7 @@ static const struct of_device_id mb86s70_gpio_dt_ids[] = {
|
||||
{ .compatible = "fujitsu,mb86s70-gpio" },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, mb86s70_gpio_dt_ids);
|
||||
|
||||
static struct platform_driver mb86s70_gpio_driver = {
|
||||
.driver = {
|
||||
@ -218,5 +215,8 @@ static struct platform_driver mb86s70_gpio_driver = {
|
||||
.probe = mb86s70_gpio_probe,
|
||||
.remove = mb86s70_gpio_remove,
|
||||
};
|
||||
module_platform_driver(mb86s70_gpio_driver);
|
||||
|
||||
builtin_platform_driver(mb86s70_gpio_driver);
|
||||
MODULE_DESCRIPTION("MB86S7x GPIO Driver");
|
||||
MODULE_ALIAS("platform:mb86s70-gpio");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
@ -357,7 +357,7 @@ static void mrfld_irq_handler(struct irq_desc *desc)
|
||||
for_each_set_bit(gpio, &pending, 32) {
|
||||
unsigned int irq;
|
||||
|
||||
irq = irq_find_mapping(gc->irqdomain, base + gpio);
|
||||
irq = irq_find_mapping(gc->irq.domain, base + gpio);
|
||||
generic_handle_irq(irq);
|
||||
}
|
||||
}
|
||||
|
@ -126,20 +126,16 @@ static unsigned long bgpio_read32be(void __iomem *reg)
|
||||
return ioread32be(reg);
|
||||
}
|
||||
|
||||
static unsigned long bgpio_pin2mask(struct gpio_chip *gc, unsigned int pin)
|
||||
static unsigned long bgpio_line2mask(struct gpio_chip *gc, unsigned int line)
|
||||
{
|
||||
return BIT(pin);
|
||||
}
|
||||
|
||||
static unsigned long bgpio_pin2mask_be(struct gpio_chip *gc,
|
||||
unsigned int pin)
|
||||
{
|
||||
return BIT(gc->bgpio_bits - 1 - pin);
|
||||
if (gc->be_bits)
|
||||
return BIT(gc->bgpio_bits - 1 - line);
|
||||
return BIT(line);
|
||||
}
|
||||
|
||||
static int bgpio_get_set(struct gpio_chip *gc, unsigned int gpio)
|
||||
{
|
||||
unsigned long pinmask = gc->pin2mask(gc, gpio);
|
||||
unsigned long pinmask = bgpio_line2mask(gc, gpio);
|
||||
|
||||
if (gc->bgpio_dir & pinmask)
|
||||
return !!(gc->read_reg(gc->reg_set) & pinmask);
|
||||
@ -147,9 +143,76 @@ static int bgpio_get_set(struct gpio_chip *gc, unsigned int gpio)
|
||||
return !!(gc->read_reg(gc->reg_dat) & pinmask);
|
||||
}
|
||||
|
||||
/*
|
||||
* This assumes that the bits in the GPIO register are in native endianness.
|
||||
* We only assign the function pointer if we have that.
|
||||
*/
|
||||
static int bgpio_get_set_multiple(struct gpio_chip *gc, unsigned long *mask,
|
||||
unsigned long *bits)
|
||||
{
|
||||
unsigned long get_mask = 0;
|
||||
unsigned long set_mask = 0;
|
||||
int bit = 0;
|
||||
|
||||
while ((bit = find_next_bit(mask, gc->ngpio, bit)) != gc->ngpio) {
|
||||
if (gc->bgpio_dir & BIT(bit))
|
||||
set_mask |= BIT(bit);
|
||||
else
|
||||
get_mask |= BIT(bit);
|
||||
}
|
||||
|
||||
if (set_mask)
|
||||
*bits |= gc->read_reg(gc->reg_set) & set_mask;
|
||||
if (get_mask)
|
||||
*bits |= gc->read_reg(gc->reg_dat) & get_mask;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bgpio_get(struct gpio_chip *gc, unsigned int gpio)
|
||||
{
|
||||
return !!(gc->read_reg(gc->reg_dat) & gc->pin2mask(gc, gpio));
|
||||
return !!(gc->read_reg(gc->reg_dat) & bgpio_line2mask(gc, gpio));
|
||||
}
|
||||
|
||||
/*
|
||||
* This only works if the bits in the GPIO register are in native endianness.
|
||||
* It is dirt simple and fast in this case. (Also the most common case.)
|
||||
*/
|
||||
static int bgpio_get_multiple(struct gpio_chip *gc, unsigned long *mask,
|
||||
unsigned long *bits)
|
||||
{
|
||||
|
||||
*bits = gc->read_reg(gc->reg_dat) & *mask;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* With big endian mirrored bit order it becomes more tedious.
|
||||
*/
|
||||
static int bgpio_get_multiple_be(struct gpio_chip *gc, unsigned long *mask,
|
||||
unsigned long *bits)
|
||||
{
|
||||
unsigned long readmask = 0;
|
||||
unsigned long val;
|
||||
int bit;
|
||||
|
||||
/* Create a mirrored mask */
|
||||
bit = 0;
|
||||
while ((bit = find_next_bit(mask, gc->ngpio, bit)) != gc->ngpio)
|
||||
readmask |= bgpio_line2mask(gc, bit);
|
||||
|
||||
/* Read the register */
|
||||
val = gc->read_reg(gc->reg_dat) & readmask;
|
||||
|
||||
/*
|
||||
* Mirror the result into the "bits" result, this will give line 0
|
||||
* in bit 0 ... line 31 in bit 31 for a 32bit register.
|
||||
*/
|
||||
bit = 0;
|
||||
while ((bit = find_next_bit(&val, gc->ngpio, bit)) != gc->ngpio)
|
||||
*bits |= bgpio_line2mask(gc, bit);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void bgpio_set_none(struct gpio_chip *gc, unsigned int gpio, int val)
|
||||
@ -158,7 +221,7 @@ static void bgpio_set_none(struct gpio_chip *gc, unsigned int gpio, int val)
|
||||
|
||||
static void bgpio_set(struct gpio_chip *gc, unsigned int gpio, int val)
|
||||
{
|
||||
unsigned long mask = gc->pin2mask(gc, gpio);
|
||||
unsigned long mask = bgpio_line2mask(gc, gpio);
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&gc->bgpio_lock, flags);
|
||||
@ -176,7 +239,7 @@ static void bgpio_set(struct gpio_chip *gc, unsigned int gpio, int val)
|
||||
static void bgpio_set_with_clear(struct gpio_chip *gc, unsigned int gpio,
|
||||
int val)
|
||||
{
|
||||
unsigned long mask = gc->pin2mask(gc, gpio);
|
||||
unsigned long mask = bgpio_line2mask(gc, gpio);
|
||||
|
||||
if (val)
|
||||
gc->write_reg(gc->reg_set, mask);
|
||||
@ -186,7 +249,7 @@ static void bgpio_set_with_clear(struct gpio_chip *gc, unsigned int gpio,
|
||||
|
||||
static void bgpio_set_set(struct gpio_chip *gc, unsigned int gpio, int val)
|
||||
{
|
||||
unsigned long mask = gc->pin2mask(gc, gpio);
|
||||
unsigned long mask = bgpio_line2mask(gc, gpio);
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&gc->bgpio_lock, flags);
|
||||
@ -216,9 +279,9 @@ static void bgpio_multiple_get_masks(struct gpio_chip *gc,
|
||||
break;
|
||||
if (__test_and_clear_bit(i, mask)) {
|
||||
if (test_bit(i, bits))
|
||||
*set_mask |= gc->pin2mask(gc, i);
|
||||
*set_mask |= bgpio_line2mask(gc, i);
|
||||
else
|
||||
*clear_mask |= gc->pin2mask(gc, i);
|
||||
*clear_mask |= bgpio_line2mask(gc, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -294,7 +357,7 @@ static int bgpio_dir_in(struct gpio_chip *gc, unsigned int gpio)
|
||||
|
||||
spin_lock_irqsave(&gc->bgpio_lock, flags);
|
||||
|
||||
gc->bgpio_dir &= ~gc->pin2mask(gc, gpio);
|
||||
gc->bgpio_dir &= ~bgpio_line2mask(gc, gpio);
|
||||
gc->write_reg(gc->reg_dir, gc->bgpio_dir);
|
||||
|
||||
spin_unlock_irqrestore(&gc->bgpio_lock, flags);
|
||||
@ -305,7 +368,7 @@ 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 of input */
|
||||
return !(gc->read_reg(gc->reg_dir) & gc->pin2mask(gc, gpio));
|
||||
return !(gc->read_reg(gc->reg_dir) & bgpio_line2mask(gc, gpio));
|
||||
}
|
||||
|
||||
static int bgpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val)
|
||||
@ -316,7 +379,7 @@ static int bgpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val)
|
||||
|
||||
spin_lock_irqsave(&gc->bgpio_lock, flags);
|
||||
|
||||
gc->bgpio_dir |= gc->pin2mask(gc, gpio);
|
||||
gc->bgpio_dir |= bgpio_line2mask(gc, gpio);
|
||||
gc->write_reg(gc->reg_dir, gc->bgpio_dir);
|
||||
|
||||
spin_unlock_irqrestore(&gc->bgpio_lock, flags);
|
||||
@ -330,7 +393,7 @@ static int bgpio_dir_in_inv(struct gpio_chip *gc, unsigned int gpio)
|
||||
|
||||
spin_lock_irqsave(&gc->bgpio_lock, flags);
|
||||
|
||||
gc->bgpio_dir |= gc->pin2mask(gc, gpio);
|
||||
gc->bgpio_dir |= bgpio_line2mask(gc, gpio);
|
||||
gc->write_reg(gc->reg_dir, gc->bgpio_dir);
|
||||
|
||||
spin_unlock_irqrestore(&gc->bgpio_lock, flags);
|
||||
@ -346,7 +409,7 @@ static int bgpio_dir_out_inv(struct gpio_chip *gc, unsigned int gpio, int val)
|
||||
|
||||
spin_lock_irqsave(&gc->bgpio_lock, flags);
|
||||
|
||||
gc->bgpio_dir &= ~gc->pin2mask(gc, gpio);
|
||||
gc->bgpio_dir &= ~bgpio_line2mask(gc, gpio);
|
||||
gc->write_reg(gc->reg_dir, gc->bgpio_dir);
|
||||
|
||||
spin_unlock_irqrestore(&gc->bgpio_lock, flags);
|
||||
@ -357,12 +420,11 @@ static int bgpio_dir_out_inv(struct gpio_chip *gc, unsigned int gpio, int val)
|
||||
static int bgpio_get_dir_inv(struct gpio_chip *gc, unsigned int gpio)
|
||||
{
|
||||
/* Return 0 if output, 1 if input */
|
||||
return !!(gc->read_reg(gc->reg_dir) & gc->pin2mask(gc, gpio));
|
||||
return !!(gc->read_reg(gc->reg_dir) & bgpio_line2mask(gc, gpio));
|
||||
}
|
||||
|
||||
static int bgpio_setup_accessors(struct device *dev,
|
||||
struct gpio_chip *gc,
|
||||
bool bit_be,
|
||||
bool byte_be)
|
||||
{
|
||||
|
||||
@ -406,8 +468,6 @@ static int bgpio_setup_accessors(struct device *dev,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
gc->pin2mask = bit_be ? bgpio_pin2mask_be : bgpio_pin2mask;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -462,10 +522,24 @@ static int bgpio_setup_io(struct gpio_chip *gc,
|
||||
}
|
||||
|
||||
if (!(flags & BGPIOF_UNREADABLE_REG_SET) &&
|
||||
(flags & BGPIOF_READ_OUTPUT_REG_SET))
|
||||
(flags & BGPIOF_READ_OUTPUT_REG_SET)) {
|
||||
gc->get = bgpio_get_set;
|
||||
else
|
||||
if (!gc->be_bits)
|
||||
gc->get_multiple = bgpio_get_set_multiple;
|
||||
/*
|
||||
* We deliberately avoid assigning the ->get_multiple() call
|
||||
* for big endian mirrored registers which are ALSO reflecting
|
||||
* their value in the set register when used as output. It is
|
||||
* simply too much complexity, let the GPIO core fall back to
|
||||
* reading each line individually in that fringe case.
|
||||
*/
|
||||
} else {
|
||||
gc->get = bgpio_get;
|
||||
if (gc->be_bits)
|
||||
gc->get_multiple = bgpio_get_multiple_be;
|
||||
else
|
||||
gc->get_multiple = bgpio_get_multiple;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -526,13 +600,13 @@ int bgpio_init(struct gpio_chip *gc, struct device *dev,
|
||||
gc->base = -1;
|
||||
gc->ngpio = gc->bgpio_bits;
|
||||
gc->request = bgpio_request;
|
||||
gc->be_bits = !!(flags & BGPIOF_BIG_ENDIAN);
|
||||
|
||||
ret = bgpio_setup_io(gc, dat, set, clr, flags);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = bgpio_setup_accessors(dev, gc, flags & BGPIOF_BIG_ENDIAN,
|
||||
flags & BGPIOF_BIG_ENDIAN_BYTE_ORDER);
|
||||
ret = bgpio_setup_accessors(dev, gc, flags & BGPIOF_BIG_ENDIAN_BYTE_ORDER);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include <linux/slab.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/gpio/driver.h>
|
||||
#include <linux/bitops.h>
|
||||
|
||||
#define MPC8XXX_GPIO_PINS 32
|
||||
|
||||
@ -44,6 +45,16 @@ struct mpc8xxx_gpio_chip {
|
||||
unsigned int irqn;
|
||||
};
|
||||
|
||||
/*
|
||||
* This hardware has a big endian bit assignment such that GPIO line 0 is
|
||||
* connected to bit 31, line 1 to bit 30 ... line 31 to bit 0.
|
||||
* This inline helper give the right bitmask for a certain line.
|
||||
*/
|
||||
static inline u32 mpc_pin2mask(unsigned int offset)
|
||||
{
|
||||
return BIT(31 - offset);
|
||||
}
|
||||
|
||||
/* Workaround GPIO 1 errata on MPC8572/MPC8536. The status of GPIOs
|
||||
* defined as output cannot be determined by reading GPDAT register,
|
||||
* so we use shadow data register instead. The status of input pins
|
||||
@ -59,7 +70,7 @@ static int mpc8572_gpio_get(struct gpio_chip *gc, unsigned int gpio)
|
||||
val = gc->read_reg(mpc8xxx_gc->regs + GPIO_DAT) & ~out_mask;
|
||||
out_shadow = gc->bgpio_data & out_mask;
|
||||
|
||||
return !!((val | out_shadow) & gc->pin2mask(gc, gpio));
|
||||
return !!((val | out_shadow) & mpc_pin2mask(gpio));
|
||||
}
|
||||
|
||||
static int mpc5121_gpio_dir_out(struct gpio_chip *gc,
|
||||
@ -120,7 +131,7 @@ static void mpc8xxx_irq_unmask(struct irq_data *d)
|
||||
|
||||
gc->write_reg(mpc8xxx_gc->regs + GPIO_IMR,
|
||||
gc->read_reg(mpc8xxx_gc->regs + GPIO_IMR)
|
||||
| gc->pin2mask(gc, irqd_to_hwirq(d)));
|
||||
| mpc_pin2mask(irqd_to_hwirq(d)));
|
||||
|
||||
raw_spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags);
|
||||
}
|
||||
@ -135,7 +146,7 @@ static void mpc8xxx_irq_mask(struct irq_data *d)
|
||||
|
||||
gc->write_reg(mpc8xxx_gc->regs + GPIO_IMR,
|
||||
gc->read_reg(mpc8xxx_gc->regs + GPIO_IMR)
|
||||
& ~(gc->pin2mask(gc, irqd_to_hwirq(d))));
|
||||
& ~mpc_pin2mask(irqd_to_hwirq(d)));
|
||||
|
||||
raw_spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags);
|
||||
}
|
||||
@ -146,7 +157,7 @@ static void mpc8xxx_irq_ack(struct irq_data *d)
|
||||
struct gpio_chip *gc = &mpc8xxx_gc->gc;
|
||||
|
||||
gc->write_reg(mpc8xxx_gc->regs + GPIO_IER,
|
||||
gc->pin2mask(gc, irqd_to_hwirq(d)));
|
||||
mpc_pin2mask(irqd_to_hwirq(d)));
|
||||
}
|
||||
|
||||
static int mpc8xxx_irq_set_type(struct irq_data *d, unsigned int flow_type)
|
||||
@ -160,7 +171,7 @@ static int mpc8xxx_irq_set_type(struct irq_data *d, unsigned int flow_type)
|
||||
raw_spin_lock_irqsave(&mpc8xxx_gc->lock, flags);
|
||||
gc->write_reg(mpc8xxx_gc->regs + GPIO_ICR,
|
||||
gc->read_reg(mpc8xxx_gc->regs + GPIO_ICR)
|
||||
| gc->pin2mask(gc, irqd_to_hwirq(d)));
|
||||
| mpc_pin2mask(irqd_to_hwirq(d)));
|
||||
raw_spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags);
|
||||
break;
|
||||
|
||||
@ -168,7 +179,7 @@ static int mpc8xxx_irq_set_type(struct irq_data *d, unsigned int flow_type)
|
||||
raw_spin_lock_irqsave(&mpc8xxx_gc->lock, flags);
|
||||
gc->write_reg(mpc8xxx_gc->regs + GPIO_ICR,
|
||||
gc->read_reg(mpc8xxx_gc->regs + GPIO_ICR)
|
||||
& ~(gc->pin2mask(gc, irqd_to_hwirq(d))));
|
||||
& ~mpc_pin2mask(irqd_to_hwirq(d)));
|
||||
raw_spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags);
|
||||
break;
|
||||
|
||||
|
@ -733,7 +733,7 @@ static irqreturn_t omap_gpio_irq_handler(int irq, void *gpiobank)
|
||||
|
||||
raw_spin_lock_irqsave(&bank->wa_lock, wa_lock_flags);
|
||||
|
||||
generic_handle_irq(irq_find_mapping(bank->chip.irqdomain,
|
||||
generic_handle_irq(irq_find_mapping(bank->chip.irq.domain,
|
||||
bit));
|
||||
|
||||
raw_spin_unlock_irqrestore(&bank->wa_lock,
|
||||
|
@ -608,7 +608,7 @@ static irqreturn_t pca953x_irq_handler(int irq, void *devid)
|
||||
for (i = 0; i < NBANK(chip); i++) {
|
||||
while (pending[i]) {
|
||||
level = __ffs(pending[i]);
|
||||
handle_nested_irq(irq_find_mapping(chip->gpio_chip.irqdomain,
|
||||
handle_nested_irq(irq_find_mapping(chip->gpio_chip.irq.domain,
|
||||
level + (BANK_SZ * i)));
|
||||
pending[i] &= ~(1 << level);
|
||||
nhandled++;
|
||||
|
@ -196,7 +196,7 @@ static irqreturn_t pcf857x_irq(int irq, void *data)
|
||||
mutex_unlock(&gpio->lock);
|
||||
|
||||
for_each_set_bit(i, &change, gpio->chip.ngpio)
|
||||
handle_nested_irq(irq_find_mapping(gpio->chip.irqdomain, i));
|
||||
handle_nested_irq(irq_find_mapping(gpio->chip.irq.domain, i));
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
@ -240,7 +240,7 @@ static irqreturn_t idio_16_irq_handler(int irq, void *dev_id)
|
||||
return IRQ_NONE;
|
||||
|
||||
for_each_set_bit(gpio, &idio16gpio->irq_mask, chip->ngpio)
|
||||
generic_handle_irq(irq_find_mapping(chip->irqdomain, gpio));
|
||||
generic_handle_irq(irq_find_mapping(chip->irq.domain, gpio));
|
||||
|
||||
raw_spin_lock(&idio16gpio->lock);
|
||||
|
||||
|
@ -221,7 +221,7 @@ static void pl061_irq_handler(struct irq_desc *desc)
|
||||
pending = readb(pl061->base + GPIOMIS);
|
||||
if (pending) {
|
||||
for_each_set_bit(offset, &pending, PL061_GPIO_NR)
|
||||
generic_handle_irq(irq_find_mapping(gc->irqdomain,
|
||||
generic_handle_irq(irq_find_mapping(gc->irq.domain,
|
||||
offset));
|
||||
}
|
||||
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include <linux/irq.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/pinctrl/consumer.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
@ -206,7 +207,7 @@ static irqreturn_t gpio_rcar_irq_handler(int irq, void *dev_id)
|
||||
gpio_rcar_read(p, INTMSK))) {
|
||||
offset = __ffs(pending);
|
||||
gpio_rcar_write(p, INTCLR, BIT(offset));
|
||||
generic_handle_irq(irq_find_mapping(p->gpio_chip.irqdomain,
|
||||
generic_handle_irq(irq_find_mapping(p->gpio_chip.irq.domain,
|
||||
offset));
|
||||
irqs_handled++;
|
||||
}
|
||||
@ -393,16 +394,11 @@ MODULE_DEVICE_TABLE(of, gpio_rcar_of_table);
|
||||
static int gpio_rcar_parse_dt(struct gpio_rcar_priv *p, unsigned int *npins)
|
||||
{
|
||||
struct device_node *np = p->pdev->dev.of_node;
|
||||
const struct of_device_id *match;
|
||||
const struct gpio_rcar_info *info;
|
||||
struct of_phandle_args args;
|
||||
int ret;
|
||||
|
||||
match = of_match_node(gpio_rcar_of_table, np);
|
||||
if (!match)
|
||||
return -EINVAL;
|
||||
|
||||
info = match->data;
|
||||
info = of_device_get_match_data(&p->pdev->dev);
|
||||
|
||||
ret = of_parse_phandle_with_fixed_args(np, "gpio-ranges", 3, 0, &args);
|
||||
*npins = ret == 0 ? args.args[2] : RCAR_MAX_GPIO_PER_BANK;
|
||||
@ -456,19 +452,17 @@ static int gpio_rcar_probe(struct platform_device *pdev)
|
||||
|
||||
pm_runtime_enable(dev);
|
||||
|
||||
io = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
|
||||
|
||||
if (!io || !irq) {
|
||||
dev_err(dev, "missing IRQ or IOMEM\n");
|
||||
if (!irq) {
|
||||
dev_err(dev, "missing IRQ\n");
|
||||
ret = -EINVAL;
|
||||
goto err0;
|
||||
}
|
||||
|
||||
p->base = devm_ioremap_nocache(dev, io->start, resource_size(io));
|
||||
if (!p->base) {
|
||||
dev_err(dev, "failed to remap I/O memory\n");
|
||||
ret = -ENXIO;
|
||||
io = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
p->base = devm_ioremap_resource(dev, io);
|
||||
if (IS_ERR(p->base)) {
|
||||
ret = PTR_ERR(p->base);
|
||||
goto err0;
|
||||
}
|
||||
|
||||
|
@ -103,8 +103,8 @@ static int gpio_reg_to_irq(struct gpio_chip *gc, unsigned offset)
|
||||
struct gpio_reg *r = to_gpio_reg(gc);
|
||||
int irq = r->irqs[offset];
|
||||
|
||||
if (irq >= 0 && r->irqdomain)
|
||||
irq = irq_find_mapping(r->irqdomain, irq);
|
||||
if (irq >= 0 && r->irq.domain)
|
||||
irq = irq_find_mapping(r->irq.domain, irq);
|
||||
|
||||
return irq;
|
||||
}
|
||||
|
@ -299,7 +299,7 @@ static void stmpe_dbg_show_one(struct seq_file *s,
|
||||
if (ret < 0)
|
||||
return;
|
||||
edge_det = !!(ret & mask);
|
||||
|
||||
/* fall through */
|
||||
case STMPE1801:
|
||||
rise_reg = stmpe->regs[STMPE_IDX_GPRER_LSB + bank];
|
||||
fall_reg = stmpe->regs[STMPE_IDX_GPFER_LSB + bank];
|
||||
@ -312,7 +312,7 @@ static void stmpe_dbg_show_one(struct seq_file *s,
|
||||
if (ret < 0)
|
||||
return;
|
||||
fall = !!(ret & mask);
|
||||
|
||||
/* fall through */
|
||||
case STMPE801:
|
||||
case STMPE1600:
|
||||
irqen_reg = stmpe->regs[STMPE_IDX_IEGPIOR_LSB + bank];
|
||||
@ -397,7 +397,7 @@ static irqreturn_t stmpe_gpio_irq(int irq, void *dev)
|
||||
while (stat) {
|
||||
int bit = __ffs(stat);
|
||||
int line = bank * 8 + bit;
|
||||
int child_irq = irq_find_mapping(stmpe_gpio->chip.irqdomain,
|
||||
int child_irq = irq_find_mapping(stmpe_gpio->chip.irq.domain,
|
||||
line);
|
||||
|
||||
handle_nested_irq(child_irq);
|
||||
@ -451,7 +451,7 @@ static int stmpe_gpio_probe(struct platform_device *pdev)
|
||||
of_property_read_u32(np, "st,norequest-mask",
|
||||
&stmpe_gpio->norequest_mask);
|
||||
if (stmpe_gpio->norequest_mask)
|
||||
stmpe_gpio->chip.irq_need_valid_mask = true;
|
||||
stmpe_gpio->chip.irq.need_valid_mask = true;
|
||||
|
||||
if (irq < 0)
|
||||
dev_info(&pdev->dev,
|
||||
@ -482,7 +482,7 @@ static int stmpe_gpio_probe(struct platform_device *pdev)
|
||||
/* Forbid unused lines to be mapped as IRQs */
|
||||
for (i = 0; i < sizeof(u32); i++)
|
||||
if (stmpe_gpio->norequest_mask & BIT(i))
|
||||
clear_bit(i, stmpe_gpio->chip.irq_valid_mask);
|
||||
clear_bit(i, stmpe_gpio->chip.irq.valid_mask);
|
||||
}
|
||||
ret = gpiochip_irqchip_add_nested(&stmpe_gpio->chip,
|
||||
&stmpe_gpio_irq_chip,
|
||||
|
@ -193,6 +193,9 @@ static int tb10x_gpio_probe(struct platform_device *pdev)
|
||||
|
||||
tb10x_gpio->gc.label =
|
||||
devm_kasprintf(&pdev->dev, GFP_KERNEL, "%pOF", pdev->dev.of_node);
|
||||
if (!tb10x_gpio->gc.label)
|
||||
return -ENOMEM;
|
||||
|
||||
tb10x_gpio->gc.parent = &pdev->dev;
|
||||
tb10x_gpio->gc.owner = THIS_MODULE;
|
||||
tb10x_gpio->gc.direction_input = tb10x_gpio_direction_in;
|
||||
|
@ -268,7 +268,7 @@ static irqreturn_t tc3589x_gpio_irq(int irq, void *dev)
|
||||
while (stat) {
|
||||
int bit = __ffs(stat);
|
||||
int line = i * 8 + bit;
|
||||
int irq = irq_find_mapping(tc3589x_gpio->chip.irqdomain,
|
||||
int irq = irq_find_mapping(tc3589x_gpio->chip.irq.domain,
|
||||
line);
|
||||
|
||||
handle_nested_irq(irq);
|
||||
|
623
drivers/gpio/gpio-tegra186.c
Normal file
623
drivers/gpio/gpio-tegra186.c
Normal file
@ -0,0 +1,623 @@
|
||||
/*
|
||||
* Copyright (c) 2016-2017 NVIDIA Corporation
|
||||
*
|
||||
* Author: Thierry Reding <treding@nvidia.com>
|
||||
*
|
||||
* This software is licensed under the terms of the GNU General Public
|
||||
* License version 2, as published by the Free Software Foundation, and
|
||||
* may be copied, distributed, and modified under those terms.
|
||||
*/
|
||||
|
||||
#include <linux/gpio/driver.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#include <dt-bindings/gpio/tegra186-gpio.h>
|
||||
|
||||
#define TEGRA186_GPIO_ENABLE_CONFIG 0x00
|
||||
#define TEGRA186_GPIO_ENABLE_CONFIG_ENABLE BIT(0)
|
||||
#define TEGRA186_GPIO_ENABLE_CONFIG_OUT BIT(1)
|
||||
#define TEGRA186_GPIO_ENABLE_CONFIG_TRIGGER_TYPE_NONE (0x0 << 2)
|
||||
#define TEGRA186_GPIO_ENABLE_CONFIG_TRIGGER_TYPE_LEVEL (0x1 << 2)
|
||||
#define TEGRA186_GPIO_ENABLE_CONFIG_TRIGGER_TYPE_SINGLE_EDGE (0x2 << 2)
|
||||
#define TEGRA186_GPIO_ENABLE_CONFIG_TRIGGER_TYPE_DOUBLE_EDGE (0x3 << 2)
|
||||
#define TEGRA186_GPIO_ENABLE_CONFIG_TRIGGER_TYPE_MASK (0x3 << 2)
|
||||
#define TEGRA186_GPIO_ENABLE_CONFIG_TRIGGER_LEVEL BIT(4)
|
||||
#define TEGRA186_GPIO_ENABLE_CONFIG_INTERRUPT BIT(6)
|
||||
|
||||
#define TEGRA186_GPIO_DEBOUNCE_CONTROL 0x04
|
||||
#define TEGRA186_GPIO_DEBOUNCE_CONTROL_THRESHOLD(x) ((x) & 0xff)
|
||||
|
||||
#define TEGRA186_GPIO_INPUT 0x08
|
||||
#define TEGRA186_GPIO_INPUT_HIGH BIT(0)
|
||||
|
||||
#define TEGRA186_GPIO_OUTPUT_CONTROL 0x0c
|
||||
#define TEGRA186_GPIO_OUTPUT_CONTROL_FLOATED BIT(0)
|
||||
|
||||
#define TEGRA186_GPIO_OUTPUT_VALUE 0x10
|
||||
#define TEGRA186_GPIO_OUTPUT_VALUE_HIGH BIT(0)
|
||||
|
||||
#define TEGRA186_GPIO_INTERRUPT_CLEAR 0x14
|
||||
|
||||
#define TEGRA186_GPIO_INTERRUPT_STATUS(x) (0x100 + (x) * 4)
|
||||
|
||||
struct tegra_gpio_port {
|
||||
const char *name;
|
||||
unsigned int offset;
|
||||
unsigned int pins;
|
||||
unsigned int irq;
|
||||
};
|
||||
|
||||
struct tegra_gpio_soc {
|
||||
const struct tegra_gpio_port *ports;
|
||||
unsigned int num_ports;
|
||||
const char *name;
|
||||
};
|
||||
|
||||
struct tegra_gpio {
|
||||
struct gpio_chip gpio;
|
||||
struct irq_chip intc;
|
||||
unsigned int num_irq;
|
||||
unsigned int *irq;
|
||||
|
||||
const struct tegra_gpio_soc *soc;
|
||||
|
||||
void __iomem *base;
|
||||
};
|
||||
|
||||
static const struct tegra_gpio_port *
|
||||
tegra186_gpio_get_port(struct tegra_gpio *gpio, unsigned int *pin)
|
||||
{
|
||||
unsigned int start = 0, i;
|
||||
|
||||
for (i = 0; i < gpio->soc->num_ports; i++) {
|
||||
const struct tegra_gpio_port *port = &gpio->soc->ports[i];
|
||||
|
||||
if (*pin >= start && *pin < start + port->pins) {
|
||||
*pin -= start;
|
||||
return port;
|
||||
}
|
||||
|
||||
start += port->pins;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void __iomem *tegra186_gpio_get_base(struct tegra_gpio *gpio,
|
||||
unsigned int pin)
|
||||
{
|
||||
const struct tegra_gpio_port *port;
|
||||
|
||||
port = tegra186_gpio_get_port(gpio, &pin);
|
||||
if (!port)
|
||||
return NULL;
|
||||
|
||||
return gpio->base + port->offset + pin * 0x20;
|
||||
}
|
||||
|
||||
static int tegra186_gpio_get_direction(struct gpio_chip *chip,
|
||||
unsigned int offset)
|
||||
{
|
||||
struct tegra_gpio *gpio = gpiochip_get_data(chip);
|
||||
void __iomem *base;
|
||||
u32 value;
|
||||
|
||||
base = tegra186_gpio_get_base(gpio, offset);
|
||||
if (WARN_ON(base == NULL))
|
||||
return -ENODEV;
|
||||
|
||||
value = readl(base + TEGRA186_GPIO_ENABLE_CONFIG);
|
||||
if (value & TEGRA186_GPIO_ENABLE_CONFIG_OUT)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int tegra186_gpio_direction_input(struct gpio_chip *chip,
|
||||
unsigned int offset)
|
||||
{
|
||||
struct tegra_gpio *gpio = gpiochip_get_data(chip);
|
||||
void __iomem *base;
|
||||
u32 value;
|
||||
|
||||
base = tegra186_gpio_get_base(gpio, offset);
|
||||
if (WARN_ON(base == NULL))
|
||||
return -ENODEV;
|
||||
|
||||
value = readl(base + TEGRA186_GPIO_OUTPUT_CONTROL);
|
||||
value |= TEGRA186_GPIO_OUTPUT_CONTROL_FLOATED;
|
||||
writel(value, base + TEGRA186_GPIO_OUTPUT_CONTROL);
|
||||
|
||||
value = readl(base + TEGRA186_GPIO_ENABLE_CONFIG);
|
||||
value |= TEGRA186_GPIO_ENABLE_CONFIG_ENABLE;
|
||||
value &= ~TEGRA186_GPIO_ENABLE_CONFIG_OUT;
|
||||
writel(value, base + TEGRA186_GPIO_ENABLE_CONFIG);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tegra186_gpio_direction_output(struct gpio_chip *chip,
|
||||
unsigned int offset, int level)
|
||||
{
|
||||
struct tegra_gpio *gpio = gpiochip_get_data(chip);
|
||||
void __iomem *base;
|
||||
u32 value;
|
||||
|
||||
/* configure output level first */
|
||||
chip->set(chip, offset, level);
|
||||
|
||||
base = tegra186_gpio_get_base(gpio, offset);
|
||||
if (WARN_ON(base == NULL))
|
||||
return -EINVAL;
|
||||
|
||||
/* set the direction */
|
||||
value = readl(base + TEGRA186_GPIO_OUTPUT_CONTROL);
|
||||
value &= ~TEGRA186_GPIO_OUTPUT_CONTROL_FLOATED;
|
||||
writel(value, base + TEGRA186_GPIO_OUTPUT_CONTROL);
|
||||
|
||||
value = readl(base + TEGRA186_GPIO_ENABLE_CONFIG);
|
||||
value |= TEGRA186_GPIO_ENABLE_CONFIG_ENABLE;
|
||||
value |= TEGRA186_GPIO_ENABLE_CONFIG_OUT;
|
||||
writel(value, base + TEGRA186_GPIO_ENABLE_CONFIG);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tegra186_gpio_get(struct gpio_chip *chip, unsigned int offset)
|
||||
{
|
||||
struct tegra_gpio *gpio = gpiochip_get_data(chip);
|
||||
void __iomem *base;
|
||||
u32 value;
|
||||
|
||||
base = tegra186_gpio_get_base(gpio, offset);
|
||||
if (WARN_ON(base == NULL))
|
||||
return -ENODEV;
|
||||
|
||||
value = readl(base + TEGRA186_GPIO_ENABLE_CONFIG);
|
||||
if (value & TEGRA186_GPIO_ENABLE_CONFIG_OUT)
|
||||
value = readl(base + TEGRA186_GPIO_OUTPUT_VALUE);
|
||||
else
|
||||
value = readl(base + TEGRA186_GPIO_INPUT);
|
||||
|
||||
return value & BIT(0);
|
||||
}
|
||||
|
||||
static void tegra186_gpio_set(struct gpio_chip *chip, unsigned int offset,
|
||||
int level)
|
||||
{
|
||||
struct tegra_gpio *gpio = gpiochip_get_data(chip);
|
||||
void __iomem *base;
|
||||
u32 value;
|
||||
|
||||
base = tegra186_gpio_get_base(gpio, offset);
|
||||
if (WARN_ON(base == NULL))
|
||||
return;
|
||||
|
||||
value = readl(base + TEGRA186_GPIO_OUTPUT_VALUE);
|
||||
if (level == 0)
|
||||
value &= ~TEGRA186_GPIO_OUTPUT_VALUE_HIGH;
|
||||
else
|
||||
value |= TEGRA186_GPIO_OUTPUT_VALUE_HIGH;
|
||||
|
||||
writel(value, base + TEGRA186_GPIO_OUTPUT_VALUE);
|
||||
}
|
||||
|
||||
static int tegra186_gpio_of_xlate(struct gpio_chip *chip,
|
||||
const struct of_phandle_args *spec,
|
||||
u32 *flags)
|
||||
{
|
||||
struct tegra_gpio *gpio = gpiochip_get_data(chip);
|
||||
unsigned int port, pin, i, offset = 0;
|
||||
|
||||
if (WARN_ON(chip->of_gpio_n_cells < 2))
|
||||
return -EINVAL;
|
||||
|
||||
if (WARN_ON(spec->args_count < chip->of_gpio_n_cells))
|
||||
return -EINVAL;
|
||||
|
||||
port = spec->args[0] / 8;
|
||||
pin = spec->args[0] % 8;
|
||||
|
||||
if (port >= gpio->soc->num_ports) {
|
||||
dev_err(chip->parent, "invalid port number: %u\n", port);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
for (i = 0; i < port; i++)
|
||||
offset += gpio->soc->ports[i].pins;
|
||||
|
||||
if (flags)
|
||||
*flags = spec->args[1];
|
||||
|
||||
return offset + pin;
|
||||
}
|
||||
|
||||
static void tegra186_irq_ack(struct irq_data *data)
|
||||
{
|
||||
struct tegra_gpio *gpio = irq_data_get_irq_chip_data(data);
|
||||
void __iomem *base;
|
||||
|
||||
base = tegra186_gpio_get_base(gpio, data->hwirq);
|
||||
if (WARN_ON(base == NULL))
|
||||
return;
|
||||
|
||||
writel(1, base + TEGRA186_GPIO_INTERRUPT_CLEAR);
|
||||
}
|
||||
|
||||
static void tegra186_irq_mask(struct irq_data *data)
|
||||
{
|
||||
struct tegra_gpio *gpio = irq_data_get_irq_chip_data(data);
|
||||
void __iomem *base;
|
||||
u32 value;
|
||||
|
||||
base = tegra186_gpio_get_base(gpio, data->hwirq);
|
||||
if (WARN_ON(base == NULL))
|
||||
return;
|
||||
|
||||
value = readl(base + TEGRA186_GPIO_ENABLE_CONFIG);
|
||||
value &= ~TEGRA186_GPIO_ENABLE_CONFIG_INTERRUPT;
|
||||
writel(value, base + TEGRA186_GPIO_ENABLE_CONFIG);
|
||||
}
|
||||
|
||||
static void tegra186_irq_unmask(struct irq_data *data)
|
||||
{
|
||||
struct tegra_gpio *gpio = irq_data_get_irq_chip_data(data);
|
||||
void __iomem *base;
|
||||
u32 value;
|
||||
|
||||
base = tegra186_gpio_get_base(gpio, data->hwirq);
|
||||
if (WARN_ON(base == NULL))
|
||||
return;
|
||||
|
||||
value = readl(base + TEGRA186_GPIO_ENABLE_CONFIG);
|
||||
value |= TEGRA186_GPIO_ENABLE_CONFIG_INTERRUPT;
|
||||
writel(value, base + TEGRA186_GPIO_ENABLE_CONFIG);
|
||||
}
|
||||
|
||||
static int tegra186_irq_set_type(struct irq_data *data, unsigned int flow)
|
||||
{
|
||||
struct tegra_gpio *gpio = irq_data_get_irq_chip_data(data);
|
||||
void __iomem *base;
|
||||
u32 value;
|
||||
|
||||
base = tegra186_gpio_get_base(gpio, data->hwirq);
|
||||
if (WARN_ON(base == NULL))
|
||||
return -ENODEV;
|
||||
|
||||
value = readl(base + TEGRA186_GPIO_ENABLE_CONFIG);
|
||||
value &= ~TEGRA186_GPIO_ENABLE_CONFIG_TRIGGER_TYPE_MASK;
|
||||
value &= ~TEGRA186_GPIO_ENABLE_CONFIG_TRIGGER_LEVEL;
|
||||
|
||||
switch (flow & IRQ_TYPE_SENSE_MASK) {
|
||||
case IRQ_TYPE_NONE:
|
||||
break;
|
||||
|
||||
case IRQ_TYPE_EDGE_RISING:
|
||||
value |= TEGRA186_GPIO_ENABLE_CONFIG_TRIGGER_TYPE_SINGLE_EDGE;
|
||||
value |= TEGRA186_GPIO_ENABLE_CONFIG_TRIGGER_LEVEL;
|
||||
break;
|
||||
|
||||
case IRQ_TYPE_EDGE_FALLING:
|
||||
value |= TEGRA186_GPIO_ENABLE_CONFIG_TRIGGER_TYPE_SINGLE_EDGE;
|
||||
break;
|
||||
|
||||
case IRQ_TYPE_EDGE_BOTH:
|
||||
value |= TEGRA186_GPIO_ENABLE_CONFIG_TRIGGER_TYPE_DOUBLE_EDGE;
|
||||
break;
|
||||
|
||||
case IRQ_TYPE_LEVEL_HIGH:
|
||||
value |= TEGRA186_GPIO_ENABLE_CONFIG_TRIGGER_TYPE_LEVEL;
|
||||
value |= TEGRA186_GPIO_ENABLE_CONFIG_TRIGGER_LEVEL;
|
||||
break;
|
||||
|
||||
case IRQ_TYPE_LEVEL_LOW:
|
||||
value |= TEGRA186_GPIO_ENABLE_CONFIG_TRIGGER_TYPE_LEVEL;
|
||||
break;
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
writel(value, base + TEGRA186_GPIO_ENABLE_CONFIG);
|
||||
|
||||
if ((flow & IRQ_TYPE_EDGE_BOTH) == 0)
|
||||
irq_set_handler_locked(data, handle_level_irq);
|
||||
else
|
||||
irq_set_handler_locked(data, handle_edge_irq);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void tegra186_gpio_irq(struct irq_desc *desc)
|
||||
{
|
||||
struct tegra_gpio *gpio = irq_desc_get_handler_data(desc);
|
||||
struct irq_domain *domain = gpio->gpio.irq.domain;
|
||||
struct irq_chip *chip = irq_desc_get_chip(desc);
|
||||
unsigned int parent = irq_desc_get_irq(desc);
|
||||
unsigned int i, offset = 0;
|
||||
|
||||
chained_irq_enter(chip, 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;
|
||||
|
||||
/* skip ports that are not associated with this controller */
|
||||
if (parent != gpio->irq[port->irq])
|
||||
goto skip;
|
||||
|
||||
value = readl(base + TEGRA186_GPIO_INTERRUPT_STATUS(1));
|
||||
|
||||
for_each_set_bit(pin, &value, port->pins) {
|
||||
irq = irq_find_mapping(domain, offset + pin);
|
||||
if (WARN_ON(irq == 0))
|
||||
continue;
|
||||
|
||||
generic_handle_irq(irq);
|
||||
}
|
||||
|
||||
skip:
|
||||
offset += port->pins;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
struct tegra_gpio *gpio = gpiochip_get_data(domain->host_data);
|
||||
unsigned int port, pin, i, offset = 0;
|
||||
|
||||
if (size < 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);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
for (i = 0; i < port; i++)
|
||||
offset += gpio->soc->ports[i].pins;
|
||||
|
||||
*type = spec[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 struct lock_class_key tegra186_gpio_lock_class;
|
||||
|
||||
static int tegra186_gpio_probe(struct platform_device *pdev)
|
||||
{
|
||||
unsigned int i, j, offset;
|
||||
struct gpio_irq_chip *irq;
|
||||
struct tegra_gpio *gpio;
|
||||
struct resource *res;
|
||||
char **names;
|
||||
int err;
|
||||
|
||||
gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL);
|
||||
if (!gpio)
|
||||
return -ENOMEM;
|
||||
|
||||
gpio->soc = of_device_get_match_data(&pdev->dev);
|
||||
|
||||
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "gpio");
|
||||
gpio->base = devm_ioremap_resource(&pdev->dev, res);
|
||||
if (IS_ERR(gpio->base))
|
||||
return PTR_ERR(gpio->base);
|
||||
|
||||
err = platform_irq_count(pdev);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
gpio->num_irq = err;
|
||||
|
||||
gpio->irq = devm_kcalloc(&pdev->dev, gpio->num_irq, sizeof(*gpio->irq),
|
||||
GFP_KERNEL);
|
||||
if (!gpio->irq)
|
||||
return -ENOMEM;
|
||||
|
||||
for (i = 0; i < gpio->num_irq; i++) {
|
||||
err = platform_get_irq(pdev, i);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
gpio->irq[i] = err;
|
||||
}
|
||||
|
||||
gpio->gpio.label = gpio->soc->name;
|
||||
gpio->gpio.parent = &pdev->dev;
|
||||
|
||||
gpio->gpio.get_direction = tegra186_gpio_get_direction;
|
||||
gpio->gpio.direction_input = tegra186_gpio_direction_input;
|
||||
gpio->gpio.direction_output = tegra186_gpio_direction_output;
|
||||
gpio->gpio.get = tegra186_gpio_get,
|
||||
gpio->gpio.set = tegra186_gpio_set;
|
||||
|
||||
gpio->gpio.base = -1;
|
||||
|
||||
for (i = 0; i < gpio->soc->num_ports; i++)
|
||||
gpio->gpio.ngpio += gpio->soc->ports[i].pins;
|
||||
|
||||
names = devm_kcalloc(gpio->gpio.parent, gpio->gpio.ngpio,
|
||||
sizeof(*names), GFP_KERNEL);
|
||||
if (!names)
|
||||
return -ENOMEM;
|
||||
|
||||
for (i = 0, offset = 0; i < gpio->soc->num_ports; i++) {
|
||||
const struct tegra_gpio_port *port = &gpio->soc->ports[i];
|
||||
char *name;
|
||||
|
||||
for (j = 0; j < port->pins; j++) {
|
||||
name = devm_kasprintf(gpio->gpio.parent, GFP_KERNEL,
|
||||
"P%s.%02x", port->name, j);
|
||||
if (!name)
|
||||
return -ENOMEM;
|
||||
|
||||
names[offset + j] = name;
|
||||
}
|
||||
|
||||
offset += port->pins;
|
||||
}
|
||||
|
||||
gpio->gpio.names = (const char * const *)names;
|
||||
|
||||
gpio->gpio.of_node = pdev->dev.of_node;
|
||||
gpio->gpio.of_gpio_n_cells = 2;
|
||||
gpio->gpio.of_xlate = tegra186_gpio_of_xlate;
|
||||
|
||||
gpio->intc.name = pdev->dev.of_node->name;
|
||||
gpio->intc.irq_ack = tegra186_irq_ack;
|
||||
gpio->intc.irq_mask = tegra186_irq_mask;
|
||||
gpio->intc.irq_unmask = tegra186_irq_unmask;
|
||||
gpio->intc.irq_set_type = tegra186_irq_set_type;
|
||||
|
||||
irq = &gpio->gpio.irq;
|
||||
irq->chip = &gpio->intc;
|
||||
irq->domain_ops = &tegra186_gpio_irq_domain_ops;
|
||||
irq->handler = handle_simple_irq;
|
||||
irq->lock_key = &tegra186_gpio_lock_class;
|
||||
irq->default_type = IRQ_TYPE_NONE;
|
||||
irq->parent_handler = tegra186_gpio_irq;
|
||||
irq->parent_handler_data = gpio;
|
||||
irq->num_parents = gpio->num_irq;
|
||||
irq->parents = gpio->irq;
|
||||
|
||||
irq->map = devm_kcalloc(&pdev->dev, gpio->gpio.ngpio,
|
||||
sizeof(*irq->map), GFP_KERNEL);
|
||||
if (!irq->map)
|
||||
return -ENOMEM;
|
||||
|
||||
for (i = 0, offset = 0; i < gpio->soc->num_ports; i++) {
|
||||
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];
|
||||
|
||||
offset += port->pins;
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, gpio);
|
||||
|
||||
err = devm_gpiochip_add_data(&pdev->dev, &gpio->gpio, gpio);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tegra186_gpio_remove(struct platform_device *pdev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define TEGRA_MAIN_GPIO_PORT(port, base, count, controller) \
|
||||
[TEGRA_MAIN_GPIO_PORT_##port] = { \
|
||||
.name = #port, \
|
||||
.offset = base, \
|
||||
.pins = count, \
|
||||
.irq = controller, \
|
||||
}
|
||||
|
||||
static const struct tegra_gpio_port tegra186_main_ports[] = {
|
||||
TEGRA_MAIN_GPIO_PORT( A, 0x2000, 7, 2),
|
||||
TEGRA_MAIN_GPIO_PORT( B, 0x3000, 7, 3),
|
||||
TEGRA_MAIN_GPIO_PORT( C, 0x3200, 7, 3),
|
||||
TEGRA_MAIN_GPIO_PORT( D, 0x3400, 6, 3),
|
||||
TEGRA_MAIN_GPIO_PORT( E, 0x2200, 8, 2),
|
||||
TEGRA_MAIN_GPIO_PORT( F, 0x2400, 6, 2),
|
||||
TEGRA_MAIN_GPIO_PORT( G, 0x4200, 6, 4),
|
||||
TEGRA_MAIN_GPIO_PORT( H, 0x1000, 7, 1),
|
||||
TEGRA_MAIN_GPIO_PORT( I, 0x0800, 8, 0),
|
||||
TEGRA_MAIN_GPIO_PORT( J, 0x5000, 8, 5),
|
||||
TEGRA_MAIN_GPIO_PORT( K, 0x5200, 1, 5),
|
||||
TEGRA_MAIN_GPIO_PORT( L, 0x1200, 8, 1),
|
||||
TEGRA_MAIN_GPIO_PORT( M, 0x5600, 6, 5),
|
||||
TEGRA_MAIN_GPIO_PORT( N, 0x0000, 7, 0),
|
||||
TEGRA_MAIN_GPIO_PORT( O, 0x0200, 4, 0),
|
||||
TEGRA_MAIN_GPIO_PORT( P, 0x4000, 7, 4),
|
||||
TEGRA_MAIN_GPIO_PORT( Q, 0x0400, 6, 0),
|
||||
TEGRA_MAIN_GPIO_PORT( R, 0x0a00, 6, 0),
|
||||
TEGRA_MAIN_GPIO_PORT( T, 0x0600, 4, 0),
|
||||
TEGRA_MAIN_GPIO_PORT( X, 0x1400, 8, 1),
|
||||
TEGRA_MAIN_GPIO_PORT( Y, 0x1600, 7, 1),
|
||||
TEGRA_MAIN_GPIO_PORT(BB, 0x2600, 2, 2),
|
||||
TEGRA_MAIN_GPIO_PORT(CC, 0x5400, 4, 5),
|
||||
};
|
||||
|
||||
static const struct tegra_gpio_soc tegra186_main_soc = {
|
||||
.num_ports = ARRAY_SIZE(tegra186_main_ports),
|
||||
.ports = tegra186_main_ports,
|
||||
.name = "tegra186-gpio",
|
||||
};
|
||||
|
||||
#define TEGRA_AON_GPIO_PORT(port, base, count, controller) \
|
||||
[TEGRA_AON_GPIO_PORT_##port] = { \
|
||||
.name = #port, \
|
||||
.offset = base, \
|
||||
.pins = count, \
|
||||
.irq = controller, \
|
||||
}
|
||||
|
||||
static const struct tegra_gpio_port tegra186_aon_ports[] = {
|
||||
TEGRA_AON_GPIO_PORT( S, 0x0200, 5, 0),
|
||||
TEGRA_AON_GPIO_PORT( U, 0x0400, 6, 0),
|
||||
TEGRA_AON_GPIO_PORT( V, 0x0800, 8, 0),
|
||||
TEGRA_AON_GPIO_PORT( W, 0x0a00, 8, 0),
|
||||
TEGRA_AON_GPIO_PORT( Z, 0x0e00, 4, 0),
|
||||
TEGRA_AON_GPIO_PORT(AA, 0x0c00, 8, 0),
|
||||
TEGRA_AON_GPIO_PORT(EE, 0x0600, 3, 0),
|
||||
TEGRA_AON_GPIO_PORT(FF, 0x0000, 5, 0),
|
||||
};
|
||||
|
||||
static const struct tegra_gpio_soc tegra186_aon_soc = {
|
||||
.num_ports = ARRAY_SIZE(tegra186_aon_ports),
|
||||
.ports = tegra186_aon_ports,
|
||||
.name = "tegra186-gpio-aon",
|
||||
};
|
||||
|
||||
static const struct of_device_id tegra186_gpio_of_match[] = {
|
||||
{
|
||||
.compatible = "nvidia,tegra186-gpio",
|
||||
.data = &tegra186_main_soc
|
||||
}, {
|
||||
.compatible = "nvidia,tegra186-gpio-aon",
|
||||
.data = &tegra186_aon_soc
|
||||
}, {
|
||||
/* sentinel */
|
||||
}
|
||||
};
|
||||
|
||||
static struct platform_driver tegra186_gpio_driver = {
|
||||
.driver = {
|
||||
.name = "tegra186-gpio",
|
||||
.of_match_table = tegra186_gpio_of_match,
|
||||
},
|
||||
.probe = tegra186_gpio_probe,
|
||||
.remove = tegra186_gpio_remove,
|
||||
};
|
||||
module_platform_driver(tegra186_gpio_driver);
|
||||
|
||||
MODULE_DESCRIPTION("NVIDIA Tegra186 GPIO controller driver");
|
||||
MODULE_AUTHOR("Thierry Reding <treding@nvidia.com>");
|
||||
MODULE_LICENSE("GPL v2");
|
@ -417,18 +417,6 @@ static struct irq_chip thunderx_gpio_irq_chip = {
|
||||
.flags = IRQCHIP_SET_TYPE_MASKED
|
||||
};
|
||||
|
||||
static int thunderx_gpio_irq_map(struct irq_domain *d, unsigned int irq,
|
||||
irq_hw_number_t hwirq)
|
||||
{
|
||||
struct thunderx_gpio *txgpio = d->host_data;
|
||||
|
||||
if (hwirq >= txgpio->chip.ngpio)
|
||||
return -EINVAL;
|
||||
if (!thunderx_gpio_is_gpio_nowarn(txgpio, hwirq))
|
||||
return -EPERM;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int thunderx_gpio_irq_translate(struct irq_domain *d,
|
||||
struct irq_fwspec *fwspec,
|
||||
irq_hw_number_t *hwirq,
|
||||
@ -455,7 +443,6 @@ static int thunderx_gpio_irq_alloc(struct irq_domain *d, unsigned int virq,
|
||||
}
|
||||
|
||||
static const struct irq_domain_ops thunderx_gpio_irqd_ops = {
|
||||
.map = thunderx_gpio_irq_map,
|
||||
.alloc = thunderx_gpio_irq_alloc,
|
||||
.translate = thunderx_gpio_irq_translate
|
||||
};
|
||||
|
507
drivers/gpio/gpio-uniphier.c
Normal file
507
drivers/gpio/gpio-uniphier.c
Normal file
@ -0,0 +1,507 @@
|
||||
/*
|
||||
* Copyright (C) 2017 Socionext Inc.
|
||||
* Author: Masahiro Yamada <yamada.masahiro@socionext.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/gpio/driver.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/irqdomain.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <dt-bindings/gpio/uniphier-gpio.h>
|
||||
|
||||
#define UNIPHIER_GPIO_BANK_MASK \
|
||||
GENMASK((UNIPHIER_GPIO_LINES_PER_BANK) - 1, 0)
|
||||
|
||||
#define UNIPHIER_GPIO_IRQ_MAX_NUM 24
|
||||
|
||||
#define UNIPHIER_GPIO_PORT_DATA 0x0 /* data */
|
||||
#define UNIPHIER_GPIO_PORT_DIR 0x4 /* direction (1:in, 0:out) */
|
||||
#define UNIPHIER_GPIO_IRQ_EN 0x90 /* irq enable */
|
||||
#define UNIPHIER_GPIO_IRQ_MODE 0x94 /* irq mode (1: both edge) */
|
||||
#define UNIPHIER_GPIO_IRQ_FLT_EN 0x98 /* noise filter enable */
|
||||
#define UNIPHIER_GPIO_IRQ_FLT_CYC 0x9c /* noise filter clock cycle */
|
||||
|
||||
struct uniphier_gpio_priv {
|
||||
struct gpio_chip chip;
|
||||
struct irq_chip irq_chip;
|
||||
struct irq_domain *domain;
|
||||
void __iomem *regs;
|
||||
spinlock_t lock;
|
||||
u32 saved_vals[0];
|
||||
};
|
||||
|
||||
static unsigned int uniphier_gpio_bank_to_reg(unsigned int bank)
|
||||
{
|
||||
unsigned int reg;
|
||||
|
||||
reg = (bank + 1) * 8;
|
||||
|
||||
/*
|
||||
* Unfortunately, the GPIO port registers are not contiguous because
|
||||
* offset 0x90-0x9f is used for IRQ. Add 0x10 when crossing the region.
|
||||
*/
|
||||
if (reg >= UNIPHIER_GPIO_IRQ_EN)
|
||||
reg += 0x10;
|
||||
|
||||
return reg;
|
||||
}
|
||||
|
||||
static void uniphier_gpio_get_bank_and_mask(unsigned int offset,
|
||||
unsigned int *bank, u32 *mask)
|
||||
{
|
||||
*bank = offset / UNIPHIER_GPIO_LINES_PER_BANK;
|
||||
*mask = BIT(offset % UNIPHIER_GPIO_LINES_PER_BANK);
|
||||
}
|
||||
|
||||
static void uniphier_gpio_reg_update(struct uniphier_gpio_priv *priv,
|
||||
unsigned int reg, u32 mask, u32 val)
|
||||
{
|
||||
unsigned long flags;
|
||||
u32 tmp;
|
||||
|
||||
spin_lock_irqsave(&priv->lock, flags);
|
||||
tmp = readl(priv->regs + reg);
|
||||
tmp &= ~mask;
|
||||
tmp |= mask & val;
|
||||
writel(tmp, priv->regs + reg);
|
||||
spin_unlock_irqrestore(&priv->lock, flags);
|
||||
}
|
||||
|
||||
static void uniphier_gpio_bank_write(struct gpio_chip *chip, unsigned int bank,
|
||||
unsigned int reg, u32 mask, u32 val)
|
||||
{
|
||||
struct uniphier_gpio_priv *priv = gpiochip_get_data(chip);
|
||||
|
||||
if (!mask)
|
||||
return;
|
||||
|
||||
uniphier_gpio_reg_update(priv, uniphier_gpio_bank_to_reg(bank) + reg,
|
||||
mask, val);
|
||||
}
|
||||
|
||||
static void uniphier_gpio_offset_write(struct gpio_chip *chip,
|
||||
unsigned int offset, unsigned int reg,
|
||||
int val)
|
||||
{
|
||||
unsigned int bank;
|
||||
u32 mask;
|
||||
|
||||
uniphier_gpio_get_bank_and_mask(offset, &bank, &mask);
|
||||
|
||||
uniphier_gpio_bank_write(chip, bank, reg, mask, val ? mask : 0);
|
||||
}
|
||||
|
||||
static int uniphier_gpio_offset_read(struct gpio_chip *chip,
|
||||
unsigned int offset, unsigned int reg)
|
||||
{
|
||||
struct uniphier_gpio_priv *priv = gpiochip_get_data(chip);
|
||||
unsigned int bank, reg_offset;
|
||||
u32 mask;
|
||||
|
||||
uniphier_gpio_get_bank_and_mask(offset, &bank, &mask);
|
||||
reg_offset = uniphier_gpio_bank_to_reg(bank) + reg;
|
||||
|
||||
return !!(readl(priv->regs + reg_offset) & mask);
|
||||
}
|
||||
|
||||
static int uniphier_gpio_get_direction(struct gpio_chip *chip,
|
||||
unsigned int offset)
|
||||
{
|
||||
return uniphier_gpio_offset_read(chip, offset, UNIPHIER_GPIO_PORT_DIR);
|
||||
}
|
||||
|
||||
static int uniphier_gpio_direction_input(struct gpio_chip *chip,
|
||||
unsigned int offset)
|
||||
{
|
||||
uniphier_gpio_offset_write(chip, offset, UNIPHIER_GPIO_PORT_DIR, 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int uniphier_gpio_direction_output(struct gpio_chip *chip,
|
||||
unsigned int offset, int val)
|
||||
{
|
||||
uniphier_gpio_offset_write(chip, offset, UNIPHIER_GPIO_PORT_DATA, val);
|
||||
uniphier_gpio_offset_write(chip, offset, UNIPHIER_GPIO_PORT_DIR, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int uniphier_gpio_get(struct gpio_chip *chip, unsigned int offset)
|
||||
{
|
||||
return uniphier_gpio_offset_read(chip, offset, UNIPHIER_GPIO_PORT_DATA);
|
||||
}
|
||||
|
||||
static void uniphier_gpio_set(struct gpio_chip *chip,
|
||||
unsigned int offset, int val)
|
||||
{
|
||||
uniphier_gpio_offset_write(chip, offset, UNIPHIER_GPIO_PORT_DATA, val);
|
||||
}
|
||||
|
||||
static void uniphier_gpio_set_multiple(struct gpio_chip *chip,
|
||||
unsigned long *mask, unsigned long *bits)
|
||||
{
|
||||
unsigned int bank, shift, bank_mask, bank_bits;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < chip->ngpio; i += UNIPHIER_GPIO_LINES_PER_BANK) {
|
||||
bank = i / UNIPHIER_GPIO_LINES_PER_BANK;
|
||||
shift = i % BITS_PER_LONG;
|
||||
bank_mask = (mask[BIT_WORD(i)] >> shift) &
|
||||
UNIPHIER_GPIO_BANK_MASK;
|
||||
bank_bits = bits[BIT_WORD(i)] >> shift;
|
||||
|
||||
uniphier_gpio_bank_write(chip, bank, UNIPHIER_GPIO_PORT_DATA,
|
||||
bank_mask, bank_bits);
|
||||
}
|
||||
}
|
||||
|
||||
static int uniphier_gpio_to_irq(struct gpio_chip *chip, unsigned int offset)
|
||||
{
|
||||
struct irq_fwspec fwspec;
|
||||
|
||||
if (offset < UNIPHIER_GPIO_IRQ_OFFSET)
|
||||
return -ENXIO;
|
||||
|
||||
fwspec.fwnode = of_node_to_fwnode(chip->parent->of_node);
|
||||
fwspec.param_count = 2;
|
||||
fwspec.param[0] = offset - UNIPHIER_GPIO_IRQ_OFFSET;
|
||||
fwspec.param[1] = IRQ_TYPE_NONE;
|
||||
|
||||
return irq_create_fwspec_mapping(&fwspec);
|
||||
}
|
||||
|
||||
static void uniphier_gpio_irq_mask(struct irq_data *data)
|
||||
{
|
||||
struct uniphier_gpio_priv *priv = data->chip_data;
|
||||
u32 mask = BIT(data->hwirq);
|
||||
|
||||
uniphier_gpio_reg_update(priv, UNIPHIER_GPIO_IRQ_EN, mask, 0);
|
||||
|
||||
return irq_chip_mask_parent(data);
|
||||
}
|
||||
|
||||
static void uniphier_gpio_irq_unmask(struct irq_data *data)
|
||||
{
|
||||
struct uniphier_gpio_priv *priv = data->chip_data;
|
||||
u32 mask = BIT(data->hwirq);
|
||||
|
||||
uniphier_gpio_reg_update(priv, UNIPHIER_GPIO_IRQ_EN, mask, mask);
|
||||
|
||||
return irq_chip_unmask_parent(data);
|
||||
}
|
||||
|
||||
static int uniphier_gpio_irq_set_type(struct irq_data *data, unsigned int type)
|
||||
{
|
||||
struct uniphier_gpio_priv *priv = data->chip_data;
|
||||
u32 mask = BIT(data->hwirq);
|
||||
u32 val = 0;
|
||||
|
||||
if (type == IRQ_TYPE_EDGE_BOTH) {
|
||||
val = mask;
|
||||
type = IRQ_TYPE_EDGE_FALLING;
|
||||
}
|
||||
|
||||
uniphier_gpio_reg_update(priv, UNIPHIER_GPIO_IRQ_MODE, mask, val);
|
||||
/* To enable both edge detection, the noise filter must be enabled. */
|
||||
uniphier_gpio_reg_update(priv, UNIPHIER_GPIO_IRQ_FLT_EN, mask, val);
|
||||
|
||||
return irq_chip_set_type_parent(data, type);
|
||||
}
|
||||
|
||||
static int uniphier_gpio_irq_get_parent_hwirq(struct uniphier_gpio_priv *priv,
|
||||
unsigned int hwirq)
|
||||
{
|
||||
struct device_node *np = priv->chip.parent->of_node;
|
||||
const __be32 *range;
|
||||
u32 base, parent_base, size;
|
||||
int len;
|
||||
|
||||
range = of_get_property(np, "socionext,interrupt-ranges", &len);
|
||||
if (!range)
|
||||
return -EINVAL;
|
||||
|
||||
len /= sizeof(*range);
|
||||
|
||||
for (; len >= 3; len -= 3) {
|
||||
base = be32_to_cpu(*range++);
|
||||
parent_base = be32_to_cpu(*range++);
|
||||
size = be32_to_cpu(*range++);
|
||||
|
||||
if (base <= hwirq && hwirq < base + size)
|
||||
return hwirq - base + parent_base;
|
||||
}
|
||||
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
static int uniphier_gpio_irq_domain_translate(struct irq_domain *domain,
|
||||
struct irq_fwspec *fwspec,
|
||||
unsigned long *out_hwirq,
|
||||
unsigned int *out_type)
|
||||
{
|
||||
if (WARN_ON(fwspec->param_count < 2))
|
||||
return -EINVAL;
|
||||
|
||||
*out_hwirq = fwspec->param[0];
|
||||
*out_type = fwspec->param[1] & IRQ_TYPE_SENSE_MASK;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int uniphier_gpio_irq_domain_alloc(struct irq_domain *domain,
|
||||
unsigned int virq,
|
||||
unsigned int nr_irqs, void *arg)
|
||||
{
|
||||
struct uniphier_gpio_priv *priv = domain->host_data;
|
||||
struct irq_fwspec parent_fwspec;
|
||||
irq_hw_number_t hwirq;
|
||||
unsigned int type;
|
||||
int ret;
|
||||
|
||||
if (WARN_ON(nr_irqs != 1))
|
||||
return -EINVAL;
|
||||
|
||||
ret = uniphier_gpio_irq_domain_translate(domain, arg, &hwirq, &type);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = uniphier_gpio_irq_get_parent_hwirq(priv, hwirq);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* parent is UniPhier AIDET */
|
||||
parent_fwspec.fwnode = domain->parent->fwnode;
|
||||
parent_fwspec.param_count = 2;
|
||||
parent_fwspec.param[0] = ret;
|
||||
parent_fwspec.param[1] = (type == IRQ_TYPE_EDGE_BOTH) ?
|
||||
IRQ_TYPE_EDGE_FALLING : type;
|
||||
|
||||
ret = irq_domain_set_hwirq_and_chip(domain, virq, hwirq,
|
||||
&priv->irq_chip, priv);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return irq_domain_alloc_irqs_parent(domain, virq, 1, &parent_fwspec);
|
||||
}
|
||||
|
||||
static void uniphier_gpio_irq_domain_activate(struct irq_domain *domain,
|
||||
struct irq_data *data)
|
||||
{
|
||||
struct uniphier_gpio_priv *priv = domain->host_data;
|
||||
struct gpio_chip *chip = &priv->chip;
|
||||
|
||||
gpiochip_lock_as_irq(chip, data->hwirq + UNIPHIER_GPIO_IRQ_OFFSET);
|
||||
}
|
||||
|
||||
static void uniphier_gpio_irq_domain_deactivate(struct irq_domain *domain,
|
||||
struct irq_data *data)
|
||||
{
|
||||
struct uniphier_gpio_priv *priv = domain->host_data;
|
||||
struct gpio_chip *chip = &priv->chip;
|
||||
|
||||
gpiochip_unlock_as_irq(chip, data->hwirq + UNIPHIER_GPIO_IRQ_OFFSET);
|
||||
}
|
||||
|
||||
static const struct irq_domain_ops uniphier_gpio_irq_domain_ops = {
|
||||
.alloc = uniphier_gpio_irq_domain_alloc,
|
||||
.free = irq_domain_free_irqs_common,
|
||||
.activate = uniphier_gpio_irq_domain_activate,
|
||||
.deactivate = uniphier_gpio_irq_domain_deactivate,
|
||||
.translate = uniphier_gpio_irq_domain_translate,
|
||||
};
|
||||
|
||||
static void uniphier_gpio_hw_init(struct uniphier_gpio_priv *priv)
|
||||
{
|
||||
/*
|
||||
* Due to the hardware design, the noise filter must be enabled to
|
||||
* detect both edge interrupts. This filter is intended to remove the
|
||||
* noise from the irq lines. It does not work for GPIO input, so GPIO
|
||||
* debounce is not supported. Unfortunately, the filter period is
|
||||
* shared among all irq lines. Just choose a sensible period here.
|
||||
*/
|
||||
writel(0xff, priv->regs + UNIPHIER_GPIO_IRQ_FLT_CYC);
|
||||
}
|
||||
|
||||
static unsigned int uniphier_gpio_get_nbanks(unsigned int ngpio)
|
||||
{
|
||||
return DIV_ROUND_UP(ngpio, UNIPHIER_GPIO_LINES_PER_BANK);
|
||||
}
|
||||
|
||||
static int uniphier_gpio_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct device_node *parent_np;
|
||||
struct irq_domain *parent_domain;
|
||||
struct uniphier_gpio_priv *priv;
|
||||
struct gpio_chip *chip;
|
||||
struct irq_chip *irq_chip;
|
||||
struct resource *regs;
|
||||
unsigned int nregs;
|
||||
u32 ngpios;
|
||||
int ret;
|
||||
|
||||
parent_np = of_irq_find_parent(dev->of_node);
|
||||
if (!parent_np)
|
||||
return -ENXIO;
|
||||
|
||||
parent_domain = irq_find_host(parent_np);
|
||||
of_node_put(parent_np);
|
||||
if (!parent_domain)
|
||||
return -EPROBE_DEFER;
|
||||
|
||||
ret = of_property_read_u32(dev->of_node, "ngpios", &ngpios);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
nregs = uniphier_gpio_get_nbanks(ngpios) * 2 + 3;
|
||||
priv = devm_kzalloc(dev,
|
||||
sizeof(*priv) + sizeof(priv->saved_vals[0]) * nregs,
|
||||
GFP_KERNEL);
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
|
||||
regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
priv->regs = devm_ioremap_resource(dev, regs);
|
||||
if (IS_ERR(priv->regs))
|
||||
return PTR_ERR(priv->regs);
|
||||
|
||||
spin_lock_init(&priv->lock);
|
||||
|
||||
chip = &priv->chip;
|
||||
chip->label = dev_name(dev);
|
||||
chip->parent = dev;
|
||||
chip->request = gpiochip_generic_request;
|
||||
chip->free = gpiochip_generic_free;
|
||||
chip->get_direction = uniphier_gpio_get_direction;
|
||||
chip->direction_input = uniphier_gpio_direction_input;
|
||||
chip->direction_output = uniphier_gpio_direction_output;
|
||||
chip->get = uniphier_gpio_get;
|
||||
chip->set = uniphier_gpio_set;
|
||||
chip->set_multiple = uniphier_gpio_set_multiple;
|
||||
chip->to_irq = uniphier_gpio_to_irq;
|
||||
chip->base = -1;
|
||||
chip->ngpio = ngpios;
|
||||
|
||||
irq_chip = &priv->irq_chip;
|
||||
irq_chip->name = dev_name(dev);
|
||||
irq_chip->irq_mask = uniphier_gpio_irq_mask;
|
||||
irq_chip->irq_unmask = uniphier_gpio_irq_unmask;
|
||||
irq_chip->irq_eoi = irq_chip_eoi_parent;
|
||||
irq_chip->irq_set_affinity = irq_chip_set_affinity_parent;
|
||||
irq_chip->irq_set_type = uniphier_gpio_irq_set_type;
|
||||
|
||||
uniphier_gpio_hw_init(priv);
|
||||
|
||||
ret = devm_gpiochip_add_data(dev, chip, priv);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
priv->domain = irq_domain_create_hierarchy(
|
||||
parent_domain, 0,
|
||||
UNIPHIER_GPIO_IRQ_MAX_NUM,
|
||||
of_node_to_fwnode(dev->of_node),
|
||||
&uniphier_gpio_irq_domain_ops, priv);
|
||||
if (!priv->domain)
|
||||
return -ENOMEM;
|
||||
|
||||
platform_set_drvdata(pdev, priv);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int uniphier_gpio_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct uniphier_gpio_priv *priv = platform_get_drvdata(pdev);
|
||||
|
||||
irq_domain_remove(priv->domain);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __maybe_unused uniphier_gpio_suspend(struct device *dev)
|
||||
{
|
||||
struct uniphier_gpio_priv *priv = dev_get_drvdata(dev);
|
||||
unsigned int nbanks = uniphier_gpio_get_nbanks(priv->chip.ngpio);
|
||||
u32 *val = priv->saved_vals;
|
||||
unsigned int reg;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < nbanks; i++) {
|
||||
reg = uniphier_gpio_bank_to_reg(i);
|
||||
|
||||
*val++ = readl(priv->regs + reg + UNIPHIER_GPIO_PORT_DATA);
|
||||
*val++ = readl(priv->regs + reg + UNIPHIER_GPIO_PORT_DIR);
|
||||
}
|
||||
|
||||
*val++ = readl(priv->regs + UNIPHIER_GPIO_IRQ_EN);
|
||||
*val++ = readl(priv->regs + UNIPHIER_GPIO_IRQ_MODE);
|
||||
*val++ = readl(priv->regs + UNIPHIER_GPIO_IRQ_FLT_EN);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __maybe_unused uniphier_gpio_resume(struct device *dev)
|
||||
{
|
||||
struct uniphier_gpio_priv *priv = dev_get_drvdata(dev);
|
||||
unsigned int nbanks = uniphier_gpio_get_nbanks(priv->chip.ngpio);
|
||||
const u32 *val = priv->saved_vals;
|
||||
unsigned int reg;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < nbanks; i++) {
|
||||
reg = uniphier_gpio_bank_to_reg(i);
|
||||
|
||||
writel(*val++, priv->regs + reg + UNIPHIER_GPIO_PORT_DATA);
|
||||
writel(*val++, priv->regs + reg + UNIPHIER_GPIO_PORT_DIR);
|
||||
}
|
||||
|
||||
writel(*val++, priv->regs + UNIPHIER_GPIO_IRQ_EN);
|
||||
writel(*val++, priv->regs + UNIPHIER_GPIO_IRQ_MODE);
|
||||
writel(*val++, priv->regs + UNIPHIER_GPIO_IRQ_FLT_EN);
|
||||
|
||||
uniphier_gpio_hw_init(priv);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dev_pm_ops uniphier_gpio_pm_ops = {
|
||||
SET_LATE_SYSTEM_SLEEP_PM_OPS(uniphier_gpio_suspend,
|
||||
uniphier_gpio_resume)
|
||||
};
|
||||
|
||||
static const struct of_device_id uniphier_gpio_match[] = {
|
||||
{ .compatible = "socionext,uniphier-gpio" },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, uniphier_gpio_match);
|
||||
|
||||
static struct platform_driver uniphier_gpio_driver = {
|
||||
.probe = uniphier_gpio_probe,
|
||||
.remove = uniphier_gpio_remove,
|
||||
.driver = {
|
||||
.name = "uniphier-gpio",
|
||||
.of_match_table = uniphier_gpio_match,
|
||||
.pm = &uniphier_gpio_pm_ops,
|
||||
},
|
||||
};
|
||||
module_platform_driver(uniphier_gpio_driver);
|
||||
|
||||
MODULE_AUTHOR("Masahiro Yamada <yamada.masahiro@socionext.com>");
|
||||
MODULE_DESCRIPTION("UniPhier GPIO driver");
|
||||
MODULE_LICENSE("GPL");
|
@ -160,7 +160,7 @@ static void vf610_gpio_irq_handler(struct irq_desc *desc)
|
||||
for_each_set_bit(pin, &irq_isfr, VF610_GPIO_PER_PORT) {
|
||||
vf610_gpio_writel(BIT(pin), port->base + PORT_ISFR);
|
||||
|
||||
generic_handle_irq(irq_find_mapping(port->gc.irqdomain, pin));
|
||||
generic_handle_irq(irq_find_mapping(port->gc.irq.domain, pin));
|
||||
}
|
||||
|
||||
chained_irq_exit(chip, desc);
|
||||
|
@ -350,7 +350,7 @@ static irqreturn_t wcove_gpio_irq_handler(int irq, void *data)
|
||||
offset = (gpio > GROUP0_NR_IRQS) ? 1 : 0;
|
||||
mask = (offset == 1) ? BIT(gpio - GROUP0_NR_IRQS) :
|
||||
BIT(gpio);
|
||||
virq = irq_find_mapping(wg->chip.irqdomain, gpio);
|
||||
virq = irq_find_mapping(wg->chip.irq.domain, gpio);
|
||||
handle_nested_irq(virq);
|
||||
regmap_update_bits(wg->regmap, IRQ_STATUS_BASE + offset,
|
||||
mask, mask);
|
||||
|
@ -332,7 +332,7 @@ static irqreturn_t ws16c48_irq_handler(int irq, void *dev_id)
|
||||
int_id = inb(ws16c48gpio->base + 8 + port);
|
||||
for_each_set_bit(gpio, &int_id, 8)
|
||||
generic_handle_irq(irq_find_mapping(
|
||||
chip->irqdomain, gpio + 8*port));
|
||||
chip->irq.domain, gpio + 8*port));
|
||||
}
|
||||
|
||||
int_pending = inb(ws16c48gpio->base + 6) & 0x7;
|
||||
|
@ -130,10 +130,7 @@ static int xgene_gpio_sb_to_irq(struct gpio_chip *gc, u32 gpio)
|
||||
(gpio > HWIRQ_TO_GPIO(priv, priv->nirq)))
|
||||
return -ENXIO;
|
||||
|
||||
if (gc->parent->of_node)
|
||||
fwspec.fwnode = of_node_to_fwnode(gc->parent->of_node);
|
||||
else
|
||||
fwspec.fwnode = gc->parent->fwnode;
|
||||
fwspec.fwnode = gc->parent->fwnode;
|
||||
fwspec.param_count = 2;
|
||||
fwspec.param[0] = GPIO_TO_HWIRQ(priv, gpio);
|
||||
fwspec.param[1] = IRQ_TYPE_NONE;
|
||||
@ -231,7 +228,6 @@ static int xgene_gpio_sb_probe(struct platform_device *pdev)
|
||||
struct resource *res;
|
||||
void __iomem *regs;
|
||||
struct irq_domain *parent_domain = NULL;
|
||||
struct fwnode_handle *fwnode;
|
||||
u32 val32;
|
||||
|
||||
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
|
||||
@ -285,18 +281,13 @@ static int xgene_gpio_sb_probe(struct platform_device *pdev)
|
||||
|
||||
platform_set_drvdata(pdev, priv);
|
||||
|
||||
if (pdev->dev.of_node)
|
||||
fwnode = of_node_to_fwnode(pdev->dev.of_node);
|
||||
else
|
||||
fwnode = pdev->dev.fwnode;
|
||||
|
||||
priv->irq_domain = irq_domain_create_hierarchy(parent_domain,
|
||||
0, priv->nirq, fwnode,
|
||||
0, priv->nirq, pdev->dev.fwnode,
|
||||
&xgene_gpio_sb_domain_ops, priv);
|
||||
if (!priv->irq_domain)
|
||||
return -ENODEV;
|
||||
|
||||
priv->gc.irqdomain = priv->irq_domain;
|
||||
priv->gc.irq.domain = priv->irq_domain;
|
||||
|
||||
ret = devm_gpiochip_add_data(&pdev->dev, &priv->gc, priv);
|
||||
if (ret) {
|
||||
|
@ -225,7 +225,7 @@ static void xlp_gpio_generic_handler(struct irq_desc *desc)
|
||||
|
||||
if (gpio_stat & BIT(gpio % XLP_GPIO_REGSZ))
|
||||
generic_handle_irq(irq_find_mapping(
|
||||
priv->chip.irqdomain, gpio));
|
||||
priv->chip.irq.domain, gpio));
|
||||
}
|
||||
chained_irq_exit(irqchip, desc);
|
||||
}
|
||||
|
@ -170,7 +170,7 @@ static void zx_irq_handler(struct irq_desc *desc)
|
||||
writew_relaxed(pending, chip->base + ZX_GPIO_IC);
|
||||
if (pending) {
|
||||
for_each_set_bit(offset, &pending, ZX_GPIO_NR)
|
||||
generic_handle_irq(irq_find_mapping(gc->irqdomain,
|
||||
generic_handle_irq(irq_find_mapping(gc->irq.domain,
|
||||
offset));
|
||||
}
|
||||
|
||||
|
@ -562,7 +562,7 @@ static void zynq_gpio_handle_bank_irq(struct zynq_gpio *gpio,
|
||||
unsigned long pending)
|
||||
{
|
||||
unsigned int bank_offset = gpio->p_data->bank_min[bank_num];
|
||||
struct irq_domain *irqdomain = gpio->chip.irqdomain;
|
||||
struct irq_domain *irqdomain = gpio->chip.irq.domain;
|
||||
int offset;
|
||||
|
||||
if (!pending)
|
||||
|
@ -153,8 +153,8 @@ struct gpio_desc *of_find_gpio(struct device *dev, const char *con_id,
|
||||
*flags |= GPIO_OPEN_SOURCE;
|
||||
}
|
||||
|
||||
if (of_flags & OF_GPIO_SLEEP_MAY_LOOSE_VALUE)
|
||||
*flags |= GPIO_SLEEP_MAY_LOOSE_VALUE;
|
||||
if (of_flags & OF_GPIO_SLEEP_MAY_LOSE_VALUE)
|
||||
*flags |= GPIO_SLEEP_MAY_LOSE_VALUE;
|
||||
|
||||
return desc;
|
||||
}
|
||||
|
@ -72,6 +72,8 @@ static LIST_HEAD(gpio_lookup_list);
|
||||
LIST_HEAD(gpio_devices);
|
||||
|
||||
static void gpiochip_free_hogs(struct gpio_chip *chip);
|
||||
static int gpiochip_add_irqchip(struct gpio_chip *gpiochip,
|
||||
struct lock_class_key *key);
|
||||
static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip);
|
||||
static int gpiochip_irqchip_init_valid_mask(struct gpio_chip *gpiochip);
|
||||
static void gpiochip_irqchip_free_valid_mask(struct gpio_chip *gpiochip);
|
||||
@ -365,28 +367,28 @@ static long linehandle_ioctl(struct file *filep, unsigned int cmd,
|
||||
struct linehandle_state *lh = filep->private_data;
|
||||
void __user *ip = (void __user *)arg;
|
||||
struct gpiohandle_data ghd;
|
||||
int vals[GPIOHANDLES_MAX];
|
||||
int i;
|
||||
|
||||
if (cmd == GPIOHANDLE_GET_LINE_VALUES_IOCTL) {
|
||||
int val;
|
||||
/* TODO: check if descriptors are really input */
|
||||
int ret = gpiod_get_array_value_complex(false,
|
||||
true,
|
||||
lh->numdescs,
|
||||
lh->descs,
|
||||
vals);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
memset(&ghd, 0, sizeof(ghd));
|
||||
|
||||
/* TODO: check if descriptors are really input */
|
||||
for (i = 0; i < lh->numdescs; i++) {
|
||||
val = gpiod_get_value_cansleep(lh->descs[i]);
|
||||
if (val < 0)
|
||||
return val;
|
||||
ghd.values[i] = val;
|
||||
}
|
||||
for (i = 0; i < lh->numdescs; i++)
|
||||
ghd.values[i] = vals[i];
|
||||
|
||||
if (copy_to_user(ip, &ghd, sizeof(ghd)))
|
||||
return -EFAULT;
|
||||
|
||||
return 0;
|
||||
} else if (cmd == GPIOHANDLE_SET_LINE_VALUES_IOCTL) {
|
||||
int vals[GPIOHANDLES_MAX];
|
||||
|
||||
/* TODO: check if descriptors are really output */
|
||||
if (copy_from_user(&ghd, ip, sizeof(ghd)))
|
||||
return -EFAULT;
|
||||
@ -444,12 +446,25 @@ static int linehandle_create(struct gpio_device *gdev, void __user *ip)
|
||||
struct linehandle_state *lh;
|
||||
struct file *file;
|
||||
int fd, i, ret;
|
||||
u32 lflags;
|
||||
|
||||
if (copy_from_user(&handlereq, ip, sizeof(handlereq)))
|
||||
return -EFAULT;
|
||||
if ((handlereq.lines == 0) || (handlereq.lines > GPIOHANDLES_MAX))
|
||||
return -EINVAL;
|
||||
|
||||
lflags = handlereq.flags;
|
||||
|
||||
/* Return an error if an unknown flag is set */
|
||||
if (lflags & ~GPIOHANDLE_REQUEST_VALID_FLAGS)
|
||||
return -EINVAL;
|
||||
|
||||
/* OPEN_DRAIN and OPEN_SOURCE flags only make sense for output mode. */
|
||||
if (!(lflags & GPIOHANDLE_REQUEST_OUTPUT) &&
|
||||
((lflags & GPIOHANDLE_REQUEST_OPEN_DRAIN) ||
|
||||
(lflags & GPIOHANDLE_REQUEST_OPEN_SOURCE)))
|
||||
return -EINVAL;
|
||||
|
||||
lh = kzalloc(sizeof(*lh), GFP_KERNEL);
|
||||
if (!lh)
|
||||
return -ENOMEM;
|
||||
@ -470,7 +485,6 @@ static int linehandle_create(struct gpio_device *gdev, void __user *ip)
|
||||
/* Request each GPIO */
|
||||
for (i = 0; i < handlereq.lines; i++) {
|
||||
u32 offset = handlereq.lineoffsets[i];
|
||||
u32 lflags = handlereq.flags;
|
||||
struct gpio_desc *desc;
|
||||
|
||||
if (offset >= gdev->ngpio) {
|
||||
@ -478,12 +492,6 @@ static int linehandle_create(struct gpio_device *gdev, void __user *ip)
|
||||
goto out_free_descs;
|
||||
}
|
||||
|
||||
/* Return an error if a unknown flag is set */
|
||||
if (lflags & ~GPIOHANDLE_REQUEST_VALID_FLAGS) {
|
||||
ret = -EINVAL;
|
||||
goto out_free_descs;
|
||||
}
|
||||
|
||||
desc = &gdev->descs[offset];
|
||||
ret = gpiod_request(desc, lh->label);
|
||||
if (ret)
|
||||
@ -1091,30 +1099,8 @@ static void gpiochip_setup_devs(void)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* gpiochip_add_data() - register a gpio_chip
|
||||
* @chip: the chip to register, with chip->base initialized
|
||||
* @data: driver-private data associated with this chip
|
||||
*
|
||||
* Context: potentially before irqs will work
|
||||
*
|
||||
* When gpiochip_add_data() is called very early during boot, so that GPIOs
|
||||
* can be freely used, the chip->parent device must be registered before
|
||||
* the gpio framework's arch_initcall(). Otherwise sysfs initialization
|
||||
* for GPIOs will fail rudely.
|
||||
*
|
||||
* gpiochip_add_data() must only be called after gpiolib initialization,
|
||||
* ie after core_initcall().
|
||||
*
|
||||
* If chip->base is negative, this requests dynamic assignment of
|
||||
* a range of valid GPIOs.
|
||||
*
|
||||
* Returns:
|
||||
* A negative errno if the chip can't be registered, such as because the
|
||||
* chip->base is invalid or already associated with a different chip.
|
||||
* Otherwise it returns zero as a success code.
|
||||
*/
|
||||
int gpiochip_add_data(struct gpio_chip *chip, void *data)
|
||||
int gpiochip_add_data_with_key(struct gpio_chip *chip, void *data,
|
||||
struct lock_class_key *key)
|
||||
{
|
||||
unsigned long flags;
|
||||
int status = 0;
|
||||
@ -1260,6 +1246,10 @@ int gpiochip_add_data(struct gpio_chip *chip, void *data)
|
||||
if (status)
|
||||
goto err_remove_from_list;
|
||||
|
||||
status = gpiochip_add_irqchip(chip, key);
|
||||
if (status)
|
||||
goto err_remove_chip;
|
||||
|
||||
status = of_gpiochip_add(chip);
|
||||
if (status)
|
||||
goto err_remove_chip;
|
||||
@ -1303,7 +1293,7 @@ err_free_gdev:
|
||||
kfree(gdev);
|
||||
return status;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(gpiochip_add_data);
|
||||
EXPORT_SYMBOL_GPL(gpiochip_add_data_with_key);
|
||||
|
||||
/**
|
||||
* gpiochip_get_data() - get per-subdriver data for the chip
|
||||
@ -1498,33 +1488,33 @@ static struct gpio_chip *find_chip_by_name(const char *name)
|
||||
|
||||
static int gpiochip_irqchip_init_valid_mask(struct gpio_chip *gpiochip)
|
||||
{
|
||||
if (!gpiochip->irq_need_valid_mask)
|
||||
if (!gpiochip->irq.need_valid_mask)
|
||||
return 0;
|
||||
|
||||
gpiochip->irq_valid_mask = kcalloc(BITS_TO_LONGS(gpiochip->ngpio),
|
||||
gpiochip->irq.valid_mask = kcalloc(BITS_TO_LONGS(gpiochip->ngpio),
|
||||
sizeof(long), GFP_KERNEL);
|
||||
if (!gpiochip->irq_valid_mask)
|
||||
if (!gpiochip->irq.valid_mask)
|
||||
return -ENOMEM;
|
||||
|
||||
/* Assume by default all GPIOs are valid */
|
||||
bitmap_fill(gpiochip->irq_valid_mask, gpiochip->ngpio);
|
||||
bitmap_fill(gpiochip->irq.valid_mask, gpiochip->ngpio);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void gpiochip_irqchip_free_valid_mask(struct gpio_chip *gpiochip)
|
||||
{
|
||||
kfree(gpiochip->irq_valid_mask);
|
||||
gpiochip->irq_valid_mask = NULL;
|
||||
kfree(gpiochip->irq.valid_mask);
|
||||
gpiochip->irq.valid_mask = NULL;
|
||||
}
|
||||
|
||||
static bool gpiochip_irqchip_irq_valid(const struct gpio_chip *gpiochip,
|
||||
unsigned int offset)
|
||||
{
|
||||
/* No mask means all valid */
|
||||
if (likely(!gpiochip->irq_valid_mask))
|
||||
if (likely(!gpiochip->irq.valid_mask))
|
||||
return true;
|
||||
return test_bit(offset, gpiochip->irq_valid_mask);
|
||||
return test_bit(offset, gpiochip->irq.valid_mask);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1544,7 +1534,7 @@ static void gpiochip_set_cascaded_irqchip(struct gpio_chip *gpiochip,
|
||||
{
|
||||
unsigned int offset;
|
||||
|
||||
if (!gpiochip->irqdomain) {
|
||||
if (!gpiochip->irq.domain) {
|
||||
chip_err(gpiochip, "called %s before setting up irqchip\n",
|
||||
__func__);
|
||||
return;
|
||||
@ -1564,14 +1554,15 @@ static void gpiochip_set_cascaded_irqchip(struct gpio_chip *gpiochip,
|
||||
irq_set_chained_handler_and_data(parent_irq, parent_handler,
|
||||
gpiochip);
|
||||
|
||||
gpiochip->irq_chained_parent = parent_irq;
|
||||
gpiochip->irq.parents = &parent_irq;
|
||||
gpiochip->irq.num_parents = 1;
|
||||
}
|
||||
|
||||
/* Set the parent IRQ for all affected IRQs */
|
||||
for (offset = 0; offset < gpiochip->ngpio; offset++) {
|
||||
if (!gpiochip_irqchip_irq_valid(gpiochip, offset))
|
||||
continue;
|
||||
irq_set_parent(irq_find_mapping(gpiochip->irqdomain, offset),
|
||||
irq_set_parent(irq_find_mapping(gpiochip->irq.domain, offset),
|
||||
parent_irq);
|
||||
}
|
||||
}
|
||||
@ -1591,6 +1582,11 @@ void gpiochip_set_chained_irqchip(struct gpio_chip *gpiochip,
|
||||
unsigned int parent_irq,
|
||||
irq_flow_handler_t parent_handler)
|
||||
{
|
||||
if (gpiochip->irq.threaded) {
|
||||
chip_err(gpiochip, "tried to chain a threaded gpiochip\n");
|
||||
return;
|
||||
}
|
||||
|
||||
gpiochip_set_cascaded_irqchip(gpiochip, irqchip, parent_irq,
|
||||
parent_handler);
|
||||
}
|
||||
@ -1607,10 +1603,6 @@ void gpiochip_set_nested_irqchip(struct gpio_chip *gpiochip,
|
||||
struct irq_chip *irqchip,
|
||||
unsigned int parent_irq)
|
||||
{
|
||||
if (!gpiochip->irq_nested) {
|
||||
chip_err(gpiochip, "tried to nest a chained gpiochip\n");
|
||||
return;
|
||||
}
|
||||
gpiochip_set_cascaded_irqchip(gpiochip, irqchip, parent_irq,
|
||||
NULL);
|
||||
}
|
||||
@ -1626,10 +1618,11 @@ EXPORT_SYMBOL_GPL(gpiochip_set_nested_irqchip);
|
||||
* gpiochip by assigning the gpiochip as chip data, and using the irqchip
|
||||
* stored inside the gpiochip.
|
||||
*/
|
||||
static int gpiochip_irq_map(struct irq_domain *d, unsigned int irq,
|
||||
irq_hw_number_t hwirq)
|
||||
int gpiochip_irq_map(struct irq_domain *d, unsigned int irq,
|
||||
irq_hw_number_t hwirq)
|
||||
{
|
||||
struct gpio_chip *chip = d->host_data;
|
||||
int err = 0;
|
||||
|
||||
if (!gpiochip_irqchip_irq_valid(chip, hwirq))
|
||||
return -ENXIO;
|
||||
@ -1639,32 +1632,42 @@ static int gpiochip_irq_map(struct irq_domain *d, unsigned int irq,
|
||||
* This lock class tells lockdep that GPIO irqs are in a different
|
||||
* category than their parents, so it won't report false recursion.
|
||||
*/
|
||||
irq_set_lockdep_class(irq, chip->lock_key);
|
||||
irq_set_chip_and_handler(irq, chip->irqchip, chip->irq_handler);
|
||||
irq_set_lockdep_class(irq, chip->irq.lock_key);
|
||||
irq_set_chip_and_handler(irq, chip->irq.chip, chip->irq.handler);
|
||||
/* Chips that use nested thread handlers have them marked */
|
||||
if (chip->irq_nested)
|
||||
if (chip->irq.threaded)
|
||||
irq_set_nested_thread(irq, 1);
|
||||
irq_set_noprobe(irq);
|
||||
|
||||
if (chip->irq.num_parents == 1)
|
||||
err = irq_set_parent(irq, chip->irq.parents[0]);
|
||||
else if (chip->irq.map)
|
||||
err = irq_set_parent(irq, chip->irq.map[hwirq]);
|
||||
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
/*
|
||||
* No set-up of the hardware will happen if IRQ_TYPE_NONE
|
||||
* is passed as default type.
|
||||
*/
|
||||
if (chip->irq_default_type != IRQ_TYPE_NONE)
|
||||
irq_set_irq_type(irq, chip->irq_default_type);
|
||||
if (chip->irq.default_type != IRQ_TYPE_NONE)
|
||||
irq_set_irq_type(irq, chip->irq.default_type);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(gpiochip_irq_map);
|
||||
|
||||
static void gpiochip_irq_unmap(struct irq_domain *d, unsigned int irq)
|
||||
void gpiochip_irq_unmap(struct irq_domain *d, unsigned int irq)
|
||||
{
|
||||
struct gpio_chip *chip = d->host_data;
|
||||
|
||||
if (chip->irq_nested)
|
||||
if (chip->irq.threaded)
|
||||
irq_set_nested_thread(irq, 0);
|
||||
irq_set_chip_and_handler(irq, NULL, NULL);
|
||||
irq_set_chip_data(irq, NULL);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(gpiochip_irq_unmap);
|
||||
|
||||
static const struct irq_domain_ops gpiochip_domain_ops = {
|
||||
.map = gpiochip_irq_map,
|
||||
@ -1702,7 +1705,94 @@ static int gpiochip_to_irq(struct gpio_chip *chip, unsigned offset)
|
||||
{
|
||||
if (!gpiochip_irqchip_irq_valid(chip, offset))
|
||||
return -ENXIO;
|
||||
return irq_create_mapping(chip->irqdomain, offset);
|
||||
|
||||
return irq_create_mapping(chip->irq.domain, offset);
|
||||
}
|
||||
|
||||
/**
|
||||
* gpiochip_add_irqchip() - adds an IRQ chip to a GPIO chip
|
||||
* @gpiochip: the GPIO chip to add the IRQ chip to
|
||||
* @lock_key: lockdep class
|
||||
*/
|
||||
static int gpiochip_add_irqchip(struct gpio_chip *gpiochip,
|
||||
struct lock_class_key *lock_key)
|
||||
{
|
||||
struct irq_chip *irqchip = gpiochip->irq.chip;
|
||||
const struct irq_domain_ops *ops;
|
||||
struct device_node *np;
|
||||
unsigned int type;
|
||||
unsigned int i;
|
||||
|
||||
if (!irqchip)
|
||||
return 0;
|
||||
|
||||
if (gpiochip->irq.parent_handler && gpiochip->can_sleep) {
|
||||
chip_err(gpiochip, "you cannot have chained interrupts on a "
|
||||
"chip that may sleep\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
np = gpiochip->gpiodev->dev.of_node;
|
||||
type = gpiochip->irq.default_type;
|
||||
|
||||
/*
|
||||
* Specifying a default trigger is a terrible idea if DT or ACPI is
|
||||
* used to configure the interrupts, as you may end up with
|
||||
* conflicting triggers. Tell the user, and reset to NONE.
|
||||
*/
|
||||
if (WARN(np && type != IRQ_TYPE_NONE,
|
||||
"%s: Ignoring %u default trigger\n", np->full_name, type))
|
||||
type = IRQ_TYPE_NONE;
|
||||
|
||||
if (has_acpi_companion(gpiochip->parent) && type != IRQ_TYPE_NONE) {
|
||||
acpi_handle_warn(ACPI_HANDLE(gpiochip->parent),
|
||||
"Ignoring %u default trigger\n", type);
|
||||
type = IRQ_TYPE_NONE;
|
||||
}
|
||||
|
||||
gpiochip->to_irq = gpiochip_to_irq;
|
||||
gpiochip->irq.default_type = type;
|
||||
gpiochip->irq.lock_key = lock_key;
|
||||
|
||||
if (gpiochip->irq.domain_ops)
|
||||
ops = gpiochip->irq.domain_ops;
|
||||
else
|
||||
ops = &gpiochip_domain_ops;
|
||||
|
||||
gpiochip->irq.domain = irq_domain_add_simple(np, gpiochip->ngpio,
|
||||
gpiochip->irq.first,
|
||||
ops, gpiochip);
|
||||
if (!gpiochip->irq.domain)
|
||||
return -EINVAL;
|
||||
|
||||
/*
|
||||
* It is possible for a driver to override this, but only if the
|
||||
* alternative functions are both implemented.
|
||||
*/
|
||||
if (!irqchip->irq_request_resources &&
|
||||
!irqchip->irq_release_resources) {
|
||||
irqchip->irq_request_resources = gpiochip_irq_reqres;
|
||||
irqchip->irq_release_resources = gpiochip_irq_relres;
|
||||
}
|
||||
|
||||
if (gpiochip->irq.parent_handler) {
|
||||
void *data = gpiochip->irq.parent_handler_data ?: gpiochip;
|
||||
|
||||
for (i = 0; i < gpiochip->irq.num_parents; i++) {
|
||||
/*
|
||||
* The parent IRQ chip is already using the chip_data
|
||||
* for this IRQ chip, so our callbacks simply use the
|
||||
* handler_data.
|
||||
*/
|
||||
irq_set_chained_handler_and_data(gpiochip->irq.parents[i],
|
||||
gpiochip->irq.parent_handler,
|
||||
data);
|
||||
}
|
||||
}
|
||||
|
||||
acpi_gpiochip_request_interrupts(gpiochip);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1717,26 +1807,34 @@ static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip)
|
||||
|
||||
acpi_gpiochip_free_interrupts(gpiochip);
|
||||
|
||||
if (gpiochip->irq_chained_parent) {
|
||||
irq_set_chained_handler(gpiochip->irq_chained_parent, NULL);
|
||||
irq_set_handler_data(gpiochip->irq_chained_parent, NULL);
|
||||
if (gpiochip->irq.chip && gpiochip->irq.parent_handler) {
|
||||
struct gpio_irq_chip *irq = &gpiochip->irq;
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < irq->num_parents; i++)
|
||||
irq_set_chained_handler_and_data(irq->parents[i],
|
||||
NULL, NULL);
|
||||
}
|
||||
|
||||
/* Remove all IRQ mappings and delete the domain */
|
||||
if (gpiochip->irqdomain) {
|
||||
if (gpiochip->irq.domain) {
|
||||
unsigned int irq;
|
||||
|
||||
for (offset = 0; offset < gpiochip->ngpio; offset++) {
|
||||
if (!gpiochip_irqchip_irq_valid(gpiochip, offset))
|
||||
continue;
|
||||
irq_dispose_mapping(
|
||||
irq_find_mapping(gpiochip->irqdomain, offset));
|
||||
|
||||
irq = irq_find_mapping(gpiochip->irq.domain, offset);
|
||||
irq_dispose_mapping(irq);
|
||||
}
|
||||
irq_domain_remove(gpiochip->irqdomain);
|
||||
|
||||
irq_domain_remove(gpiochip->irq.domain);
|
||||
}
|
||||
|
||||
if (gpiochip->irqchip) {
|
||||
gpiochip->irqchip->irq_request_resources = NULL;
|
||||
gpiochip->irqchip->irq_release_resources = NULL;
|
||||
gpiochip->irqchip = NULL;
|
||||
if (gpiochip->irq.chip) {
|
||||
gpiochip->irq.chip->irq_request_resources = NULL;
|
||||
gpiochip->irq.chip->irq_release_resources = NULL;
|
||||
gpiochip->irq.chip = NULL;
|
||||
}
|
||||
|
||||
gpiochip_irqchip_free_valid_mask(gpiochip);
|
||||
@ -1751,8 +1849,7 @@ static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip)
|
||||
* @handler: the irq handler to use (often a predefined irq core function)
|
||||
* @type: the default type for IRQs on this irqchip, pass IRQ_TYPE_NONE
|
||||
* to have the core avoid setting up any default type in the hardware.
|
||||
* @nested: whether this is a nested irqchip calling handle_nested_irq()
|
||||
* in its IRQ handler
|
||||
* @threaded: whether this irqchip uses a nested thread handler
|
||||
* @lock_key: lockdep class
|
||||
*
|
||||
* This function closely associates a certain irqchip with a certain
|
||||
@ -1774,7 +1871,7 @@ int gpiochip_irqchip_add_key(struct gpio_chip *gpiochip,
|
||||
unsigned int first_irq,
|
||||
irq_flow_handler_t handler,
|
||||
unsigned int type,
|
||||
bool nested,
|
||||
bool threaded,
|
||||
struct lock_class_key *lock_key)
|
||||
{
|
||||
struct device_node *of_node;
|
||||
@ -1786,7 +1883,7 @@ int gpiochip_irqchip_add_key(struct gpio_chip *gpiochip,
|
||||
pr_err("missing gpiochip .dev parent pointer\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
gpiochip->irq_nested = nested;
|
||||
gpiochip->irq.threaded = threaded;
|
||||
of_node = gpiochip->parent->of_node;
|
||||
#ifdef CONFIG_OF_GPIO
|
||||
/*
|
||||
@ -1811,16 +1908,16 @@ int gpiochip_irqchip_add_key(struct gpio_chip *gpiochip,
|
||||
type = IRQ_TYPE_NONE;
|
||||
}
|
||||
|
||||
gpiochip->irqchip = irqchip;
|
||||
gpiochip->irq_handler = handler;
|
||||
gpiochip->irq_default_type = type;
|
||||
gpiochip->irq.chip = irqchip;
|
||||
gpiochip->irq.handler = handler;
|
||||
gpiochip->irq.default_type = type;
|
||||
gpiochip->to_irq = gpiochip_to_irq;
|
||||
gpiochip->lock_key = lock_key;
|
||||
gpiochip->irqdomain = irq_domain_add_simple(of_node,
|
||||
gpiochip->irq.lock_key = lock_key;
|
||||
gpiochip->irq.domain = irq_domain_add_simple(of_node,
|
||||
gpiochip->ngpio, first_irq,
|
||||
&gpiochip_domain_ops, gpiochip);
|
||||
if (!gpiochip->irqdomain) {
|
||||
gpiochip->irqchip = NULL;
|
||||
if (!gpiochip->irq.domain) {
|
||||
gpiochip->irq.chip = NULL;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@ -1842,6 +1939,12 @@ EXPORT_SYMBOL_GPL(gpiochip_irqchip_add_key);
|
||||
|
||||
#else /* CONFIG_GPIOLIB_IRQCHIP */
|
||||
|
||||
static inline int gpiochip_add_irqchip(struct gpio_chip *gpiochip,
|
||||
struct lock_class_key *key)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip) {}
|
||||
static inline int gpiochip_irqchip_init_valid_mask(struct gpio_chip *gpiochip)
|
||||
{
|
||||
@ -2013,7 +2116,7 @@ EXPORT_SYMBOL_GPL(gpiochip_remove_pin_ranges);
|
||||
* on each other, and help provide better diagnostics in debugfs.
|
||||
* They're called even less than the "set direction" calls.
|
||||
*/
|
||||
static int __gpiod_request(struct gpio_desc *desc, const char *label)
|
||||
static int gpiod_request_commit(struct gpio_desc *desc, const char *label)
|
||||
{
|
||||
struct gpio_chip *chip = desc->gdev->chip;
|
||||
int status;
|
||||
@ -2106,7 +2209,7 @@ int gpiod_request(struct gpio_desc *desc, const char *label)
|
||||
gdev = desc->gdev;
|
||||
|
||||
if (try_module_get(gdev->owner)) {
|
||||
status = __gpiod_request(desc, label);
|
||||
status = gpiod_request_commit(desc, label);
|
||||
if (status < 0)
|
||||
module_put(gdev->owner);
|
||||
else
|
||||
@ -2119,7 +2222,7 @@ int gpiod_request(struct gpio_desc *desc, const char *label)
|
||||
return status;
|
||||
}
|
||||
|
||||
static bool __gpiod_free(struct gpio_desc *desc)
|
||||
static bool gpiod_free_commit(struct gpio_desc *desc)
|
||||
{
|
||||
bool ret = false;
|
||||
unsigned long flags;
|
||||
@ -2154,7 +2257,7 @@ static bool __gpiod_free(struct gpio_desc *desc)
|
||||
|
||||
void gpiod_free(struct gpio_desc *desc)
|
||||
{
|
||||
if (desc && desc->gdev && __gpiod_free(desc)) {
|
||||
if (desc && desc->gdev && gpiod_free_commit(desc)) {
|
||||
module_put(desc->gdev->owner);
|
||||
put_device(&desc->gdev->dev);
|
||||
} else {
|
||||
@ -2217,7 +2320,7 @@ struct gpio_desc *gpiochip_request_own_desc(struct gpio_chip *chip, u16 hwnum,
|
||||
return desc;
|
||||
}
|
||||
|
||||
err = __gpiod_request(desc, label);
|
||||
err = gpiod_request_commit(desc, label);
|
||||
if (err < 0)
|
||||
return ERR_PTR(err);
|
||||
|
||||
@ -2235,7 +2338,7 @@ EXPORT_SYMBOL_GPL(gpiochip_request_own_desc);
|
||||
void gpiochip_free_own_desc(struct gpio_desc *desc)
|
||||
{
|
||||
if (desc)
|
||||
__gpiod_free(desc);
|
||||
gpiod_free_commit(desc);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(gpiochip_free_own_desc);
|
||||
|
||||
@ -2291,44 +2394,12 @@ static int gpio_set_drive_single_ended(struct gpio_chip *gc, unsigned offset,
|
||||
return gc->set_config ? gc->set_config(gc, offset, config) : -ENOTSUPP;
|
||||
}
|
||||
|
||||
static int _gpiod_direction_output_raw(struct gpio_desc *desc, int value)
|
||||
static int gpiod_direction_output_raw_commit(struct gpio_desc *desc, int value)
|
||||
{
|
||||
struct gpio_chip *gc = desc->gdev->chip;
|
||||
int val = !!value;
|
||||
int ret;
|
||||
|
||||
/* GPIOs used for IRQs shall not be set as output */
|
||||
if (test_bit(FLAG_USED_AS_IRQ, &desc->flags)) {
|
||||
gpiod_err(desc,
|
||||
"%s: tried to set a GPIO tied to an IRQ as output\n",
|
||||
__func__);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if (test_bit(FLAG_OPEN_DRAIN, &desc->flags)) {
|
||||
/* First see if we can enable open drain in hardware */
|
||||
ret = gpio_set_drive_single_ended(gc, gpio_chip_hwgpio(desc),
|
||||
PIN_CONFIG_DRIVE_OPEN_DRAIN);
|
||||
if (!ret)
|
||||
goto set_output_value;
|
||||
/* Emulate open drain by not actively driving the line high */
|
||||
if (val)
|
||||
return gpiod_direction_input(desc);
|
||||
}
|
||||
else if (test_bit(FLAG_OPEN_SOURCE, &desc->flags)) {
|
||||
ret = gpio_set_drive_single_ended(gc, gpio_chip_hwgpio(desc),
|
||||
PIN_CONFIG_DRIVE_OPEN_SOURCE);
|
||||
if (!ret)
|
||||
goto set_output_value;
|
||||
/* Emulate open source by not actively driving the line low */
|
||||
if (!val)
|
||||
return gpiod_direction_input(desc);
|
||||
} else {
|
||||
gpio_set_drive_single_ended(gc, gpio_chip_hwgpio(desc),
|
||||
PIN_CONFIG_DRIVE_PUSH_PULL);
|
||||
}
|
||||
|
||||
set_output_value:
|
||||
if (!gc->set || !gc->direction_output) {
|
||||
gpiod_warn(desc,
|
||||
"%s: missing set() or direction_output() operations\n",
|
||||
@ -2358,7 +2429,7 @@ set_output_value:
|
||||
int gpiod_direction_output_raw(struct gpio_desc *desc, int value)
|
||||
{
|
||||
VALIDATE_DESC(desc);
|
||||
return _gpiod_direction_output_raw(desc, value);
|
||||
return gpiod_direction_output_raw_commit(desc, value);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(gpiod_direction_output_raw);
|
||||
|
||||
@ -2376,12 +2447,48 @@ EXPORT_SYMBOL_GPL(gpiod_direction_output_raw);
|
||||
*/
|
||||
int gpiod_direction_output(struct gpio_desc *desc, int value)
|
||||
{
|
||||
struct gpio_chip *gc = desc->gdev->chip;
|
||||
int ret;
|
||||
|
||||
VALIDATE_DESC(desc);
|
||||
if (test_bit(FLAG_ACTIVE_LOW, &desc->flags))
|
||||
value = !value;
|
||||
else
|
||||
value = !!value;
|
||||
return _gpiod_direction_output_raw(desc, value);
|
||||
|
||||
/* GPIOs used for IRQs shall not be set as output */
|
||||
if (test_bit(FLAG_USED_AS_IRQ, &desc->flags)) {
|
||||
gpiod_err(desc,
|
||||
"%s: tried to set a GPIO tied to an IRQ as output\n",
|
||||
__func__);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if (test_bit(FLAG_OPEN_DRAIN, &desc->flags)) {
|
||||
/* First see if we can enable open drain in hardware */
|
||||
ret = gpio_set_drive_single_ended(gc, gpio_chip_hwgpio(desc),
|
||||
PIN_CONFIG_DRIVE_OPEN_DRAIN);
|
||||
if (!ret)
|
||||
goto set_output_value;
|
||||
/* Emulate open drain by not actively driving the line high */
|
||||
if (value)
|
||||
return gpiod_direction_input(desc);
|
||||
}
|
||||
else if (test_bit(FLAG_OPEN_SOURCE, &desc->flags)) {
|
||||
ret = gpio_set_drive_single_ended(gc, gpio_chip_hwgpio(desc),
|
||||
PIN_CONFIG_DRIVE_OPEN_SOURCE);
|
||||
if (!ret)
|
||||
goto set_output_value;
|
||||
/* Emulate open source by not actively driving the line low */
|
||||
if (!value)
|
||||
return gpiod_direction_input(desc);
|
||||
} else {
|
||||
gpio_set_drive_single_ended(gc, gpio_chip_hwgpio(desc),
|
||||
PIN_CONFIG_DRIVE_PUSH_PULL);
|
||||
}
|
||||
|
||||
set_output_value:
|
||||
return gpiod_direction_output_raw_commit(desc, value);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(gpiod_direction_output);
|
||||
|
||||
@ -2448,7 +2555,7 @@ EXPORT_SYMBOL_GPL(gpiod_is_active_low);
|
||||
* that the GPIO was actually requested.
|
||||
*/
|
||||
|
||||
static int _gpiod_get_raw_value(const struct gpio_desc *desc)
|
||||
static int gpiod_get_raw_value_commit(const struct gpio_desc *desc)
|
||||
{
|
||||
struct gpio_chip *chip;
|
||||
int offset;
|
||||
@ -2462,6 +2569,71 @@ static int _gpiod_get_raw_value(const struct gpio_desc *desc)
|
||||
return value;
|
||||
}
|
||||
|
||||
static int gpio_chip_get_multiple(struct gpio_chip *chip,
|
||||
unsigned long *mask, unsigned long *bits)
|
||||
{
|
||||
if (chip->get_multiple) {
|
||||
return chip->get_multiple(chip, mask, bits);
|
||||
} else if (chip->get) {
|
||||
int i, value;
|
||||
|
||||
for_each_set_bit(i, mask, chip->ngpio) {
|
||||
value = chip->get(chip, i);
|
||||
if (value < 0)
|
||||
return value;
|
||||
__assign_bit(i, bits, value);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
int gpiod_get_array_value_complex(bool raw, bool can_sleep,
|
||||
unsigned int array_size,
|
||||
struct gpio_desc **desc_array,
|
||||
int *value_array)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
while (i < array_size) {
|
||||
struct gpio_chip *chip = desc_array[i]->gdev->chip;
|
||||
unsigned long mask[BITS_TO_LONGS(chip->ngpio)];
|
||||
unsigned long bits[BITS_TO_LONGS(chip->ngpio)];
|
||||
int first, j, ret;
|
||||
|
||||
if (!can_sleep)
|
||||
WARN_ON(chip->can_sleep);
|
||||
|
||||
/* collect all inputs belonging to the same chip */
|
||||
first = i;
|
||||
memset(mask, 0, sizeof(mask));
|
||||
do {
|
||||
const struct gpio_desc *desc = desc_array[i];
|
||||
int hwgpio = gpio_chip_hwgpio(desc);
|
||||
|
||||
__set_bit(hwgpio, mask);
|
||||
i++;
|
||||
} while ((i < array_size) &&
|
||||
(desc_array[i]->gdev->chip == chip));
|
||||
|
||||
ret = gpio_chip_get_multiple(chip, mask, bits);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
for (j = first; j < i; j++) {
|
||||
const struct gpio_desc *desc = desc_array[j];
|
||||
int hwgpio = gpio_chip_hwgpio(desc);
|
||||
int value = test_bit(hwgpio, bits);
|
||||
|
||||
if (!raw && test_bit(FLAG_ACTIVE_LOW, &desc->flags))
|
||||
value = !value;
|
||||
value_array[j] = value;
|
||||
trace_gpio_value(desc_to_gpio(desc), 1, value);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* gpiod_get_raw_value() - return a gpio's raw value
|
||||
* @desc: gpio whose value will be returned
|
||||
@ -2477,7 +2649,7 @@ int gpiod_get_raw_value(const struct gpio_desc *desc)
|
||||
VALIDATE_DESC(desc);
|
||||
/* Should be using gpio_get_value_cansleep() */
|
||||
WARN_ON(desc->gdev->chip->can_sleep);
|
||||
return _gpiod_get_raw_value(desc);
|
||||
return gpiod_get_raw_value_commit(desc);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(gpiod_get_raw_value);
|
||||
|
||||
@ -2499,7 +2671,7 @@ int gpiod_get_value(const struct gpio_desc *desc)
|
||||
/* Should be using gpio_get_value_cansleep() */
|
||||
WARN_ON(desc->gdev->chip->can_sleep);
|
||||
|
||||
value = _gpiod_get_raw_value(desc);
|
||||
value = gpiod_get_raw_value_commit(desc);
|
||||
if (value < 0)
|
||||
return value;
|
||||
|
||||
@ -2510,12 +2682,57 @@ int gpiod_get_value(const struct gpio_desc *desc)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(gpiod_get_value);
|
||||
|
||||
/**
|
||||
* gpiod_get_raw_array_value() - read raw values from an array of GPIOs
|
||||
* @array_size: number of elements in the descriptor / value arrays
|
||||
* @desc_array: array of GPIO descriptors whose values will be read
|
||||
* @value_array: array to store the read values
|
||||
*
|
||||
* Read the raw values of the GPIOs, i.e. the values of the physical lines
|
||||
* without regard for their ACTIVE_LOW status. Return 0 in case of success,
|
||||
* else an error code.
|
||||
*
|
||||
* This function should be called from contexts where we cannot sleep,
|
||||
* and it will complain if the GPIO chip functions potentially sleep.
|
||||
*/
|
||||
int gpiod_get_raw_array_value(unsigned int array_size,
|
||||
struct gpio_desc **desc_array, int *value_array)
|
||||
{
|
||||
if (!desc_array)
|
||||
return -EINVAL;
|
||||
return gpiod_get_array_value_complex(true, false, array_size,
|
||||
desc_array, value_array);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(gpiod_get_raw_array_value);
|
||||
|
||||
/**
|
||||
* gpiod_get_array_value() - read values from an array of GPIOs
|
||||
* @array_size: number of elements in the descriptor / value arrays
|
||||
* @desc_array: array of GPIO descriptors whose values will be read
|
||||
* @value_array: array to store the read values
|
||||
*
|
||||
* Read the logical values of the GPIOs, i.e. taking their ACTIVE_LOW status
|
||||
* into account. Return 0 in case of success, else an error code.
|
||||
*
|
||||
* This function should be called from contexts where we cannot sleep,
|
||||
* and it will complain if the GPIO chip functions potentially sleep.
|
||||
*/
|
||||
int gpiod_get_array_value(unsigned int array_size,
|
||||
struct gpio_desc **desc_array, int *value_array)
|
||||
{
|
||||
if (!desc_array)
|
||||
return -EINVAL;
|
||||
return gpiod_get_array_value_complex(false, false, array_size,
|
||||
desc_array, value_array);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(gpiod_get_array_value);
|
||||
|
||||
/*
|
||||
* _gpio_set_open_drain_value() - Set the open drain gpio's value.
|
||||
* gpio_set_open_drain_value_commit() - Set the open drain gpio's value.
|
||||
* @desc: gpio descriptor whose state need to be set.
|
||||
* @value: Non-zero for setting it HIGH otherwise it will set to LOW.
|
||||
*/
|
||||
static void _gpio_set_open_drain_value(struct gpio_desc *desc, bool value)
|
||||
static void gpio_set_open_drain_value_commit(struct gpio_desc *desc, bool value)
|
||||
{
|
||||
int err = 0;
|
||||
struct gpio_chip *chip = desc->gdev->chip;
|
||||
@ -2542,7 +2759,7 @@ static void _gpio_set_open_drain_value(struct gpio_desc *desc, bool value)
|
||||
* @desc: gpio descriptor whose state need to be set.
|
||||
* @value: Non-zero for setting it HIGH otherwise it will set to LOW.
|
||||
*/
|
||||
static void _gpio_set_open_source_value(struct gpio_desc *desc, bool value)
|
||||
static void gpio_set_open_source_value_commit(struct gpio_desc *desc, bool value)
|
||||
{
|
||||
int err = 0;
|
||||
struct gpio_chip *chip = desc->gdev->chip;
|
||||
@ -2564,18 +2781,13 @@ static void _gpio_set_open_source_value(struct gpio_desc *desc, bool value)
|
||||
__func__, err);
|
||||
}
|
||||
|
||||
static void _gpiod_set_raw_value(struct gpio_desc *desc, bool value)
|
||||
static void gpiod_set_raw_value_commit(struct gpio_desc *desc, bool value)
|
||||
{
|
||||
struct gpio_chip *chip;
|
||||
|
||||
chip = desc->gdev->chip;
|
||||
trace_gpio_value(desc_to_gpio(desc), 0, value);
|
||||
if (test_bit(FLAG_OPEN_DRAIN, &desc->flags))
|
||||
_gpio_set_open_drain_value(desc, value);
|
||||
else if (test_bit(FLAG_OPEN_SOURCE, &desc->flags))
|
||||
_gpio_set_open_source_value(desc, value);
|
||||
else
|
||||
chip->set(chip, gpio_chip_hwgpio(desc), value);
|
||||
chip->set(chip, gpio_chip_hwgpio(desc), value);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -2630,10 +2842,10 @@ void gpiod_set_array_value_complex(bool raw, bool can_sleep,
|
||||
* collect all normal outputs belonging to the same chip
|
||||
* open drain and open source outputs are set individually
|
||||
*/
|
||||
if (test_bit(FLAG_OPEN_DRAIN, &desc->flags)) {
|
||||
_gpio_set_open_drain_value(desc, value);
|
||||
} else if (test_bit(FLAG_OPEN_SOURCE, &desc->flags)) {
|
||||
_gpio_set_open_source_value(desc, value);
|
||||
if (test_bit(FLAG_OPEN_DRAIN, &desc->flags) && !raw) {
|
||||
gpio_set_open_drain_value_commit(desc, value);
|
||||
} else if (test_bit(FLAG_OPEN_SOURCE, &desc->flags) && !raw) {
|
||||
gpio_set_open_source_value_commit(desc, value);
|
||||
} else {
|
||||
__set_bit(hwgpio, mask);
|
||||
if (value)
|
||||
@ -2667,7 +2879,7 @@ void gpiod_set_raw_value(struct gpio_desc *desc, int value)
|
||||
VALIDATE_DESC_VOID(desc);
|
||||
/* Should be using gpiod_set_value_cansleep() */
|
||||
WARN_ON(desc->gdev->chip->can_sleep);
|
||||
_gpiod_set_raw_value(desc, value);
|
||||
gpiod_set_raw_value_commit(desc, value);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(gpiod_set_raw_value);
|
||||
|
||||
@ -2676,8 +2888,8 @@ EXPORT_SYMBOL_GPL(gpiod_set_raw_value);
|
||||
* @desc: gpio whose value will be assigned
|
||||
* @value: value to assign
|
||||
*
|
||||
* Set the logical value of the GPIO, i.e. taking its ACTIVE_LOW status into
|
||||
* account
|
||||
* Set the logical value of the GPIO, i.e. taking its ACTIVE_LOW,
|
||||
* OPEN_DRAIN and OPEN_SOURCE flags into account.
|
||||
*
|
||||
* This function should be called from contexts where we cannot sleep, and will
|
||||
* complain if the GPIO chip functions potentially sleep.
|
||||
@ -2689,7 +2901,12 @@ void gpiod_set_value(struct gpio_desc *desc, int value)
|
||||
WARN_ON(desc->gdev->chip->can_sleep);
|
||||
if (test_bit(FLAG_ACTIVE_LOW, &desc->flags))
|
||||
value = !value;
|
||||
_gpiod_set_raw_value(desc, value);
|
||||
if (test_bit(FLAG_OPEN_DRAIN, &desc->flags))
|
||||
gpio_set_open_drain_value_commit(desc, value);
|
||||
else if (test_bit(FLAG_OPEN_SOURCE, &desc->flags))
|
||||
gpio_set_open_source_value_commit(desc, value);
|
||||
else
|
||||
gpiod_set_raw_value_commit(desc, value);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(gpiod_set_value);
|
||||
|
||||
@ -2890,7 +3107,7 @@ bool gpiochip_line_is_persistent(struct gpio_chip *chip, unsigned int offset)
|
||||
if (offset >= chip->ngpio)
|
||||
return false;
|
||||
|
||||
return !test_bit(FLAG_SLEEP_MAY_LOOSE_VALUE,
|
||||
return !test_bit(FLAG_SLEEP_MAY_LOSE_VALUE,
|
||||
&chip->gpiodev->descs[offset].flags);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(gpiochip_line_is_persistent);
|
||||
@ -2908,7 +3125,7 @@ int gpiod_get_raw_value_cansleep(const struct gpio_desc *desc)
|
||||
{
|
||||
might_sleep_if(extra_checks);
|
||||
VALIDATE_DESC(desc);
|
||||
return _gpiod_get_raw_value(desc);
|
||||
return gpiod_get_raw_value_commit(desc);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(gpiod_get_raw_value_cansleep);
|
||||
|
||||
@ -2927,7 +3144,7 @@ int gpiod_get_value_cansleep(const struct gpio_desc *desc)
|
||||
|
||||
might_sleep_if(extra_checks);
|
||||
VALIDATE_DESC(desc);
|
||||
value = _gpiod_get_raw_value(desc);
|
||||
value = gpiod_get_raw_value_commit(desc);
|
||||
if (value < 0)
|
||||
return value;
|
||||
|
||||
@ -2938,6 +3155,53 @@ int gpiod_get_value_cansleep(const struct gpio_desc *desc)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(gpiod_get_value_cansleep);
|
||||
|
||||
/**
|
||||
* gpiod_get_raw_array_value_cansleep() - read raw values from an array of GPIOs
|
||||
* @array_size: number of elements in the descriptor / value arrays
|
||||
* @desc_array: array of GPIO descriptors whose values will be read
|
||||
* @value_array: array to store the read values
|
||||
*
|
||||
* Read the raw values of the GPIOs, i.e. the values of the physical lines
|
||||
* without regard for their ACTIVE_LOW status. Return 0 in case of success,
|
||||
* else an error code.
|
||||
*
|
||||
* This function is to be called from contexts that can sleep.
|
||||
*/
|
||||
int gpiod_get_raw_array_value_cansleep(unsigned int array_size,
|
||||
struct gpio_desc **desc_array,
|
||||
int *value_array)
|
||||
{
|
||||
might_sleep_if(extra_checks);
|
||||
if (!desc_array)
|
||||
return -EINVAL;
|
||||
return gpiod_get_array_value_complex(true, true, array_size,
|
||||
desc_array, value_array);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(gpiod_get_raw_array_value_cansleep);
|
||||
|
||||
/**
|
||||
* gpiod_get_array_value_cansleep() - read values from an array of GPIOs
|
||||
* @array_size: number of elements in the descriptor / value arrays
|
||||
* @desc_array: array of GPIO descriptors whose values will be read
|
||||
* @value_array: array to store the read values
|
||||
*
|
||||
* Read the logical values of the GPIOs, i.e. taking their ACTIVE_LOW status
|
||||
* into account. Return 0 in case of success, else an error code.
|
||||
*
|
||||
* This function is to be called from contexts that can sleep.
|
||||
*/
|
||||
int gpiod_get_array_value_cansleep(unsigned int array_size,
|
||||
struct gpio_desc **desc_array,
|
||||
int *value_array)
|
||||
{
|
||||
might_sleep_if(extra_checks);
|
||||
if (!desc_array)
|
||||
return -EINVAL;
|
||||
return gpiod_get_array_value_complex(false, true, array_size,
|
||||
desc_array, value_array);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(gpiod_get_array_value_cansleep);
|
||||
|
||||
/**
|
||||
* gpiod_set_raw_value_cansleep() - assign a gpio's raw value
|
||||
* @desc: gpio whose value will be assigned
|
||||
@ -2952,7 +3216,7 @@ void gpiod_set_raw_value_cansleep(struct gpio_desc *desc, int value)
|
||||
{
|
||||
might_sleep_if(extra_checks);
|
||||
VALIDATE_DESC_VOID(desc);
|
||||
_gpiod_set_raw_value(desc, value);
|
||||
gpiod_set_raw_value_commit(desc, value);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(gpiod_set_raw_value_cansleep);
|
||||
|
||||
@ -2972,7 +3236,7 @@ void gpiod_set_value_cansleep(struct gpio_desc *desc, int value)
|
||||
VALIDATE_DESC_VOID(desc);
|
||||
if (test_bit(FLAG_ACTIVE_LOW, &desc->flags))
|
||||
value = !value;
|
||||
_gpiod_set_raw_value(desc, value);
|
||||
gpiod_set_raw_value_commit(desc, value);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(gpiod_set_value_cansleep);
|
||||
|
||||
@ -3268,8 +3532,8 @@ int gpiod_configure_flags(struct gpio_desc *desc, const char *con_id,
|
||||
set_bit(FLAG_OPEN_DRAIN, &desc->flags);
|
||||
if (lflags & GPIO_OPEN_SOURCE)
|
||||
set_bit(FLAG_OPEN_SOURCE, &desc->flags);
|
||||
if (lflags & GPIO_SLEEP_MAY_LOOSE_VALUE)
|
||||
set_bit(FLAG_SLEEP_MAY_LOOSE_VALUE, &desc->flags);
|
||||
if (lflags & GPIO_SLEEP_MAY_LOSE_VALUE)
|
||||
set_bit(FLAG_SLEEP_MAY_LOSE_VALUE, &desc->flags);
|
||||
|
||||
/* No particular flag request, return here... */
|
||||
if (!(dflags & GPIOD_FLAGS_BIT_DIR_SET)) {
|
||||
|
@ -180,6 +180,10 @@ static inline bool acpi_can_fallback_to_crs(struct acpi_device *adev,
|
||||
#endif
|
||||
|
||||
struct gpio_desc *gpiochip_get_desc(struct gpio_chip *chip, u16 hwnum);
|
||||
int gpiod_get_array_value_complex(bool raw, bool can_sleep,
|
||||
unsigned int array_size,
|
||||
struct gpio_desc **desc_array,
|
||||
int *value_array);
|
||||
void gpiod_set_array_value_complex(bool raw, bool can_sleep,
|
||||
unsigned int array_size,
|
||||
struct gpio_desc **desc_array,
|
||||
@ -201,7 +205,7 @@ struct gpio_desc {
|
||||
#define FLAG_OPEN_SOURCE 8 /* Gpio is open source type */
|
||||
#define FLAG_USED_AS_IRQ 9 /* GPIO is connected to an IRQ */
|
||||
#define FLAG_IS_HOGGED 11 /* GPIO is hogged */
|
||||
#define FLAG_SLEEP_MAY_LOOSE_VALUE 12 /* GPIO may loose value in sleep */
|
||||
#define FLAG_SLEEP_MAY_LOSE_VALUE 12 /* GPIO may lose value in sleep */
|
||||
|
||||
/* Connection label */
|
||||
const char *label;
|
||||
|
@ -641,14 +641,6 @@ static void process_queued_bios(struct work_struct *work)
|
||||
blk_finish_plug(&plug);
|
||||
}
|
||||
|
||||
static void assign_bit(bool value, long nr, unsigned long *addr)
|
||||
{
|
||||
if (value)
|
||||
set_bit(nr, addr);
|
||||
else
|
||||
clear_bit(nr, addr);
|
||||
}
|
||||
|
||||
/*
|
||||
* If we run out of usable paths, should we queue I/O or error it?
|
||||
*/
|
||||
@ -658,11 +650,11 @@ static int queue_if_no_path(struct multipath *m, bool queue_if_no_path,
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&m->lock, flags);
|
||||
assign_bit((save_old_value && test_bit(MPATHF_QUEUE_IF_NO_PATH, &m->flags)) ||
|
||||
(!save_old_value && queue_if_no_path),
|
||||
MPATHF_SAVED_QUEUE_IF_NO_PATH, &m->flags);
|
||||
assign_bit(queue_if_no_path || dm_noflush_suspending(m->ti),
|
||||
MPATHF_QUEUE_IF_NO_PATH, &m->flags);
|
||||
assign_bit(MPATHF_SAVED_QUEUE_IF_NO_PATH, &m->flags,
|
||||
(save_old_value && test_bit(MPATHF_QUEUE_IF_NO_PATH, &m->flags)) ||
|
||||
(!save_old_value && queue_if_no_path));
|
||||
assign_bit(MPATHF_QUEUE_IF_NO_PATH, &m->flags,
|
||||
queue_if_no_path || dm_noflush_suspending(m->ti));
|
||||
spin_unlock_irqrestore(&m->lock, flags);
|
||||
|
||||
if (!queue_if_no_path) {
|
||||
@ -1588,8 +1580,8 @@ static void multipath_resume(struct dm_target *ti)
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&m->lock, flags);
|
||||
assign_bit(test_bit(MPATHF_SAVED_QUEUE_IF_NO_PATH, &m->flags),
|
||||
MPATHF_QUEUE_IF_NO_PATH, &m->flags);
|
||||
assign_bit(MPATHF_QUEUE_IF_NO_PATH, &m->flags,
|
||||
test_bit(MPATHF_SAVED_QUEUE_IF_NO_PATH, &m->flags));
|
||||
spin_unlock_irqrestore(&m->lock, flags);
|
||||
}
|
||||
|
||||
|
@ -383,7 +383,7 @@ static void bcm2835_gpio_irq_handle_bank(struct bcm2835_pinctrl *pc,
|
||||
/* FIXME: no clue why the code looks up the type here */
|
||||
type = pc->irq_type[gpio];
|
||||
|
||||
generic_handle_irq(irq_linear_revmap(pc->gpio_chip.irqdomain,
|
||||
generic_handle_irq(irq_linear_revmap(pc->gpio_chip.irq.domain,
|
||||
gpio));
|
||||
}
|
||||
}
|
||||
@ -665,7 +665,7 @@ static void bcm2835_pctl_pin_dbg_show(struct pinctrl_dev *pctldev,
|
||||
enum bcm2835_fsel fsel = bcm2835_pinctrl_fsel_get(pc, offset);
|
||||
const char *fname = bcm2835_functions[fsel];
|
||||
int value = bcm2835_gpio_get_bit(pc, GPLEV0, offset);
|
||||
int irq = irq_find_mapping(chip->irqdomain, offset);
|
||||
int irq = irq_find_mapping(chip->irq.domain, offset);
|
||||
|
||||
seq_printf(s, "function %s in %s; irq %d (%s)",
|
||||
fname, value ? "hi" : "lo",
|
||||
|
@ -172,7 +172,7 @@ static void iproc_gpio_irq_handler(struct irq_desc *desc)
|
||||
|
||||
for_each_set_bit(bit, &val, NGPIOS_PER_BANK) {
|
||||
unsigned pin = NGPIOS_PER_BANK * i + bit;
|
||||
int child_irq = irq_find_mapping(gc->irqdomain, pin);
|
||||
int child_irq = irq_find_mapping(gc->irq.domain, pin);
|
||||
|
||||
/*
|
||||
* Clear the interrupt before invoking the
|
||||
|
@ -1627,7 +1627,7 @@ static void byt_gpio_irq_handler(struct irq_desc *desc)
|
||||
pending = readl(reg);
|
||||
raw_spin_unlock(&vg->lock);
|
||||
for_each_set_bit(pin, &pending, 32) {
|
||||
virq = irq_find_mapping(vg->chip.irqdomain, base + pin);
|
||||
virq = irq_find_mapping(vg->chip.irq.domain, base + pin);
|
||||
generic_handle_irq(virq);
|
||||
}
|
||||
}
|
||||
@ -1660,7 +1660,7 @@ static void byt_gpio_irq_init_hw(struct byt_gpio *vg)
|
||||
|
||||
value = readl(reg);
|
||||
if (value & BYT_DIRECT_IRQ_EN) {
|
||||
clear_bit(i, gc->irq_valid_mask);
|
||||
clear_bit(i, gc->irq.valid_mask);
|
||||
dev_dbg(dev, "excluding GPIO %d from IRQ domain\n", i);
|
||||
} else if ((value & BYT_PIN_MUX) == byt_get_gpio_mux(vg, i)) {
|
||||
byt_gpio_clear_triggering(vg, i);
|
||||
@ -1703,7 +1703,7 @@ static int byt_gpio_probe(struct byt_gpio *vg)
|
||||
gc->can_sleep = false;
|
||||
gc->parent = &vg->pdev->dev;
|
||||
gc->ngpio = vg->soc_data->npins;
|
||||
gc->irq_need_valid_mask = true;
|
||||
gc->irq.need_valid_mask = true;
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
vg->saved_context = devm_kcalloc(&vg->pdev->dev, gc->ngpio,
|
||||
|
@ -1523,7 +1523,7 @@ static void chv_gpio_irq_handler(struct irq_desc *desc)
|
||||
unsigned irq, offset;
|
||||
|
||||
offset = pctrl->intr_lines[intr_line];
|
||||
irq = irq_find_mapping(gc->irqdomain, offset);
|
||||
irq = irq_find_mapping(gc->irq.domain, offset);
|
||||
generic_handle_irq(irq);
|
||||
}
|
||||
|
||||
@ -1584,7 +1584,7 @@ static int chv_gpio_probe(struct chv_pinctrl *pctrl, int irq)
|
||||
chip->label = dev_name(pctrl->dev);
|
||||
chip->parent = pctrl->dev;
|
||||
chip->base = -1;
|
||||
chip->irq_need_valid_mask = need_valid_mask;
|
||||
chip->irq.need_valid_mask = need_valid_mask;
|
||||
|
||||
ret = devm_gpiochip_add_data(pctrl->dev, chip, pctrl);
|
||||
if (ret) {
|
||||
@ -1616,7 +1616,7 @@ static int chv_gpio_probe(struct chv_pinctrl *pctrl, int irq)
|
||||
intsel >>= CHV_PADCTRL0_INTSEL_SHIFT;
|
||||
|
||||
if (need_valid_mask && intsel >= pctrl->community->nirqs)
|
||||
clear_bit(i, chip->irq_valid_mask);
|
||||
clear_bit(i, chip->irq.valid_mask);
|
||||
}
|
||||
|
||||
/* Clear all interrupts */
|
||||
|
@ -1006,7 +1006,7 @@ static irqreturn_t intel_gpio_community_irq_handler(struct intel_pinctrl *pctrl,
|
||||
if (padno >= community->npins)
|
||||
break;
|
||||
|
||||
irq = irq_find_mapping(gc->irqdomain,
|
||||
irq = irq_find_mapping(gc->irq.domain,
|
||||
community->pin_base + padno);
|
||||
generic_handle_irq(irq);
|
||||
|
||||
|
@ -639,7 +639,7 @@ static void armada_37xx_irq_handler(struct irq_desc *desc)
|
||||
struct gpio_chip *gc = irq_desc_get_handler_data(desc);
|
||||
struct irq_chip *chip = irq_desc_get_chip(desc);
|
||||
struct armada_37xx_pinctrl *info = gpiochip_get_data(gc);
|
||||
struct irq_domain *d = gc->irqdomain;
|
||||
struct irq_domain *d = gc->irq.domain;
|
||||
int i;
|
||||
|
||||
chained_irq_enter(chip, desc);
|
||||
@ -690,15 +690,13 @@ static void armada_37xx_irq_handler(struct irq_desc *desc)
|
||||
|
||||
static unsigned int armada_37xx_irq_startup(struct irq_data *d)
|
||||
{
|
||||
struct gpio_chip *chip = irq_data_get_irq_chip_data(d);
|
||||
int irq = d->hwirq - chip->irq_base;
|
||||
/*
|
||||
* The mask field is a "precomputed bitmask for accessing the
|
||||
* chip registers" which was introduced for the generic
|
||||
* irqchip framework. As we don't use this framework, we can
|
||||
* reuse this field for our own usage.
|
||||
*/
|
||||
d->mask = BIT(irq % GPIO_PER_REG);
|
||||
d->mask = BIT(d->hwirq % GPIO_PER_REG);
|
||||
|
||||
armada_37xx_irq_unmask(d);
|
||||
|
||||
|
@ -413,7 +413,7 @@ nmk_gpio_disable_lazy_irq(struct nmk_gpio_chip *nmk_chip, unsigned offset)
|
||||
u32 falling = nmk_chip->fimsc & BIT(offset);
|
||||
u32 rising = nmk_chip->rimsc & BIT(offset);
|
||||
int gpio = nmk_chip->chip.base + offset;
|
||||
int irq = irq_find_mapping(nmk_chip->chip.irqdomain, offset);
|
||||
int irq = irq_find_mapping(nmk_chip->chip.irq.domain, offset);
|
||||
struct irq_data *d = irq_get_irq_data(irq);
|
||||
|
||||
if (!rising && !falling)
|
||||
@ -815,7 +815,7 @@ static void __nmk_gpio_irq_handler(struct irq_desc *desc, u32 status)
|
||||
while (status) {
|
||||
int bit = __ffs(status);
|
||||
|
||||
generic_handle_irq(irq_find_mapping(chip->irqdomain, bit));
|
||||
generic_handle_irq(irq_find_mapping(chip->irq.domain, bit));
|
||||
status &= ~BIT(bit);
|
||||
}
|
||||
|
||||
|
@ -532,7 +532,7 @@ static irqreturn_t amd_gpio_irq_handler(int irq, void *dev_id)
|
||||
regval = readl(regs + i);
|
||||
if (!(regval & PIN_IRQ_PENDING))
|
||||
continue;
|
||||
irq = irq_find_mapping(gc->irqdomain, irqnr + i);
|
||||
irq = irq_find_mapping(gc->irq.domain, irqnr + i);
|
||||
generic_handle_irq(irq);
|
||||
/* Clear interrupt */
|
||||
writel(regval, regs + i);
|
||||
|
@ -1603,7 +1603,7 @@ static void gpio_irq_handler(struct irq_desc *desc)
|
||||
|
||||
for_each_set_bit(n, &isr, BITS_PER_LONG) {
|
||||
generic_handle_irq(irq_find_mapping(
|
||||
gpio_chip->irqdomain, n));
|
||||
gpio_chip->irq.domain, n));
|
||||
}
|
||||
}
|
||||
chained_irq_exit(chip, desc);
|
||||
|
@ -517,7 +517,7 @@ static void u300_gpio_irq_handler(struct irq_desc *desc)
|
||||
|
||||
for_each_set_bit(irqoffset, &val, U300_GPIO_PINS_PER_PORT) {
|
||||
int offset = pinoffset + irqoffset;
|
||||
int pin_irq = irq_find_mapping(chip->irqdomain, offset);
|
||||
int pin_irq = irq_find_mapping(chip->irq.domain, offset);
|
||||
|
||||
dev_dbg(gpio->dev, "GPIO IRQ %d on pin %d\n",
|
||||
pin_irq, offset);
|
||||
|
@ -535,7 +535,7 @@ static irqreturn_t mcp23s08_irq(int irq, void *data)
|
||||
((gpio_bit_changed || intcap_changed) &&
|
||||
(BIT(i) & mcp->irq_fall) && !gpio_set) ||
|
||||
defval_changed) {
|
||||
child_irq = irq_find_mapping(mcp->chip.irqdomain, i);
|
||||
child_irq = irq_find_mapping(mcp->chip.irq.domain, i);
|
||||
handle_nested_irq(child_irq);
|
||||
}
|
||||
}
|
||||
|
@ -1064,7 +1064,7 @@ static void oxnas_gpio_irq_handler(struct irq_desc *desc)
|
||||
stat = readl(bank->reg_base + IRQ_PENDING);
|
||||
|
||||
for_each_set_bit(pin, &stat, BITS_PER_LONG)
|
||||
generic_handle_irq(irq_linear_revmap(gc->irqdomain, pin));
|
||||
generic_handle_irq(irq_linear_revmap(gc->irq.domain, pin));
|
||||
|
||||
chained_irq_exit(chip, desc);
|
||||
}
|
||||
|
@ -2106,7 +2106,7 @@ static void pic32_gpio_irq_handler(struct irq_desc *desc)
|
||||
pending = pic32_gpio_get_pending(gc, stat);
|
||||
|
||||
for_each_set_bit(pin, &pending, BITS_PER_LONG)
|
||||
generic_handle_irq(irq_linear_revmap(gc->irqdomain, pin));
|
||||
generic_handle_irq(irq_linear_revmap(gc->irq.domain, pin));
|
||||
|
||||
chained_irq_exit(chip, desc);
|
||||
}
|
||||
|
@ -1307,7 +1307,7 @@ static void pistachio_gpio_irq_handler(struct irq_desc *desc)
|
||||
pending = gpio_readl(bank, GPIO_INTERRUPT_STATUS) &
|
||||
gpio_readl(bank, GPIO_INTERRUPT_EN);
|
||||
for_each_set_bit(pin, &pending, 16)
|
||||
generic_handle_irq(irq_linear_revmap(gc->irqdomain, pin));
|
||||
generic_handle_irq(irq_linear_revmap(gc->irq.domain, pin));
|
||||
chained_irq_exit(chip, desc);
|
||||
}
|
||||
|
||||
|
@ -1408,7 +1408,7 @@ static void __gpio_irq_handler(struct st_gpio_bank *bank)
|
||||
continue;
|
||||
}
|
||||
|
||||
generic_handle_irq(irq_find_mapping(bank->gpio_chip.irqdomain, n));
|
||||
generic_handle_irq(irq_find_mapping(bank->gpio_chip.irq.domain, n));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -561,7 +561,7 @@ static irqreturn_t sx150x_irq_thread_fn(int irq, void *dev_id)
|
||||
|
||||
status = val;
|
||||
for_each_set_bit(n, &status, pctl->data->ngpios)
|
||||
handle_nested_irq(irq_find_mapping(pctl->gpio.irqdomain, n));
|
||||
handle_nested_irq(irq_find_mapping(pctl->gpio.irq.domain, n));
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
@ -795,7 +795,7 @@ static void msm_gpio_irq_handler(struct irq_desc *desc)
|
||||
g = &pctrl->soc->groups[i];
|
||||
val = readl(pctrl->regs + g->intr_status_reg);
|
||||
if (val & BIT(g->intr_status_bit)) {
|
||||
irq_pin = irq_find_mapping(gc->irqdomain, i);
|
||||
irq_pin = irq_find_mapping(gc->irq.domain, i);
|
||||
generic_handle_irq(irq_pin);
|
||||
handled++;
|
||||
}
|
||||
|
@ -5820,7 +5820,7 @@ static void atlas7_gpio_handle_irq(struct irq_desc *desc)
|
||||
__func__, gc->label,
|
||||
bank->gpio_offset + pin_in_bank);
|
||||
generic_handle_irq(
|
||||
irq_find_mapping(gc->irqdomain,
|
||||
irq_find_mapping(gc->irq.domain,
|
||||
bank->gpio_offset + pin_in_bank));
|
||||
}
|
||||
|
||||
|
@ -587,7 +587,7 @@ static void sirfsoc_gpio_handle_irq(struct irq_desc *desc)
|
||||
if ((status & 0x1) && (ctrl & SIRFSOC_GPIO_CTL_INTR_EN_MASK)) {
|
||||
pr_debug("%s: gpio id %d idx %d happens\n",
|
||||
__func__, bank->id, idx);
|
||||
generic_handle_irq(irq_find_mapping(gc->irqdomain, idx +
|
||||
generic_handle_irq(irq_find_mapping(gc->irq.domain, idx +
|
||||
bank->id * SIRFSOC_GPIO_BANK_SIZE));
|
||||
}
|
||||
|
||||
|
@ -401,7 +401,7 @@ static void plgpio_irq_handler(struct irq_desc *desc)
|
||||
/* get correct irq line number */
|
||||
pin = i * MAX_GPIO_PER_REG + pin;
|
||||
generic_handle_irq(
|
||||
irq_find_mapping(gc->irqdomain, pin));
|
||||
irq_find_mapping(gc->irq.domain, pin));
|
||||
}
|
||||
}
|
||||
chained_irq_exit(irqchip, desc);
|
||||
|
@ -119,7 +119,7 @@ static irqreturn_t int0002_irq(int irq, void *data)
|
||||
if (!(gpe_sts_reg & GPE0A_PME_B0_STS_BIT))
|
||||
return IRQ_NONE;
|
||||
|
||||
generic_handle_irq(irq_find_mapping(chip->irqdomain,
|
||||
generic_handle_irq(irq_find_mapping(chip->irq.domain,
|
||||
GPE0A_PME_B0_VIRT_GPIO_PIN));
|
||||
|
||||
pm_system_wakeup();
|
||||
@ -165,7 +165,7 @@ static int int0002_probe(struct platform_device *pdev)
|
||||
chip->direction_output = int0002_gpio_direction_output;
|
||||
chip->base = -1;
|
||||
chip->ngpio = GPE0A_PME_B0_VIRT_GPIO_PIN + 1;
|
||||
chip->irq_need_valid_mask = true;
|
||||
chip->irq.need_valid_mask = true;
|
||||
|
||||
ret = devm_gpiochip_add_data(&pdev->dev, chip, NULL);
|
||||
if (ret) {
|
||||
@ -173,7 +173,7 @@ static int int0002_probe(struct platform_device *pdev)
|
||||
return ret;
|
||||
}
|
||||
|
||||
bitmap_clear(chip->irq_valid_mask, 0, GPE0A_PME_B0_VIRT_GPIO_PIN);
|
||||
bitmap_clear(chip->irq.valid_mask, 0, GPE0A_PME_B0_VIRT_GPIO_PIN);
|
||||
|
||||
/*
|
||||
* We manually request the irq here instead of passing a flow-handler
|
||||
|
@ -30,6 +30,6 @@
|
||||
|
||||
/* Bit 3 express GPIO suspend/resume persistence */
|
||||
#define GPIO_SLEEP_MAINTAIN_VALUE 0
|
||||
#define GPIO_SLEEP_MAY_LOOSE_VALUE 8
|
||||
#define GPIO_SLEEP_MAY_LOSE_VALUE 8
|
||||
|
||||
#endif
|
||||
|
18
include/dt-bindings/gpio/uniphier-gpio.h
Normal file
18
include/dt-bindings/gpio/uniphier-gpio.h
Normal file
@ -0,0 +1,18 @@
|
||||
/*
|
||||
* Copyright (C) 2017 Socionext Inc.
|
||||
* Author: Masahiro Yamada <yamada.masahiro@socionext.com>
|
||||
*/
|
||||
|
||||
#ifndef _DT_BINDINGS_GPIO_UNIPHIER_H
|
||||
#define _DT_BINDINGS_GPIO_UNIPHIER_H
|
||||
|
||||
#define UNIPHIER_GPIO_LINES_PER_BANK 8
|
||||
|
||||
#define UNIPHIER_GPIO_IRQ_OFFSET ((UNIPHIER_GPIO_LINES_PER_BANK) * 15)
|
||||
|
||||
#define UNIPHIER_GPIO_PORT(bank, line) \
|
||||
((UNIPHIER_GPIO_LINES_PER_BANK) * (bank) + (line))
|
||||
|
||||
#define UNIPHIER_GPIO_IRQ(n) ((UNIPHIER_GPIO_IRQ_OFFSET) + (n))
|
||||
|
||||
#endif /* _DT_BINDINGS_GPIO_UNIPHIER_H */
|
@ -227,6 +227,30 @@ static inline unsigned long __ffs64(u64 word)
|
||||
return __ffs((unsigned long)word);
|
||||
}
|
||||
|
||||
/**
|
||||
* assign_bit - Assign value to a bit in memory
|
||||
* @nr: the bit to set
|
||||
* @addr: the address to start counting from
|
||||
* @value: the value to assign
|
||||
*/
|
||||
static __always_inline void assign_bit(long nr, volatile unsigned long *addr,
|
||||
bool value)
|
||||
{
|
||||
if (value)
|
||||
set_bit(nr, addr);
|
||||
else
|
||||
clear_bit(nr, addr);
|
||||
}
|
||||
|
||||
static __always_inline void __assign_bit(long nr, volatile unsigned long *addr,
|
||||
bool value)
|
||||
{
|
||||
if (value)
|
||||
__set_bit(nr, addr);
|
||||
else
|
||||
__clear_bit(nr, addr);
|
||||
}
|
||||
|
||||
#ifdef __KERNEL__
|
||||
|
||||
#ifndef set_mask_bits
|
||||
|
@ -99,10 +99,15 @@ int gpiod_direction_output_raw(struct gpio_desc *desc, int value);
|
||||
|
||||
/* Value get/set from non-sleeping context */
|
||||
int gpiod_get_value(const struct gpio_desc *desc);
|
||||
int gpiod_get_array_value(unsigned int array_size,
|
||||
struct gpio_desc **desc_array, int *value_array);
|
||||
void gpiod_set_value(struct gpio_desc *desc, int value);
|
||||
void gpiod_set_array_value(unsigned int array_size,
|
||||
struct gpio_desc **desc_array, int *value_array);
|
||||
int gpiod_get_raw_value(const struct gpio_desc *desc);
|
||||
int gpiod_get_raw_array_value(unsigned int array_size,
|
||||
struct gpio_desc **desc_array,
|
||||
int *value_array);
|
||||
void gpiod_set_raw_value(struct gpio_desc *desc, int value);
|
||||
void gpiod_set_raw_array_value(unsigned int array_size,
|
||||
struct gpio_desc **desc_array,
|
||||
@ -110,11 +115,17 @@ void gpiod_set_raw_array_value(unsigned int array_size,
|
||||
|
||||
/* Value get/set from sleeping context */
|
||||
int gpiod_get_value_cansleep(const struct gpio_desc *desc);
|
||||
int gpiod_get_array_value_cansleep(unsigned int array_size,
|
||||
struct gpio_desc **desc_array,
|
||||
int *value_array);
|
||||
void gpiod_set_value_cansleep(struct gpio_desc *desc, int value);
|
||||
void gpiod_set_array_value_cansleep(unsigned int array_size,
|
||||
struct gpio_desc **desc_array,
|
||||
int *value_array);
|
||||
int gpiod_get_raw_value_cansleep(const struct gpio_desc *desc);
|
||||
int gpiod_get_raw_array_value_cansleep(unsigned int array_size,
|
||||
struct gpio_desc **desc_array,
|
||||
int *value_array);
|
||||
void gpiod_set_raw_value_cansleep(struct gpio_desc *desc, int value);
|
||||
void gpiod_set_raw_array_value_cansleep(unsigned int array_size,
|
||||
struct gpio_desc **desc_array,
|
||||
@ -305,6 +316,14 @@ static inline int gpiod_get_value(const struct gpio_desc *desc)
|
||||
WARN_ON(1);
|
||||
return 0;
|
||||
}
|
||||
static inline int gpiod_get_array_value(unsigned int array_size,
|
||||
struct gpio_desc **desc_array,
|
||||
int *value_array)
|
||||
{
|
||||
/* GPIO can never have been requested */
|
||||
WARN_ON(1);
|
||||
return 0;
|
||||
}
|
||||
static inline void gpiod_set_value(struct gpio_desc *desc, int value)
|
||||
{
|
||||
/* GPIO can never have been requested */
|
||||
@ -323,6 +342,14 @@ static inline int gpiod_get_raw_value(const struct gpio_desc *desc)
|
||||
WARN_ON(1);
|
||||
return 0;
|
||||
}
|
||||
static inline int gpiod_get_raw_array_value(unsigned int array_size,
|
||||
struct gpio_desc **desc_array,
|
||||
int *value_array)
|
||||
{
|
||||
/* GPIO can never have been requested */
|
||||
WARN_ON(1);
|
||||
return 0;
|
||||
}
|
||||
static inline void gpiod_set_raw_value(struct gpio_desc *desc, int value)
|
||||
{
|
||||
/* GPIO can never have been requested */
|
||||
@ -342,6 +369,14 @@ static inline int gpiod_get_value_cansleep(const struct gpio_desc *desc)
|
||||
WARN_ON(1);
|
||||
return 0;
|
||||
}
|
||||
static inline int gpiod_get_array_value_cansleep(unsigned int array_size,
|
||||
struct gpio_desc **desc_array,
|
||||
int *value_array)
|
||||
{
|
||||
/* GPIO can never have been requested */
|
||||
WARN_ON(1);
|
||||
return 0;
|
||||
}
|
||||
static inline void gpiod_set_value_cansleep(struct gpio_desc *desc, int value)
|
||||
{
|
||||
/* GPIO can never have been requested */
|
||||
@ -360,6 +395,14 @@ static inline int gpiod_get_raw_value_cansleep(const struct gpio_desc *desc)
|
||||
WARN_ON(1);
|
||||
return 0;
|
||||
}
|
||||
static inline int gpiod_get_raw_array_value_cansleep(unsigned int array_size,
|
||||
struct gpio_desc **desc_array,
|
||||
int *value_array)
|
||||
{
|
||||
/* GPIO can never have been requested */
|
||||
WARN_ON(1);
|
||||
return 0;
|
||||
}
|
||||
static inline void gpiod_set_raw_value_cansleep(struct gpio_desc *desc,
|
||||
int value)
|
||||
{
|
||||
|
@ -19,6 +19,131 @@ struct module;
|
||||
|
||||
#ifdef CONFIG_GPIOLIB
|
||||
|
||||
#ifdef CONFIG_GPIOLIB_IRQCHIP
|
||||
/**
|
||||
* struct gpio_irq_chip - GPIO interrupt controller
|
||||
*/
|
||||
struct gpio_irq_chip {
|
||||
/**
|
||||
* @chip:
|
||||
*
|
||||
* GPIO IRQ chip implementation, provided by GPIO driver.
|
||||
*/
|
||||
struct irq_chip *chip;
|
||||
|
||||
/**
|
||||
* @domain:
|
||||
*
|
||||
* Interrupt translation domain; responsible for mapping between GPIO
|
||||
* hwirq number and Linux IRQ number.
|
||||
*/
|
||||
struct irq_domain *domain;
|
||||
|
||||
/**
|
||||
* @domain_ops:
|
||||
*
|
||||
* Table of interrupt domain operations for this IRQ chip.
|
||||
*/
|
||||
const struct irq_domain_ops *domain_ops;
|
||||
|
||||
/**
|
||||
* @handler:
|
||||
*
|
||||
* The IRQ handler to use (often a predefined IRQ core function) for
|
||||
* GPIO IRQs, provided by GPIO driver.
|
||||
*/
|
||||
irq_flow_handler_t handler;
|
||||
|
||||
/**
|
||||
* @default_type:
|
||||
*
|
||||
* Default IRQ triggering type applied during GPIO driver
|
||||
* initialization, provided by GPIO driver.
|
||||
*/
|
||||
unsigned int default_type;
|
||||
|
||||
/**
|
||||
* @lock_key:
|
||||
*
|
||||
* Per GPIO IRQ chip lockdep class.
|
||||
*/
|
||||
struct lock_class_key *lock_key;
|
||||
|
||||
/**
|
||||
* @parent_handler:
|
||||
*
|
||||
* The interrupt handler for the GPIO chip's parent interrupts, may be
|
||||
* NULL if the parent interrupts are nested rather than cascaded.
|
||||
*/
|
||||
irq_flow_handler_t parent_handler;
|
||||
|
||||
/**
|
||||
* @parent_handler_data:
|
||||
*
|
||||
* Data associated, and passed to, the handler for the parent
|
||||
* interrupt.
|
||||
*/
|
||||
void *parent_handler_data;
|
||||
|
||||
/**
|
||||
* @num_parents:
|
||||
*
|
||||
* The number of interrupt parents of a GPIO chip.
|
||||
*/
|
||||
unsigned int num_parents;
|
||||
|
||||
/**
|
||||
* @parents:
|
||||
*
|
||||
* A list of interrupt parents of a GPIO chip. This is owned by the
|
||||
* driver, so the core will only reference this list, not modify it.
|
||||
*/
|
||||
unsigned int *parents;
|
||||
|
||||
/**
|
||||
* @map:
|
||||
*
|
||||
* A list of interrupt parents for each line of a GPIO chip.
|
||||
*/
|
||||
unsigned int *map;
|
||||
|
||||
/**
|
||||
* @threaded:
|
||||
*
|
||||
* True if set the interrupt handling uses nested threads.
|
||||
*/
|
||||
bool threaded;
|
||||
|
||||
/**
|
||||
* @need_valid_mask:
|
||||
*
|
||||
* If set core allocates @valid_mask with all bits set to one.
|
||||
*/
|
||||
bool need_valid_mask;
|
||||
|
||||
/**
|
||||
* @valid_mask:
|
||||
*
|
||||
* If not %NULL holds bitmask of GPIOs which are valid to be included
|
||||
* in IRQ domain of the chip.
|
||||
*/
|
||||
unsigned long *valid_mask;
|
||||
|
||||
/**
|
||||
* @first:
|
||||
*
|
||||
* Required for static IRQ allocation. If set, irq_domain_add_simple()
|
||||
* will allocate and map all IRQs during initialization.
|
||||
*/
|
||||
unsigned int first;
|
||||
};
|
||||
|
||||
static inline struct gpio_irq_chip *to_gpio_irq_chip(struct irq_chip *chip)
|
||||
{
|
||||
return container_of(chip, struct gpio_irq_chip, chip);
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* struct gpio_chip - abstract a GPIO controller
|
||||
* @label: a functional name for the GPIO device, such as a part
|
||||
@ -35,6 +160,8 @@ struct module;
|
||||
* @direction_input: configures signal "offset" as input, or returns error
|
||||
* @direction_output: configures signal "offset" as output, or returns error
|
||||
* @get: returns value for signal "offset", 0=low, 1=high, or negative error
|
||||
* @get_multiple: reads values for multiple signals defined by "mask" and
|
||||
* stores them in "bits", returns 0 on success or negative error
|
||||
* @set: assigns output value for signal "offset"
|
||||
* @set_multiple: assigns output values for multiple signals defined by "mask"
|
||||
* @set_config: optional hook for all kinds of settings. Uses the same
|
||||
@ -65,9 +192,9 @@ struct module;
|
||||
* registers.
|
||||
* @read_reg: reader function for generic GPIO
|
||||
* @write_reg: writer function for generic GPIO
|
||||
* @pin2mask: some generic GPIO controllers work with the big-endian bits
|
||||
* notation, e.g. in a 8-bits register, GPIO7 is the least significant
|
||||
* bit. This callback assigns the right bit mask.
|
||||
* @be_bits: if the generic GPIO has big endian bit order (bit 31 is representing
|
||||
* line 0, bit 30 is line 1 ... bit 0 is line 31) this is set to true by the
|
||||
* generic GPIO core. It is for internal housekeeping only.
|
||||
* @reg_dat: data (in) register for generic GPIO
|
||||
* @reg_set: output set register (out=high) for generic GPIO
|
||||
* @reg_clr: output clear register (out=low) for generic GPIO
|
||||
@ -80,23 +207,6 @@ struct module;
|
||||
* safely.
|
||||
* @bgpio_dir: shadowed direction register for generic GPIO to clear/set
|
||||
* direction safely.
|
||||
* @irqchip: GPIO IRQ chip impl, provided by GPIO driver
|
||||
* @irqdomain: Interrupt translation domain; responsible for mapping
|
||||
* between GPIO hwirq number and linux irq number
|
||||
* @irq_base: first linux IRQ number assigned to GPIO IRQ chip (deprecated)
|
||||
* @irq_handler: the irq handler to use (often a predefined irq core function)
|
||||
* for GPIO IRQs, provided by GPIO driver
|
||||
* @irq_default_type: default IRQ triggering type applied during GPIO driver
|
||||
* initialization, provided by GPIO driver
|
||||
* @irq_chained_parent: GPIO IRQ chip parent/bank linux irq number,
|
||||
* provided by GPIO driver for chained interrupt (not for nested
|
||||
* interrupts).
|
||||
* @irq_nested: True if set the interrupt handling is nested.
|
||||
* @irq_need_valid_mask: If set core allocates @irq_valid_mask with all
|
||||
* bits set to one
|
||||
* @irq_valid_mask: If not %NULL holds bitmask of GPIOs which are valid to
|
||||
* be included in IRQ domain of the chip
|
||||
* @lock_key: per GPIO IRQ chip lockdep class
|
||||
*
|
||||
* A gpio_chip can help platforms abstract various sources of GPIOs so
|
||||
* they can all be accessed through a common programing interface.
|
||||
@ -126,6 +236,9 @@ struct gpio_chip {
|
||||
unsigned offset, int value);
|
||||
int (*get)(struct gpio_chip *chip,
|
||||
unsigned offset);
|
||||
int (*get_multiple)(struct gpio_chip *chip,
|
||||
unsigned long *mask,
|
||||
unsigned long *bits);
|
||||
void (*set)(struct gpio_chip *chip,
|
||||
unsigned offset, int value);
|
||||
void (*set_multiple)(struct gpio_chip *chip,
|
||||
@ -147,7 +260,7 @@ struct gpio_chip {
|
||||
#if IS_ENABLED(CONFIG_GPIO_GENERIC)
|
||||
unsigned long (*read_reg)(void __iomem *reg);
|
||||
void (*write_reg)(void __iomem *reg, unsigned long data);
|
||||
unsigned long (*pin2mask)(struct gpio_chip *gc, unsigned int pin);
|
||||
bool be_bits;
|
||||
void __iomem *reg_dat;
|
||||
void __iomem *reg_set;
|
||||
void __iomem *reg_clr;
|
||||
@ -163,16 +276,14 @@ struct gpio_chip {
|
||||
* With CONFIG_GPIOLIB_IRQCHIP we get an irqchip inside the gpiolib
|
||||
* to handle IRQs for most practical cases.
|
||||
*/
|
||||
struct irq_chip *irqchip;
|
||||
struct irq_domain *irqdomain;
|
||||
unsigned int irq_base;
|
||||
irq_flow_handler_t irq_handler;
|
||||
unsigned int irq_default_type;
|
||||
unsigned int irq_chained_parent;
|
||||
bool irq_nested;
|
||||
bool irq_need_valid_mask;
|
||||
unsigned long *irq_valid_mask;
|
||||
struct lock_class_key *lock_key;
|
||||
|
||||
/**
|
||||
* @irq:
|
||||
*
|
||||
* Integrates interrupt chip functionality with the GPIO chip. Can be
|
||||
* used to handle IRQs for most practical cases.
|
||||
*/
|
||||
struct gpio_irq_chip irq;
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_OF_GPIO)
|
||||
@ -210,7 +321,41 @@ extern const char *gpiochip_is_requested(struct gpio_chip *chip,
|
||||
unsigned offset);
|
||||
|
||||
/* add/remove chips */
|
||||
extern int gpiochip_add_data(struct gpio_chip *chip, void *data);
|
||||
extern int gpiochip_add_data_with_key(struct gpio_chip *chip, void *data,
|
||||
struct lock_class_key *lock_key);
|
||||
|
||||
/**
|
||||
* gpiochip_add_data() - register a gpio_chip
|
||||
* @chip: the chip to register, with chip->base initialized
|
||||
* @data: driver-private data associated with this chip
|
||||
*
|
||||
* Context: potentially before irqs will work
|
||||
*
|
||||
* When gpiochip_add_data() is called very early during boot, so that GPIOs
|
||||
* can be freely used, the chip->parent device must be registered before
|
||||
* the gpio framework's arch_initcall(). Otherwise sysfs initialization
|
||||
* for GPIOs will fail rudely.
|
||||
*
|
||||
* gpiochip_add_data() must only be called after gpiolib initialization,
|
||||
* ie after core_initcall().
|
||||
*
|
||||
* If chip->base is negative, this requests dynamic assignment of
|
||||
* a range of valid GPIOs.
|
||||
*
|
||||
* Returns:
|
||||
* A negative errno if the chip can't be registered, such as because the
|
||||
* chip->base is invalid or already associated with a different chip.
|
||||
* Otherwise it returns zero as a success code.
|
||||
*/
|
||||
#ifdef CONFIG_LOCKDEP
|
||||
#define gpiochip_add_data(chip, data) ({ \
|
||||
static struct lock_class_key key; \
|
||||
gpiochip_add_data_with_key(chip, data, &key); \
|
||||
})
|
||||
#else
|
||||
#define gpiochip_add_data(chip, data) gpiochip_add_data_with_key(chip, data, NULL)
|
||||
#endif
|
||||
|
||||
static inline int gpiochip_add(struct gpio_chip *chip)
|
||||
{
|
||||
return gpiochip_add_data(chip, NULL);
|
||||
@ -264,6 +409,10 @@ int bgpio_init(struct gpio_chip *gc, struct device *dev,
|
||||
|
||||
#ifdef CONFIG_GPIOLIB_IRQCHIP
|
||||
|
||||
int gpiochip_irq_map(struct irq_domain *d, unsigned int irq,
|
||||
irq_hw_number_t hwirq);
|
||||
void gpiochip_irq_unmap(struct irq_domain *d, unsigned int irq);
|
||||
|
||||
void gpiochip_set_chained_irqchip(struct gpio_chip *gpiochip,
|
||||
struct irq_chip *irqchip,
|
||||
unsigned int parent_irq,
|
||||
@ -278,7 +427,7 @@ int gpiochip_irqchip_add_key(struct gpio_chip *gpiochip,
|
||||
unsigned int first_irq,
|
||||
irq_flow_handler_t handler,
|
||||
unsigned int type,
|
||||
bool nested,
|
||||
bool threaded,
|
||||
struct lock_class_key *lock_key);
|
||||
|
||||
#ifdef CONFIG_LOCKDEP
|
||||
|
@ -10,7 +10,7 @@ enum gpio_lookup_flags {
|
||||
GPIO_OPEN_DRAIN = (1 << 1),
|
||||
GPIO_OPEN_SOURCE = (1 << 2),
|
||||
GPIO_SLEEP_MAINTAIN_VALUE = (0 << 3),
|
||||
GPIO_SLEEP_MAY_LOOSE_VALUE = (1 << 3),
|
||||
GPIO_SLEEP_MAY_LOSE_VALUE = (1 << 3),
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -31,7 +31,7 @@ enum of_gpio_flags {
|
||||
OF_GPIO_ACTIVE_LOW = 0x1,
|
||||
OF_GPIO_SINGLE_ENDED = 0x2,
|
||||
OF_GPIO_OPEN_DRAIN = 0x4,
|
||||
OF_GPIO_SLEEP_MAY_LOOSE_VALUE = 0x8,
|
||||
OF_GPIO_SLEEP_MAY_LOSE_VALUE = 0x8,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_OF_GPIO
|
||||
|
@ -76,7 +76,8 @@ int gpiotools_request_linehandle(const char *device_name, unsigned int *lines,
|
||||
fd = open(chrdev_name, 0);
|
||||
if (fd == -1) {
|
||||
ret = -errno;
|
||||
fprintf(stderr, "Failed to open %s\n", chrdev_name);
|
||||
fprintf(stderr, "Failed to open %s, %s\n",
|
||||
chrdev_name, strerror(errno));
|
||||
goto exit_close_error;
|
||||
}
|
||||
|
||||
@ -92,8 +93,8 @@ int gpiotools_request_linehandle(const char *device_name, unsigned int *lines,
|
||||
ret = ioctl(fd, GPIO_GET_LINEHANDLE_IOCTL, &req);
|
||||
if (ret == -1) {
|
||||
ret = -errno;
|
||||
fprintf(stderr, "Failed to issue GET LINEHANDLE IOCTL (%d)\n",
|
||||
ret);
|
||||
fprintf(stderr, "Failed to issue %s (%d), %s\n",
|
||||
"GPIO_GET_LINEHANDLE_IOCTL", ret, strerror(errno));
|
||||
}
|
||||
|
||||
exit_close_error:
|
||||
@ -118,8 +119,9 @@ int gpiotools_set_values(const int fd, struct gpiohandle_data *data)
|
||||
ret = ioctl(fd, GPIOHANDLE_SET_LINE_VALUES_IOCTL, data);
|
||||
if (ret == -1) {
|
||||
ret = -errno;
|
||||
fprintf(stderr, "Failed to issue %s (%d)\n",
|
||||
"GPIOHANDLE_SET_LINE_VALUES_IOCTL", ret);
|
||||
fprintf(stderr, "Failed to issue %s (%d), %s\n",
|
||||
"GPIOHANDLE_SET_LINE_VALUES_IOCTL", ret,
|
||||
strerror(errno));
|
||||
}
|
||||
|
||||
return ret;
|
||||
@ -141,8 +143,9 @@ int gpiotools_get_values(const int fd, struct gpiohandle_data *data)
|
||||
ret = ioctl(fd, GPIOHANDLE_GET_LINE_VALUES_IOCTL, data);
|
||||
if (ret == -1) {
|
||||
ret = -errno;
|
||||
fprintf(stderr, "Failed to issue %s (%d)\n",
|
||||
"GPIOHANDLE_GET_LINE_VALUES_IOCTL", ret);
|
||||
fprintf(stderr, "Failed to issue %s (%d), %s\n",
|
||||
"GPIOHANDLE_GET_LINE_VALUES_IOCTL", ret,
|
||||
strerror(errno));
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
Loading…
Reference in New Issue
Block a user