forked from Minki/linux
This is the bulk of GPIO changes for the v4.15 kernel cycle:
CORE: - Fix the semantics of raw GPIO to actually be raw. No inversion semantics as before, but also no open draining, and allow the raw operations to affect lines used for interrupts as the caller supposedly knows what they are doing if they are getting the big hammer. - Rewrote the __inner_function() notation calls to names that make more sense. I just find this kind of code disturbing. - Drop the .irq_base() field from the gpiochip since now all IRQs are mapped dynamically. This is nice. - Support for .get_multiple() in the core driver API. This allows us to read several GPIO lines with a single register read. This has high value for some usecases: it can be used to create oscilloscopes and signal analyzers and other things that rely on reading several lines at exactly the same instant. Also a generally nice optimization. This uses the new assign_bit() macro from the bitops lib that was ACKed by Andrew Morton and is implemented for two drivers, one of them being the generic MMIO driver so everyone using that will be able to benefit from this. - Do not allow requests of Open Drain and Open Source setting of a GPIO line simultaneously. If the hardware actually supports enabling both at the same time the electrical result would be disastrous. - A new interrupt chip core helper. This will be helpful to deal with "banked" GPIOs, which means GPIO controllers with several logical blocks of GPIO inside them. This is several gpiochips per device in the device model, in contrast to the case when there is a 1-to-1 relationship between a device and a gpiochip. NEW DRIVERS: - Maxim MAX3191x industrial serializer, a very interesting piece of professional I/O hardware. - Uniphier GPIO driver. This is the GPIO block from the recent Socionext (ex Fujitsu and Panasonic) platform. - Tegra 186 driver. This is based on the new banked GPIO infrastructure. OTHER IMPROVEMENTS: - Some documentation improvements. - Wakeup support for the DesignWare DWAPB GPIO controller. - Reset line support on the DesignWare DWAPB GPIO controller. - Several non-critical bug fixes and improvements for the Broadcom BRCMSTB driver. - Misc non-critical bug fixes like exotic errorpaths, removal of dead code etc. - Explicit comments on fall-through switch() statements. -----BEGIN PGP SIGNATURE----- iQIcBAABAgAGBQJaCvGiAAoJEEEQszewGV1z+oAQAJUpdPH/msdgHDuXSuBcbuFq NObQdkRiz1hez4vJOT+kbgES6ay57MArnbmM/xRdy+37lKrmkP+yfZe4UUruQhhW f2GVlwBbUp9tIzNliS8IYWO0tj+BTYyg1MQx0C0nE1zMZqVZk44EDa9SO6esRaFJ SLc2BpO3oJCQRaObe0+KTHIJV0dK3vQh4QXSzL+cM5u7P67Jq+wv4xdLVVScwbJB 4jgwVER3Ah0E1jHclIG2PxI1rbYKwlOBumafOTUlq5fmfC3tULVPJEm9FXcdaBLJ KAmtxX4yi+SgUccYFsmK+fNNLVQiAjmkhJCl6kxVOrxYqamrG100YST4Iew3sakM /iQ3lpup5L6eJ/dndfgE207OqRFhvAzNRxORv1p/wJIRLmV1/QehCX8GYOcDumXY MySRcEeUeZPfBHcnjIDRP6y/XOg8zBKso7GL+feRgLZUJZlNQZqokdC95TY9S5nm QLK+sU367o41tomyv5TP3y1DDsym6+ZdpuOUh73znxuz2x/x+FfTfwM2J0r8Ussm GQTfAojeBI9aSOZ2mvgRI1XxSprXqO3FFFWBwrQ6RS9rBceLF1o2ySKC2gI0FG5d 6GBkARcN5RyyNtYkH923pyrqz/FZJc6ZkrsUTGmERM5HGuWwczcditqwYRhbHwl8 pIlmX4y0AYh6FFVoIcQE =8Mon -----END PGP SIGNATURE----- Merge tag 'gpio-v4.15-1' of ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/linusw/linux-gpio Pull GPIO updates from Linus Walleij: "This is the bulk of GPIO changes for the v4.15 kernel cycle: Core: - Fix the semantics of raw GPIO to actually be raw. No inversion semantics as before, but also no open draining, and allow the raw operations to affect lines used for interrupts as the caller supposedly knows what they are doing if they are getting the big hammer. - Rewrote the __inner_function() notation calls to names that make more sense. I just find this kind of code disturbing. - Drop the .irq_base() field from the gpiochip since now all IRQs are mapped dynamically. This is nice. - Support for .get_multiple() in the core driver API. This allows us to read several GPIO lines with a single register read. This has high value for some usecases: it can be used to create oscilloscopes and signal analyzers and other things that rely on reading several lines at exactly the same instant. Also a generally nice optimization. This uses the new assign_bit() macro from the bitops lib that was ACKed by Andrew Morton and is implemented for two drivers, one of them being the generic MMIO driver so everyone using that will be able to benefit from this. - Do not allow requests of Open Drain and Open Source setting of a GPIO line simultaneously. If the hardware actually supports enabling both at the same time the electrical result would be disastrous. - A new interrupt chip core helper. This will be helpful to deal with "banked" GPIOs, which means GPIO controllers with several logical blocks of GPIO inside them. This is several gpiochips per device in the device model, in contrast to the case when there is a 1-to-1 relationship between a device and a gpiochip. New drivers: - Maxim MAX3191x industrial serializer, a very interesting piece of professional I/O hardware. - Uniphier GPIO driver. This is the GPIO block from the recent Socionext (ex Fujitsu and Panasonic) platform. - Tegra 186 driver. This is based on the new banked GPIO infrastructure. Other improvements: - Some documentation improvements. - Wakeup support for the DesignWare DWAPB GPIO controller. - Reset line support on the DesignWare DWAPB GPIO controller. - Several non-critical bug fixes and improvements for the Broadcom BRCMSTB driver. - Misc non-critical bug fixes like exotic errorpaths, removal of dead code etc. - Explicit comments on fall-through switch() statements" * tag 'gpio-v4.15-1' of ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/linusw/linux-gpio: (65 commits) gpio: tegra186: Remove tegra186_gpio_lock_class gpio: rcar: Add r8a77995 (R-Car D3) support pinctrl: bcm2835: Fix some merge fallout gpio: Fix undefined lock_dep_class gpio: Automatically add lockdep keys gpio: Introduce struct gpio_irq_chip.first gpio: Disambiguate struct gpio_irq_chip.nested gpio: Add Tegra186 support gpio: Export gpiochip_irq_{map,unmap}() gpio: Implement tighter IRQ chip integration gpio: Move lock_key into struct gpio_irq_chip gpio: Move irq_valid_mask into struct gpio_irq_chip gpio: Move irq_nested into struct gpio_irq_chip gpio: Move irq_chained_parent to struct gpio_irq_chip gpio: Move irq_default_type to struct gpio_irq_chip gpio: Move irq_handler to struct gpio_irq_chip gpio: Move irqdomain into struct gpio_irq_chip gpio: Move irqchip into struct gpio_irq_chip gpio: Introduce struct gpio_irq_chip pinctrl: armada-37xx: remove unused variable ...
This commit is contained in:
commit
6aa2f9441f
@ -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,8 @@ 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,gpio-r8a77995": for R8A77995 (R-Car D3) 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.
|
||||
|
@ -2029,6 +2029,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/
|
||||
@ -2036,6 +2037,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/
|
||||
@ -12945,6 +12947,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>
|
||||
R: 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
|
||||
@ -475,6 +483,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
|
||||
@ -1256,6 +1272,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
|
||||
|
@ -70,6 +70,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
|
||||
@ -114,6 +115,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
|
||||
@ -132,6 +134,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);
|
||||
|
@ -150,7 +150,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;
|
||||
|
||||
|
@ -737,7 +737,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);
|
||||
|
620
drivers/gpio/gpio-tegra186.c
Normal file
620
drivers/gpio/gpio-tegra186.c
Normal file
@ -0,0 +1,620 @@
|
||||
/*
|
||||
* 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 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->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
|
||||
};
|
||||
|
508
drivers/gpio/gpio-uniphier.c
Normal file
508
drivers/gpio/gpio-uniphier.c
Normal file
@ -0,0 +1,508 @@
|
||||
/*
|
||||
* 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 int uniphier_gpio_irq_domain_activate(struct irq_domain *domain,
|
||||
struct irq_data *data, bool early)
|
||||
{
|
||||
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);
|
||||
return 0;
|
||||
}
|
||||
|
||||
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;
|
||||
@ -233,7 +230,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);
|
||||
@ -287,18 +283,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);
|
||||
}
|
||||
|
||||
|
@ -379,7 +379,7 @@ static void bcm2835_gpio_irq_handle_bank(struct bcm2835_pinctrl *pc,
|
||||
events &= pc->enabled_irq_map[bank];
|
||||
for_each_set_bit(offset, &events, 32) {
|
||||
gpio = (32 * bank) + offset;
|
||||
generic_handle_irq(irq_linear_revmap(pc->gpio_chip.irqdomain,
|
||||
generic_handle_irq(irq_linear_revmap(pc->gpio_chip.irq.domain,
|
||||
gpio));
|
||||
}
|
||||
}
|
||||
@ -661,7 +661,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);
|
||||
}
|
||||
|
||||
@ -1585,7 +1585,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) {
|
||||
@ -1617,7 +1617,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 */
|
||||
|
@ -1005,7 +1005,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);
|
||||
|
||||
|
@ -592,7 +592,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);
|
||||
@ -626,15 +626,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.
|
||||
|
@ -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);
|
||||
|
@ -537,7 +537,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
|
||||
|
@ -31,6 +31,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 */
|
@ -228,6 +228,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
|
||||
|
@ -100,10 +100,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,
|
||||
@ -111,11 +116,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,
|
||||
@ -306,6 +317,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 */
|
||||
@ -324,6 +343,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 */
|
||||
@ -343,6 +370,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 */
|
||||
@ -361,6 +396,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)
|
||||
{
|
||||
|
@ -20,6 +20,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
|
||||
@ -36,6 +161,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
|
||||
@ -66,9 +193,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
|
||||
@ -81,23 +208,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.
|
||||
@ -127,6 +237,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,
|
||||
@ -148,7 +261,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;
|
||||
@ -164,16 +277,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)
|
||||
@ -211,7 +322,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);
|
||||
@ -265,6 +410,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,
|
||||
@ -279,7 +428,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
|
||||
|
@ -11,7 +11,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