This is the bulk of changes in the GPIO subsystem for the
v5.4 kernel cycle. Core changes: - Support hierarchical GPIO irqchips. We now have three consumers that can use this: Intel IXP4xx, ThunderX and Qualcomm SPMI GPIO (in the pinctrl subsystem). The support code has been long in the making and hashed out so it should be easily adaptable for all hierarchical irqchip parents. The code only gets compiled in if hierarchical irqchip is used at the topmost irq controller at least, as the hierarchical irqchip requires strict hierarchy all the way up in the system. - Determine the need for a "valid_mask" for GPIO lines on the gpio_chip and conversely for the "valid_mask" for the GPIO interrupt chip interrupt lines by looking for a .init_valid_mask() callback in the main chip or GPIO interrupt chip respectively. Allocate it with bitmap_alloc(). - Isolate the device tree/open firmware GPIO description code out in its own file properly. - Isolate the ACPI GPIO description code out in its own file properly. - Drop a whole lot of #ifdef:s in the main includes: it does not hurt to keep the include items around, and we get quicker and clearer compile failures if the appropriate kernel symbols are not selected for drivers. New/deleted drivers: - New driver for Aspeed SGPIO. - The KS8695 driver is deleted as the platform gets deleted from arch/arm in this kernel cycle. - The Cirrus Logic Madera driver now supports CS47L92 and CS47L15. - The Freescale MPC8xxx now supports LS1028A and LS1088A. Driver improvements: - We pass the GPIO irqchip intialization by directly filling in the struct instead of using set-up functions (the new way) for Intel MID, Lynxpoint, Merrifield, XLP, HLWD, Aspeed, ZX, VF610, TQMX86, MT7621, Zynq and EP93xx. Out-of-band changes: - Fix a GPIO header inclusion in Unicore - no response from maintainer. - Drop FMC subsystem from MAINTAINERS - was deleted in the GPIO tree last cycle so let's mop up the shards. -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEElDRnuGcz/wPCXQWMQRCzN7AZXXMFAl1/BO0ACgkQQRCzN7AZ XXPiPw/9GPSYqvHuv37RJwUTiaygDleLLayCy73AsudopSeInAfcPIElJgW2/5oa i5x4rdd81SpuReQWNKqqPjuDffdZvJW9rwuXU/LXsOk0fhWIe8BidUPISRPTYSJP q3NpmBJG4opVmhWZ3yxnq9tPboabjdTikVkM90Nwpe3vpdKk/7GV5k/T8/18fXb6 bn7E6YaN6Qrt3jknb+eK+ne6zLv5/ncFIGqYvUPKeqi0MOs4JDc/YroK90MAMSrD WvtOZl72bYKutxa42ZYf0lZVKhZHKMoigulEWczxVxwHSulxbMDbNa+CzNfunkjz 5iBDA34gzliCoA5NdcqMuQs44qkiRBS6ci9PRXBlW9QJuDHzpK5j4mKy2Kp5K2bQ +FX1dAftsAQBEkqVqQs97kGIfE5z0hRsyH8+fLKH3tkZmfkLKjYAB+pwHIhAFwvV f8WJ8Ay+gorvpWDwqjBeP2SnxFCE5GmgZHCfp0oJ1Kr/BM4hLPDT6RwvavDPO7uz xMcJFH1ZS1HCdkuFKOboD+FpRHCDeL4IJvHpal3dcu3P4RMr16M3E+UAeQAwdnYM AmqDYLbXyHdEszpk4uwc0nHt+gwie0CLfhuUvswJunnDkbwXiD4nj2c9ipaFsVLI /KaZvUe44/I5ItRb8vGkpP6Z++QiVqJkmdO0Lxy+UEaV6jb7mfg= =/TRI -----END PGP SIGNATURE----- Merge tag 'gpio-v5.4-1' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-gpio Pull GPIO updates from Linus Walleij: "This is the bulk of changes in the GPIO subsystem for the v5.4 kernel cycle. Core changes: - Support hierarchical GPIO irqchips. We now have three consumers that can use this: Intel IXP4xx, ThunderX and Qualcomm SPMI GPIO (in the pinctrl subsystem). The support code has been long in the making and hashed out so it should be easily adaptable for all hierarchical irqchip parents. The code only gets compiled in if hierarchical irqchip is used at the topmost irq controller at least, as the hierarchical irqchip requires strict hierarchy all the way up in the system. - Determine the need for a "valid_mask" for GPIO lines on the gpio_chip and conversely for the "valid_mask" for the GPIO interrupt chip interrupt lines by looking for a .init_valid_mask() callback in the main chip or GPIO interrupt chip respectively. Allocate it with bitmap_alloc(). - Isolate the device tree/open firmware GPIO description code out in its own file properly. - Isolate the ACPI GPIO description code out in its own file properly. - Drop a whole lot of #ifdef:s in the main includes: it does not hurt to keep the include items around, and we get quicker and clearer compile failures if the appropriate kernel symbols are not selected for drivers. New/deleted drivers: - New driver for Aspeed SGPIO. - The KS8695 driver is deleted as the platform gets deleted from arch/arm in this kernel cycle. - The Cirrus Logic Madera driver now supports CS47L92 and CS47L15. - The Freescale MPC8xxx now supports LS1028A and LS1088A. Driver improvements: - We pass the GPIO irqchip intialization by directly filling in the struct instead of using set-up functions (the new way) for Intel MID, Lynxpoint, Merrifield, XLP, HLWD, Aspeed, ZX, VF610, TQMX86, MT7621, Zynq and EP93xx. Out-of-band changes: - Fix a GPIO header inclusion in Unicore - no response from maintainer. - Drop FMC subsystem from MAINTAINERS - was deleted in the GPIO tree last cycle so let's mop up the shards" * tag 'gpio-v5.4-1' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-gpio: (82 commits) gpiolib: of: add a fallback for wlf,reset GPIO name gpio: htc-egpio: Remove unused exported htc_egpio_get_wakeup_irq() gpio: remove explicit comparison with 0 gpio: creg-snps: use devm_platform_ioremap_resource() to simplify code gpio: devres: Switch to EXPORT_SYMBOL_GPL() gpio: of: Switch to EXPORT_SYMBOL_GPL() gpio: of: Make of_gpio_simple_xlate() private gpio: of: Make of_get_named_gpiod_flags() private gpio: aspeed: Add in ast2600 details to Aspeed driver gpio: aspeed: Use ngpio property from device tree if available gpio: aspeed: Setup irqchip dynamically gpio/aspeed: Fix incorrect number of banks gpio: aspeed: Update documentation with ast2600 controllers gpio: Initialize the irqchip valid_mask with a callback gpiolib: acpi: make acpi_can_fallback_to_crs() static gpio: Fix further merge errors gpio: Fix up merge collision in include file gpio: of: Normalize return code variable name gpio: gpiolib: Normalize return code variable name gpio: ep93xx: Pass irqchip when adding gpiochip ...
This commit is contained in:
commit
bbfe0d6b8b
|
@ -2,7 +2,8 @@ Aspeed GPIO controller Device Tree Bindings
|
|||
-------------------------------------------
|
||||
|
||||
Required properties:
|
||||
- compatible : Either "aspeed,ast2400-gpio" or "aspeed,ast2500-gpio"
|
||||
- compatible : Either "aspeed,ast2400-gpio", "aspeed,ast2500-gpio",
|
||||
or "aspeed,ast2600-gpio".
|
||||
|
||||
- #gpio-cells : Should be two
|
||||
- First cell is the GPIO line number
|
||||
|
@ -17,7 +18,9 @@ Required properties:
|
|||
|
||||
Optional properties:
|
||||
|
||||
- clocks : A phandle to the clock to use for debounce timings
|
||||
- clocks : A phandle to the clock to use for debounce timings
|
||||
- ngpios : Number of GPIOs controlled by this controller. Should be set
|
||||
when there are multiple GPIO controllers on a SoC (ast2600).
|
||||
|
||||
The gpio and interrupt properties are further described in their respective
|
||||
bindings documentation:
|
||||
|
|
|
@ -6,6 +6,7 @@ Required Properties:
|
|||
66AK2E SoCs
|
||||
"ti,k2g-gpio", "ti,keystone-gpio": for 66AK2G
|
||||
"ti,am654-gpio", "ti,keystone-gpio": for TI K3 AM654
|
||||
"ti,j721e-gpio", "ti,keystone-gpio": for J721E SoCs
|
||||
|
||||
- reg: Physical base address of the controller and the size of memory mapped
|
||||
registers.
|
||||
|
|
|
@ -4,7 +4,7 @@ Required properties:
|
|||
- compatible : Should be "fsl,<soc>-gpio"
|
||||
The following <soc>s are known to be supported:
|
||||
mpc5121, mpc5125, mpc8349, mpc8572, mpc8610, pq3, qoriq,
|
||||
ls1021a, ls1043a, ls2080a.
|
||||
ls1021a, ls1043a, ls2080a, ls1028a, ls1088a.
|
||||
- reg : Address and length of the register set for the device
|
||||
- interrupts : Should be the port interrupt shared by all 32 pins.
|
||||
- #gpio-cells : Should be two. The first cell is the pin number and
|
||||
|
@ -37,3 +37,17 @@ gpio0: gpio@2300000 {
|
|||
interrupt-controller;
|
||||
#interrupt-cells = <2>;
|
||||
};
|
||||
|
||||
|
||||
Example of gpio-controller node for a ls1028a/ls1088a SoC:
|
||||
|
||||
gpio1: gpio@2300000 {
|
||||
compatible = "fsl,ls1028a-gpio", "fsl,ls1088a-gpio", "fsl,qoriq-gpio";
|
||||
reg = <0x0 0x2300000 0x0 0x10000>;
|
||||
interrupts = <GIC_SPI 36 IRQ_TYPE_LEVEL_HIGH>;
|
||||
gpio-controller;
|
||||
#gpio-cells = <2>;
|
||||
interrupt-controller;
|
||||
#interrupt-cells = <2>;
|
||||
little-endian;
|
||||
};
|
||||
|
|
|
@ -0,0 +1,45 @@
|
|||
Aspeed SGPIO controller Device Tree Bindings
|
||||
--------------------------------------------
|
||||
|
||||
This SGPIO controller is for ASPEED AST2500 SoC, it supports up to 80 full
|
||||
featured Serial GPIOs. Each of the Serial GPIO pins can be programmed to
|
||||
support the following options:
|
||||
- Support interrupt option for each input port and various interrupt
|
||||
sensitivity option (level-high, level-low, edge-high, edge-low)
|
||||
- Support reset tolerance option for each output port
|
||||
- Directly connected to APB bus and its shift clock is from APB bus clock
|
||||
divided by a programmable value.
|
||||
- Co-work with external signal-chained TTL components (74LV165/74LV595)
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible : Should be one of
|
||||
"aspeed,ast2400-sgpio", "aspeed,ast2500-sgpio"
|
||||
- #gpio-cells : Should be 2, see gpio.txt
|
||||
- reg : Address and length of the register set for the device
|
||||
- gpio-controller : Marks the device node as a GPIO controller
|
||||
- interrupts : Interrupt specifier, see interrupt-controller/interrupts.txt
|
||||
- interrupt-controller : Mark the GPIO controller as an interrupt-controller
|
||||
- ngpios : number of GPIO lines, see gpio.txt
|
||||
(should be multiple of 8, up to 80 pins)
|
||||
- clocks : A phandle to the APB clock for SGPM clock division
|
||||
- bus-frequency : SGPM CLK frequency
|
||||
|
||||
The sgpio and interrupt properties are further described in their respective
|
||||
bindings documentation:
|
||||
|
||||
- Documentation/devicetree/bindings/gpio/gpio.txt
|
||||
- Documentation/devicetree/bindings/interrupt-controller/interrupts.txt
|
||||
|
||||
Example:
|
||||
sgpio: sgpio@1e780200 {
|
||||
#gpio-cells = <2>;
|
||||
compatible = "aspeed,ast2500-sgpio";
|
||||
gpio-controller;
|
||||
interrupts = <40>;
|
||||
reg = <0x1e780200 0x0100>;
|
||||
clocks = <&syscon ASPEED_CLK_APB>;
|
||||
interrupt-controller;
|
||||
ngpios = <8>;
|
||||
bus-frequency = <12000000>;
|
||||
};
|
|
@ -69,9 +69,9 @@ driver code:
|
|||
|
||||
The code implementing a gpio_chip should support multiple instances of the
|
||||
controller, preferably using the driver model. That code will configure each
|
||||
gpio_chip and issue ``gpiochip_add[_data]()`` or ``devm_gpiochip_add_data()``.
|
||||
Removing a GPIO controller should be rare; use ``[devm_]gpiochip_remove()``
|
||||
when it is unavoidable.
|
||||
gpio_chip and issue gpiochip_add(), gpiochip_add_data(), or
|
||||
devm_gpiochip_add_data(). Removing a GPIO controller should be rare; use
|
||||
gpiochip_remove() when it is unavoidable.
|
||||
|
||||
Often a gpio_chip is part of an instance-specific structure with states not
|
||||
exposed by the GPIO interfaces, such as addressing, power management, and more.
|
||||
|
@ -259,7 +259,7 @@ most often cascaded off a parent interrupt controller, and in some special
|
|||
cases the GPIO logic is melded with a SoC's primary interrupt controller.
|
||||
|
||||
The IRQ portions of the GPIO block are implemented using an irq_chip, using
|
||||
the header <linux/irq.h>. So basically such a driver is utilizing two sub-
|
||||
the header <linux/irq.h>. So this combined driver is utilizing two sub-
|
||||
systems simultaneously: gpio and irq.
|
||||
|
||||
It is legal for any IRQ consumer to request an IRQ from any irqchip even if it
|
||||
|
@ -391,25 +391,119 @@ Infrastructure helpers for GPIO irqchips
|
|||
----------------------------------------
|
||||
|
||||
To help out in handling the set-up and management of GPIO irqchips and the
|
||||
associated irqdomain and resource allocation callbacks, the gpiolib has
|
||||
some helpers that can be enabled by selecting the GPIOLIB_IRQCHIP Kconfig
|
||||
symbol:
|
||||
associated irqdomain and resource allocation callbacks. These are activated
|
||||
by selecting the Kconfig symbol GPIOLIB_IRQCHIP. If the symbol
|
||||
IRQ_DOMAIN_HIERARCHY is also selected, hierarchical helpers will also be
|
||||
provided. A big portion of overhead code will be managed by gpiolib,
|
||||
under the assumption that your interrupts are 1-to-1-mapped to the
|
||||
GPIO line index:
|
||||
|
||||
- gpiochip_irqchip_add(): adds a chained cascaded irqchip to a gpiochip. It
|
||||
will pass the struct gpio_chip* for the chip to all IRQ callbacks, so the
|
||||
callbacks need to embed the gpio_chip in its state container and obtain a
|
||||
pointer to the container using container_of().
|
||||
(See Documentation/driver-api/driver-model/design-patterns.rst)
|
||||
GPIO line offset Hardware IRQ
|
||||
0 0
|
||||
1 1
|
||||
2 2
|
||||
... ...
|
||||
ngpio-1 ngpio-1
|
||||
|
||||
If some GPIO lines do not have corresponding IRQs, the bitmask valid_mask
|
||||
and the flag need_valid_mask in gpio_irq_chip can be used to mask off some
|
||||
lines as invalid for associating with IRQs.
|
||||
|
||||
The preferred way to set up the helpers is to fill in the
|
||||
struct gpio_irq_chip inside struct gpio_chip before adding the gpio_chip.
|
||||
If you do this, the additional irq_chip will be set up by gpiolib at the
|
||||
same time as setting up the rest of the GPIO functionality. The following
|
||||
is a typical example of a cascaded interrupt handler using gpio_irq_chip:
|
||||
|
||||
/* Typical state container with dynamic irqchip */
|
||||
struct my_gpio {
|
||||
struct gpio_chip gc;
|
||||
struct irq_chip irq;
|
||||
};
|
||||
|
||||
int irq; /* from platform etc */
|
||||
struct my_gpio *g;
|
||||
struct gpio_irq_chip *girq;
|
||||
|
||||
/* Set up the irqchip dynamically */
|
||||
g->irq.name = "my_gpio_irq";
|
||||
g->irq.irq_ack = my_gpio_ack_irq;
|
||||
g->irq.irq_mask = my_gpio_mask_irq;
|
||||
g->irq.irq_unmask = my_gpio_unmask_irq;
|
||||
g->irq.irq_set_type = my_gpio_set_irq_type;
|
||||
|
||||
/* Get a pointer to the gpio_irq_chip */
|
||||
girq = &g->gc.irq;
|
||||
girq->chip = &g->irq;
|
||||
girq->parent_handler = ftgpio_gpio_irq_handler;
|
||||
girq->num_parents = 1;
|
||||
girq->parents = devm_kcalloc(dev, 1, sizeof(*girq->parents),
|
||||
GFP_KERNEL);
|
||||
if (!girq->parents)
|
||||
return -ENOMEM;
|
||||
girq->default_type = IRQ_TYPE_NONE;
|
||||
girq->handler = handle_bad_irq;
|
||||
girq->parents[0] = irq;
|
||||
|
||||
return devm_gpiochip_add_data(dev, &g->gc, g);
|
||||
|
||||
The helper support using hierarchical interrupt controllers as well.
|
||||
In this case the typical set-up will look like this:
|
||||
|
||||
/* Typical state container with dynamic irqchip */
|
||||
struct my_gpio {
|
||||
struct gpio_chip gc;
|
||||
struct irq_chip irq;
|
||||
struct fwnode_handle *fwnode;
|
||||
};
|
||||
|
||||
int irq; /* from platform etc */
|
||||
struct my_gpio *g;
|
||||
struct gpio_irq_chip *girq;
|
||||
|
||||
/* Set up the irqchip dynamically */
|
||||
g->irq.name = "my_gpio_irq";
|
||||
g->irq.irq_ack = my_gpio_ack_irq;
|
||||
g->irq.irq_mask = my_gpio_mask_irq;
|
||||
g->irq.irq_unmask = my_gpio_unmask_irq;
|
||||
g->irq.irq_set_type = my_gpio_set_irq_type;
|
||||
|
||||
/* Get a pointer to the gpio_irq_chip */
|
||||
girq = &g->gc.irq;
|
||||
girq->chip = &g->irq;
|
||||
girq->default_type = IRQ_TYPE_NONE;
|
||||
girq->handler = handle_bad_irq;
|
||||
girq->fwnode = g->fwnode;
|
||||
girq->parent_domain = parent;
|
||||
girq->child_to_parent_hwirq = my_gpio_child_to_parent_hwirq;
|
||||
|
||||
return devm_gpiochip_add_data(dev, &g->gc, g);
|
||||
|
||||
As you can see pretty similar, but you do not supply a parent handler for
|
||||
the IRQ, instead a parent irqdomain, an fwnode for the hardware and
|
||||
a funcion .child_to_parent_hwirq() that has the purpose of looking up
|
||||
the parent hardware irq from a child (i.e. this gpio chip) hardware irq.
|
||||
As always it is good to look at examples in the kernel tree for advice
|
||||
on how to find the required pieces.
|
||||
|
||||
The old way of adding irqchips to gpiochips after registration is also still
|
||||
available but we try to move away from this:
|
||||
|
||||
- DEPRECATED: gpiochip_irqchip_add(): adds a chained cascaded irqchip to a
|
||||
gpiochip. It will pass the struct gpio_chip* for the chip to all IRQ
|
||||
callbacks, so the callbacks need to embed the gpio_chip in its state
|
||||
container and obtain a pointer to the container using container_of().
|
||||
(See Documentation/driver-model/design-patterns.txt)
|
||||
|
||||
- gpiochip_irqchip_add_nested(): adds a nested cascaded irqchip to a gpiochip,
|
||||
as discussed above regarding different types of cascaded irqchips. The
|
||||
cascaded irq has to be handled by a threaded interrupt handler.
|
||||
Apart from that it works exactly like the chained irqchip.
|
||||
|
||||
- gpiochip_set_chained_irqchip(): sets up a chained cascaded irq handler for a
|
||||
gpio_chip from a parent IRQ and passes the struct gpio_chip* as handler
|
||||
data. Notice that we pass is as the handler data, since the irqchip data is
|
||||
likely used by the parent irqchip.
|
||||
- DEPRECATED: gpiochip_set_chained_irqchip(): sets up a chained cascaded irq
|
||||
handler for a gpio_chip from a parent IRQ and passes the struct gpio_chip*
|
||||
as handler data. Notice that we pass is as the handler data, since the
|
||||
irqchip data is likely used by the parent irqchip.
|
||||
|
||||
- gpiochip_set_nested_irqchip(): sets up a nested cascaded irq handler for a
|
||||
gpio_chip from a parent IRQ. As the parent IRQ has usually been
|
||||
|
@ -418,11 +512,11 @@ symbol:
|
|||
|
||||
If there is a need to exclude certain GPIO lines from the IRQ domain handled by
|
||||
these helpers, we can set .irq.need_valid_mask of the gpiochip before
|
||||
``[devm_]gpiochip_add_data()`` is called. This allocates an .irq.valid_mask with as
|
||||
many bits set as there are GPIO lines in the chip, each bit representing line
|
||||
0..n-1. Drivers can exclude GPIO lines by clearing bits from this mask. The mask
|
||||
must be filled in before gpiochip_irqchip_add() or gpiochip_irqchip_add_nested()
|
||||
is called.
|
||||
devm_gpiochip_add_data() or gpiochip_add_data() is called. This allocates an
|
||||
.irq.valid_mask with as many bits set as there are GPIO lines in the chip, each
|
||||
bit representing line 0..n-1. Drivers can exclude GPIO lines by clearing bits
|
||||
from this mask. The mask must be filled in before gpiochip_irqchip_add() or
|
||||
gpiochip_irqchip_add_nested() is called.
|
||||
|
||||
To use the helpers please keep the following in mind:
|
||||
|
||||
|
|
15
MAINTAINERS
15
MAINTAINERS
|
@ -6329,15 +6329,6 @@ S: Odd Fixes
|
|||
L: linux-block@vger.kernel.org
|
||||
F: drivers/block/floppy.c
|
||||
|
||||
FMC SUBSYSTEM
|
||||
M: Alessandro Rubini <rubini@gnudd.com>
|
||||
W: http://www.ohwr.org/projects/fmc-bus
|
||||
S: Supported
|
||||
F: drivers/fmc/
|
||||
F: include/linux/fmc*.h
|
||||
F: include/linux/ipmi-fru.h
|
||||
K: fmc_d.*register
|
||||
|
||||
FPGA MANAGER FRAMEWORK
|
||||
M: Moritz Fischer <mdf@kernel.org>
|
||||
L: linux-fpga@vger.kernel.org
|
||||
|
@ -8383,12 +8374,6 @@ F: Documentation/x86/intel_txt.rst
|
|||
F: include/linux/tboot.h
|
||||
F: arch/x86/kernel/tboot.c
|
||||
|
||||
INTEL-MID GPIO DRIVER
|
||||
M: David Cohen <david.a.cohen@linux.intel.com>
|
||||
L: linux-gpio@vger.kernel.org
|
||||
S: Maintained
|
||||
F: drivers/gpio/gpio-intel-mid.c
|
||||
|
||||
INTERCONNECT API
|
||||
M: Georgi Djakov <georgi.djakov@linaro.org>
|
||||
L: linux-pm@vger.kernel.org
|
||||
|
|
|
@ -93,6 +93,7 @@ CONFIG_SERIAL_HS_LPC32XX_CONSOLE=y
|
|||
# CONFIG_HW_RANDOM is not set
|
||||
CONFIG_I2C_CHARDEV=y
|
||||
CONFIG_I2C_PNX=y
|
||||
CONFIG_GPIO_LPC32XX=y
|
||||
CONFIG_SPI=y
|
||||
CONFIG_SPI_PL022=y
|
||||
CONFIG_GPIO_SYSFS=y
|
||||
|
|
|
@ -21,7 +21,6 @@
|
|||
#include <linux/kallsyms.h>
|
||||
#include <linux/proc_fs.h>
|
||||
#include <linux/syscore_ops.h>
|
||||
#include <linux/gpio.h>
|
||||
|
||||
#include <mach/hardware.h>
|
||||
|
||||
|
|
|
@ -288,7 +288,7 @@ config GPIO_IXP4XX
|
|||
depends on ARM # For <asm/mach-types.h>
|
||||
depends on ARCH_IXP4XX
|
||||
select GPIO_GENERIC
|
||||
select IRQ_DOMAIN
|
||||
select GPIOLIB_IRQCHIP
|
||||
select IRQ_DOMAIN_HIERARCHY
|
||||
help
|
||||
Say yes here to support the GPIO functionality of a number of Intel
|
||||
|
@ -311,6 +311,13 @@ config GPIO_LPC18XX
|
|||
Select this option to enable GPIO driver for
|
||||
NXP LPC18XX/43XX devices.
|
||||
|
||||
config GPIO_LPC32XX
|
||||
tristate "NXP LPC32XX GPIO support"
|
||||
depends on OF_GPIO && (ARCH_LPC32XX || COMPILE_TEST)
|
||||
help
|
||||
Select this option to enable GPIO driver for
|
||||
NXP LPC32XX devices.
|
||||
|
||||
config GPIO_LYNXPOINT
|
||||
tristate "Intel Lynxpoint GPIO support"
|
||||
depends on ACPI && X86
|
||||
|
@ -539,6 +546,7 @@ config GPIO_THUNDERX
|
|||
tristate "Cavium ThunderX/OCTEON-TX GPIO"
|
||||
depends on ARCH_THUNDER || (64BIT && COMPILE_TEST)
|
||||
depends on PCI_MSI
|
||||
select GPIOLIB_IRQCHIP
|
||||
select IRQ_DOMAIN_HIERARCHY
|
||||
select IRQ_FASTEOI_HIERARCHY_HANDLERS
|
||||
help
|
||||
|
@ -1465,7 +1473,6 @@ endmenu
|
|||
|
||||
config GPIO_MOCKUP
|
||||
tristate "GPIO Testing Driver"
|
||||
depends on GPIOLIB
|
||||
select IRQ_SIM
|
||||
help
|
||||
This enables GPIO Testing driver, which provides a way to test GPIO
|
||||
|
|
|
@ -67,14 +67,13 @@ obj-$(CONFIG_GPIO_IT87) += gpio-it87.o
|
|||
obj-$(CONFIG_GPIO_IXP4XX) += gpio-ixp4xx.o
|
||||
obj-$(CONFIG_GPIO_JANZ_TTL) += gpio-janz-ttl.o
|
||||
obj-$(CONFIG_GPIO_KEMPLD) += gpio-kempld.o
|
||||
obj-$(CONFIG_ARCH_KS8695) += gpio-ks8695.o
|
||||
obj-$(CONFIG_GPIO_LOONGSON1) += gpio-loongson1.o
|
||||
obj-$(CONFIG_GPIO_LOONGSON) += gpio-loongson.o
|
||||
obj-$(CONFIG_GPIO_LP3943) += gpio-lp3943.o
|
||||
obj-$(CONFIG_GPIO_LP873X) += gpio-lp873x.o
|
||||
obj-$(CONFIG_GPIO_LP87565) += gpio-lp87565.o
|
||||
obj-$(CONFIG_GPIO_LPC18XX) += gpio-lpc18xx.o
|
||||
obj-$(CONFIG_ARCH_LPC32XX) += gpio-lpc32xx.o
|
||||
obj-$(CONFIG_GPIO_LPC32XX) += gpio-lpc32xx.o
|
||||
obj-$(CONFIG_GPIO_LYNXPOINT) += gpio-lynxpoint.o
|
||||
obj-$(CONFIG_GPIO_MADERA) += gpio-madera.o
|
||||
obj-$(CONFIG_GPIO_MAX3191X) += gpio-max3191x.o
|
||||
|
|
|
@ -142,7 +142,7 @@ static const struct gpio_chip template_chip = {
|
|||
static int arizona_gpio_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct arizona *arizona = dev_get_drvdata(pdev->dev.parent);
|
||||
struct arizona_pdata *pdata = dev_get_platdata(arizona->dev);
|
||||
struct arizona_pdata *pdata = &arizona->pdata;
|
||||
struct arizona_gpio *arizona_gpio;
|
||||
int ret;
|
||||
|
||||
|
@ -177,7 +177,7 @@ static int arizona_gpio_probe(struct platform_device *pdev)
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (pdata && pdata->gpio_base)
|
||||
if (pdata->gpio_base)
|
||||
arizona_gpio->gpio_chip.base = pdata->gpio_base;
|
||||
else
|
||||
arizona_gpio->gpio_chip.base = -1;
|
||||
|
|
|
@ -52,6 +52,7 @@ struct aspeed_gpio_config {
|
|||
*/
|
||||
struct aspeed_gpio {
|
||||
struct gpio_chip chip;
|
||||
struct irq_chip irqc;
|
||||
spinlock_t lock;
|
||||
void __iomem *base;
|
||||
int irq;
|
||||
|
@ -661,12 +662,14 @@ static void aspeed_gpio_irq_handler(struct irq_desc *desc)
|
|||
struct gpio_chip *gc = irq_desc_get_handler_data(desc);
|
||||
struct irq_chip *ic = irq_desc_get_chip(desc);
|
||||
struct aspeed_gpio *data = gpiochip_get_data(gc);
|
||||
unsigned int i, p, girq;
|
||||
unsigned int i, p, girq, banks;
|
||||
unsigned long reg;
|
||||
struct aspeed_gpio *gpio = gpiochip_get_data(gc);
|
||||
|
||||
chained_irq_enter(ic, desc);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(aspeed_gpio_banks); i++) {
|
||||
banks = DIV_ROUND_UP(gpio->chip.ngpio, 32);
|
||||
for (i = 0; i < banks; i++) {
|
||||
const struct aspeed_gpio_bank *bank = &aspeed_gpio_banks[i];
|
||||
|
||||
reg = ioread32(bank_reg(data, bank, reg_irq_status));
|
||||
|
@ -681,16 +684,11 @@ static void aspeed_gpio_irq_handler(struct irq_desc *desc)
|
|||
chained_irq_exit(ic, desc);
|
||||
}
|
||||
|
||||
static struct irq_chip aspeed_gpio_irqchip = {
|
||||
.name = "aspeed-gpio",
|
||||
.irq_ack = aspeed_gpio_irq_ack,
|
||||
.irq_mask = aspeed_gpio_irq_mask,
|
||||
.irq_unmask = aspeed_gpio_irq_unmask,
|
||||
.irq_set_type = aspeed_gpio_set_type,
|
||||
};
|
||||
|
||||
static void set_irq_valid_mask(struct aspeed_gpio *gpio)
|
||||
static void aspeed_init_irq_valid_mask(struct gpio_chip *gc,
|
||||
unsigned long *valid_mask,
|
||||
unsigned int ngpios)
|
||||
{
|
||||
struct aspeed_gpio *gpio = gpiochip_get_data(gc);
|
||||
const struct aspeed_bank_props *props = gpio->config->props;
|
||||
|
||||
while (!is_bank_props_sentinel(props)) {
|
||||
|
@ -701,42 +699,16 @@ static void set_irq_valid_mask(struct aspeed_gpio *gpio)
|
|||
for_each_clear_bit(offset, &input, 32) {
|
||||
unsigned int i = props->bank * 32 + offset;
|
||||
|
||||
if (i >= gpio->config->nr_gpios)
|
||||
if (i >= gpio->chip.ngpio)
|
||||
break;
|
||||
|
||||
clear_bit(i, gpio->chip.irq.valid_mask);
|
||||
clear_bit(i, valid_mask);
|
||||
}
|
||||
|
||||
props++;
|
||||
}
|
||||
}
|
||||
|
||||
static int aspeed_gpio_setup_irqs(struct aspeed_gpio *gpio,
|
||||
struct platform_device *pdev)
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = platform_get_irq(pdev, 0);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
gpio->irq = rc;
|
||||
|
||||
set_irq_valid_mask(gpio);
|
||||
|
||||
rc = gpiochip_irqchip_add(&gpio->chip, &aspeed_gpio_irqchip,
|
||||
0, handle_bad_irq, IRQ_TYPE_NONE);
|
||||
if (rc) {
|
||||
dev_info(&pdev->dev, "Could not add irqchip\n");
|
||||
return rc;
|
||||
}
|
||||
|
||||
gpiochip_set_chained_irqchip(&gpio->chip, &aspeed_gpio_irqchip,
|
||||
gpio->irq, aspeed_gpio_irq_handler);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int aspeed_gpio_reset_tolerance(struct gpio_chip *chip,
|
||||
unsigned int offset, bool enable)
|
||||
{
|
||||
|
@ -1040,10 +1012,10 @@ int aspeed_gpio_copro_grab_gpio(struct gpio_desc *desc,
|
|||
unsigned long flags;
|
||||
|
||||
if (!gpio->cf_copro_bankmap)
|
||||
gpio->cf_copro_bankmap = kzalloc(gpio->config->nr_gpios >> 3, GFP_KERNEL);
|
||||
gpio->cf_copro_bankmap = kzalloc(gpio->chip.ngpio >> 3, GFP_KERNEL);
|
||||
if (!gpio->cf_copro_bankmap)
|
||||
return -ENOMEM;
|
||||
if (offset < 0 || offset > gpio->config->nr_gpios)
|
||||
if (offset < 0 || offset > gpio->chip.ngpio)
|
||||
return -EINVAL;
|
||||
bindex = offset >> 3;
|
||||
|
||||
|
@ -1088,7 +1060,7 @@ int aspeed_gpio_copro_release_gpio(struct gpio_desc *desc)
|
|||
if (!gpio->cf_copro_bankmap)
|
||||
return -ENXIO;
|
||||
|
||||
if (offset < 0 || offset > gpio->config->nr_gpios)
|
||||
if (offset < 0 || offset > gpio->chip.ngpio)
|
||||
return -EINVAL;
|
||||
bindex = offset >> 3;
|
||||
|
||||
|
@ -1141,9 +1113,25 @@ static const struct aspeed_gpio_config ast2500_config =
|
|||
/* 232 for simplicity, actual number is 228 (4-GPIO hole in GPIOAB) */
|
||||
{ .nr_gpios = 232, .props = ast2500_bank_props, };
|
||||
|
||||
static const struct aspeed_bank_props ast2600_bank_props[] = {
|
||||
/* input output */
|
||||
{5, 0xffffffff, 0x0000ffff}, /* U/V/W/X */
|
||||
{6, 0xffff0000, 0x0fff0000}, /* Y/Z */
|
||||
{ },
|
||||
};
|
||||
|
||||
static const struct aspeed_gpio_config ast2600_config =
|
||||
/*
|
||||
* ast2600 has two controllers one with 208 GPIOs and one with 36 GPIOs.
|
||||
* We expect ngpio being set in the device tree and this is a fallback
|
||||
* option.
|
||||
*/
|
||||
{ .nr_gpios = 208, .props = ast2600_bank_props, };
|
||||
|
||||
static const struct of_device_id aspeed_gpio_of_table[] = {
|
||||
{ .compatible = "aspeed,ast2400-gpio", .data = &ast2400_config, },
|
||||
{ .compatible = "aspeed,ast2500-gpio", .data = &ast2500_config, },
|
||||
{ .compatible = "aspeed,ast2600-gpio", .data = &ast2600_config, },
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, aspeed_gpio_of_table);
|
||||
|
@ -1152,7 +1140,8 @@ static int __init aspeed_gpio_probe(struct platform_device *pdev)
|
|||
{
|
||||
const struct of_device_id *gpio_id;
|
||||
struct aspeed_gpio *gpio;
|
||||
int rc, i, banks;
|
||||
int rc, i, banks, err;
|
||||
u32 ngpio;
|
||||
|
||||
gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL);
|
||||
if (!gpio)
|
||||
|
@ -1178,7 +1167,10 @@ static int __init aspeed_gpio_probe(struct platform_device *pdev)
|
|||
gpio->config = gpio_id->data;
|
||||
|
||||
gpio->chip.parent = &pdev->dev;
|
||||
gpio->chip.ngpio = gpio->config->nr_gpios;
|
||||
err = of_property_read_u32(pdev->dev.of_node, "ngpios", &ngpio);
|
||||
gpio->chip.ngpio = (u16) ngpio;
|
||||
if (err)
|
||||
gpio->chip.ngpio = gpio->config->nr_gpios;
|
||||
gpio->chip.direction_input = aspeed_gpio_dir_in;
|
||||
gpio->chip.direction_output = aspeed_gpio_dir_out;
|
||||
gpio->chip.get_direction = aspeed_gpio_get_direction;
|
||||
|
@ -1189,10 +1181,9 @@ 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;
|
||||
|
||||
/* Allocate a cache of the output registers */
|
||||
banks = gpio->config->nr_gpios >> 5;
|
||||
banks = DIV_ROUND_UP(gpio->chip.ngpio, 32);
|
||||
gpio->dcache = devm_kcalloc(&pdev->dev,
|
||||
banks, sizeof(u32), GFP_KERNEL);
|
||||
if (!gpio->dcache)
|
||||
|
@ -1212,16 +1203,42 @@ static int __init aspeed_gpio_probe(struct platform_device *pdev)
|
|||
aspeed_gpio_change_cmd_source(gpio, bank, 3, GPIO_CMDSRC_ARM);
|
||||
}
|
||||
|
||||
rc = devm_gpiochip_add_data(&pdev->dev, &gpio->chip, gpio);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
/* Optionally set up an irqchip if there is an IRQ */
|
||||
rc = platform_get_irq(pdev, 0);
|
||||
if (rc > 0) {
|
||||
struct gpio_irq_chip *girq;
|
||||
|
||||
gpio->irq = rc;
|
||||
girq = &gpio->chip.irq;
|
||||
girq->chip = &gpio->irqc;
|
||||
girq->chip->name = dev_name(&pdev->dev);
|
||||
girq->chip->irq_ack = aspeed_gpio_irq_ack;
|
||||
girq->chip->irq_mask = aspeed_gpio_irq_mask;
|
||||
girq->chip->irq_unmask = aspeed_gpio_irq_unmask;
|
||||
girq->chip->irq_set_type = aspeed_gpio_set_type;
|
||||
girq->parent_handler = aspeed_gpio_irq_handler;
|
||||
girq->num_parents = 1;
|
||||
girq->parents = devm_kcalloc(&pdev->dev, 1,
|
||||
sizeof(*girq->parents),
|
||||
GFP_KERNEL);
|
||||
if (!girq->parents)
|
||||
return -ENOMEM;
|
||||
girq->parents[0] = gpio->irq;
|
||||
girq->default_type = IRQ_TYPE_NONE;
|
||||
girq->handler = handle_bad_irq;
|
||||
girq->init_valid_mask = aspeed_init_irq_valid_mask;
|
||||
}
|
||||
|
||||
gpio->offset_timer =
|
||||
devm_kzalloc(&pdev->dev, gpio->chip.ngpio, GFP_KERNEL);
|
||||
if (!gpio->offset_timer)
|
||||
return -ENOMEM;
|
||||
|
||||
return aspeed_gpio_setup_irqs(gpio, pdev);
|
||||
rc = devm_gpiochip_add_data(&pdev->dev, &gpio->chip, gpio);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver aspeed_gpio_driver = {
|
||||
|
|
|
@ -36,7 +36,7 @@ static int bd70528_set_debounce(struct bd70528_gpio *bdgpio,
|
|||
break;
|
||||
default:
|
||||
dev_err(bdgpio->chip.dev,
|
||||
"Invalid debouce value %u\n", debounce);
|
||||
"Invalid debounce value %u\n", debounce);
|
||||
return -EINVAL;
|
||||
}
|
||||
return regmap_update_bits(bdgpio->chip.regmap, GPIO_IN_REG(offset),
|
||||
|
@ -153,7 +153,7 @@ static int bd70528_gpio_get_i(struct bd70528_gpio *bdgpio, unsigned int offset)
|
|||
|
||||
static int bd70528_gpio_get(struct gpio_chip *chip, unsigned int offset)
|
||||
{
|
||||
int ret = -EINVAL;
|
||||
int ret;
|
||||
struct bd70528_gpio *bdgpio = gpiochip_get_data(chip);
|
||||
|
||||
/*
|
||||
|
|
|
@ -636,10 +636,8 @@ static int brcmstb_gpio_probe(struct platform_device *pdev)
|
|||
|
||||
if (of_property_read_bool(np, "interrupt-controller")) {
|
||||
priv->parent_irq = platform_get_irq(pdev, 0);
|
||||
if (priv->parent_irq <= 0) {
|
||||
dev_err(dev, "Couldn't get IRQ");
|
||||
if (priv->parent_irq <= 0)
|
||||
return -ENOENT;
|
||||
}
|
||||
} else {
|
||||
priv->parent_irq = -ENOENT;
|
||||
}
|
||||
|
|
|
@ -214,29 +214,35 @@ static int cdns_gpio_probe(struct platform_device *pdev)
|
|||
goto err_revert_dir;
|
||||
}
|
||||
|
||||
/*
|
||||
* Optional irq_chip support
|
||||
*/
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq >= 0) {
|
||||
struct gpio_irq_chip *girq;
|
||||
|
||||
girq = &cgpio->gc.irq;
|
||||
girq->chip = &cdns_gpio_irqchip;
|
||||
girq->parent_handler = cdns_gpio_irq_handler;
|
||||
girq->num_parents = 1;
|
||||
girq->parents = devm_kcalloc(&pdev->dev, 1,
|
||||
sizeof(*girq->parents),
|
||||
GFP_KERNEL);
|
||||
if (!girq->parents) {
|
||||
ret = -ENOMEM;
|
||||
goto err_disable_clk;
|
||||
}
|
||||
girq->parents[0] = irq;
|
||||
girq->default_type = IRQ_TYPE_NONE;
|
||||
girq->handler = handle_level_irq;
|
||||
}
|
||||
|
||||
ret = devm_gpiochip_add_data(&pdev->dev, &cgpio->gc, cgpio);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "Could not register gpiochip, %d\n", ret);
|
||||
goto err_disable_clk;
|
||||
}
|
||||
|
||||
/*
|
||||
* irq_chip support
|
||||
*/
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq >= 0) {
|
||||
ret = gpiochip_irqchip_add(&cgpio->gc, &cdns_gpio_irqchip,
|
||||
0, handle_level_irq,
|
||||
IRQ_TYPE_NONE);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "Could not add irqchip, %d\n",
|
||||
ret);
|
||||
goto err_disable_clk;
|
||||
}
|
||||
gpiochip_set_chained_irqchip(&cgpio->gc, &cdns_gpio_irqchip,
|
||||
irq, cdns_gpio_irq_handler);
|
||||
}
|
||||
|
||||
cgpio->bypass_orig = ioread32(cgpio->regs + CDNS_GPIO_BYPASS_MODE);
|
||||
|
||||
/*
|
||||
|
|
|
@ -137,7 +137,6 @@ static int creg_gpio_probe(struct platform_device *pdev)
|
|||
const struct of_device_id *match;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct creg_gpio *hcg;
|
||||
struct resource *mem;
|
||||
u32 ngpios;
|
||||
int ret;
|
||||
|
||||
|
@ -145,8 +144,7 @@ static int creg_gpio_probe(struct platform_device *pdev)
|
|||
if (!hcg)
|
||||
return -ENOMEM;
|
||||
|
||||
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
hcg->regs = devm_ioremap_resource(dev, mem);
|
||||
hcg->regs = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(hcg->regs))
|
||||
return PTR_ERR(hcg->regs);
|
||||
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
#include <linux/slab.h>
|
||||
|
||||
#include "gpiolib.h"
|
||||
#include "gpiolib-acpi.h"
|
||||
|
||||
#define GPIO_SWPORTA_DR 0x00
|
||||
#define GPIO_SWPORTA_DDR 0x04
|
||||
|
|
|
@ -584,10 +584,8 @@ static int sprd_eic_probe(struct platform_device *pdev)
|
|||
sprd_eic->type = pdata->type;
|
||||
|
||||
sprd_eic->irq = platform_get_irq(pdev, 0);
|
||||
if (sprd_eic->irq < 0) {
|
||||
dev_err(&pdev->dev, "Failed to get EIC interrupt.\n");
|
||||
if (sprd_eic->irq < 0)
|
||||
return sprd_eic->irq;
|
||||
}
|
||||
|
||||
for (i = 0; i < SPRD_EIC_MAX_BANK; i++) {
|
||||
/*
|
||||
|
|
|
@ -272,11 +272,12 @@ static int em_gio_probe(struct platform_device *pdev)
|
|||
struct resource *io[2], *irq[2];
|
||||
struct gpio_chip *gpio_chip;
|
||||
struct irq_chip *irq_chip;
|
||||
const char *name = dev_name(&pdev->dev);
|
||||
struct device *dev = &pdev->dev;
|
||||
const char *name = dev_name(dev);
|
||||
unsigned int ngpios;
|
||||
int ret;
|
||||
|
||||
p = devm_kzalloc(&pdev->dev, sizeof(*p), GFP_KERNEL);
|
||||
p = devm_kzalloc(dev, sizeof(*p), GFP_KERNEL);
|
||||
if (!p)
|
||||
return -ENOMEM;
|
||||
|
||||
|
@ -290,27 +291,27 @@ static int em_gio_probe(struct platform_device *pdev)
|
|||
irq[1] = platform_get_resource(pdev, IORESOURCE_IRQ, 1);
|
||||
|
||||
if (!io[0] || !io[1] || !irq[0] || !irq[1]) {
|
||||
dev_err(&pdev->dev, "missing IRQ or IOMEM\n");
|
||||
dev_err(dev, "missing IRQ or IOMEM\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
p->base0 = devm_ioremap_nocache(&pdev->dev, io[0]->start,
|
||||
p->base0 = devm_ioremap_nocache(dev, io[0]->start,
|
||||
resource_size(io[0]));
|
||||
if (!p->base0)
|
||||
return -ENOMEM;
|
||||
|
||||
p->base1 = devm_ioremap_nocache(&pdev->dev, io[1]->start,
|
||||
p->base1 = devm_ioremap_nocache(dev, io[1]->start,
|
||||
resource_size(io[1]));
|
||||
if (!p->base1)
|
||||
return -ENOMEM;
|
||||
|
||||
if (of_property_read_u32(pdev->dev.of_node, "ngpios", &ngpios)) {
|
||||
dev_err(&pdev->dev, "Missing ngpios OF property\n");
|
||||
if (of_property_read_u32(dev->of_node, "ngpios", &ngpios)) {
|
||||
dev_err(dev, "Missing ngpios OF property\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
gpio_chip = &p->gpio_chip;
|
||||
gpio_chip->of_node = pdev->dev.of_node;
|
||||
gpio_chip->of_node = dev->of_node;
|
||||
gpio_chip->direction_input = em_gio_direction_input;
|
||||
gpio_chip->get = em_gio_get;
|
||||
gpio_chip->direction_output = em_gio_direction_output;
|
||||
|
@ -319,7 +320,7 @@ static int em_gio_probe(struct platform_device *pdev)
|
|||
gpio_chip->request = em_gio_request;
|
||||
gpio_chip->free = em_gio_free;
|
||||
gpio_chip->label = name;
|
||||
gpio_chip->parent = &pdev->dev;
|
||||
gpio_chip->parent = dev;
|
||||
gpio_chip->owner = THIS_MODULE;
|
||||
gpio_chip->base = -1;
|
||||
gpio_chip->ngpio = ngpios;
|
||||
|
@ -333,33 +334,33 @@ static int em_gio_probe(struct platform_device *pdev)
|
|||
irq_chip->irq_release_resources = em_gio_irq_relres;
|
||||
irq_chip->flags = IRQCHIP_SKIP_SET_WAKE | IRQCHIP_MASK_ON_SUSPEND;
|
||||
|
||||
p->irq_domain = irq_domain_add_simple(pdev->dev.of_node, ngpios, 0,
|
||||
p->irq_domain = irq_domain_add_simple(dev->of_node, ngpios, 0,
|
||||
&em_gio_irq_domain_ops, p);
|
||||
if (!p->irq_domain) {
|
||||
dev_err(&pdev->dev, "cannot initialize irq domain\n");
|
||||
dev_err(dev, "cannot initialize irq domain\n");
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
ret = devm_add_action_or_reset(&pdev->dev, em_gio_irq_domain_remove,
|
||||
ret = devm_add_action_or_reset(dev, em_gio_irq_domain_remove,
|
||||
p->irq_domain);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (devm_request_irq(&pdev->dev, irq[0]->start,
|
||||
if (devm_request_irq(dev, irq[0]->start,
|
||||
em_gio_irq_handler, 0, name, p)) {
|
||||
dev_err(&pdev->dev, "failed to request low IRQ\n");
|
||||
dev_err(dev, "failed to request low IRQ\n");
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
if (devm_request_irq(&pdev->dev, irq[1]->start,
|
||||
if (devm_request_irq(dev, irq[1]->start,
|
||||
em_gio_irq_handler, 0, name, p)) {
|
||||
dev_err(&pdev->dev, "failed to request high IRQ\n");
|
||||
dev_err(dev, "failed to request high IRQ\n");
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
ret = devm_gpiochip_add_data(&pdev->dev, gpio_chip, p);
|
||||
ret = devm_gpiochip_add_data(dev, gpio_chip, p);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "failed to add GPIO controller\n");
|
||||
dev_err(dev, "failed to add GPIO controller\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
|
@ -269,56 +269,6 @@ static struct irq_chip ep93xx_gpio_irq_chip = {
|
|||
.irq_set_type = ep93xx_gpio_irq_type,
|
||||
};
|
||||
|
||||
static int ep93xx_gpio_init_irq(struct platform_device *pdev,
|
||||
struct ep93xx_gpio *epg)
|
||||
{
|
||||
int ab_parent_irq = platform_get_irq(pdev, 0);
|
||||
struct device *dev = &pdev->dev;
|
||||
int gpio_irq;
|
||||
int ret;
|
||||
int i;
|
||||
|
||||
/* The A bank */
|
||||
ret = gpiochip_irqchip_add(&epg->gc[0], &ep93xx_gpio_irq_chip,
|
||||
64, handle_level_irq,
|
||||
IRQ_TYPE_NONE);
|
||||
if (ret) {
|
||||
dev_err(dev, "Could not add irqchip 0\n");
|
||||
return ret;
|
||||
}
|
||||
gpiochip_set_chained_irqchip(&epg->gc[0], &ep93xx_gpio_irq_chip,
|
||||
ab_parent_irq,
|
||||
ep93xx_gpio_ab_irq_handler);
|
||||
|
||||
/* The B bank */
|
||||
ret = gpiochip_irqchip_add(&epg->gc[1], &ep93xx_gpio_irq_chip,
|
||||
72, handle_level_irq,
|
||||
IRQ_TYPE_NONE);
|
||||
if (ret) {
|
||||
dev_err(dev, "Could not add irqchip 1\n");
|
||||
return ret;
|
||||
}
|
||||
gpiochip_set_chained_irqchip(&epg->gc[1], &ep93xx_gpio_irq_chip,
|
||||
ab_parent_irq,
|
||||
ep93xx_gpio_ab_irq_handler);
|
||||
|
||||
/* The F bank */
|
||||
for (i = 0; i < 8; i++) {
|
||||
gpio_irq = EP93XX_GPIO_F_IRQ_BASE + i;
|
||||
irq_set_chip_data(gpio_irq, &epg->gc[5]);
|
||||
irq_set_chip_and_handler(gpio_irq, &ep93xx_gpio_irq_chip,
|
||||
handle_level_irq);
|
||||
irq_clear_status_flags(gpio_irq, IRQ_NOREQUEST);
|
||||
}
|
||||
|
||||
for (i = 1; i <= 8; i++)
|
||||
irq_set_chained_handler_and_data(platform_get_irq(pdev, i),
|
||||
ep93xx_gpio_f_irq_handler,
|
||||
&epg->gc[i]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*************************************************************************
|
||||
* gpiolib interface for EP93xx on-chip GPIOs
|
||||
*************************************************************************/
|
||||
|
@ -328,26 +278,33 @@ struct ep93xx_gpio_bank {
|
|||
int dir;
|
||||
int base;
|
||||
bool has_irq;
|
||||
bool has_hierarchical_irq;
|
||||
unsigned int irq_base;
|
||||
};
|
||||
|
||||
#define EP93XX_GPIO_BANK(_label, _data, _dir, _base, _has_irq) \
|
||||
#define EP93XX_GPIO_BANK(_label, _data, _dir, _base, _has_irq, _has_hier, _irq_base) \
|
||||
{ \
|
||||
.label = _label, \
|
||||
.data = _data, \
|
||||
.dir = _dir, \
|
||||
.base = _base, \
|
||||
.has_irq = _has_irq, \
|
||||
.has_hierarchical_irq = _has_hier, \
|
||||
.irq_base = _irq_base, \
|
||||
}
|
||||
|
||||
static struct ep93xx_gpio_bank ep93xx_gpio_banks[] = {
|
||||
EP93XX_GPIO_BANK("A", 0x00, 0x10, 0, true), /* Bank A has 8 IRQs */
|
||||
EP93XX_GPIO_BANK("B", 0x04, 0x14, 8, true), /* Bank B has 8 IRQs */
|
||||
EP93XX_GPIO_BANK("C", 0x08, 0x18, 40, false),
|
||||
EP93XX_GPIO_BANK("D", 0x0c, 0x1c, 24, false),
|
||||
EP93XX_GPIO_BANK("E", 0x20, 0x24, 32, false),
|
||||
EP93XX_GPIO_BANK("F", 0x30, 0x34, 16, true), /* Bank F has 8 IRQs */
|
||||
EP93XX_GPIO_BANK("G", 0x38, 0x3c, 48, false),
|
||||
EP93XX_GPIO_BANK("H", 0x40, 0x44, 56, false),
|
||||
/* Bank A has 8 IRQs */
|
||||
EP93XX_GPIO_BANK("A", 0x00, 0x10, 0, true, false, 64),
|
||||
/* Bank B has 8 IRQs */
|
||||
EP93XX_GPIO_BANK("B", 0x04, 0x14, 8, true, false, 72),
|
||||
EP93XX_GPIO_BANK("C", 0x08, 0x18, 40, false, false, 0),
|
||||
EP93XX_GPIO_BANK("D", 0x0c, 0x1c, 24, false, false, 0),
|
||||
EP93XX_GPIO_BANK("E", 0x20, 0x24, 32, false, false, 0),
|
||||
/* Bank F has 8 IRQs */
|
||||
EP93XX_GPIO_BANK("F", 0x30, 0x34, 16, false, true, 0),
|
||||
EP93XX_GPIO_BANK("G", 0x38, 0x3c, 48, false, false, 0),
|
||||
EP93XX_GPIO_BANK("H", 0x40, 0x44, 56, false, false, 0),
|
||||
};
|
||||
|
||||
static int ep93xx_gpio_set_config(struct gpio_chip *gc, unsigned offset,
|
||||
|
@ -369,12 +326,15 @@ static int ep93xx_gpio_f_to_irq(struct gpio_chip *gc, unsigned offset)
|
|||
return EP93XX_GPIO_F_IRQ_BASE + offset;
|
||||
}
|
||||
|
||||
static int ep93xx_gpio_add_bank(struct gpio_chip *gc, struct device *dev,
|
||||
static int ep93xx_gpio_add_bank(struct gpio_chip *gc,
|
||||
struct platform_device *pdev,
|
||||
struct ep93xx_gpio *epg,
|
||||
struct ep93xx_gpio_bank *bank)
|
||||
{
|
||||
void __iomem *data = epg->base + bank->data;
|
||||
void __iomem *dir = epg->base + bank->dir;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct gpio_irq_chip *girq;
|
||||
int err;
|
||||
|
||||
err = bgpio_init(gc, dev, 1, data, NULL, NULL, dir, NULL, 0);
|
||||
|
@ -384,8 +344,59 @@ static int ep93xx_gpio_add_bank(struct gpio_chip *gc, struct device *dev,
|
|||
gc->label = bank->label;
|
||||
gc->base = bank->base;
|
||||
|
||||
if (bank->has_irq)
|
||||
girq = &gc->irq;
|
||||
if (bank->has_irq || bank->has_hierarchical_irq) {
|
||||
gc->set_config = ep93xx_gpio_set_config;
|
||||
girq->chip = &ep93xx_gpio_irq_chip;
|
||||
}
|
||||
|
||||
if (bank->has_irq) {
|
||||
int ab_parent_irq = platform_get_irq(pdev, 0);
|
||||
|
||||
girq->parent_handler = ep93xx_gpio_ab_irq_handler;
|
||||
girq->num_parents = 1;
|
||||
girq->parents = devm_kcalloc(dev, 1,
|
||||
sizeof(*girq->parents),
|
||||
GFP_KERNEL);
|
||||
if (!girq->parents)
|
||||
return -ENOMEM;
|
||||
girq->default_type = IRQ_TYPE_NONE;
|
||||
girq->handler = handle_level_irq;
|
||||
girq->parents[0] = ab_parent_irq;
|
||||
girq->first = bank->irq_base;
|
||||
}
|
||||
|
||||
/* Only bank F has especially funky IRQ handling */
|
||||
if (bank->has_hierarchical_irq) {
|
||||
int gpio_irq;
|
||||
int i;
|
||||
|
||||
/*
|
||||
* FIXME: convert this to use hierarchical IRQ support!
|
||||
* this requires fixing the root irqchip to be hierarchial.
|
||||
*/
|
||||
girq->parent_handler = ep93xx_gpio_f_irq_handler;
|
||||
girq->num_parents = 8;
|
||||
girq->parents = devm_kcalloc(dev, 8,
|
||||
sizeof(*girq->parents),
|
||||
GFP_KERNEL);
|
||||
if (!girq->parents)
|
||||
return -ENOMEM;
|
||||
/* Pick resources 1..8 for these IRQs */
|
||||
for (i = 1; i <= 8; i++)
|
||||
girq->parents[i - 1] = platform_get_irq(pdev, i);
|
||||
for (i = 0; i < 8; i++) {
|
||||
gpio_irq = EP93XX_GPIO_F_IRQ_BASE + i;
|
||||
irq_set_chip_data(gpio_irq, &epg->gc[5]);
|
||||
irq_set_chip_and_handler(gpio_irq,
|
||||
&ep93xx_gpio_irq_chip,
|
||||
handle_level_irq);
|
||||
irq_clear_status_flags(gpio_irq, IRQ_NOREQUEST);
|
||||
}
|
||||
girq->default_type = IRQ_TYPE_NONE;
|
||||
girq->handler = handle_level_irq;
|
||||
gc->to_irq = ep93xx_gpio_f_to_irq;
|
||||
}
|
||||
|
||||
return devm_gpiochip_add_data(dev, gc, epg);
|
||||
}
|
||||
|
@ -407,16 +418,11 @@ static int ep93xx_gpio_probe(struct platform_device *pdev)
|
|||
struct gpio_chip *gc = &epg->gc[i];
|
||||
struct ep93xx_gpio_bank *bank = &ep93xx_gpio_banks[i];
|
||||
|
||||
if (ep93xx_gpio_add_bank(gc, &pdev->dev, epg, bank))
|
||||
if (ep93xx_gpio_add_bank(gc, pdev, epg, bank))
|
||||
dev_warn(&pdev->dev, "Unable to add gpio bank %s\n",
|
||||
bank->label);
|
||||
/* Only bank F has especially funky IRQ handling */
|
||||
if (i == 5)
|
||||
gc->to_irq = ep93xx_gpio_f_to_irq;
|
||||
}
|
||||
|
||||
ep93xx_gpio_init_irq(pdev, epg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -290,16 +290,14 @@ static int ftgpio_gpio_probe(struct platform_device *pdev)
|
|||
girq->num_parents = 1;
|
||||
girq->parents = devm_kcalloc(dev, 1, sizeof(*girq->parents),
|
||||
GFP_KERNEL);
|
||||
if (!girq->parents)
|
||||
return -ENOMEM;
|
||||
if (!girq->parents) {
|
||||
ret = -ENOMEM;
|
||||
goto dis_clk;
|
||||
}
|
||||
girq->default_type = IRQ_TYPE_NONE;
|
||||
girq->handler = handle_bad_irq;
|
||||
girq->parents[0] = irq;
|
||||
|
||||
ret = devm_gpiochip_add_data(dev, &g->gc, g);
|
||||
if (ret)
|
||||
goto dis_clk;
|
||||
|
||||
/* Disable, unmask and clear all interrupts */
|
||||
writel(0x0, g->base + GPIO_INT_EN);
|
||||
writel(0x0, g->base + GPIO_INT_MASK);
|
||||
|
@ -308,6 +306,10 @@ static int ftgpio_gpio_probe(struct platform_device *pdev)
|
|||
/* Clear any use of debounce */
|
||||
writel(0x0, g->base + GPIO_DEBOUNCE_EN);
|
||||
|
||||
ret = devm_gpiochip_add_data(dev, &g->gc, g);
|
||||
if (ret)
|
||||
goto dis_clk;
|
||||
|
||||
platform_set_drvdata(pdev, g);
|
||||
dev_info(dev, "FTGPIO010 @%p registered\n", g->base);
|
||||
|
||||
|
|
|
@ -408,8 +408,6 @@ static int grgpio_probe(struct platform_device *ofdev)
|
|||
* Continue without irq functionality for that
|
||||
* gpio line
|
||||
*/
|
||||
dev_err(priv->dev,
|
||||
"Failed to get irq for offset %d\n", i);
|
||||
continue;
|
||||
}
|
||||
priv->uirqs[lirq->index].uirq = ret;
|
||||
|
|
|
@ -244,43 +244,45 @@ static int hlwd_gpio_probe(struct platform_device *pdev)
|
|||
ngpios = 32;
|
||||
hlwd->gpioc.ngpio = ngpios;
|
||||
|
||||
res = devm_gpiochip_add_data(&pdev->dev, &hlwd->gpioc, hlwd);
|
||||
if (res)
|
||||
return res;
|
||||
|
||||
/* Mask and ack all interrupts */
|
||||
iowrite32be(0, hlwd->regs + HW_GPIOB_INTMASK);
|
||||
iowrite32be(0xffffffff, hlwd->regs + HW_GPIOB_INTFLAG);
|
||||
|
||||
/*
|
||||
* If this GPIO controller is not marked as an interrupt controller in
|
||||
* the DT, return.
|
||||
* the DT, skip interrupt support.
|
||||
*/
|
||||
if (!of_property_read_bool(pdev->dev.of_node, "interrupt-controller"))
|
||||
return 0;
|
||||
if (of_property_read_bool(pdev->dev.of_node, "interrupt-controller")) {
|
||||
struct gpio_irq_chip *girq;
|
||||
|
||||
hlwd->irq = platform_get_irq(pdev, 0);
|
||||
if (hlwd->irq < 0) {
|
||||
dev_info(&pdev->dev, "platform_get_irq returned %d\n",
|
||||
hlwd->irq);
|
||||
return hlwd->irq;
|
||||
hlwd->irq = platform_get_irq(pdev, 0);
|
||||
if (hlwd->irq < 0) {
|
||||
dev_info(&pdev->dev, "platform_get_irq returned %d\n",
|
||||
hlwd->irq);
|
||||
return hlwd->irq;
|
||||
}
|
||||
|
||||
hlwd->irqc.name = dev_name(&pdev->dev);
|
||||
hlwd->irqc.irq_mask = hlwd_gpio_irq_mask;
|
||||
hlwd->irqc.irq_unmask = hlwd_gpio_irq_unmask;
|
||||
hlwd->irqc.irq_enable = hlwd_gpio_irq_enable;
|
||||
hlwd->irqc.irq_set_type = hlwd_gpio_irq_set_type;
|
||||
|
||||
girq = &hlwd->gpioc.irq;
|
||||
girq->chip = &hlwd->irqc;
|
||||
girq->parent_handler = hlwd_gpio_irqhandler;
|
||||
girq->num_parents = 1;
|
||||
girq->parents = devm_kcalloc(&pdev->dev, 1,
|
||||
sizeof(*girq->parents),
|
||||
GFP_KERNEL);
|
||||
if (!girq->parents)
|
||||
return -ENOMEM;
|
||||
girq->parents[0] = hlwd->irq;
|
||||
girq->default_type = IRQ_TYPE_NONE;
|
||||
girq->handler = handle_level_irq;
|
||||
}
|
||||
|
||||
hlwd->irqc.name = dev_name(&pdev->dev);
|
||||
hlwd->irqc.irq_mask = hlwd_gpio_irq_mask;
|
||||
hlwd->irqc.irq_unmask = hlwd_gpio_irq_unmask;
|
||||
hlwd->irqc.irq_enable = hlwd_gpio_irq_enable;
|
||||
hlwd->irqc.irq_set_type = hlwd_gpio_irq_set_type;
|
||||
|
||||
res = gpiochip_irqchip_add(&hlwd->gpioc, &hlwd->irqc, 0,
|
||||
handle_level_irq, IRQ_TYPE_NONE);
|
||||
if (res)
|
||||
return res;
|
||||
|
||||
gpiochip_set_chained_irqchip(&hlwd->gpioc, &hlwd->irqc,
|
||||
hlwd->irq, hlwd_gpio_irqhandler);
|
||||
|
||||
return 0;
|
||||
return devm_gpiochip_add_data(&pdev->dev, &hlwd->gpioc, hlwd);
|
||||
}
|
||||
|
||||
static const struct of_device_id hlwd_gpio_match[] = {
|
||||
|
|
|
@ -118,20 +118,6 @@ static void egpio_handler(struct irq_desc *desc)
|
|||
}
|
||||
}
|
||||
|
||||
int htc_egpio_get_wakeup_irq(struct device *dev)
|
||||
{
|
||||
struct egpio_info *ei = dev_get_drvdata(dev);
|
||||
|
||||
/* Read current pins. */
|
||||
u16 readval = egpio_readw(ei, ei->ack_register);
|
||||
/* Ack/unmask interrupts. */
|
||||
ack_irqs(ei);
|
||||
/* Return first set pin. */
|
||||
readval &= ei->irqs_enabled;
|
||||
return ei->irq_start + ffs(readval) - 1;
|
||||
}
|
||||
EXPORT_SYMBOL(htc_egpio_get_wakeup_irq);
|
||||
|
||||
static inline int egpio_pos(struct egpio_info *ei, int bit)
|
||||
{
|
||||
return bit >> ei->reg_shift;
|
||||
|
|
|
@ -329,6 +329,7 @@ static int intel_gpio_probe(struct pci_dev *pdev,
|
|||
u32 gpio_base;
|
||||
u32 irq_base;
|
||||
int retval;
|
||||
struct gpio_irq_chip *girq;
|
||||
struct intel_mid_gpio_ddata *ddata =
|
||||
(struct intel_mid_gpio_ddata *)id->driver_data;
|
||||
|
||||
|
@ -369,6 +370,22 @@ static int intel_gpio_probe(struct pci_dev *pdev,
|
|||
|
||||
spin_lock_init(&priv->lock);
|
||||
|
||||
girq = &priv->chip.irq;
|
||||
girq->chip = &intel_mid_irqchip;
|
||||
girq->parent_handler = intel_mid_irq_handler;
|
||||
girq->num_parents = 1;
|
||||
girq->parents = devm_kcalloc(&pdev->dev, girq->num_parents,
|
||||
sizeof(*girq->parents),
|
||||
GFP_KERNEL);
|
||||
if (!girq->parents)
|
||||
return -ENOMEM;
|
||||
girq->parents[0] = pdev->irq;
|
||||
girq->first = irq_base;
|
||||
girq->default_type = IRQ_TYPE_NONE;
|
||||
girq->handler = handle_simple_irq;
|
||||
|
||||
intel_mid_irq_init_hw(priv);
|
||||
|
||||
pci_set_drvdata(pdev, priv);
|
||||
retval = devm_gpiochip_add_data(&pdev->dev, &priv->chip, priv);
|
||||
if (retval) {
|
||||
|
@ -376,24 +393,6 @@ static int intel_gpio_probe(struct pci_dev *pdev,
|
|||
return retval;
|
||||
}
|
||||
|
||||
retval = gpiochip_irqchip_add(&priv->chip,
|
||||
&intel_mid_irqchip,
|
||||
irq_base,
|
||||
handle_simple_irq,
|
||||
IRQ_TYPE_NONE);
|
||||
if (retval) {
|
||||
dev_err(&pdev->dev,
|
||||
"could not connect irqchip to gpiochip\n");
|
||||
return retval;
|
||||
}
|
||||
|
||||
intel_mid_irq_init_hw(priv);
|
||||
|
||||
gpiochip_set_chained_irqchip(&priv->chip,
|
||||
&intel_mid_irqchip,
|
||||
pdev->irq,
|
||||
intel_mid_irq_handler);
|
||||
|
||||
pm_runtime_put_noidle(&pdev->dev);
|
||||
pm_runtime_allow(&pdev->dev);
|
||||
|
||||
|
|
|
@ -47,7 +47,6 @@
|
|||
* @dev: containing device for this instance
|
||||
* @fwnode: the fwnode for this GPIO chip
|
||||
* @gc: gpiochip for this instance
|
||||
* @domain: irqdomain for this chip instance
|
||||
* @base: remapped I/O-memory base
|
||||
* @irq_edge: Each bit represents an IRQ: 1: edge-triggered,
|
||||
* 0: level triggered
|
||||
|
@ -56,48 +55,22 @@ struct ixp4xx_gpio {
|
|||
struct device *dev;
|
||||
struct fwnode_handle *fwnode;
|
||||
struct gpio_chip gc;
|
||||
struct irq_domain *domain;
|
||||
void __iomem *base;
|
||||
unsigned long long irq_edge;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct ixp4xx_gpio_map - IXP4 GPIO to parent IRQ map
|
||||
* @gpio_offset: offset of the IXP4 GPIO line
|
||||
* @parent_hwirq: hwirq on the parent IRQ controller
|
||||
*/
|
||||
struct ixp4xx_gpio_map {
|
||||
int gpio_offset;
|
||||
int parent_hwirq;
|
||||
};
|
||||
|
||||
/* GPIO lines 0..12 have corresponding IRQs, GPIOs 13..15 have no IRQs */
|
||||
const struct ixp4xx_gpio_map ixp4xx_gpiomap[] = {
|
||||
{ .gpio_offset = 0, .parent_hwirq = 6 },
|
||||
{ .gpio_offset = 1, .parent_hwirq = 7 },
|
||||
{ .gpio_offset = 2, .parent_hwirq = 19 },
|
||||
{ .gpio_offset = 3, .parent_hwirq = 20 },
|
||||
{ .gpio_offset = 4, .parent_hwirq = 21 },
|
||||
{ .gpio_offset = 5, .parent_hwirq = 22 },
|
||||
{ .gpio_offset = 6, .parent_hwirq = 23 },
|
||||
{ .gpio_offset = 7, .parent_hwirq = 24 },
|
||||
{ .gpio_offset = 8, .parent_hwirq = 25 },
|
||||
{ .gpio_offset = 9, .parent_hwirq = 26 },
|
||||
{ .gpio_offset = 10, .parent_hwirq = 27 },
|
||||
{ .gpio_offset = 11, .parent_hwirq = 28 },
|
||||
{ .gpio_offset = 12, .parent_hwirq = 29 },
|
||||
};
|
||||
|
||||
static void ixp4xx_gpio_irq_ack(struct irq_data *d)
|
||||
{
|
||||
struct ixp4xx_gpio *g = irq_data_get_irq_chip_data(d);
|
||||
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
|
||||
struct ixp4xx_gpio *g = gpiochip_get_data(gc);
|
||||
|
||||
__raw_writel(BIT(d->hwirq), g->base + IXP4XX_REG_GPIS);
|
||||
}
|
||||
|
||||
static void ixp4xx_gpio_irq_unmask(struct irq_data *d)
|
||||
{
|
||||
struct ixp4xx_gpio *g = irq_data_get_irq_chip_data(d);
|
||||
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
|
||||
struct ixp4xx_gpio *g = gpiochip_get_data(gc);
|
||||
|
||||
/* ACK when unmasking if not edge-triggered */
|
||||
if (!(g->irq_edge & BIT(d->hwirq)))
|
||||
|
@ -108,7 +81,8 @@ static void ixp4xx_gpio_irq_unmask(struct irq_data *d)
|
|||
|
||||
static int ixp4xx_gpio_irq_set_type(struct irq_data *d, unsigned int type)
|
||||
{
|
||||
struct ixp4xx_gpio *g = irq_data_get_irq_chip_data(d);
|
||||
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
|
||||
struct ixp4xx_gpio *g = gpiochip_get_data(gc);
|
||||
int line = d->hwirq;
|
||||
unsigned long flags;
|
||||
u32 int_style;
|
||||
|
@ -187,122 +161,31 @@ static struct irq_chip ixp4xx_gpio_irqchip = {
|
|||
.irq_set_type = ixp4xx_gpio_irq_set_type,
|
||||
};
|
||||
|
||||
static int ixp4xx_gpio_to_irq(struct gpio_chip *gc, unsigned int offset)
|
||||
static int ixp4xx_gpio_child_to_parent_hwirq(struct gpio_chip *gc,
|
||||
unsigned int child,
|
||||
unsigned int child_type,
|
||||
unsigned int *parent,
|
||||
unsigned int *parent_type)
|
||||
{
|
||||
struct ixp4xx_gpio *g = gpiochip_get_data(gc);
|
||||
struct irq_fwspec fwspec;
|
||||
/* All these interrupts are level high in the CPU */
|
||||
*parent_type = IRQ_TYPE_LEVEL_HIGH;
|
||||
|
||||
fwspec.fwnode = g->fwnode;
|
||||
fwspec.param_count = 2;
|
||||
fwspec.param[0] = offset;
|
||||
fwspec.param[1] = IRQ_TYPE_NONE;
|
||||
|
||||
return irq_create_fwspec_mapping(&fwspec);
|
||||
}
|
||||
|
||||
static int ixp4xx_gpio_irq_domain_translate(struct irq_domain *domain,
|
||||
struct irq_fwspec *fwspec,
|
||||
unsigned long *hwirq,
|
||||
unsigned int *type)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/* We support standard DT translation */
|
||||
if (is_of_node(fwspec->fwnode) && fwspec->param_count == 2) {
|
||||
return irq_domain_translate_twocell(domain, fwspec,
|
||||
hwirq, type);
|
||||
/* GPIO lines 0..12 have dedicated IRQs */
|
||||
if (child == 0) {
|
||||
*parent = 6;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* This goes away when we transition to DT */
|
||||
if (is_fwnode_irqchip(fwspec->fwnode)) {
|
||||
ret = irq_domain_translate_twocell(domain, fwspec,
|
||||
hwirq, type);
|
||||
if (ret)
|
||||
return ret;
|
||||
WARN_ON(*type == IRQ_TYPE_NONE);
|
||||
if (child == 1) {
|
||||
*parent = 7;
|
||||
return 0;
|
||||
}
|
||||
if (child >= 2 && child <= 12) {
|
||||
*parent = child + 17;
|
||||
return 0;
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int ixp4xx_gpio_irq_domain_alloc(struct irq_domain *d,
|
||||
unsigned int irq, unsigned int nr_irqs,
|
||||
void *data)
|
||||
{
|
||||
struct ixp4xx_gpio *g = d->host_data;
|
||||
irq_hw_number_t hwirq;
|
||||
unsigned int type = IRQ_TYPE_NONE;
|
||||
struct irq_fwspec *fwspec = data;
|
||||
int ret;
|
||||
int i;
|
||||
|
||||
ret = ixp4xx_gpio_irq_domain_translate(d, fwspec, &hwirq, &type);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
dev_dbg(g->dev, "allocate IRQ %d..%d, hwirq %lu..%lu\n",
|
||||
irq, irq + nr_irqs - 1,
|
||||
hwirq, hwirq + nr_irqs - 1);
|
||||
|
||||
for (i = 0; i < nr_irqs; i++) {
|
||||
struct irq_fwspec parent_fwspec;
|
||||
const struct ixp4xx_gpio_map *map;
|
||||
int j;
|
||||
|
||||
/* Not all lines support IRQs */
|
||||
for (j = 0; j < ARRAY_SIZE(ixp4xx_gpiomap); j++) {
|
||||
map = &ixp4xx_gpiomap[j];
|
||||
if (map->gpio_offset == hwirq)
|
||||
break;
|
||||
}
|
||||
if (j == ARRAY_SIZE(ixp4xx_gpiomap)) {
|
||||
dev_err(g->dev, "can't look up hwirq %lu\n", hwirq);
|
||||
return -EINVAL;
|
||||
}
|
||||
dev_dbg(g->dev, "found parent hwirq %u\n", map->parent_hwirq);
|
||||
|
||||
/*
|
||||
* We set handle_bad_irq because the .set_type() should
|
||||
* always be invoked and set the right type of handler.
|
||||
*/
|
||||
irq_domain_set_info(d,
|
||||
irq + i,
|
||||
hwirq + i,
|
||||
&ixp4xx_gpio_irqchip,
|
||||
g,
|
||||
handle_bad_irq,
|
||||
NULL, NULL);
|
||||
irq_set_probe(irq + i);
|
||||
|
||||
/*
|
||||
* Create a IRQ fwspec to send up to the parent irqdomain:
|
||||
* specify the hwirq we address on the parent and tie it
|
||||
* all together up the chain.
|
||||
*/
|
||||
parent_fwspec.fwnode = d->parent->fwnode;
|
||||
parent_fwspec.param_count = 2;
|
||||
parent_fwspec.param[0] = map->parent_hwirq;
|
||||
/* This parent only handles asserted level IRQs */
|
||||
parent_fwspec.param[1] = IRQ_TYPE_LEVEL_HIGH;
|
||||
dev_dbg(g->dev, "alloc_irqs_parent for %d parent hwirq %d\n",
|
||||
irq + i, map->parent_hwirq);
|
||||
ret = irq_domain_alloc_irqs_parent(d, irq + i, 1,
|
||||
&parent_fwspec);
|
||||
if (ret)
|
||||
dev_err(g->dev,
|
||||
"failed to allocate parent hwirq %d for hwirq %lu\n",
|
||||
map->parent_hwirq, hwirq);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct irq_domain_ops ixp4xx_gpio_irqdomain_ops = {
|
||||
.translate = ixp4xx_gpio_irq_domain_translate,
|
||||
.alloc = ixp4xx_gpio_irq_domain_alloc,
|
||||
.free = irq_domain_free_irqs_common,
|
||||
};
|
||||
|
||||
static int ixp4xx_gpio_probe(struct platform_device *pdev)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
@ -311,8 +194,8 @@ static int ixp4xx_gpio_probe(struct platform_device *pdev)
|
|||
struct irq_domain *parent;
|
||||
struct resource *res;
|
||||
struct ixp4xx_gpio *g;
|
||||
struct gpio_irq_chip *girq;
|
||||
int ret;
|
||||
int i;
|
||||
|
||||
g = devm_kzalloc(dev, sizeof(*g), GFP_KERNEL);
|
||||
if (!g)
|
||||
|
@ -321,9 +204,36 @@ static int ixp4xx_gpio_probe(struct platform_device *pdev)
|
|||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
g->base = devm_ioremap_resource(dev, res);
|
||||
if (IS_ERR(g->base)) {
|
||||
dev_err(dev, "ioremap error\n");
|
||||
if (IS_ERR(g->base))
|
||||
return PTR_ERR(g->base);
|
||||
|
||||
/*
|
||||
* When we convert to device tree we will simply look up the
|
||||
* parent irqdomain using irq_find_host(parent) as parent comes
|
||||
* from IRQCHIP_DECLARE(), then use of_node_to_fwnode() to get
|
||||
* the fwnode. For now we need this boardfile style code.
|
||||
*/
|
||||
if (np) {
|
||||
struct device_node *irq_parent;
|
||||
|
||||
irq_parent = of_irq_find_parent(np);
|
||||
if (!irq_parent) {
|
||||
dev_err(dev, "no IRQ parent node\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
parent = irq_find_host(irq_parent);
|
||||
if (!parent) {
|
||||
dev_err(dev, "no IRQ parent domain\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
g->fwnode = of_node_to_fwnode(np);
|
||||
} else {
|
||||
parent = ixp4xx_get_irq_domain();
|
||||
g->fwnode = irq_domain_alloc_fwnode(&res->start);
|
||||
if (!g->fwnode) {
|
||||
dev_err(dev, "no domain base\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -360,7 +270,6 @@ static int ixp4xx_gpio_probe(struct platform_device *pdev)
|
|||
dev_err(dev, "unable to init generic GPIO\n");
|
||||
return ret;
|
||||
}
|
||||
g->gc.to_irq = ixp4xx_gpio_to_irq;
|
||||
g->gc.ngpio = 16;
|
||||
g->gc.label = "IXP4XX_GPIO_CHIP";
|
||||
/*
|
||||
|
@ -372,86 +281,22 @@ static int ixp4xx_gpio_probe(struct platform_device *pdev)
|
|||
g->gc.parent = &pdev->dev;
|
||||
g->gc.owner = THIS_MODULE;
|
||||
|
||||
girq = &g->gc.irq;
|
||||
girq->chip = &ixp4xx_gpio_irqchip;
|
||||
girq->fwnode = g->fwnode;
|
||||
girq->parent_domain = parent;
|
||||
girq->child_to_parent_hwirq = ixp4xx_gpio_child_to_parent_hwirq;
|
||||
girq->handler = handle_bad_irq;
|
||||
girq->default_type = IRQ_TYPE_NONE;
|
||||
|
||||
ret = devm_gpiochip_add_data(dev, &g->gc, g);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to add SoC gpiochip\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* When we convert to device tree we will simply look up the
|
||||
* parent irqdomain using irq_find_host(parent) as parent comes
|
||||
* from IRQCHIP_DECLARE(), then use of_node_to_fwnode() to get
|
||||
* the fwnode. For now we need this boardfile style code.
|
||||
*/
|
||||
if (np) {
|
||||
struct device_node *irq_parent;
|
||||
|
||||
irq_parent = of_irq_find_parent(np);
|
||||
if (!irq_parent) {
|
||||
dev_err(dev, "no IRQ parent node\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
parent = irq_find_host(irq_parent);
|
||||
if (!parent) {
|
||||
dev_err(dev, "no IRQ parent domain\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
g->fwnode = of_node_to_fwnode(np);
|
||||
} else {
|
||||
parent = ixp4xx_get_irq_domain();
|
||||
g->fwnode = irq_domain_alloc_fwnode(g->base);
|
||||
if (!g->fwnode) {
|
||||
dev_err(dev, "no domain base\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
}
|
||||
g->domain = irq_domain_create_hierarchy(parent,
|
||||
IRQ_DOMAIN_FLAG_HIERARCHY,
|
||||
ARRAY_SIZE(ixp4xx_gpiomap),
|
||||
g->fwnode,
|
||||
&ixp4xx_gpio_irqdomain_ops,
|
||||
g);
|
||||
if (!g->domain) {
|
||||
irq_domain_free_fwnode(g->fwnode);
|
||||
dev_err(dev, "no hierarchical irq domain\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* After adding OF support, this is no longer needed: irqs
|
||||
* will be allocated for the respective fwnodes.
|
||||
*/
|
||||
if (!np) {
|
||||
for (i = 0; i < ARRAY_SIZE(ixp4xx_gpiomap); i++) {
|
||||
const struct ixp4xx_gpio_map *map = &ixp4xx_gpiomap[i];
|
||||
struct irq_fwspec fwspec;
|
||||
|
||||
fwspec.fwnode = g->fwnode;
|
||||
/* This is the hwirq for the GPIO line side of things */
|
||||
fwspec.param[0] = map->gpio_offset;
|
||||
fwspec.param[1] = IRQ_TYPE_EDGE_RISING;
|
||||
fwspec.param_count = 2;
|
||||
ret = __irq_domain_alloc_irqs(g->domain,
|
||||
-1, /* just pick something */
|
||||
1,
|
||||
NUMA_NO_NODE,
|
||||
&fwspec,
|
||||
false,
|
||||
NULL);
|
||||
if (ret < 0) {
|
||||
irq_domain_free_fwnode(g->fwnode);
|
||||
dev_err(dev,
|
||||
"can not allocate irq for GPIO line %d parent hwirq %d in hierarchy domain: %d\n",
|
||||
map->gpio_offset, map->parent_hwirq,
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, g);
|
||||
dev_info(dev, "IXP4 GPIO @%p registered\n", g->base);
|
||||
dev_info(dev, "IXP4 GPIO registered\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -1,284 +0,0 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* arch/arm/mach-ks8695/gpio.c
|
||||
*
|
||||
* Copyright (C) 2006 Andrew Victor
|
||||
* Updated to GPIOLIB, Copyright 2008 Simtec Electronics
|
||||
* Daniel Silverstone <dsilvers@simtec.co.uk>
|
||||
*/
|
||||
#include <linux/gpio/driver.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/io.h>
|
||||
|
||||
#include <mach/hardware.h>
|
||||
#include <asm/mach/irq.h>
|
||||
|
||||
#include <mach/regs-gpio.h>
|
||||
#include <mach/gpio-ks8695.h>
|
||||
|
||||
/*
|
||||
* Configure a GPIO line for either GPIO function, or its internal
|
||||
* function (Interrupt, Timer, etc).
|
||||
*/
|
||||
static void ks8695_gpio_mode(unsigned int pin, short gpio)
|
||||
{
|
||||
unsigned int enable[] = { IOPC_IOEINT0EN, IOPC_IOEINT1EN, IOPC_IOEINT2EN, IOPC_IOEINT3EN, IOPC_IOTIM0EN, IOPC_IOTIM1EN };
|
||||
unsigned long x, flags;
|
||||
|
||||
if (pin > KS8695_GPIO_5) /* only GPIO 0..5 have internal functions */
|
||||
return;
|
||||
|
||||
local_irq_save(flags);
|
||||
|
||||
x = __raw_readl(KS8695_GPIO_VA + KS8695_IOPC);
|
||||
if (gpio) /* GPIO: set bit to 0 */
|
||||
x &= ~enable[pin];
|
||||
else /* Internal function: set bit to 1 */
|
||||
x |= enable[pin];
|
||||
__raw_writel(x, KS8695_GPIO_VA + KS8695_IOPC);
|
||||
|
||||
local_irq_restore(flags);
|
||||
}
|
||||
|
||||
|
||||
static unsigned short gpio_irq[] = { KS8695_IRQ_EXTERN0, KS8695_IRQ_EXTERN1, KS8695_IRQ_EXTERN2, KS8695_IRQ_EXTERN3 };
|
||||
|
||||
/*
|
||||
* Configure GPIO pin as external interrupt source.
|
||||
*/
|
||||
int ks8695_gpio_interrupt(unsigned int pin, unsigned int type)
|
||||
{
|
||||
unsigned long x, flags;
|
||||
|
||||
if (pin > KS8695_GPIO_3) /* only GPIO 0..3 can generate IRQ */
|
||||
return -EINVAL;
|
||||
|
||||
local_irq_save(flags);
|
||||
|
||||
/* set pin as input */
|
||||
x = __raw_readl(KS8695_GPIO_VA + KS8695_IOPM);
|
||||
x &= ~IOPM(pin);
|
||||
__raw_writel(x, KS8695_GPIO_VA + KS8695_IOPM);
|
||||
|
||||
local_irq_restore(flags);
|
||||
|
||||
/* Set IRQ triggering type */
|
||||
irq_set_irq_type(gpio_irq[pin], type);
|
||||
|
||||
/* enable interrupt mode */
|
||||
ks8695_gpio_mode(pin, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(ks8695_gpio_interrupt);
|
||||
|
||||
|
||||
|
||||
/* .... Generic GPIO interface .............................................. */
|
||||
|
||||
/*
|
||||
* Configure the GPIO line as an input.
|
||||
*/
|
||||
static int ks8695_gpio_direction_input(struct gpio_chip *gc, unsigned int pin)
|
||||
{
|
||||
unsigned long x, flags;
|
||||
|
||||
if (pin > KS8695_GPIO_15)
|
||||
return -EINVAL;
|
||||
|
||||
/* set pin to GPIO mode */
|
||||
ks8695_gpio_mode(pin, 1);
|
||||
|
||||
local_irq_save(flags);
|
||||
|
||||
/* set pin as input */
|
||||
x = __raw_readl(KS8695_GPIO_VA + KS8695_IOPM);
|
||||
x &= ~IOPM(pin);
|
||||
__raw_writel(x, KS8695_GPIO_VA + KS8695_IOPM);
|
||||
|
||||
local_irq_restore(flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Configure the GPIO line as an output, with default state.
|
||||
*/
|
||||
static int ks8695_gpio_direction_output(struct gpio_chip *gc,
|
||||
unsigned int pin, int state)
|
||||
{
|
||||
unsigned long x, flags;
|
||||
|
||||
if (pin > KS8695_GPIO_15)
|
||||
return -EINVAL;
|
||||
|
||||
/* set pin to GPIO mode */
|
||||
ks8695_gpio_mode(pin, 1);
|
||||
|
||||
local_irq_save(flags);
|
||||
|
||||
/* set line state */
|
||||
x = __raw_readl(KS8695_GPIO_VA + KS8695_IOPD);
|
||||
if (state)
|
||||
x |= IOPD(pin);
|
||||
else
|
||||
x &= ~IOPD(pin);
|
||||
__raw_writel(x, KS8695_GPIO_VA + KS8695_IOPD);
|
||||
|
||||
/* set pin as output */
|
||||
x = __raw_readl(KS8695_GPIO_VA + KS8695_IOPM);
|
||||
x |= IOPM(pin);
|
||||
__raw_writel(x, KS8695_GPIO_VA + KS8695_IOPM);
|
||||
|
||||
local_irq_restore(flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Set the state of an output GPIO line.
|
||||
*/
|
||||
static void ks8695_gpio_set_value(struct gpio_chip *gc,
|
||||
unsigned int pin, int state)
|
||||
{
|
||||
unsigned long x, flags;
|
||||
|
||||
if (pin > KS8695_GPIO_15)
|
||||
return;
|
||||
|
||||
local_irq_save(flags);
|
||||
|
||||
/* set output line state */
|
||||
x = __raw_readl(KS8695_GPIO_VA + KS8695_IOPD);
|
||||
if (state)
|
||||
x |= IOPD(pin);
|
||||
else
|
||||
x &= ~IOPD(pin);
|
||||
__raw_writel(x, KS8695_GPIO_VA + KS8695_IOPD);
|
||||
|
||||
local_irq_restore(flags);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Read the state of a GPIO line.
|
||||
*/
|
||||
static int ks8695_gpio_get_value(struct gpio_chip *gc, unsigned int pin)
|
||||
{
|
||||
unsigned long x;
|
||||
|
||||
if (pin > KS8695_GPIO_15)
|
||||
return -EINVAL;
|
||||
|
||||
x = __raw_readl(KS8695_GPIO_VA + KS8695_IOPD);
|
||||
return (x & IOPD(pin)) != 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Map GPIO line to IRQ number.
|
||||
*/
|
||||
static int ks8695_gpio_to_irq(struct gpio_chip *gc, unsigned int pin)
|
||||
{
|
||||
if (pin > KS8695_GPIO_3) /* only GPIO 0..3 can generate IRQ */
|
||||
return -EINVAL;
|
||||
|
||||
return gpio_irq[pin];
|
||||
}
|
||||
|
||||
/* GPIOLIB interface */
|
||||
|
||||
static struct gpio_chip ks8695_gpio_chip = {
|
||||
.label = "KS8695",
|
||||
.direction_input = ks8695_gpio_direction_input,
|
||||
.direction_output = ks8695_gpio_direction_output,
|
||||
.get = ks8695_gpio_get_value,
|
||||
.set = ks8695_gpio_set_value,
|
||||
.to_irq = ks8695_gpio_to_irq,
|
||||
.base = 0,
|
||||
.ngpio = 16,
|
||||
.can_sleep = false,
|
||||
};
|
||||
|
||||
/* Register the GPIOs */
|
||||
void ks8695_register_gpios(void)
|
||||
{
|
||||
if (gpiochip_add_data(&ks8695_gpio_chip, NULL))
|
||||
printk(KERN_ERR "Unable to register core GPIOs\n");
|
||||
}
|
||||
|
||||
/* .... Debug interface ..................................................... */
|
||||
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
|
||||
static int ks8695_gpio_show(struct seq_file *s, void *unused)
|
||||
{
|
||||
unsigned int enable[] = { IOPC_IOEINT0EN, IOPC_IOEINT1EN, IOPC_IOEINT2EN, IOPC_IOEINT3EN, IOPC_IOTIM0EN, IOPC_IOTIM1EN };
|
||||
unsigned int intmask[] = { IOPC_IOEINT0TM, IOPC_IOEINT1TM, IOPC_IOEINT2TM, IOPC_IOEINT3TM };
|
||||
unsigned long mode, ctrl, data;
|
||||
int i;
|
||||
|
||||
mode = __raw_readl(KS8695_GPIO_VA + KS8695_IOPM);
|
||||
ctrl = __raw_readl(KS8695_GPIO_VA + KS8695_IOPC);
|
||||
data = __raw_readl(KS8695_GPIO_VA + KS8695_IOPD);
|
||||
|
||||
seq_printf(s, "Pin\tI/O\tFunction\tState\n\n");
|
||||
|
||||
for (i = KS8695_GPIO_0; i <= KS8695_GPIO_15 ; i++) {
|
||||
seq_printf(s, "%i:\t", i);
|
||||
|
||||
seq_printf(s, "%s\t", (mode & IOPM(i)) ? "Output" : "Input");
|
||||
|
||||
if (i <= KS8695_GPIO_3) {
|
||||
if (ctrl & enable[i]) {
|
||||
seq_printf(s, "EXT%i ", i);
|
||||
|
||||
switch ((ctrl & intmask[i]) >> (4 * i)) {
|
||||
case IOPC_TM_LOW:
|
||||
seq_printf(s, "(Low)"); break;
|
||||
case IOPC_TM_HIGH:
|
||||
seq_printf(s, "(High)"); break;
|
||||
case IOPC_TM_RISING:
|
||||
seq_printf(s, "(Rising)"); break;
|
||||
case IOPC_TM_FALLING:
|
||||
seq_printf(s, "(Falling)"); break;
|
||||
case IOPC_TM_EDGE:
|
||||
seq_printf(s, "(Edges)"); break;
|
||||
}
|
||||
} else
|
||||
seq_printf(s, "GPIO\t");
|
||||
} else if (i <= KS8695_GPIO_5) {
|
||||
if (ctrl & enable[i])
|
||||
seq_printf(s, "TOUT%i\t", i - KS8695_GPIO_4);
|
||||
else
|
||||
seq_printf(s, "GPIO\t");
|
||||
} else {
|
||||
seq_printf(s, "GPIO\t");
|
||||
}
|
||||
|
||||
seq_printf(s, "\t");
|
||||
|
||||
seq_printf(s, "%i\n", (data & IOPD(i)) ? 1 : 0);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEFINE_SHOW_ATTRIBUTE(ks8695_gpio);
|
||||
|
||||
static int __init ks8695_gpio_debugfs_init(void)
|
||||
{
|
||||
/* /sys/kernel/debug/ks8695_gpio */
|
||||
debugfs_create_file("ks8695_gpio", S_IFREG | S_IRUGO, NULL, NULL,
|
||||
&ks8695_gpio_fops);
|
||||
return 0;
|
||||
}
|
||||
postcore_initcall(ks8695_gpio_debugfs_init);
|
||||
|
||||
#endif
|
|
@ -16,36 +16,33 @@
|
|||
#include <linux/platform_device.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
#include <mach/hardware.h>
|
||||
#include <mach/platform.h>
|
||||
|
||||
#define LPC32XX_GPIO_P3_INP_STATE _GPREG(0x000)
|
||||
#define LPC32XX_GPIO_P3_OUTP_SET _GPREG(0x004)
|
||||
#define LPC32XX_GPIO_P3_OUTP_CLR _GPREG(0x008)
|
||||
#define LPC32XX_GPIO_P3_OUTP_STATE _GPREG(0x00C)
|
||||
#define LPC32XX_GPIO_P2_DIR_SET _GPREG(0x010)
|
||||
#define LPC32XX_GPIO_P2_DIR_CLR _GPREG(0x014)
|
||||
#define LPC32XX_GPIO_P2_DIR_STATE _GPREG(0x018)
|
||||
#define LPC32XX_GPIO_P2_INP_STATE _GPREG(0x01C)
|
||||
#define LPC32XX_GPIO_P2_OUTP_SET _GPREG(0x020)
|
||||
#define LPC32XX_GPIO_P2_OUTP_CLR _GPREG(0x024)
|
||||
#define LPC32XX_GPIO_P2_MUX_SET _GPREG(0x028)
|
||||
#define LPC32XX_GPIO_P2_MUX_CLR _GPREG(0x02C)
|
||||
#define LPC32XX_GPIO_P2_MUX_STATE _GPREG(0x030)
|
||||
#define LPC32XX_GPIO_P0_INP_STATE _GPREG(0x040)
|
||||
#define LPC32XX_GPIO_P0_OUTP_SET _GPREG(0x044)
|
||||
#define LPC32XX_GPIO_P0_OUTP_CLR _GPREG(0x048)
|
||||
#define LPC32XX_GPIO_P0_OUTP_STATE _GPREG(0x04C)
|
||||
#define LPC32XX_GPIO_P0_DIR_SET _GPREG(0x050)
|
||||
#define LPC32XX_GPIO_P0_DIR_CLR _GPREG(0x054)
|
||||
#define LPC32XX_GPIO_P0_DIR_STATE _GPREG(0x058)
|
||||
#define LPC32XX_GPIO_P1_INP_STATE _GPREG(0x060)
|
||||
#define LPC32XX_GPIO_P1_OUTP_SET _GPREG(0x064)
|
||||
#define LPC32XX_GPIO_P1_OUTP_CLR _GPREG(0x068)
|
||||
#define LPC32XX_GPIO_P1_OUTP_STATE _GPREG(0x06C)
|
||||
#define LPC32XX_GPIO_P1_DIR_SET _GPREG(0x070)
|
||||
#define LPC32XX_GPIO_P1_DIR_CLR _GPREG(0x074)
|
||||
#define LPC32XX_GPIO_P1_DIR_STATE _GPREG(0x078)
|
||||
#define LPC32XX_GPIO_P3_INP_STATE (0x000)
|
||||
#define LPC32XX_GPIO_P3_OUTP_SET (0x004)
|
||||
#define LPC32XX_GPIO_P3_OUTP_CLR (0x008)
|
||||
#define LPC32XX_GPIO_P3_OUTP_STATE (0x00C)
|
||||
#define LPC32XX_GPIO_P2_DIR_SET (0x010)
|
||||
#define LPC32XX_GPIO_P2_DIR_CLR (0x014)
|
||||
#define LPC32XX_GPIO_P2_DIR_STATE (0x018)
|
||||
#define LPC32XX_GPIO_P2_INP_STATE (0x01C)
|
||||
#define LPC32XX_GPIO_P2_OUTP_SET (0x020)
|
||||
#define LPC32XX_GPIO_P2_OUTP_CLR (0x024)
|
||||
#define LPC32XX_GPIO_P2_MUX_SET (0x028)
|
||||
#define LPC32XX_GPIO_P2_MUX_CLR (0x02C)
|
||||
#define LPC32XX_GPIO_P2_MUX_STATE (0x030)
|
||||
#define LPC32XX_GPIO_P0_INP_STATE (0x040)
|
||||
#define LPC32XX_GPIO_P0_OUTP_SET (0x044)
|
||||
#define LPC32XX_GPIO_P0_OUTP_CLR (0x048)
|
||||
#define LPC32XX_GPIO_P0_OUTP_STATE (0x04C)
|
||||
#define LPC32XX_GPIO_P0_DIR_SET (0x050)
|
||||
#define LPC32XX_GPIO_P0_DIR_CLR (0x054)
|
||||
#define LPC32XX_GPIO_P0_DIR_STATE (0x058)
|
||||
#define LPC32XX_GPIO_P1_INP_STATE (0x060)
|
||||
#define LPC32XX_GPIO_P1_OUTP_SET (0x064)
|
||||
#define LPC32XX_GPIO_P1_OUTP_CLR (0x068)
|
||||
#define LPC32XX_GPIO_P1_OUTP_STATE (0x06C)
|
||||
#define LPC32XX_GPIO_P1_DIR_SET (0x070)
|
||||
#define LPC32XX_GPIO_P1_DIR_CLR (0x074)
|
||||
#define LPC32XX_GPIO_P1_DIR_STATE (0x078)
|
||||
|
||||
#define GPIO012_PIN_TO_BIT(x) (1 << (x))
|
||||
#define GPIO3_PIN_TO_BIT(x) (1 << ((x) + 25))
|
||||
|
@ -72,12 +69,12 @@
|
|||
#define LPC32XX_GPO_P3_GRP (LPC32XX_GPI_P3_GRP + LPC32XX_GPI_P3_MAX)
|
||||
|
||||
struct gpio_regs {
|
||||
void __iomem *inp_state;
|
||||
void __iomem *outp_state;
|
||||
void __iomem *outp_set;
|
||||
void __iomem *outp_clr;
|
||||
void __iomem *dir_set;
|
||||
void __iomem *dir_clr;
|
||||
unsigned long inp_state;
|
||||
unsigned long outp_state;
|
||||
unsigned long outp_set;
|
||||
unsigned long outp_clr;
|
||||
unsigned long dir_set;
|
||||
unsigned long dir_clr;
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -165,16 +162,27 @@ static struct gpio_regs gpio_grp_regs_p3 = {
|
|||
struct lpc32xx_gpio_chip {
|
||||
struct gpio_chip chip;
|
||||
struct gpio_regs *gpio_grp;
|
||||
void __iomem *reg_base;
|
||||
};
|
||||
|
||||
static inline u32 gpreg_read(struct lpc32xx_gpio_chip *group, unsigned long offset)
|
||||
{
|
||||
return __raw_readl(group->reg_base + offset);
|
||||
}
|
||||
|
||||
static inline void gpreg_write(struct lpc32xx_gpio_chip *group, u32 val, unsigned long offset)
|
||||
{
|
||||
__raw_writel(val, group->reg_base + offset);
|
||||
}
|
||||
|
||||
static void __set_gpio_dir_p012(struct lpc32xx_gpio_chip *group,
|
||||
unsigned pin, int input)
|
||||
{
|
||||
if (input)
|
||||
__raw_writel(GPIO012_PIN_TO_BIT(pin),
|
||||
gpreg_write(group, GPIO012_PIN_TO_BIT(pin),
|
||||
group->gpio_grp->dir_clr);
|
||||
else
|
||||
__raw_writel(GPIO012_PIN_TO_BIT(pin),
|
||||
gpreg_write(group, GPIO012_PIN_TO_BIT(pin),
|
||||
group->gpio_grp->dir_set);
|
||||
}
|
||||
|
||||
|
@ -184,19 +192,19 @@ static void __set_gpio_dir_p3(struct lpc32xx_gpio_chip *group,
|
|||
u32 u = GPIO3_PIN_TO_BIT(pin);
|
||||
|
||||
if (input)
|
||||
__raw_writel(u, group->gpio_grp->dir_clr);
|
||||
gpreg_write(group, u, group->gpio_grp->dir_clr);
|
||||
else
|
||||
__raw_writel(u, group->gpio_grp->dir_set);
|
||||
gpreg_write(group, u, group->gpio_grp->dir_set);
|
||||
}
|
||||
|
||||
static void __set_gpio_level_p012(struct lpc32xx_gpio_chip *group,
|
||||
unsigned pin, int high)
|
||||
{
|
||||
if (high)
|
||||
__raw_writel(GPIO012_PIN_TO_BIT(pin),
|
||||
gpreg_write(group, GPIO012_PIN_TO_BIT(pin),
|
||||
group->gpio_grp->outp_set);
|
||||
else
|
||||
__raw_writel(GPIO012_PIN_TO_BIT(pin),
|
||||
gpreg_write(group, GPIO012_PIN_TO_BIT(pin),
|
||||
group->gpio_grp->outp_clr);
|
||||
}
|
||||
|
||||
|
@ -206,31 +214,31 @@ static void __set_gpio_level_p3(struct lpc32xx_gpio_chip *group,
|
|||
u32 u = GPIO3_PIN_TO_BIT(pin);
|
||||
|
||||
if (high)
|
||||
__raw_writel(u, group->gpio_grp->outp_set);
|
||||
gpreg_write(group, u, group->gpio_grp->outp_set);
|
||||
else
|
||||
__raw_writel(u, group->gpio_grp->outp_clr);
|
||||
gpreg_write(group, u, group->gpio_grp->outp_clr);
|
||||
}
|
||||
|
||||
static void __set_gpo_level_p3(struct lpc32xx_gpio_chip *group,
|
||||
unsigned pin, int high)
|
||||
{
|
||||
if (high)
|
||||
__raw_writel(GPO3_PIN_TO_BIT(pin), group->gpio_grp->outp_set);
|
||||
gpreg_write(group, GPO3_PIN_TO_BIT(pin), group->gpio_grp->outp_set);
|
||||
else
|
||||
__raw_writel(GPO3_PIN_TO_BIT(pin), group->gpio_grp->outp_clr);
|
||||
gpreg_write(group, GPO3_PIN_TO_BIT(pin), group->gpio_grp->outp_clr);
|
||||
}
|
||||
|
||||
static int __get_gpio_state_p012(struct lpc32xx_gpio_chip *group,
|
||||
unsigned pin)
|
||||
{
|
||||
return GPIO012_PIN_IN_SEL(__raw_readl(group->gpio_grp->inp_state),
|
||||
return GPIO012_PIN_IN_SEL(gpreg_read(group, group->gpio_grp->inp_state),
|
||||
pin);
|
||||
}
|
||||
|
||||
static int __get_gpio_state_p3(struct lpc32xx_gpio_chip *group,
|
||||
unsigned pin)
|
||||
{
|
||||
int state = __raw_readl(group->gpio_grp->inp_state);
|
||||
int state = gpreg_read(group, group->gpio_grp->inp_state);
|
||||
|
||||
/*
|
||||
* P3 GPIO pin input mapping is not contiguous, GPIOP3-0..4 is mapped
|
||||
|
@ -242,13 +250,13 @@ static int __get_gpio_state_p3(struct lpc32xx_gpio_chip *group,
|
|||
static int __get_gpi_state_p3(struct lpc32xx_gpio_chip *group,
|
||||
unsigned pin)
|
||||
{
|
||||
return GPI3_PIN_IN_SEL(__raw_readl(group->gpio_grp->inp_state), pin);
|
||||
return GPI3_PIN_IN_SEL(gpreg_read(group, group->gpio_grp->inp_state), pin);
|
||||
}
|
||||
|
||||
static int __get_gpo_state_p3(struct lpc32xx_gpio_chip *group,
|
||||
unsigned pin)
|
||||
{
|
||||
return GPO3_PIN_IN_SEL(__raw_readl(group->gpio_grp->outp_state), pin);
|
||||
return GPO3_PIN_IN_SEL(gpreg_read(group, group->gpio_grp->outp_state), pin);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -497,12 +505,18 @@ static int lpc32xx_of_xlate(struct gpio_chip *gc,
|
|||
static int lpc32xx_gpio_probe(struct platform_device *pdev)
|
||||
{
|
||||
int i;
|
||||
void __iomem *reg_base;
|
||||
|
||||
reg_base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(reg_base))
|
||||
return PTR_ERR(reg_base);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(lpc32xx_gpiochip); i++) {
|
||||
if (pdev->dev.of_node) {
|
||||
lpc32xx_gpiochip[i].chip.of_xlate = lpc32xx_of_xlate;
|
||||
lpc32xx_gpiochip[i].chip.of_gpio_n_cells = 3;
|
||||
lpc32xx_gpiochip[i].chip.of_node = pdev->dev.of_node;
|
||||
lpc32xx_gpiochip[i].reg_base = reg_base;
|
||||
}
|
||||
devm_gpiochip_add_data(&pdev->dev, &lpc32xx_gpiochip[i].chip,
|
||||
&lpc32xx_gpiochip[i]);
|
||||
|
@ -527,3 +541,7 @@ static struct platform_driver lpc32xx_gpio_driver = {
|
|||
};
|
||||
|
||||
module_platform_driver(lpc32xx_gpio_driver);
|
||||
|
||||
MODULE_AUTHOR("Kevin Wells <kevin.wells@nxp.com>");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_DESCRIPTION("GPIO driver for LPC32xx SoC");
|
||||
|
|
|
@ -358,27 +358,32 @@ static int lp_gpio_probe(struct platform_device *pdev)
|
|||
gc->can_sleep = false;
|
||||
gc->parent = dev;
|
||||
|
||||
/* set up interrupts */
|
||||
if (irq_rc && irq_rc->start) {
|
||||
struct gpio_irq_chip *girq;
|
||||
|
||||
girq = &gc->irq;
|
||||
girq->chip = &lp_irqchip;
|
||||
girq->parent_handler = lp_gpio_irq_handler;
|
||||
girq->num_parents = 1;
|
||||
girq->parents = devm_kcalloc(&pdev->dev, girq->num_parents,
|
||||
sizeof(*girq->parents),
|
||||
GFP_KERNEL);
|
||||
if (!girq->parents)
|
||||
return -ENOMEM;
|
||||
girq->parents[0] = (unsigned)irq_rc->start;
|
||||
girq->default_type = IRQ_TYPE_NONE;
|
||||
girq->handler = handle_simple_irq;
|
||||
|
||||
lp_gpio_irq_init_hw(lg);
|
||||
}
|
||||
|
||||
ret = devm_gpiochip_add_data(dev, gc, lg);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed adding lp-gpio chip\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* set up interrupts */
|
||||
if (irq_rc && irq_rc->start) {
|
||||
lp_gpio_irq_init_hw(lg);
|
||||
ret = gpiochip_irqchip_add(gc, &lp_irqchip, 0,
|
||||
handle_simple_irq, IRQ_TYPE_NONE);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to add irqchip\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
gpiochip_set_chained_irqchip(gc, &lp_irqchip,
|
||||
(unsigned)irq_rc->start,
|
||||
lp_gpio_irq_handler);
|
||||
}
|
||||
|
||||
pm_runtime_enable(dev);
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -120,7 +120,7 @@ static const struct gpio_chip madera_gpio_chip = {
|
|||
static int madera_gpio_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct madera *madera = dev_get_drvdata(pdev->dev.parent);
|
||||
struct madera_pdata *pdata = dev_get_platdata(madera->dev);
|
||||
struct madera_pdata *pdata = &madera->pdata;
|
||||
struct madera_gpio *madera_gpio;
|
||||
int ret;
|
||||
|
||||
|
@ -136,6 +136,9 @@ static int madera_gpio_probe(struct platform_device *pdev)
|
|||
madera_gpio->gpio_chip.parent = pdev->dev.parent;
|
||||
|
||||
switch (madera->type) {
|
||||
case CS47L15:
|
||||
madera_gpio->gpio_chip.ngpio = CS47L15_NUM_GPIOS;
|
||||
break;
|
||||
case CS47L35:
|
||||
madera_gpio->gpio_chip.ngpio = CS47L35_NUM_GPIOS;
|
||||
break;
|
||||
|
@ -147,13 +150,18 @@ static int madera_gpio_probe(struct platform_device *pdev)
|
|||
case CS47L91:
|
||||
madera_gpio->gpio_chip.ngpio = CS47L90_NUM_GPIOS;
|
||||
break;
|
||||
case CS42L92:
|
||||
case CS47L92:
|
||||
case CS47L93:
|
||||
madera_gpio->gpio_chip.ngpio = CS47L92_NUM_GPIOS;
|
||||
break;
|
||||
default:
|
||||
dev_err(&pdev->dev, "Unknown chip variant %d\n", madera->type);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* We want to be usable on systems that don't use devicetree or acpi */
|
||||
if (pdata && pdata->gpio_base)
|
||||
if (pdata->gpio_base)
|
||||
madera_gpio->gpio_chip.base = pdata->gpio_base;
|
||||
else
|
||||
madera_gpio->gpio_chip.base = -1;
|
||||
|
|
|
@ -270,10 +270,8 @@ static int max77620_gpio_probe(struct platform_device *pdev)
|
|||
int ret;
|
||||
|
||||
gpio_irq = platform_get_irq(pdev, 0);
|
||||
if (gpio_irq <= 0) {
|
||||
dev_err(&pdev->dev, "GPIO irq not available %d\n", gpio_irq);
|
||||
if (gpio_irq <= 0)
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
mgpio = devm_kzalloc(&pdev->dev, sizeof(*mgpio), GFP_KERNEL);
|
||||
if (!mgpio)
|
||||
|
|
|
@ -188,3 +188,4 @@ module_platform_driver(max77650_gpio_driver);
|
|||
MODULE_DESCRIPTION("MAXIM 77650/77651 GPIO driver");
|
||||
MODULE_AUTHOR("Bartosz Golaszewski <bgolaszewski@baylibre.com>");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_ALIAS("platform:max77650-gpio");
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include <linux/slab.h>
|
||||
|
||||
#include "gpiolib.h"
|
||||
#include "gpiolib-acpi.h"
|
||||
|
||||
/*
|
||||
* Only first 8bits of a register correspond to each pin,
|
||||
|
|
|
@ -397,6 +397,7 @@ static int mrfld_gpio_probe(struct pci_dev *pdev, const struct pci_device_id *id
|
|||
{
|
||||
const struct mrfld_gpio_pinrange *range;
|
||||
const char *pinctrl_dev_name;
|
||||
struct gpio_irq_chip *girq;
|
||||
struct mrfld_gpio *priv;
|
||||
u32 gpio_base, irq_base;
|
||||
void __iomem *base;
|
||||
|
@ -444,6 +445,21 @@ static int mrfld_gpio_probe(struct pci_dev *pdev, const struct pci_device_id *id
|
|||
|
||||
raw_spin_lock_init(&priv->lock);
|
||||
|
||||
girq = &priv->chip.irq;
|
||||
girq->chip = &mrfld_irqchip;
|
||||
girq->parent_handler = mrfld_irq_handler;
|
||||
girq->num_parents = 1;
|
||||
girq->parents = devm_kcalloc(&pdev->dev, girq->num_parents,
|
||||
sizeof(*girq->parents),
|
||||
GFP_KERNEL);
|
||||
if (!girq->parents)
|
||||
return -ENOMEM;
|
||||
girq->parents[0] = pdev->irq;
|
||||
girq->default_type = IRQ_TYPE_NONE;
|
||||
girq->handler = handle_bad_irq;
|
||||
|
||||
mrfld_irq_init_hw(priv);
|
||||
|
||||
pci_set_drvdata(pdev, priv);
|
||||
retval = devm_gpiochip_add_data(&pdev->dev, &priv->chip, priv);
|
||||
if (retval) {
|
||||
|
@ -465,18 +481,6 @@ static int mrfld_gpio_probe(struct pci_dev *pdev, const struct pci_device_id *id
|
|||
}
|
||||
}
|
||||
|
||||
retval = gpiochip_irqchip_add(&priv->chip, &mrfld_irqchip, irq_base,
|
||||
handle_bad_irq, IRQ_TYPE_NONE);
|
||||
if (retval) {
|
||||
dev_err(&pdev->dev, "could not connect irqchip to gpiochip\n");
|
||||
return retval;
|
||||
}
|
||||
|
||||
mrfld_irq_init_hw(priv);
|
||||
|
||||
gpiochip_set_chained_irqchip(&priv->chip, &mrfld_irqchip, pdev->irq,
|
||||
mrfld_irq_handler);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
#define GPIO_IMR 0x10
|
||||
#define GPIO_ICR 0x14
|
||||
#define GPIO_ICR2 0x18
|
||||
#define GPIO_IBE 0x18
|
||||
|
||||
struct mpc8xxx_gpio_chip {
|
||||
struct gpio_chip gc;
|
||||
|
@ -45,6 +46,27 @@ struct mpc8xxx_gpio_chip {
|
|||
unsigned int irqn;
|
||||
};
|
||||
|
||||
/* The GPIO Input Buffer Enable register(GPIO_IBE) is used to
|
||||
* control the input enable of each individual GPIO port.
|
||||
* When an individual GPIO port’s direction is set to
|
||||
* input (GPIO_GPDIR[DRn=0]), the associated input enable must be
|
||||
* set (GPIOxGPIE[IEn]=1) to propagate the port value to the GPIO
|
||||
* Data Register.
|
||||
*/
|
||||
static int ls1028a_gpio_dir_in_init(struct gpio_chip *gc)
|
||||
{
|
||||
unsigned long flags;
|
||||
struct mpc8xxx_gpio_chip *mpc8xxx_gc = gpiochip_get_data(gc);
|
||||
|
||||
spin_lock_irqsave(&gc->bgpio_lock, flags);
|
||||
|
||||
gc->write_reg(mpc8xxx_gc->regs + GPIO_IBE, 0xffffffff);
|
||||
|
||||
spin_unlock_irqrestore(&gc->bgpio_lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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.
|
||||
|
@ -261,6 +283,7 @@ static const struct irq_domain_ops mpc8xxx_gpio_irq_ops = {
|
|||
};
|
||||
|
||||
struct mpc8xxx_gpio_devtype {
|
||||
int (*gpio_dir_in_init)(struct gpio_chip *chip);
|
||||
int (*gpio_dir_out)(struct gpio_chip *, unsigned int, int);
|
||||
int (*gpio_get)(struct gpio_chip *, unsigned int);
|
||||
int (*irq_set_type)(struct irq_data *, unsigned int);
|
||||
|
@ -271,6 +294,10 @@ static const struct mpc8xxx_gpio_devtype mpc512x_gpio_devtype = {
|
|||
.irq_set_type = mpc512x_irq_set_type,
|
||||
};
|
||||
|
||||
static const struct mpc8xxx_gpio_devtype ls1028a_gpio_devtype = {
|
||||
.gpio_dir_in_init = ls1028a_gpio_dir_in_init,
|
||||
};
|
||||
|
||||
static const struct mpc8xxx_gpio_devtype mpc5125_gpio_devtype = {
|
||||
.gpio_dir_out = mpc5125_gpio_dir_out,
|
||||
.irq_set_type = mpc512x_irq_set_type,
|
||||
|
@ -291,6 +318,8 @@ static const struct of_device_id mpc8xxx_gpio_ids[] = {
|
|||
{ .compatible = "fsl,mpc5121-gpio", .data = &mpc512x_gpio_devtype, },
|
||||
{ .compatible = "fsl,mpc5125-gpio", .data = &mpc5125_gpio_devtype, },
|
||||
{ .compatible = "fsl,pq3-gpio", },
|
||||
{ .compatible = "fsl,ls1028a-gpio", .data = &ls1028a_gpio_devtype, },
|
||||
{ .compatible = "fsl,ls1088a-gpio", .data = &ls1028a_gpio_devtype, },
|
||||
{ .compatible = "fsl,qoriq-gpio", },
|
||||
{}
|
||||
};
|
||||
|
@ -376,6 +405,9 @@ static int mpc8xxx_probe(struct platform_device *pdev)
|
|||
/* ack and mask all irqs */
|
||||
gc->write_reg(mpc8xxx_gc->regs + GPIO_IER, 0xffffffff);
|
||||
gc->write_reg(mpc8xxx_gc->regs + GPIO_IMR, 0);
|
||||
/* enable input buffer */
|
||||
if (devtype->gpio_dir_in_init)
|
||||
devtype->gpio_dir_in_init(gc);
|
||||
|
||||
irq_set_chained_handler_and_data(mpc8xxx_gc->irqn,
|
||||
mpc8xxx_gpio_irq_cascade, mpc8xxx_gc);
|
||||
|
|
|
@ -241,13 +241,6 @@ mediatek_gpio_bank_probe(struct device *dev,
|
|||
if (!rg->chip.label)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = devm_gpiochip_add_data(dev, &rg->chip, mtk);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "Could not register gpio %d, ret=%d\n",
|
||||
rg->chip.ngpio, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
rg->irq_chip.name = dev_name(dev);
|
||||
rg->irq_chip.parent_device = dev;
|
||||
rg->irq_chip.irq_unmask = mediatek_gpio_irq_unmask;
|
||||
|
@ -256,8 +249,10 @@ mediatek_gpio_bank_probe(struct device *dev,
|
|||
rg->irq_chip.irq_set_type = mediatek_gpio_irq_type;
|
||||
|
||||
if (mtk->gpio_irq) {
|
||||
struct gpio_irq_chip *girq;
|
||||
|
||||
/*
|
||||
* Manually request the irq here instead of passing
|
||||
* Directly request the irq here instead of passing
|
||||
* a flow-handler to gpiochip_set_chained_irqchip,
|
||||
* because the irq is shared.
|
||||
*/
|
||||
|
@ -271,15 +266,21 @@ mediatek_gpio_bank_probe(struct device *dev,
|
|||
return ret;
|
||||
}
|
||||
|
||||
ret = gpiochip_irqchip_add(&rg->chip, &rg->irq_chip,
|
||||
0, handle_simple_irq, IRQ_TYPE_NONE);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to add gpiochip_irqchip\n");
|
||||
return ret;
|
||||
}
|
||||
girq = &rg->chip.irq;
|
||||
girq->chip = &rg->irq_chip;
|
||||
/* This will let us handle the parent IRQ in the driver */
|
||||
girq->parent_handler = NULL;
|
||||
girq->num_parents = 0;
|
||||
girq->parents = NULL;
|
||||
girq->default_type = IRQ_TYPE_NONE;
|
||||
girq->handler = handle_simple_irq;
|
||||
}
|
||||
|
||||
gpiochip_set_chained_irqchip(&rg->chip, &rg->irq_chip,
|
||||
mtk->gpio_irq, NULL);
|
||||
ret = devm_gpiochip_add_data(dev, &rg->chip, mtk);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "Could not register gpio %d, ret=%d\n",
|
||||
rg->chip.ngpio, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* set polarity to low for all gpios */
|
||||
|
|
|
@ -435,12 +435,9 @@ static int mxc_gpio_probe(struct platform_device *pdev)
|
|||
return port->irq;
|
||||
|
||||
/* the controller clock is optional */
|
||||
port->clk = devm_clk_get(&pdev->dev, NULL);
|
||||
if (IS_ERR(port->clk)) {
|
||||
if (PTR_ERR(port->clk) == -EPROBE_DEFER)
|
||||
return -EPROBE_DEFER;
|
||||
port->clk = NULL;
|
||||
}
|
||||
port->clk = devm_clk_get_optional(&pdev->dev, NULL);
|
||||
if (IS_ERR(port->clk))
|
||||
return PTR_ERR(port->clk);
|
||||
|
||||
err = clk_prepare_enable(port->clk);
|
||||
if (err) {
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
*/
|
||||
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/bits.h>
|
||||
#include <linux/gpio/driver.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/i2c.h>
|
||||
|
@ -28,9 +29,9 @@
|
|||
#define PCA953X_INVERT 0x02
|
||||
#define PCA953X_DIRECTION 0x03
|
||||
|
||||
#define REG_ADDR_MASK 0x3f
|
||||
#define REG_ADDR_EXT 0x40
|
||||
#define REG_ADDR_AI 0x80
|
||||
#define REG_ADDR_MASK GENMASK(5, 0)
|
||||
#define REG_ADDR_EXT BIT(6)
|
||||
#define REG_ADDR_AI BIT(7)
|
||||
|
||||
#define PCA957X_IN 0x00
|
||||
#define PCA957X_INVRT 0x01
|
||||
|
@ -55,17 +56,17 @@
|
|||
#define PCAL6524_OUT_INDCONF 0x2c
|
||||
#define PCAL6524_DEBOUNCE 0x2d
|
||||
|
||||
#define PCA_GPIO_MASK 0x00FF
|
||||
#define PCA_GPIO_MASK GENMASK(7, 0)
|
||||
|
||||
#define PCAL_GPIO_MASK 0x1f
|
||||
#define PCAL_PINCTRL_MASK 0x60
|
||||
#define PCAL_GPIO_MASK GENMASK(4, 0)
|
||||
#define PCAL_PINCTRL_MASK GENMASK(6, 5)
|
||||
|
||||
#define PCA_INT 0x0100
|
||||
#define PCA_PCAL 0x0200
|
||||
#define PCA_INT BIT(8)
|
||||
#define PCA_PCAL BIT(9)
|
||||
#define PCA_LATCH_INT (PCA_PCAL | PCA_INT)
|
||||
#define PCA953X_TYPE 0x1000
|
||||
#define PCA957X_TYPE 0x2000
|
||||
#define PCA_TYPE_MASK 0xF000
|
||||
#define PCA953X_TYPE BIT(12)
|
||||
#define PCA957X_TYPE BIT(13)
|
||||
#define PCA_TYPE_MASK GENMASK(15, 12)
|
||||
|
||||
#define PCA_CHIP_TYPE(x) ((x) & PCA_TYPE_MASK)
|
||||
|
||||
|
@ -565,7 +566,7 @@ static void pca953x_irq_mask(struct irq_data *d)
|
|||
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
|
||||
struct pca953x_chip *chip = gpiochip_get_data(gc);
|
||||
|
||||
chip->irq_mask[d->hwirq / BANK_SZ] &= ~(1 << (d->hwirq % BANK_SZ));
|
||||
chip->irq_mask[d->hwirq / BANK_SZ] &= ~BIT(d->hwirq % BANK_SZ);
|
||||
}
|
||||
|
||||
static void pca953x_irq_unmask(struct irq_data *d)
|
||||
|
@ -573,7 +574,7 @@ static void pca953x_irq_unmask(struct irq_data *d)
|
|||
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
|
||||
struct pca953x_chip *chip = gpiochip_get_data(gc);
|
||||
|
||||
chip->irq_mask[d->hwirq / BANK_SZ] |= 1 << (d->hwirq % BANK_SZ);
|
||||
chip->irq_mask[d->hwirq / BANK_SZ] |= BIT(d->hwirq % BANK_SZ);
|
||||
}
|
||||
|
||||
static int pca953x_irq_set_wake(struct irq_data *d, unsigned int on)
|
||||
|
@ -640,7 +641,7 @@ static int pca953x_irq_set_type(struct irq_data *d, unsigned int type)
|
|||
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
|
||||
struct pca953x_chip *chip = gpiochip_get_data(gc);
|
||||
int bank_nb = d->hwirq / BANK_SZ;
|
||||
u8 mask = 1 << (d->hwirq % BANK_SZ);
|
||||
u8 mask = BIT(d->hwirq % BANK_SZ);
|
||||
|
||||
if (!(type & IRQ_TYPE_EDGE_BOTH)) {
|
||||
dev_err(&chip->client->dev, "irq %d: unsupported type %d\n",
|
||||
|
@ -665,7 +666,7 @@ static void pca953x_irq_shutdown(struct irq_data *d)
|
|||
{
|
||||
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
|
||||
struct pca953x_chip *chip = gpiochip_get_data(gc);
|
||||
u8 mask = 1 << (d->hwirq % BANK_SZ);
|
||||
u8 mask = BIT(d->hwirq % BANK_SZ);
|
||||
|
||||
chip->irq_trig_raise[d->hwirq / BANK_SZ] &= ~mask;
|
||||
chip->irq_trig_fall[d->hwirq / BANK_SZ] &= ~mask;
|
||||
|
@ -846,12 +847,12 @@ static int device_pca95xx_init(struct pca953x_chip *chip, u32 invert)
|
|||
|
||||
ret = regcache_sync_region(chip->regmap, chip->regs->output,
|
||||
chip->regs->output + NBANK(chip));
|
||||
if (ret != 0)
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
ret = regcache_sync_region(chip->regmap, chip->regs->direction,
|
||||
chip->regs->direction + NBANK(chip));
|
||||
if (ret != 0)
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
/* set platform specific polarity inversion */
|
||||
|
@ -946,19 +947,15 @@ static int pca953x_probe(struct i2c_client *client,
|
|||
if (i2c_id) {
|
||||
chip->driver_data = i2c_id->driver_data;
|
||||
} else {
|
||||
const struct acpi_device_id *acpi_id;
|
||||
struct device *dev = &client->dev;
|
||||
const void *match;
|
||||
|
||||
chip->driver_data = (uintptr_t)of_device_get_match_data(dev);
|
||||
if (!chip->driver_data) {
|
||||
acpi_id = acpi_match_device(pca953x_acpi_ids, dev);
|
||||
if (!acpi_id) {
|
||||
ret = -ENODEV;
|
||||
goto err_exit;
|
||||
}
|
||||
|
||||
chip->driver_data = acpi_id->driver_data;
|
||||
match = device_get_match_data(&client->dev);
|
||||
if (!match) {
|
||||
ret = -ENODEV;
|
||||
goto err_exit;
|
||||
}
|
||||
|
||||
chip->driver_data = (uintptr_t)match;
|
||||
}
|
||||
|
||||
i2c_set_clientdata(client, chip);
|
||||
|
@ -1038,8 +1035,7 @@ static int pca953x_remove(struct i2c_client *client)
|
|||
ret = pdata->teardown(client, chip->gpio_chip.base,
|
||||
chip->gpio_chip.ngpio, pdata->context);
|
||||
if (ret < 0)
|
||||
dev_err(&client->dev, "%s failed, %d\n",
|
||||
"teardown", ret);
|
||||
dev_err(&client->dev, "teardown failed, %d\n", ret);
|
||||
} else {
|
||||
ret = 0;
|
||||
}
|
||||
|
@ -1061,14 +1057,14 @@ static int pca953x_regcache_sync(struct device *dev)
|
|||
*/
|
||||
ret = regcache_sync_region(chip->regmap, chip->regs->direction,
|
||||
chip->regs->direction + NBANK(chip));
|
||||
if (ret != 0) {
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to sync GPIO dir registers: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = regcache_sync_region(chip->regmap, chip->regs->output,
|
||||
chip->regs->output + NBANK(chip));
|
||||
if (ret != 0) {
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to sync GPIO out registers: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
@ -1077,7 +1073,7 @@ static int pca953x_regcache_sync(struct device *dev)
|
|||
if (chip->driver_data & PCA_PCAL) {
|
||||
ret = regcache_sync_region(chip->regmap, PCAL953X_IN_LATCH,
|
||||
PCAL953X_IN_LATCH + NBANK(chip));
|
||||
if (ret != 0) {
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to sync INT latch registers: %d\n",
|
||||
ret);
|
||||
return ret;
|
||||
|
@ -1085,7 +1081,7 @@ static int pca953x_regcache_sync(struct device *dev)
|
|||
|
||||
ret = regcache_sync_region(chip->regmap, PCAL953X_INT_MASK,
|
||||
PCAL953X_INT_MASK + NBANK(chip));
|
||||
if (ret != 0) {
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to sync INT mask registers: %d\n",
|
||||
ret);
|
||||
return ret;
|
||||
|
@ -1117,7 +1113,7 @@ static int pca953x_resume(struct device *dev)
|
|||
|
||||
if (!atomic_read(&chip->wakeup_path)) {
|
||||
ret = regulator_enable(chip->regulator);
|
||||
if (ret != 0) {
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to enable regulator: %d\n", ret);
|
||||
return 0;
|
||||
}
|
||||
|
@ -1130,7 +1126,7 @@ static int pca953x_resume(struct device *dev)
|
|||
return ret;
|
||||
|
||||
ret = regcache_sync(chip->regmap);
|
||||
if (ret != 0) {
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to restore register map: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -409,8 +409,7 @@ static int pch_gpio_probe(struct pci_dev *pdev,
|
|||
|
||||
static int __maybe_unused pch_gpio_suspend(struct device *dev)
|
||||
{
|
||||
struct pci_dev *pdev = to_pci_dev(dev);
|
||||
struct pch_gpio *chip = pci_get_drvdata(pdev);
|
||||
struct pch_gpio *chip = dev_get_drvdata(dev);
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&chip->spinlock, flags);
|
||||
|
@ -422,8 +421,7 @@ static int __maybe_unused pch_gpio_suspend(struct device *dev)
|
|||
|
||||
static int __maybe_unused pch_gpio_resume(struct device *dev)
|
||||
{
|
||||
struct pci_dev *pdev = to_pci_dev(dev);
|
||||
struct pch_gpio *chip = pci_get_drvdata(pdev);
|
||||
struct pch_gpio *chip = dev_get_drvdata(dev);
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&chip->spinlock, flags);
|
||||
|
|
|
@ -305,10 +305,8 @@ static int sprd_pmic_eic_probe(struct platform_device *pdev)
|
|||
mutex_init(&pmic_eic->buslock);
|
||||
|
||||
pmic_eic->irq = platform_get_irq(pdev, 0);
|
||||
if (pmic_eic->irq < 0) {
|
||||
dev_err(&pdev->dev, "Failed to get PMIC EIC interrupt.\n");
|
||||
if (pmic_eic->irq < 0)
|
||||
return pmic_eic->irq;
|
||||
}
|
||||
|
||||
pmic_eic->map = dev_get_regmap(pdev->dev.parent, NULL);
|
||||
if (!pmic_eic->map)
|
||||
|
|
|
@ -226,10 +226,8 @@ static int sprd_gpio_probe(struct platform_device *pdev)
|
|||
return -ENOMEM;
|
||||
|
||||
sprd_gpio->irq = platform_get_irq(pdev, 0);
|
||||
if (sprd_gpio->irq < 0) {
|
||||
dev_err(&pdev->dev, "Failed to get GPIO interrupt.\n");
|
||||
if (sprd_gpio->irq < 0)
|
||||
return sprd_gpio->irq;
|
||||
}
|
||||
|
||||
sprd_gpio->base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(sprd_gpio->base))
|
||||
|
|
|
@ -429,6 +429,23 @@ static irqreturn_t stmpe_gpio_irq(int irq, void *dev)
|
|||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static void stmpe_init_irq_valid_mask(struct gpio_chip *gc,
|
||||
unsigned long *valid_mask,
|
||||
unsigned int ngpios)
|
||||
{
|
||||
struct stmpe_gpio *stmpe_gpio = gpiochip_get_data(gc);
|
||||
int i;
|
||||
|
||||
if (!stmpe_gpio->norequest_mask)
|
||||
return;
|
||||
|
||||
/* 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, valid_mask);
|
||||
}
|
||||
}
|
||||
|
||||
static int stmpe_gpio_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct stmpe *stmpe = dev_get_drvdata(pdev->dev.parent);
|
||||
|
@ -454,14 +471,21 @@ static int stmpe_gpio_probe(struct platform_device *pdev)
|
|||
stmpe_gpio->chip.parent = &pdev->dev;
|
||||
stmpe_gpio->chip.of_node = np;
|
||||
stmpe_gpio->chip.base = -1;
|
||||
/*
|
||||
* REVISIT: this makes sure the valid mask gets allocated and
|
||||
* filled in when adding the gpio_chip, but the rest of the
|
||||
* gpio_irqchip is still filled in using the old method
|
||||
* in gpiochip_irqchip_add_nested() so clean this up once we
|
||||
* get the gpio_irqchip to initialize while adding the
|
||||
* gpio_chip also for threaded irqchips.
|
||||
*/
|
||||
stmpe_gpio->chip.irq.init_valid_mask = stmpe_init_irq_valid_mask;
|
||||
|
||||
if (IS_ENABLED(CONFIG_DEBUG_FS))
|
||||
stmpe_gpio->chip.dbg_show = stmpe_dbg_show;
|
||||
|
||||
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;
|
||||
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq < 0)
|
||||
|
@ -487,14 +511,6 @@ static int stmpe_gpio_probe(struct platform_device *pdev)
|
|||
dev_err(&pdev->dev, "unable to get irq: %d\n", ret);
|
||||
goto out_disable;
|
||||
}
|
||||
if (stmpe_gpio->norequest_mask) {
|
||||
int i;
|
||||
|
||||
/* 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);
|
||||
}
|
||||
ret = gpiochip_irqchip_add_nested(&stmpe_gpio->chip,
|
||||
&stmpe_gpio_irq_chip,
|
||||
0,
|
||||
|
|
|
@ -171,10 +171,8 @@ static int tb10x_gpio_probe(struct platform_device *pdev)
|
|||
struct irq_chip_generic *gc;
|
||||
|
||||
ret = platform_get_irq(pdev, 0);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "No interrupt specified.\n");
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
tb10x_gpio->gc.to_irq = tb10x_gpio_to_irq;
|
||||
tb10x_gpio->irq = ret;
|
||||
|
|
|
@ -624,10 +624,8 @@ static int tegra_gpio_probe(struct platform_device *pdev)
|
|||
|
||||
for (i = 0; i < tgi->bank_count; i++) {
|
||||
ret = platform_get_irq(pdev, i);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "Missing IRQ resource: %d\n", ret);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
bank = &tgi->bank_info[i];
|
||||
bank->bank = i;
|
||||
|
|
|
@ -53,7 +53,6 @@ struct thunderx_line {
|
|||
struct thunderx_gpio {
|
||||
struct gpio_chip chip;
|
||||
u8 __iomem *register_base;
|
||||
struct irq_domain *irqd;
|
||||
struct msix_entry *msix_entries; /* per line MSI-X */
|
||||
struct thunderx_line *line_entries; /* per line irq info */
|
||||
raw_spinlock_t lock;
|
||||
|
@ -283,54 +282,60 @@ static void thunderx_gpio_set_multiple(struct gpio_chip *chip,
|
|||
}
|
||||
}
|
||||
|
||||
static void thunderx_gpio_irq_ack(struct irq_data *data)
|
||||
static void thunderx_gpio_irq_ack(struct irq_data *d)
|
||||
{
|
||||
struct thunderx_line *txline = irq_data_get_irq_chip_data(data);
|
||||
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
|
||||
struct thunderx_gpio *txgpio = gpiochip_get_data(gc);
|
||||
|
||||
writeq(GPIO_INTR_INTR,
|
||||
txline->txgpio->register_base + intr_reg(txline->line));
|
||||
txgpio->register_base + intr_reg(irqd_to_hwirq(d)));
|
||||
}
|
||||
|
||||
static void thunderx_gpio_irq_mask(struct irq_data *data)
|
||||
static void thunderx_gpio_irq_mask(struct irq_data *d)
|
||||
{
|
||||
struct thunderx_line *txline = irq_data_get_irq_chip_data(data);
|
||||
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
|
||||
struct thunderx_gpio *txgpio = gpiochip_get_data(gc);
|
||||
|
||||
writeq(GPIO_INTR_ENA_W1C,
|
||||
txline->txgpio->register_base + intr_reg(txline->line));
|
||||
txgpio->register_base + intr_reg(irqd_to_hwirq(d)));
|
||||
}
|
||||
|
||||
static void thunderx_gpio_irq_mask_ack(struct irq_data *data)
|
||||
static void thunderx_gpio_irq_mask_ack(struct irq_data *d)
|
||||
{
|
||||
struct thunderx_line *txline = irq_data_get_irq_chip_data(data);
|
||||
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
|
||||
struct thunderx_gpio *txgpio = gpiochip_get_data(gc);
|
||||
|
||||
writeq(GPIO_INTR_ENA_W1C | GPIO_INTR_INTR,
|
||||
txline->txgpio->register_base + intr_reg(txline->line));
|
||||
txgpio->register_base + intr_reg(irqd_to_hwirq(d)));
|
||||
}
|
||||
|
||||
static void thunderx_gpio_irq_unmask(struct irq_data *data)
|
||||
static void thunderx_gpio_irq_unmask(struct irq_data *d)
|
||||
{
|
||||
struct thunderx_line *txline = irq_data_get_irq_chip_data(data);
|
||||
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
|
||||
struct thunderx_gpio *txgpio = gpiochip_get_data(gc);
|
||||
|
||||
writeq(GPIO_INTR_ENA_W1S,
|
||||
txline->txgpio->register_base + intr_reg(txline->line));
|
||||
txgpio->register_base + intr_reg(irqd_to_hwirq(d)));
|
||||
}
|
||||
|
||||
static int thunderx_gpio_irq_set_type(struct irq_data *data,
|
||||
static int thunderx_gpio_irq_set_type(struct irq_data *d,
|
||||
unsigned int flow_type)
|
||||
{
|
||||
struct thunderx_line *txline = irq_data_get_irq_chip_data(data);
|
||||
struct thunderx_gpio *txgpio = txline->txgpio;
|
||||
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
|
||||
struct thunderx_gpio *txgpio = gpiochip_get_data(gc);
|
||||
struct thunderx_line *txline =
|
||||
&txgpio->line_entries[irqd_to_hwirq(d)];
|
||||
u64 bit_cfg;
|
||||
|
||||
irqd_set_trigger_type(data, flow_type);
|
||||
irqd_set_trigger_type(d, flow_type);
|
||||
|
||||
bit_cfg = txline->fil_bits | GPIO_BIT_CFG_INT_EN;
|
||||
|
||||
if (flow_type & IRQ_TYPE_EDGE_BOTH) {
|
||||
irq_set_handler_locked(data, handle_fasteoi_ack_irq);
|
||||
irq_set_handler_locked(d, handle_fasteoi_ack_irq);
|
||||
bit_cfg |= GPIO_BIT_CFG_INT_TYPE;
|
||||
} else {
|
||||
irq_set_handler_locked(data, handle_fasteoi_mask_irq);
|
||||
irq_set_handler_locked(d, handle_fasteoi_mask_irq);
|
||||
}
|
||||
|
||||
raw_spin_lock(&txgpio->lock);
|
||||
|
@ -359,33 +364,6 @@ static void thunderx_gpio_irq_disable(struct irq_data *data)
|
|||
irq_chip_disable_parent(data);
|
||||
}
|
||||
|
||||
static int thunderx_gpio_irq_request_resources(struct irq_data *data)
|
||||
{
|
||||
struct thunderx_line *txline = irq_data_get_irq_chip_data(data);
|
||||
struct thunderx_gpio *txgpio = txline->txgpio;
|
||||
int r;
|
||||
|
||||
r = gpiochip_lock_as_irq(&txgpio->chip, txline->line);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
r = irq_chip_request_resources_parent(data);
|
||||
if (r)
|
||||
gpiochip_unlock_as_irq(&txgpio->chip, txline->line);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static void thunderx_gpio_irq_release_resources(struct irq_data *data)
|
||||
{
|
||||
struct thunderx_line *txline = irq_data_get_irq_chip_data(data);
|
||||
struct thunderx_gpio *txgpio = txline->txgpio;
|
||||
|
||||
irq_chip_release_resources_parent(data);
|
||||
|
||||
gpiochip_unlock_as_irq(&txgpio->chip, txline->line);
|
||||
}
|
||||
|
||||
/*
|
||||
* Interrupts are chained from underlying MSI-X vectors. We have
|
||||
* these irq_chip functions to be able to handle level triggering
|
||||
|
@ -402,50 +380,24 @@ static struct irq_chip thunderx_gpio_irq_chip = {
|
|||
.irq_unmask = thunderx_gpio_irq_unmask,
|
||||
.irq_eoi = irq_chip_eoi_parent,
|
||||
.irq_set_affinity = irq_chip_set_affinity_parent,
|
||||
.irq_request_resources = thunderx_gpio_irq_request_resources,
|
||||
.irq_release_resources = thunderx_gpio_irq_release_resources,
|
||||
.irq_set_type = thunderx_gpio_irq_set_type,
|
||||
|
||||
.flags = IRQCHIP_SET_TYPE_MASKED
|
||||
};
|
||||
|
||||
static int thunderx_gpio_irq_translate(struct irq_domain *d,
|
||||
struct irq_fwspec *fwspec,
|
||||
irq_hw_number_t *hwirq,
|
||||
unsigned int *type)
|
||||
static int thunderx_gpio_child_to_parent_hwirq(struct gpio_chip *gc,
|
||||
unsigned int child,
|
||||
unsigned int child_type,
|
||||
unsigned int *parent,
|
||||
unsigned int *parent_type)
|
||||
{
|
||||
struct thunderx_gpio *txgpio = d->host_data;
|
||||
struct thunderx_gpio *txgpio = gpiochip_get_data(gc);
|
||||
|
||||
if (WARN_ON(fwspec->param_count < 2))
|
||||
return -EINVAL;
|
||||
if (fwspec->param[0] >= txgpio->chip.ngpio)
|
||||
return -EINVAL;
|
||||
*hwirq = fwspec->param[0];
|
||||
*type = fwspec->param[1] & IRQ_TYPE_SENSE_MASK;
|
||||
*parent = txgpio->base_msi + (2 * child);
|
||||
*parent_type = IRQ_TYPE_LEVEL_HIGH;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int thunderx_gpio_irq_alloc(struct irq_domain *d, unsigned int virq,
|
||||
unsigned int nr_irqs, void *arg)
|
||||
{
|
||||
struct thunderx_line *txline = arg;
|
||||
|
||||
return irq_domain_set_hwirq_and_chip(d, virq, txline->line,
|
||||
&thunderx_gpio_irq_chip, txline);
|
||||
}
|
||||
|
||||
static const struct irq_domain_ops thunderx_gpio_irqd_ops = {
|
||||
.alloc = thunderx_gpio_irq_alloc,
|
||||
.translate = thunderx_gpio_irq_translate
|
||||
};
|
||||
|
||||
static int thunderx_gpio_to_irq(struct gpio_chip *chip, unsigned int offset)
|
||||
{
|
||||
struct thunderx_gpio *txgpio = gpiochip_get_data(chip);
|
||||
|
||||
return irq_find_mapping(txgpio->irqd, offset);
|
||||
}
|
||||
|
||||
static int thunderx_gpio_probe(struct pci_dev *pdev,
|
||||
const struct pci_device_id *id)
|
||||
{
|
||||
|
@ -453,6 +405,7 @@ static int thunderx_gpio_probe(struct pci_dev *pdev,
|
|||
struct device *dev = &pdev->dev;
|
||||
struct thunderx_gpio *txgpio;
|
||||
struct gpio_chip *chip;
|
||||
struct gpio_irq_chip *girq;
|
||||
int ngpio, i;
|
||||
int err = 0;
|
||||
|
||||
|
@ -497,8 +450,8 @@ static int thunderx_gpio_probe(struct pci_dev *pdev,
|
|||
}
|
||||
|
||||
txgpio->msix_entries = devm_kcalloc(dev,
|
||||
ngpio, sizeof(struct msix_entry),
|
||||
GFP_KERNEL);
|
||||
ngpio, sizeof(struct msix_entry),
|
||||
GFP_KERNEL);
|
||||
if (!txgpio->msix_entries) {
|
||||
err = -ENOMEM;
|
||||
goto out;
|
||||
|
@ -539,27 +492,6 @@ static int thunderx_gpio_probe(struct pci_dev *pdev,
|
|||
if (err < 0)
|
||||
goto out;
|
||||
|
||||
/*
|
||||
* Push GPIO specific irqdomain on hierarchy created as a side
|
||||
* effect of the pci_enable_msix()
|
||||
*/
|
||||
txgpio->irqd = irq_domain_create_hierarchy(irq_get_irq_data(txgpio->msix_entries[0].vector)->domain,
|
||||
0, 0, of_node_to_fwnode(dev->of_node),
|
||||
&thunderx_gpio_irqd_ops, txgpio);
|
||||
if (!txgpio->irqd) {
|
||||
err = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Push on irq_data and the domain for each line. */
|
||||
for (i = 0; i < ngpio; i++) {
|
||||
err = irq_domain_push_irq(txgpio->irqd,
|
||||
txgpio->msix_entries[i].vector,
|
||||
&txgpio->line_entries[i]);
|
||||
if (err < 0)
|
||||
dev_err(dev, "irq_domain_push_irq: %d\n", err);
|
||||
}
|
||||
|
||||
chip->label = KBUILD_MODNAME;
|
||||
chip->parent = dev;
|
||||
chip->owner = THIS_MODULE;
|
||||
|
@ -574,11 +506,28 @@ static int thunderx_gpio_probe(struct pci_dev *pdev,
|
|||
chip->set = thunderx_gpio_set;
|
||||
chip->set_multiple = thunderx_gpio_set_multiple;
|
||||
chip->set_config = thunderx_gpio_set_config;
|
||||
chip->to_irq = thunderx_gpio_to_irq;
|
||||
girq = &chip->irq;
|
||||
girq->chip = &thunderx_gpio_irq_chip;
|
||||
girq->fwnode = of_node_to_fwnode(dev->of_node);
|
||||
girq->parent_domain =
|
||||
irq_get_irq_data(txgpio->msix_entries[0].vector)->domain;
|
||||
girq->child_to_parent_hwirq = thunderx_gpio_child_to_parent_hwirq;
|
||||
girq->handler = handle_bad_irq;
|
||||
girq->default_type = IRQ_TYPE_NONE;
|
||||
|
||||
err = devm_gpiochip_add_data(dev, chip, txgpio);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
/* Push on irq_data and the domain for each line. */
|
||||
for (i = 0; i < ngpio; i++) {
|
||||
err = irq_domain_push_irq(chip->irq.domain,
|
||||
txgpio->msix_entries[i].vector,
|
||||
chip);
|
||||
if (err < 0)
|
||||
dev_err(dev, "irq_domain_push_irq: %d\n", err);
|
||||
}
|
||||
|
||||
dev_info(dev, "ThunderX GPIO: %d lines with base %d.\n",
|
||||
ngpio, chip->base);
|
||||
return 0;
|
||||
|
@ -593,10 +542,10 @@ static void thunderx_gpio_remove(struct pci_dev *pdev)
|
|||
struct thunderx_gpio *txgpio = pci_get_drvdata(pdev);
|
||||
|
||||
for (i = 0; i < txgpio->chip.ngpio; i++)
|
||||
irq_domain_pop_irq(txgpio->irqd,
|
||||
irq_domain_pop_irq(txgpio->chip.irq.domain,
|
||||
txgpio->msix_entries[i].vector);
|
||||
|
||||
irq_domain_remove(txgpio->irqd);
|
||||
irq_domain_remove(txgpio->chip.irq.domain);
|
||||
|
||||
pci_set_drvdata(pdev, NULL);
|
||||
}
|
||||
|
|
|
@ -214,11 +214,23 @@ static const struct dev_pm_ops tqmx86_gpio_dev_pm_ops = {
|
|||
tqmx86_gpio_runtime_resume, NULL)
|
||||
};
|
||||
|
||||
static void tqmx86_init_irq_valid_mask(struct gpio_chip *chip,
|
||||
unsigned long *valid_mask,
|
||||
unsigned int ngpios)
|
||||
{
|
||||
/* Only GPIOs 4-7 are valid for interrupts. Clear the others */
|
||||
clear_bit(0, valid_mask);
|
||||
clear_bit(1, valid_mask);
|
||||
clear_bit(2, valid_mask);
|
||||
clear_bit(3, valid_mask);
|
||||
}
|
||||
|
||||
static int tqmx86_gpio_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct tqmx86_gpio_data *gpio;
|
||||
struct gpio_chip *chip;
|
||||
struct gpio_irq_chip *girq;
|
||||
void __iomem *io_base;
|
||||
struct resource *res;
|
||||
int ret, irq;
|
||||
|
@ -259,17 +271,10 @@ static int tqmx86_gpio_probe(struct platform_device *pdev)
|
|||
chip->get = tqmx86_gpio_get;
|
||||
chip->set = tqmx86_gpio_set;
|
||||
chip->ngpio = TQMX86_NGPIO;
|
||||
chip->irq.need_valid_mask = true;
|
||||
chip->parent = pdev->dev.parent;
|
||||
|
||||
pm_runtime_enable(&pdev->dev);
|
||||
|
||||
ret = devm_gpiochip_add_data(dev, chip, gpio);
|
||||
if (ret) {
|
||||
dev_err(dev, "Could not register GPIO chip\n");
|
||||
goto out_pm_dis;
|
||||
}
|
||||
|
||||
if (irq) {
|
||||
struct irq_chip *irq_chip = &gpio->irq_chip;
|
||||
u8 irq_status;
|
||||
|
@ -287,23 +292,28 @@ static int tqmx86_gpio_probe(struct platform_device *pdev)
|
|||
irq_status = tqmx86_gpio_read(gpio, TQMX86_GPIIS);
|
||||
tqmx86_gpio_write(gpio, irq_status, TQMX86_GPIIS);
|
||||
|
||||
ret = gpiochip_irqchip_add(chip, irq_chip,
|
||||
0, handle_simple_irq,
|
||||
IRQ_TYPE_EDGE_BOTH);
|
||||
if (ret) {
|
||||
dev_err(dev, "Could not add irq chip\n");
|
||||
girq = &chip->irq;
|
||||
girq->chip = irq_chip;
|
||||
girq->parent_handler = tqmx86_gpio_irq_handler;
|
||||
girq->num_parents = 1;
|
||||
girq->parents = devm_kcalloc(&pdev->dev, 1,
|
||||
sizeof(*girq->parents),
|
||||
GFP_KERNEL);
|
||||
if (!girq->parents) {
|
||||
ret = -ENOMEM;
|
||||
goto out_pm_dis;
|
||||
}
|
||||
|
||||
gpiochip_set_chained_irqchip(chip, irq_chip,
|
||||
irq, tqmx86_gpio_irq_handler);
|
||||
girq->parents[0] = irq;
|
||||
girq->default_type = IRQ_TYPE_NONE;
|
||||
girq->handler = handle_simple_irq;
|
||||
girq->init_valid_mask = tqmx86_init_irq_valid_mask;
|
||||
}
|
||||
|
||||
/* Only GPIOs 4-7 are valid for interrupts. Clear the others */
|
||||
clear_bit(0, chip->irq.valid_mask);
|
||||
clear_bit(1, chip->irq.valid_mask);
|
||||
clear_bit(2, chip->irq.valid_mask);
|
||||
clear_bit(3, chip->irq.valid_mask);
|
||||
ret = devm_gpiochip_add_data(dev, chip, gpio);
|
||||
if (ret) {
|
||||
dev_err(dev, "Could not register GPIO chip\n");
|
||||
goto out_pm_dis;
|
||||
}
|
||||
|
||||
dev_info(dev, "GPIO functionality initialized with %d pins\n",
|
||||
chip->ngpio);
|
||||
|
|
|
@ -243,6 +243,7 @@ static int vf610_gpio_probe(struct platform_device *pdev)
|
|||
struct device_node *np = dev->of_node;
|
||||
struct vf610_gpio_port *port;
|
||||
struct gpio_chip *gc;
|
||||
struct gpio_irq_chip *girq;
|
||||
struct irq_chip *ic;
|
||||
int i;
|
||||
int ret;
|
||||
|
@ -318,10 +319,6 @@ static int vf610_gpio_probe(struct platform_device *pdev)
|
|||
ic->irq_set_type = vf610_gpio_irq_set_type;
|
||||
ic->irq_set_wake = vf610_gpio_irq_set_wake;
|
||||
|
||||
ret = devm_gpiochip_add_data(dev, gc, port);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Mask all GPIO interrupts */
|
||||
for (i = 0; i < gc->ngpio; i++)
|
||||
vf610_gpio_writel(0, port->base + PORT_PCR(i));
|
||||
|
@ -329,15 +326,20 @@ static int vf610_gpio_probe(struct platform_device *pdev)
|
|||
/* Clear the interrupt status register for all GPIO's */
|
||||
vf610_gpio_writel(~0, port->base + PORT_ISFR);
|
||||
|
||||
ret = gpiochip_irqchip_add(gc, ic, 0, handle_edge_irq, IRQ_TYPE_NONE);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to add irqchip\n");
|
||||
return ret;
|
||||
}
|
||||
gpiochip_set_chained_irqchip(gc, ic, port->irq,
|
||||
vf610_gpio_irq_handler);
|
||||
girq = &gc->irq;
|
||||
girq->chip = ic;
|
||||
girq->parent_handler = vf610_gpio_irq_handler;
|
||||
girq->num_parents = 1;
|
||||
girq->parents = devm_kcalloc(&pdev->dev, 1,
|
||||
sizeof(*girq->parents),
|
||||
GFP_KERNEL);
|
||||
if (!girq->parents)
|
||||
return -ENOMEM;
|
||||
girq->parents[0] = port->irq;
|
||||
girq->default_type = IRQ_TYPE_NONE;
|
||||
girq->handler = handle_edge_irq;
|
||||
|
||||
return 0;
|
||||
return devm_gpiochip_add_data(dev, gc, port);
|
||||
}
|
||||
|
||||
static struct platform_driver vf610_gpio_driver = {
|
||||
|
|
|
@ -79,7 +79,7 @@ MODULE_PARM_DESC(gpioa_freq,
|
|||
/* ----- begin of gipo a chip -------------------------------------------- */
|
||||
|
||||
static int vprbrd_gpioa_get(struct gpio_chip *chip,
|
||||
unsigned offset)
|
||||
unsigned int offset)
|
||||
{
|
||||
int ret, answer, error = 0;
|
||||
struct vprbrd_gpio *gpio = gpiochip_get_data(chip);
|
||||
|
@ -129,7 +129,7 @@ static int vprbrd_gpioa_get(struct gpio_chip *chip,
|
|||
}
|
||||
|
||||
static void vprbrd_gpioa_set(struct gpio_chip *chip,
|
||||
unsigned offset, int value)
|
||||
unsigned int offset, int value)
|
||||
{
|
||||
int ret;
|
||||
struct vprbrd_gpio *gpio = gpiochip_get_data(chip);
|
||||
|
@ -170,7 +170,7 @@ static void vprbrd_gpioa_set(struct gpio_chip *chip,
|
|||
}
|
||||
|
||||
static int vprbrd_gpioa_direction_input(struct gpio_chip *chip,
|
||||
unsigned offset)
|
||||
unsigned int offset)
|
||||
{
|
||||
int ret;
|
||||
struct vprbrd_gpio *gpio = gpiochip_get_data(chip);
|
||||
|
@ -207,7 +207,7 @@ static int vprbrd_gpioa_direction_input(struct gpio_chip *chip,
|
|||
}
|
||||
|
||||
static int vprbrd_gpioa_direction_output(struct gpio_chip *chip,
|
||||
unsigned offset, int value)
|
||||
unsigned int offset, int value)
|
||||
{
|
||||
int ret;
|
||||
struct vprbrd_gpio *gpio = gpiochip_get_data(chip);
|
||||
|
@ -251,8 +251,8 @@ static int vprbrd_gpioa_direction_output(struct gpio_chip *chip,
|
|||
|
||||
/* ----- begin of gipo b chip -------------------------------------------- */
|
||||
|
||||
static int vprbrd_gpiob_setdir(struct vprbrd *vb, unsigned offset,
|
||||
unsigned dir)
|
||||
static int vprbrd_gpiob_setdir(struct vprbrd *vb, unsigned int offset,
|
||||
unsigned int dir)
|
||||
{
|
||||
struct vprbrd_gpiob_msg *gbmsg = (struct vprbrd_gpiob_msg *)vb->buf;
|
||||
int ret;
|
||||
|
@ -273,7 +273,7 @@ static int vprbrd_gpiob_setdir(struct vprbrd *vb, unsigned offset,
|
|||
}
|
||||
|
||||
static int vprbrd_gpiob_get(struct gpio_chip *chip,
|
||||
unsigned offset)
|
||||
unsigned int offset)
|
||||
{
|
||||
int ret;
|
||||
u16 val;
|
||||
|
@ -305,7 +305,7 @@ static int vprbrd_gpiob_get(struct gpio_chip *chip,
|
|||
}
|
||||
|
||||
static void vprbrd_gpiob_set(struct gpio_chip *chip,
|
||||
unsigned offset, int value)
|
||||
unsigned int offset, int value)
|
||||
{
|
||||
int ret;
|
||||
struct vprbrd_gpio *gpio = gpiochip_get_data(chip);
|
||||
|
@ -338,7 +338,7 @@ static void vprbrd_gpiob_set(struct gpio_chip *chip,
|
|||
}
|
||||
|
||||
static int vprbrd_gpiob_direction_input(struct gpio_chip *chip,
|
||||
unsigned offset)
|
||||
unsigned int offset)
|
||||
{
|
||||
int ret;
|
||||
struct vprbrd_gpio *gpio = gpiochip_get_data(chip);
|
||||
|
@ -359,7 +359,7 @@ static int vprbrd_gpiob_direction_input(struct gpio_chip *chip,
|
|||
}
|
||||
|
||||
static int vprbrd_gpiob_direction_output(struct gpio_chip *chip,
|
||||
unsigned offset, int value)
|
||||
unsigned int offset, int value)
|
||||
{
|
||||
int ret;
|
||||
struct vprbrd_gpio *gpio = gpiochip_get_data(chip);
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#include <linux/acpi.h>
|
||||
|
||||
#include "gpiolib.h"
|
||||
#include "gpiolib-acpi.h"
|
||||
|
||||
/* Common property names */
|
||||
#define XGENE_NIRQ_PROPERTY "apm,nr-irqs"
|
||||
|
|
|
@ -290,6 +290,7 @@ MODULE_DEVICE_TABLE(of, xlp_gpio_of_ids);
|
|||
static int xlp_gpio_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct gpio_chip *gc;
|
||||
struct gpio_irq_chip *girq;
|
||||
struct xlp_gpio_priv *priv;
|
||||
void __iomem *gpio_base;
|
||||
int irq_base, irq, err;
|
||||
|
@ -395,27 +396,27 @@ static int xlp_gpio_probe(struct platform_device *pdev)
|
|||
irq_base = 0;
|
||||
}
|
||||
|
||||
girq = &gc->irq;
|
||||
girq->chip = &xlp_gpio_irq_chip;
|
||||
girq->parent_handler = xlp_gpio_generic_handler;
|
||||
girq->num_parents = 1;
|
||||
girq->parents = devm_kcalloc(&pdev->dev, 1,
|
||||
sizeof(*girq->parents),
|
||||
GFP_KERNEL);
|
||||
if (!girq->parents)
|
||||
return -ENOMEM;
|
||||
girq->parents[0] = irq;
|
||||
girq->first = irq_base;
|
||||
girq->default_type = IRQ_TYPE_NONE;
|
||||
girq->handler = handle_level_irq;
|
||||
|
||||
err = gpiochip_add_data(gc, priv);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
err = gpiochip_irqchip_add(gc, &xlp_gpio_irq_chip, irq_base,
|
||||
handle_level_irq, IRQ_TYPE_NONE);
|
||||
if (err) {
|
||||
dev_err(&pdev->dev, "Could not connect irqchip to gpiochip!\n");
|
||||
goto out_gpio_remove;
|
||||
}
|
||||
|
||||
gpiochip_set_chained_irqchip(gc, &xlp_gpio_irq_chip, irq,
|
||||
xlp_gpio_generic_handler);
|
||||
|
||||
dev_info(&pdev->dev, "registered %d GPIOs\n", gc->ngpio);
|
||||
|
||||
return 0;
|
||||
|
||||
out_gpio_remove:
|
||||
gpiochip_remove(gc);
|
||||
return err;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_ACPI
|
||||
|
|
|
@ -215,6 +215,7 @@ static int zx_gpio_probe(struct platform_device *pdev)
|
|||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct zx_gpio *chip;
|
||||
struct gpio_irq_chip *girq;
|
||||
int irq, id, ret;
|
||||
|
||||
chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL);
|
||||
|
@ -242,32 +243,30 @@ static int zx_gpio_probe(struct platform_device *pdev)
|
|||
chip->gc.parent = dev;
|
||||
chip->gc.owner = THIS_MODULE;
|
||||
|
||||
ret = gpiochip_add_data(&chip->gc, chip);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* irq_chip support
|
||||
*/
|
||||
writew_relaxed(0xffff, chip->base + ZX_GPIO_IM);
|
||||
writew_relaxed(0, chip->base + ZX_GPIO_IE);
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq < 0) {
|
||||
dev_err(dev, "invalid IRQ\n");
|
||||
gpiochip_remove(&chip->gc);
|
||||
return -ENODEV;
|
||||
}
|
||||
if (irq < 0)
|
||||
return irq;
|
||||
girq = &chip->gc.irq;
|
||||
girq->chip = &zx_irqchip;
|
||||
girq->parent_handler = zx_irq_handler;
|
||||
girq->num_parents = 1;
|
||||
girq->parents = devm_kcalloc(&pdev->dev, 1,
|
||||
sizeof(*girq->parents),
|
||||
GFP_KERNEL);
|
||||
if (!girq->parents)
|
||||
return -ENOMEM;
|
||||
girq->parents[0] = irq;
|
||||
girq->default_type = IRQ_TYPE_NONE;
|
||||
girq->handler = handle_simple_irq;
|
||||
|
||||
ret = gpiochip_irqchip_add(&chip->gc, &zx_irqchip,
|
||||
0, handle_simple_irq,
|
||||
IRQ_TYPE_NONE);
|
||||
if (ret) {
|
||||
dev_err(dev, "could not add irqchip\n");
|
||||
gpiochip_remove(&chip->gc);
|
||||
ret = gpiochip_add_data(&chip->gc, chip);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
gpiochip_set_chained_irqchip(&chip->gc, &zx_irqchip,
|
||||
irq, zx_irq_handler);
|
||||
|
||||
platform_set_drvdata(pdev, chip);
|
||||
dev_info(dev, "ZX GPIO chip registered\n");
|
||||
|
|
|
@ -830,6 +830,7 @@ static int zynq_gpio_probe(struct platform_device *pdev)
|
|||
int ret, bank_num;
|
||||
struct zynq_gpio *gpio;
|
||||
struct gpio_chip *chip;
|
||||
struct gpio_irq_chip *girq;
|
||||
const struct of_device_id *match;
|
||||
|
||||
gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL);
|
||||
|
@ -849,10 +850,8 @@ static int zynq_gpio_probe(struct platform_device *pdev)
|
|||
return PTR_ERR(gpio->base_addr);
|
||||
|
||||
gpio->irq = platform_get_irq(pdev, 0);
|
||||
if (gpio->irq < 0) {
|
||||
dev_err(&pdev->dev, "invalid IRQ\n");
|
||||
if (gpio->irq < 0)
|
||||
return gpio->irq;
|
||||
}
|
||||
|
||||
/* configure the gpio chip */
|
||||
chip = &gpio->chip;
|
||||
|
@ -887,6 +886,27 @@ static int zynq_gpio_probe(struct platform_device *pdev)
|
|||
if (ret < 0)
|
||||
goto err_pm_dis;
|
||||
|
||||
/* disable interrupts for all banks */
|
||||
for (bank_num = 0; bank_num < gpio->p_data->max_bank; bank_num++)
|
||||
writel_relaxed(ZYNQ_GPIO_IXR_DISABLE_ALL, gpio->base_addr +
|
||||
ZYNQ_GPIO_INTDIS_OFFSET(bank_num));
|
||||
|
||||
/* Set up the GPIO irqchip */
|
||||
girq = &chip->irq;
|
||||
girq->chip = &zynq_gpio_edge_irqchip;
|
||||
girq->parent_handler = zynq_gpio_irqhandler;
|
||||
girq->num_parents = 1;
|
||||
girq->parents = devm_kcalloc(&pdev->dev, 1,
|
||||
sizeof(*girq->parents),
|
||||
GFP_KERNEL);
|
||||
if (!girq->parents) {
|
||||
ret = -ENOMEM;
|
||||
goto err_pm_put;
|
||||
}
|
||||
girq->parents[0] = gpio->irq;
|
||||
girq->default_type = IRQ_TYPE_NONE;
|
||||
girq->handler = handle_level_irq;
|
||||
|
||||
/* report a bug if gpio chip registration fails */
|
||||
ret = gpiochip_add_data(chip, gpio);
|
||||
if (ret) {
|
||||
|
@ -894,27 +914,10 @@ static int zynq_gpio_probe(struct platform_device *pdev)
|
|||
goto err_pm_put;
|
||||
}
|
||||
|
||||
/* disable interrupts for all banks */
|
||||
for (bank_num = 0; bank_num < gpio->p_data->max_bank; bank_num++)
|
||||
writel_relaxed(ZYNQ_GPIO_IXR_DISABLE_ALL, gpio->base_addr +
|
||||
ZYNQ_GPIO_INTDIS_OFFSET(bank_num));
|
||||
|
||||
ret = gpiochip_irqchip_add(chip, &zynq_gpio_edge_irqchip, 0,
|
||||
handle_level_irq, IRQ_TYPE_NONE);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "Failed to add irq chip\n");
|
||||
goto err_rm_gpiochip;
|
||||
}
|
||||
|
||||
gpiochip_set_chained_irqchip(chip, &zynq_gpio_edge_irqchip, gpio->irq,
|
||||
zynq_gpio_irqhandler);
|
||||
|
||||
pm_runtime_put(&pdev->dev);
|
||||
|
||||
return 0;
|
||||
|
||||
err_rm_gpiochip:
|
||||
gpiochip_remove(chip);
|
||||
err_pm_put:
|
||||
pm_runtime_put(&pdev->dev);
|
||||
err_pm_dis:
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include <linux/pinctrl/pinctrl.h>
|
||||
|
||||
#include "gpiolib.h"
|
||||
#include "gpiolib-acpi.h"
|
||||
|
||||
static int run_edge_events_on_boot = -1;
|
||||
module_param(run_edge_events_on_boot, int, 0444);
|
||||
|
@ -391,6 +392,13 @@ int acpi_dev_add_driver_gpios(struct acpi_device *adev,
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(acpi_dev_add_driver_gpios);
|
||||
|
||||
void acpi_dev_remove_driver_gpios(struct acpi_device *adev)
|
||||
{
|
||||
if (adev)
|
||||
adev->driver_gpios = NULL;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(acpi_dev_remove_driver_gpios);
|
||||
|
||||
static void devm_acpi_dev_release_driver_gpios(struct device *dev, void *res)
|
||||
{
|
||||
acpi_dev_remove_driver_gpios(ACPI_COMPANION(dev));
|
||||
|
@ -729,6 +737,16 @@ static struct gpio_desc *acpi_get_gpiod_by_index(struct acpi_device *adev,
|
|||
return ret ? ERR_PTR(ret) : lookup.desc;
|
||||
}
|
||||
|
||||
static bool acpi_can_fallback_to_crs(struct acpi_device *adev,
|
||||
const char *con_id)
|
||||
{
|
||||
/* Never allow fallback if the device has properties */
|
||||
if (acpi_dev_has_props(adev) || adev->driver_gpios)
|
||||
return false;
|
||||
|
||||
return con_id == NULL;
|
||||
}
|
||||
|
||||
struct gpio_desc *acpi_find_gpio(struct device *dev,
|
||||
const char *con_id,
|
||||
unsigned int idx,
|
||||
|
@ -1265,15 +1283,6 @@ int acpi_gpio_count(struct device *dev, const char *con_id)
|
|||
return count ? count : -ENOENT;
|
||||
}
|
||||
|
||||
bool acpi_can_fallback_to_crs(struct acpi_device *adev, const char *con_id)
|
||||
{
|
||||
/* Never allow fallback if the device has properties */
|
||||
if (acpi_dev_has_props(adev) || adev->driver_gpios)
|
||||
return false;
|
||||
|
||||
return con_id == NULL;
|
||||
}
|
||||
|
||||
/* Run deferred acpi_gpiochip_request_irqs() */
|
||||
static int acpi_gpio_handle_deferred_request_irqs(void)
|
||||
{
|
||||
|
|
|
@ -0,0 +1,96 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* ACPI helpers for GPIO API
|
||||
*
|
||||
* Copyright (C) 2012,2019 Intel Corporation
|
||||
*/
|
||||
|
||||
#ifndef GPIOLIB_ACPI_H
|
||||
#define GPIOLIB_ACPI_H
|
||||
|
||||
struct acpi_device;
|
||||
|
||||
/**
|
||||
* struct acpi_gpio_info - ACPI GPIO specific information
|
||||
* @adev: reference to ACPI device which consumes GPIO resource
|
||||
* @flags: GPIO initialization flags
|
||||
* @gpioint: if %true this GPIO is of type GpioInt otherwise type is GpioIo
|
||||
* @pin_config: pin bias as provided by ACPI
|
||||
* @polarity: interrupt polarity as provided by ACPI
|
||||
* @triggering: triggering type as provided by ACPI
|
||||
* @quirks: Linux specific quirks as provided by struct acpi_gpio_mapping
|
||||
*/
|
||||
struct acpi_gpio_info {
|
||||
struct acpi_device *adev;
|
||||
enum gpiod_flags flags;
|
||||
bool gpioint;
|
||||
int pin_config;
|
||||
int polarity;
|
||||
int triggering;
|
||||
unsigned int quirks;
|
||||
};
|
||||
|
||||
#ifdef CONFIG_ACPI
|
||||
void acpi_gpiochip_add(struct gpio_chip *chip);
|
||||
void acpi_gpiochip_remove(struct gpio_chip *chip);
|
||||
|
||||
void acpi_gpiochip_request_interrupts(struct gpio_chip *chip);
|
||||
void acpi_gpiochip_free_interrupts(struct gpio_chip *chip);
|
||||
|
||||
int acpi_gpio_update_gpiod_flags(enum gpiod_flags *flags,
|
||||
struct acpi_gpio_info *info);
|
||||
int acpi_gpio_update_gpiod_lookup_flags(unsigned long *lookupflags,
|
||||
struct acpi_gpio_info *info);
|
||||
|
||||
struct gpio_desc *acpi_find_gpio(struct device *dev,
|
||||
const char *con_id,
|
||||
unsigned int idx,
|
||||
enum gpiod_flags *dflags,
|
||||
unsigned long *lookupflags);
|
||||
struct gpio_desc *acpi_node_get_gpiod(struct fwnode_handle *fwnode,
|
||||
const char *propname, int index,
|
||||
struct acpi_gpio_info *info);
|
||||
|
||||
int acpi_gpio_count(struct device *dev, const char *con_id);
|
||||
#else
|
||||
static inline void acpi_gpiochip_add(struct gpio_chip *chip) { }
|
||||
static inline void acpi_gpiochip_remove(struct gpio_chip *chip) { }
|
||||
|
||||
static inline void
|
||||
acpi_gpiochip_request_interrupts(struct gpio_chip *chip) { }
|
||||
|
||||
static inline void
|
||||
acpi_gpiochip_free_interrupts(struct gpio_chip *chip) { }
|
||||
|
||||
static inline int
|
||||
acpi_gpio_update_gpiod_flags(enum gpiod_flags *flags, struct acpi_gpio_info *info)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
static inline int
|
||||
acpi_gpio_update_gpiod_lookup_flags(unsigned long *lookupflags,
|
||||
struct acpi_gpio_info *info)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline struct gpio_desc *
|
||||
acpi_find_gpio(struct device *dev, const char *con_id,
|
||||
unsigned int idx, enum gpiod_flags *dflags,
|
||||
unsigned long *lookupflags)
|
||||
{
|
||||
return ERR_PTR(-ENOENT);
|
||||
}
|
||||
static inline struct gpio_desc *
|
||||
acpi_node_get_gpiod(struct fwnode_handle *fwnode, const char *propname,
|
||||
int index, struct acpi_gpio_info *info)
|
||||
{
|
||||
return ERR_PTR(-ENXIO);
|
||||
}
|
||||
static inline int acpi_gpio_count(struct device *dev, const char *con_id)
|
||||
{
|
||||
return -ENODEV;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* GPIOLIB_ACPI_H */
|
|
@ -59,7 +59,7 @@ struct gpio_desc *__must_check devm_gpiod_get(struct device *dev,
|
|||
{
|
||||
return devm_gpiod_get_index(dev, con_id, 0, flags);
|
||||
}
|
||||
EXPORT_SYMBOL(devm_gpiod_get);
|
||||
EXPORT_SYMBOL_GPL(devm_gpiod_get);
|
||||
|
||||
/**
|
||||
* devm_gpiod_get_optional - Resource-managed gpiod_get_optional()
|
||||
|
@ -77,7 +77,7 @@ struct gpio_desc *__must_check devm_gpiod_get_optional(struct device *dev,
|
|||
{
|
||||
return devm_gpiod_get_index_optional(dev, con_id, 0, flags);
|
||||
}
|
||||
EXPORT_SYMBOL(devm_gpiod_get_optional);
|
||||
EXPORT_SYMBOL_GPL(devm_gpiod_get_optional);
|
||||
|
||||
/**
|
||||
* devm_gpiod_get_index - Resource-managed gpiod_get_index()
|
||||
|
@ -127,7 +127,7 @@ struct gpio_desc *__must_check devm_gpiod_get_index(struct device *dev,
|
|||
|
||||
return desc;
|
||||
}
|
||||
EXPORT_SYMBOL(devm_gpiod_get_index);
|
||||
EXPORT_SYMBOL_GPL(devm_gpiod_get_index);
|
||||
|
||||
/**
|
||||
* devm_gpiod_get_from_of_node() - obtain a GPIO from an OF node
|
||||
|
@ -182,7 +182,7 @@ struct gpio_desc *devm_gpiod_get_from_of_node(struct device *dev,
|
|||
|
||||
return desc;
|
||||
}
|
||||
EXPORT_SYMBOL(devm_gpiod_get_from_of_node);
|
||||
EXPORT_SYMBOL_GPL(devm_gpiod_get_from_of_node);
|
||||
|
||||
/**
|
||||
* devm_fwnode_get_index_gpiod_from_child - get a GPIO descriptor from a
|
||||
|
@ -239,7 +239,7 @@ struct gpio_desc *devm_fwnode_get_index_gpiod_from_child(struct device *dev,
|
|||
|
||||
return desc;
|
||||
}
|
||||
EXPORT_SYMBOL(devm_fwnode_get_index_gpiod_from_child);
|
||||
EXPORT_SYMBOL_GPL(devm_fwnode_get_index_gpiod_from_child);
|
||||
|
||||
/**
|
||||
* devm_gpiod_get_index_optional - Resource-managed gpiod_get_index_optional()
|
||||
|
@ -268,7 +268,7 @@ struct gpio_desc *__must_check devm_gpiod_get_index_optional(struct device *dev,
|
|||
|
||||
return desc;
|
||||
}
|
||||
EXPORT_SYMBOL(devm_gpiod_get_index_optional);
|
||||
EXPORT_SYMBOL_GPL(devm_gpiod_get_index_optional);
|
||||
|
||||
/**
|
||||
* devm_gpiod_get_array - Resource-managed gpiod_get_array()
|
||||
|
@ -303,7 +303,7 @@ struct gpio_descs *__must_check devm_gpiod_get_array(struct device *dev,
|
|||
|
||||
return descs;
|
||||
}
|
||||
EXPORT_SYMBOL(devm_gpiod_get_array);
|
||||
EXPORT_SYMBOL_GPL(devm_gpiod_get_array);
|
||||
|
||||
/**
|
||||
* devm_gpiod_get_array_optional - Resource-managed gpiod_get_array_optional()
|
||||
|
@ -328,7 +328,7 @@ devm_gpiod_get_array_optional(struct device *dev, const char *con_id,
|
|||
|
||||
return descs;
|
||||
}
|
||||
EXPORT_SYMBOL(devm_gpiod_get_array_optional);
|
||||
EXPORT_SYMBOL_GPL(devm_gpiod_get_array_optional);
|
||||
|
||||
/**
|
||||
* devm_gpiod_put - Resource-managed gpiod_put()
|
||||
|
@ -344,7 +344,7 @@ void devm_gpiod_put(struct device *dev, struct gpio_desc *desc)
|
|||
WARN_ON(devres_release(dev, devm_gpiod_release, devm_gpiod_match,
|
||||
&desc));
|
||||
}
|
||||
EXPORT_SYMBOL(devm_gpiod_put);
|
||||
EXPORT_SYMBOL_GPL(devm_gpiod_put);
|
||||
|
||||
/**
|
||||
* devm_gpiod_unhinge - Remove resource management from a gpio descriptor
|
||||
|
@ -374,7 +374,7 @@ void devm_gpiod_unhinge(struct device *dev, struct gpio_desc *desc)
|
|||
/* Anything else we should warn about */
|
||||
WARN_ON(ret);
|
||||
}
|
||||
EXPORT_SYMBOL(devm_gpiod_unhinge);
|
||||
EXPORT_SYMBOL_GPL(devm_gpiod_unhinge);
|
||||
|
||||
/**
|
||||
* devm_gpiod_put_array - Resource-managed gpiod_put_array()
|
||||
|
@ -390,7 +390,7 @@ void devm_gpiod_put_array(struct device *dev, struct gpio_descs *descs)
|
|||
WARN_ON(devres_release(dev, devm_gpiod_release_array,
|
||||
devm_gpiod_match_array, &descs));
|
||||
}
|
||||
EXPORT_SYMBOL(devm_gpiod_put_array);
|
||||
EXPORT_SYMBOL_GPL(devm_gpiod_put_array);
|
||||
|
||||
|
||||
|
||||
|
@ -444,7 +444,7 @@ int devm_gpio_request(struct device *dev, unsigned gpio, const char *label)
|
|||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(devm_gpio_request);
|
||||
EXPORT_SYMBOL_GPL(devm_gpio_request);
|
||||
|
||||
/**
|
||||
* devm_gpio_request_one - request a single GPIO with initial setup
|
||||
|
@ -474,7 +474,7 @@ int devm_gpio_request_one(struct device *dev, unsigned gpio,
|
|||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(devm_gpio_request_one);
|
||||
EXPORT_SYMBOL_GPL(devm_gpio_request_one);
|
||||
|
||||
/**
|
||||
* devm_gpio_free - free a GPIO
|
||||
|
@ -492,4 +492,4 @@ void devm_gpio_free(struct device *dev, unsigned int gpio)
|
|||
WARN_ON(devres_release(dev, devm_gpio_release, devm_gpio_match,
|
||||
&gpio));
|
||||
}
|
||||
EXPORT_SYMBOL(devm_gpio_free);
|
||||
EXPORT_SYMBOL_GPL(devm_gpio_free);
|
||||
|
|
|
@ -21,6 +21,34 @@
|
|||
#include <linux/gpio/machine.h>
|
||||
|
||||
#include "gpiolib.h"
|
||||
#include "gpiolib-of.h"
|
||||
|
||||
/*
|
||||
* This is used by external users of of_gpio_count() from <linux/of_gpio.h>
|
||||
*
|
||||
* FIXME: get rid of those external users by converting them to GPIO
|
||||
* descriptors and let them all use gpiod_get_count()
|
||||
*/
|
||||
int of_gpio_get_count(struct device *dev, const char *con_id)
|
||||
{
|
||||
int ret;
|
||||
char propname[32];
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(gpio_suffixes); i++) {
|
||||
if (con_id)
|
||||
snprintf(propname, sizeof(propname), "%s-%s",
|
||||
con_id, gpio_suffixes[i]);
|
||||
else
|
||||
snprintf(propname, sizeof(propname), "%s",
|
||||
gpio_suffixes[i]);
|
||||
|
||||
ret = of_gpio_named_count(dev->of_node, propname);
|
||||
if (ret > 0)
|
||||
break;
|
||||
}
|
||||
return ret ? ret : -ENOENT;
|
||||
}
|
||||
|
||||
static int of_gpiochip_match_node_and_xlate(struct gpio_chip *chip, void *data)
|
||||
{
|
||||
|
@ -53,6 +81,23 @@ static struct gpio_desc *of_xlate_and_get_gpiod_flags(struct gpio_chip *chip,
|
|||
return gpiochip_get_desc(chip, ret);
|
||||
}
|
||||
|
||||
/**
|
||||
* of_gpio_need_valid_mask() - figure out if the OF GPIO driver needs
|
||||
* to set the .valid_mask
|
||||
* @dev: the device for the GPIO provider
|
||||
* @return: true if the valid mask needs to be set
|
||||
*/
|
||||
bool of_gpio_need_valid_mask(const struct gpio_chip *gc)
|
||||
{
|
||||
int size;
|
||||
struct device_node *np = gc->of_node;
|
||||
|
||||
size = of_property_count_u32_elems(np, "gpio-reserved-ranges");
|
||||
if (size > 0 && size % 2 == 0)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
static void of_gpio_flags_quirks(struct device_node *np,
|
||||
const char *propname,
|
||||
enum of_gpio_flags *flags,
|
||||
|
@ -178,7 +223,7 @@ static void of_gpio_flags_quirks(struct device_node *np,
|
|||
* value on the error condition. If @flags is not NULL the function also fills
|
||||
* in flags for the GPIO.
|
||||
*/
|
||||
struct gpio_desc *of_get_named_gpiod_flags(struct device_node *np,
|
||||
static struct gpio_desc *of_get_named_gpiod_flags(struct device_node *np,
|
||||
const char *propname, int index, enum of_gpio_flags *flags)
|
||||
{
|
||||
struct of_phandle_args gpiospec;
|
||||
|
@ -229,7 +274,76 @@ int of_get_named_gpio_flags(struct device_node *np, const char *list_name,
|
|||
else
|
||||
return desc_to_gpio(desc);
|
||||
}
|
||||
EXPORT_SYMBOL(of_get_named_gpio_flags);
|
||||
EXPORT_SYMBOL_GPL(of_get_named_gpio_flags);
|
||||
|
||||
/**
|
||||
* gpiod_get_from_of_node() - obtain a GPIO from an OF node
|
||||
* @node: handle of the OF node
|
||||
* @propname: name of the DT property representing the GPIO
|
||||
* @index: index of the GPIO to obtain for the consumer
|
||||
* @dflags: GPIO initialization flags
|
||||
* @label: label to attach to the requested GPIO
|
||||
*
|
||||
* Returns:
|
||||
* On successful request the GPIO pin is configured in accordance with
|
||||
* provided @dflags.
|
||||
*
|
||||
* In case of error an ERR_PTR() is returned.
|
||||
*/
|
||||
struct gpio_desc *gpiod_get_from_of_node(struct device_node *node,
|
||||
const char *propname, int index,
|
||||
enum gpiod_flags dflags,
|
||||
const char *label)
|
||||
{
|
||||
unsigned long lflags = GPIO_LOOKUP_FLAGS_DEFAULT;
|
||||
struct gpio_desc *desc;
|
||||
enum of_gpio_flags flags;
|
||||
bool active_low = false;
|
||||
bool single_ended = false;
|
||||
bool open_drain = false;
|
||||
bool transitory = false;
|
||||
int ret;
|
||||
|
||||
desc = of_get_named_gpiod_flags(node, propname,
|
||||
index, &flags);
|
||||
|
||||
if (!desc || IS_ERR(desc)) {
|
||||
return desc;
|
||||
}
|
||||
|
||||
active_low = flags & OF_GPIO_ACTIVE_LOW;
|
||||
single_ended = flags & OF_GPIO_SINGLE_ENDED;
|
||||
open_drain = flags & OF_GPIO_OPEN_DRAIN;
|
||||
transitory = flags & OF_GPIO_TRANSITORY;
|
||||
|
||||
ret = gpiod_request(desc, label);
|
||||
if (ret == -EBUSY && (flags & GPIOD_FLAGS_BIT_NONEXCLUSIVE))
|
||||
return desc;
|
||||
if (ret)
|
||||
return ERR_PTR(ret);
|
||||
|
||||
if (active_low)
|
||||
lflags |= GPIO_ACTIVE_LOW;
|
||||
|
||||
if (single_ended) {
|
||||
if (open_drain)
|
||||
lflags |= GPIO_OPEN_DRAIN;
|
||||
else
|
||||
lflags |= GPIO_OPEN_SOURCE;
|
||||
}
|
||||
|
||||
if (transitory)
|
||||
lflags |= GPIO_TRANSITORY;
|
||||
|
||||
ret = gpiod_configure_flags(desc, propname, lflags, dflags);
|
||||
if (ret < 0) {
|
||||
gpiod_put(desc);
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
return desc;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(gpiod_get_from_of_node);
|
||||
|
||||
/*
|
||||
* The SPI GPIO bindings happened before we managed to establish that GPIO
|
||||
|
@ -324,6 +438,19 @@ static struct gpio_desc *of_find_regulator_gpio(struct device *dev, const char *
|
|||
return desc;
|
||||
}
|
||||
|
||||
static struct gpio_desc *of_find_arizona_gpio(struct device *dev,
|
||||
const char *con_id,
|
||||
enum of_gpio_flags *of_flags)
|
||||
{
|
||||
if (!IS_ENABLED(CONFIG_MFD_ARIZONA))
|
||||
return ERR_PTR(-ENOENT);
|
||||
|
||||
if (!con_id || strcmp(con_id, "wlf,reset"))
|
||||
return ERR_PTR(-ENOENT);
|
||||
|
||||
return of_get_named_gpiod_flags(dev->of_node, con_id, 0, of_flags);
|
||||
}
|
||||
|
||||
struct gpio_desc *of_find_gpio(struct device *dev, const char *con_id,
|
||||
unsigned int idx, unsigned long *flags)
|
||||
{
|
||||
|
@ -365,6 +492,9 @@ struct gpio_desc *of_find_gpio(struct device *dev, const char *con_id,
|
|||
desc = of_find_regulator_gpio(dev, con_id, &of_flags);
|
||||
}
|
||||
|
||||
if (IS_ERR(desc) && PTR_ERR(desc) == -ENOENT)
|
||||
desc = of_find_arizona_gpio(dev, con_id, &of_flags);
|
||||
|
||||
if (IS_ERR(desc))
|
||||
return desc;
|
||||
|
||||
|
@ -514,8 +644,9 @@ static int of_gpiochip_scan_gpios(struct gpio_chip *chip)
|
|||
* GPIO chips. This function performs only one sanity check: whether GPIO
|
||||
* is less than ngpios (that is specified in the gpio_chip).
|
||||
*/
|
||||
int of_gpio_simple_xlate(struct gpio_chip *gc,
|
||||
const struct of_phandle_args *gpiospec, u32 *flags)
|
||||
static int of_gpio_simple_xlate(struct gpio_chip *gc,
|
||||
const struct of_phandle_args *gpiospec,
|
||||
u32 *flags)
|
||||
{
|
||||
/*
|
||||
* We're discouraging gpio_cells < 2, since that way you'll have to
|
||||
|
@ -539,7 +670,6 @@ int of_gpio_simple_xlate(struct gpio_chip *gc,
|
|||
|
||||
return gpiospec->args[0];
|
||||
}
|
||||
EXPORT_SYMBOL(of_gpio_simple_xlate);
|
||||
|
||||
/**
|
||||
* of_mm_gpiochip_add_data - Add memory mapped GPIO chip (bank)
|
||||
|
@ -596,7 +726,7 @@ err0:
|
|||
pr_err("%pOF: GPIO chip registration failed with status %d\n", np, ret);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(of_mm_gpiochip_add_data);
|
||||
EXPORT_SYMBOL_GPL(of_mm_gpiochip_add_data);
|
||||
|
||||
/**
|
||||
* of_mm_gpiochip_remove - Remove memory mapped GPIO chip (bank)
|
||||
|
@ -613,7 +743,7 @@ void of_mm_gpiochip_remove(struct of_mm_gpio_chip *mm_gc)
|
|||
iounmap(mm_gc->regs);
|
||||
kfree(gc->label);
|
||||
}
|
||||
EXPORT_SYMBOL(of_mm_gpiochip_remove);
|
||||
EXPORT_SYMBOL_GPL(of_mm_gpiochip_remove);
|
||||
|
||||
static void of_gpiochip_init_valid_mask(struct gpio_chip *chip)
|
||||
{
|
||||
|
@ -725,7 +855,7 @@ static int of_gpiochip_add_pin_range(struct gpio_chip *chip) { return 0; }
|
|||
|
||||
int of_gpiochip_add(struct gpio_chip *chip)
|
||||
{
|
||||
int status;
|
||||
int ret;
|
||||
|
||||
if (!chip->of_node)
|
||||
return 0;
|
||||
|
@ -740,9 +870,9 @@ int of_gpiochip_add(struct gpio_chip *chip)
|
|||
|
||||
of_gpiochip_init_valid_mask(chip);
|
||||
|
||||
status = of_gpiochip_add_pin_range(chip);
|
||||
if (status)
|
||||
return status;
|
||||
ret = of_gpiochip_add_pin_range(chip);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* If the chip defines names itself, these take precedence */
|
||||
if (!chip->names)
|
||||
|
@ -751,13 +881,13 @@ int of_gpiochip_add(struct gpio_chip *chip)
|
|||
|
||||
of_node_get(chip->of_node);
|
||||
|
||||
status = of_gpiochip_scan_gpios(chip);
|
||||
if (status) {
|
||||
ret = of_gpiochip_scan_gpios(chip);
|
||||
if (ret) {
|
||||
of_node_put(chip->of_node);
|
||||
gpiochip_remove_pin_ranges(chip);
|
||||
}
|
||||
|
||||
return status;
|
||||
return ret;
|
||||
}
|
||||
|
||||
void of_gpiochip_remove(struct gpio_chip *chip)
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
|
||||
#ifndef GPIOLIB_OF_H
|
||||
#define GPIOLIB_OF_H
|
||||
|
||||
struct gpio_chip;
|
||||
enum of_gpio_flags;
|
||||
|
||||
#ifdef CONFIG_OF_GPIO
|
||||
struct gpio_desc *of_find_gpio(struct device *dev,
|
||||
const char *con_id,
|
||||
unsigned int idx,
|
||||
unsigned long *lookupflags);
|
||||
int of_gpiochip_add(struct gpio_chip *gc);
|
||||
void of_gpiochip_remove(struct gpio_chip *gc);
|
||||
int of_gpio_get_count(struct device *dev, const char *con_id);
|
||||
bool of_gpio_need_valid_mask(const struct gpio_chip *gc);
|
||||
#else
|
||||
static inline struct gpio_desc *of_find_gpio(struct device *dev,
|
||||
const char *con_id,
|
||||
unsigned int idx,
|
||||
unsigned long *lookupflags)
|
||||
{
|
||||
return ERR_PTR(-ENOENT);
|
||||
}
|
||||
static inline int of_gpiochip_add(struct gpio_chip *gc) { return 0; }
|
||||
static inline void of_gpiochip_remove(struct gpio_chip *gc) { }
|
||||
static inline int of_gpio_get_count(struct device *dev, const char *con_id)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
static inline bool of_gpio_need_valid_mask(const struct gpio_chip *gc)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
#endif /* CONFIG_OF_GPIO */
|
||||
|
||||
#endif /* GPIOLIB_OF_H */
|
File diff suppressed because it is too large
Load Diff
|
@ -16,9 +16,6 @@
|
|||
#include <linux/module.h>
|
||||
#include <linux/cdev.h>
|
||||
|
||||
enum of_gpio_flags;
|
||||
struct acpi_device;
|
||||
|
||||
/**
|
||||
* struct gpio_device - internal state container for GPIO devices
|
||||
* @id: numerical ID number for the GPIO chip
|
||||
|
@ -69,126 +66,9 @@ struct gpio_device {
|
|||
#endif
|
||||
};
|
||||
|
||||
/**
|
||||
* struct acpi_gpio_info - ACPI GPIO specific information
|
||||
* @adev: reference to ACPI device which consumes GPIO resource
|
||||
* @flags: GPIO initialization flags
|
||||
* @gpioint: if %true this GPIO is of type GpioInt otherwise type is GpioIo
|
||||
* @pin_config: pin bias as provided by ACPI
|
||||
* @polarity: interrupt polarity as provided by ACPI
|
||||
* @triggering: triggering type as provided by ACPI
|
||||
* @quirks: Linux specific quirks as provided by struct acpi_gpio_mapping
|
||||
*/
|
||||
struct acpi_gpio_info {
|
||||
struct acpi_device *adev;
|
||||
enum gpiod_flags flags;
|
||||
bool gpioint;
|
||||
int pin_config;
|
||||
int polarity;
|
||||
int triggering;
|
||||
unsigned int quirks;
|
||||
};
|
||||
|
||||
/* gpio suffixes used for ACPI and device tree lookup */
|
||||
static __maybe_unused const char * const gpio_suffixes[] = { "gpios", "gpio" };
|
||||
|
||||
#ifdef CONFIG_OF_GPIO
|
||||
struct gpio_desc *of_find_gpio(struct device *dev,
|
||||
const char *con_id,
|
||||
unsigned int idx,
|
||||
unsigned long *lookupflags);
|
||||
struct gpio_desc *of_get_named_gpiod_flags(struct device_node *np,
|
||||
const char *list_name, int index, enum of_gpio_flags *flags);
|
||||
int of_gpiochip_add(struct gpio_chip *gc);
|
||||
void of_gpiochip_remove(struct gpio_chip *gc);
|
||||
#else
|
||||
static inline struct gpio_desc *of_find_gpio(struct device *dev,
|
||||
const char *con_id,
|
||||
unsigned int idx,
|
||||
unsigned long *lookupflags)
|
||||
{
|
||||
return ERR_PTR(-ENOENT);
|
||||
}
|
||||
static inline struct gpio_desc *of_get_named_gpiod_flags(struct device_node *np,
|
||||
const char *list_name, int index, enum of_gpio_flags *flags)
|
||||
{
|
||||
return ERR_PTR(-ENOENT);
|
||||
}
|
||||
static inline int of_gpiochip_add(struct gpio_chip *gc) { return 0; }
|
||||
static inline void of_gpiochip_remove(struct gpio_chip *gc) { }
|
||||
#endif /* CONFIG_OF_GPIO */
|
||||
|
||||
#ifdef CONFIG_ACPI
|
||||
void acpi_gpiochip_add(struct gpio_chip *chip);
|
||||
void acpi_gpiochip_remove(struct gpio_chip *chip);
|
||||
|
||||
void acpi_gpiochip_request_interrupts(struct gpio_chip *chip);
|
||||
void acpi_gpiochip_free_interrupts(struct gpio_chip *chip);
|
||||
|
||||
int acpi_gpio_update_gpiod_flags(enum gpiod_flags *flags,
|
||||
struct acpi_gpio_info *info);
|
||||
int acpi_gpio_update_gpiod_lookup_flags(unsigned long *lookupflags,
|
||||
struct acpi_gpio_info *info);
|
||||
|
||||
struct gpio_desc *acpi_find_gpio(struct device *dev,
|
||||
const char *con_id,
|
||||
unsigned int idx,
|
||||
enum gpiod_flags *dflags,
|
||||
unsigned long *lookupflags);
|
||||
struct gpio_desc *acpi_node_get_gpiod(struct fwnode_handle *fwnode,
|
||||
const char *propname, int index,
|
||||
struct acpi_gpio_info *info);
|
||||
|
||||
int acpi_gpio_count(struct device *dev, const char *con_id);
|
||||
|
||||
bool acpi_can_fallback_to_crs(struct acpi_device *adev, const char *con_id);
|
||||
#else
|
||||
static inline void acpi_gpiochip_add(struct gpio_chip *chip) { }
|
||||
static inline void acpi_gpiochip_remove(struct gpio_chip *chip) { }
|
||||
|
||||
static inline void
|
||||
acpi_gpiochip_request_interrupts(struct gpio_chip *chip) { }
|
||||
|
||||
static inline void
|
||||
acpi_gpiochip_free_interrupts(struct gpio_chip *chip) { }
|
||||
|
||||
static inline int
|
||||
acpi_gpio_update_gpiod_flags(enum gpiod_flags *flags, struct acpi_gpio_info *info)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
static inline int
|
||||
acpi_gpio_update_gpiod_lookup_flags(unsigned long *lookupflags,
|
||||
struct acpi_gpio_info *info)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline struct gpio_desc *
|
||||
acpi_find_gpio(struct device *dev, const char *con_id,
|
||||
unsigned int idx, enum gpiod_flags *dflags,
|
||||
unsigned long *lookupflags)
|
||||
{
|
||||
return ERR_PTR(-ENOENT);
|
||||
}
|
||||
static inline struct gpio_desc *
|
||||
acpi_node_get_gpiod(struct fwnode_handle *fwnode, const char *propname,
|
||||
int index, struct acpi_gpio_info *info)
|
||||
{
|
||||
return ERR_PTR(-ENXIO);
|
||||
}
|
||||
static inline int acpi_gpio_count(struct device *dev, const char *con_id)
|
||||
{
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
static inline bool acpi_can_fallback_to_crs(struct acpi_device *adev,
|
||||
const char *con_id)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
struct gpio_array {
|
||||
struct gpio_desc **desc;
|
||||
unsigned int size;
|
||||
|
|
|
@ -0,0 +1,533 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* Copyright 2019 American Megatrends International LLC.
|
||||
*
|
||||
* Author: Karthikeyan Mani <karthikeyanm@amiindia.co.in>
|
||||
*/
|
||||
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/gpio/driver.h>
|
||||
#include <linux/hashtable.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/string.h>
|
||||
|
||||
#define MAX_NR_SGPIO 80
|
||||
|
||||
#define ASPEED_SGPIO_CTRL 0x54
|
||||
|
||||
#define ASPEED_SGPIO_PINS_MASK GENMASK(9, 6)
|
||||
#define ASPEED_SGPIO_CLK_DIV_MASK GENMASK(31, 16)
|
||||
#define ASPEED_SGPIO_ENABLE BIT(0)
|
||||
|
||||
struct aspeed_sgpio {
|
||||
struct gpio_chip chip;
|
||||
struct clk *pclk;
|
||||
spinlock_t lock;
|
||||
void __iomem *base;
|
||||
uint32_t dir_in[3];
|
||||
int irq;
|
||||
};
|
||||
|
||||
struct aspeed_sgpio_bank {
|
||||
uint16_t val_regs;
|
||||
uint16_t rdata_reg;
|
||||
uint16_t irq_regs;
|
||||
const char names[4][3];
|
||||
};
|
||||
|
||||
/*
|
||||
* Note: The "value" register returns the input value when the GPIO is
|
||||
* configured as an input.
|
||||
*
|
||||
* The "rdata" register returns the output value when the GPIO is
|
||||
* configured as an output.
|
||||
*/
|
||||
static const struct aspeed_sgpio_bank aspeed_sgpio_banks[] = {
|
||||
{
|
||||
.val_regs = 0x0000,
|
||||
.rdata_reg = 0x0070,
|
||||
.irq_regs = 0x0004,
|
||||
.names = { "A", "B", "C", "D" },
|
||||
},
|
||||
{
|
||||
.val_regs = 0x001C,
|
||||
.rdata_reg = 0x0074,
|
||||
.irq_regs = 0x0020,
|
||||
.names = { "E", "F", "G", "H" },
|
||||
},
|
||||
{
|
||||
.val_regs = 0x0038,
|
||||
.rdata_reg = 0x0078,
|
||||
.irq_regs = 0x003C,
|
||||
.names = { "I", "J" },
|
||||
},
|
||||
};
|
||||
|
||||
enum aspeed_sgpio_reg {
|
||||
reg_val,
|
||||
reg_rdata,
|
||||
reg_irq_enable,
|
||||
reg_irq_type0,
|
||||
reg_irq_type1,
|
||||
reg_irq_type2,
|
||||
reg_irq_status,
|
||||
};
|
||||
|
||||
#define GPIO_VAL_VALUE 0x00
|
||||
#define GPIO_IRQ_ENABLE 0x00
|
||||
#define GPIO_IRQ_TYPE0 0x04
|
||||
#define GPIO_IRQ_TYPE1 0x08
|
||||
#define GPIO_IRQ_TYPE2 0x0C
|
||||
#define GPIO_IRQ_STATUS 0x10
|
||||
|
||||
static void __iomem *bank_reg(struct aspeed_sgpio *gpio,
|
||||
const struct aspeed_sgpio_bank *bank,
|
||||
const enum aspeed_sgpio_reg reg)
|
||||
{
|
||||
switch (reg) {
|
||||
case reg_val:
|
||||
return gpio->base + bank->val_regs + GPIO_VAL_VALUE;
|
||||
case reg_rdata:
|
||||
return gpio->base + bank->rdata_reg;
|
||||
case reg_irq_enable:
|
||||
return gpio->base + bank->irq_regs + GPIO_IRQ_ENABLE;
|
||||
case reg_irq_type0:
|
||||
return gpio->base + bank->irq_regs + GPIO_IRQ_TYPE0;
|
||||
case reg_irq_type1:
|
||||
return gpio->base + bank->irq_regs + GPIO_IRQ_TYPE1;
|
||||
case reg_irq_type2:
|
||||
return gpio->base + bank->irq_regs + GPIO_IRQ_TYPE2;
|
||||
case reg_irq_status:
|
||||
return gpio->base + bank->irq_regs + GPIO_IRQ_STATUS;
|
||||
default:
|
||||
/* acturally if code runs to here, it's an error case */
|
||||
BUG_ON(1);
|
||||
}
|
||||
}
|
||||
|
||||
#define GPIO_BANK(x) ((x) >> 5)
|
||||
#define GPIO_OFFSET(x) ((x) & 0x1f)
|
||||
#define GPIO_BIT(x) BIT(GPIO_OFFSET(x))
|
||||
|
||||
static const struct aspeed_sgpio_bank *to_bank(unsigned int offset)
|
||||
{
|
||||
unsigned int bank = GPIO_BANK(offset);
|
||||
|
||||
WARN_ON(bank >= ARRAY_SIZE(aspeed_sgpio_banks));
|
||||
return &aspeed_sgpio_banks[bank];
|
||||
}
|
||||
|
||||
static int aspeed_sgpio_get(struct gpio_chip *gc, unsigned int offset)
|
||||
{
|
||||
struct aspeed_sgpio *gpio = gpiochip_get_data(gc);
|
||||
const struct aspeed_sgpio_bank *bank = to_bank(offset);
|
||||
unsigned long flags;
|
||||
enum aspeed_sgpio_reg reg;
|
||||
bool is_input;
|
||||
int rc = 0;
|
||||
|
||||
spin_lock_irqsave(&gpio->lock, flags);
|
||||
|
||||
is_input = gpio->dir_in[GPIO_BANK(offset)] & GPIO_BIT(offset);
|
||||
reg = is_input ? reg_val : reg_rdata;
|
||||
rc = !!(ioread32(bank_reg(gpio, bank, reg)) & GPIO_BIT(offset));
|
||||
|
||||
spin_unlock_irqrestore(&gpio->lock, flags);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void sgpio_set_value(struct gpio_chip *gc, unsigned int offset, int val)
|
||||
{
|
||||
struct aspeed_sgpio *gpio = gpiochip_get_data(gc);
|
||||
const struct aspeed_sgpio_bank *bank = to_bank(offset);
|
||||
void __iomem *addr;
|
||||
u32 reg = 0;
|
||||
|
||||
addr = bank_reg(gpio, bank, reg_val);
|
||||
reg = ioread32(addr);
|
||||
|
||||
if (val)
|
||||
reg |= GPIO_BIT(offset);
|
||||
else
|
||||
reg &= ~GPIO_BIT(offset);
|
||||
|
||||
iowrite32(reg, addr);
|
||||
}
|
||||
|
||||
static void aspeed_sgpio_set(struct gpio_chip *gc, unsigned int offset, int val)
|
||||
{
|
||||
struct aspeed_sgpio *gpio = gpiochip_get_data(gc);
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&gpio->lock, flags);
|
||||
|
||||
sgpio_set_value(gc, offset, val);
|
||||
|
||||
spin_unlock_irqrestore(&gpio->lock, flags);
|
||||
}
|
||||
|
||||
static int aspeed_sgpio_dir_in(struct gpio_chip *gc, unsigned int offset)
|
||||
{
|
||||
struct aspeed_sgpio *gpio = gpiochip_get_data(gc);
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&gpio->lock, flags);
|
||||
gpio->dir_in[GPIO_BANK(offset)] |= GPIO_BIT(offset);
|
||||
spin_unlock_irqrestore(&gpio->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int aspeed_sgpio_dir_out(struct gpio_chip *gc, unsigned int offset, int val)
|
||||
{
|
||||
struct aspeed_sgpio *gpio = gpiochip_get_data(gc);
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&gpio->lock, flags);
|
||||
|
||||
gpio->dir_in[GPIO_BANK(offset)] &= ~GPIO_BIT(offset);
|
||||
sgpio_set_value(gc, offset, val);
|
||||
|
||||
spin_unlock_irqrestore(&gpio->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int aspeed_sgpio_get_direction(struct gpio_chip *gc, unsigned int offset)
|
||||
{
|
||||
int dir_status;
|
||||
struct aspeed_sgpio *gpio = gpiochip_get_data(gc);
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&gpio->lock, flags);
|
||||
dir_status = gpio->dir_in[GPIO_BANK(offset)] & GPIO_BIT(offset);
|
||||
spin_unlock_irqrestore(&gpio->lock, flags);
|
||||
|
||||
return dir_status;
|
||||
|
||||
}
|
||||
|
||||
static void irqd_to_aspeed_sgpio_data(struct irq_data *d,
|
||||
struct aspeed_sgpio **gpio,
|
||||
const struct aspeed_sgpio_bank **bank,
|
||||
u32 *bit, int *offset)
|
||||
{
|
||||
struct aspeed_sgpio *internal;
|
||||
|
||||
*offset = irqd_to_hwirq(d);
|
||||
internal = irq_data_get_irq_chip_data(d);
|
||||
WARN_ON(!internal);
|
||||
|
||||
*gpio = internal;
|
||||
*bank = to_bank(*offset);
|
||||
*bit = GPIO_BIT(*offset);
|
||||
}
|
||||
|
||||
static void aspeed_sgpio_irq_ack(struct irq_data *d)
|
||||
{
|
||||
const struct aspeed_sgpio_bank *bank;
|
||||
struct aspeed_sgpio *gpio;
|
||||
unsigned long flags;
|
||||
void __iomem *status_addr;
|
||||
int offset;
|
||||
u32 bit;
|
||||
|
||||
irqd_to_aspeed_sgpio_data(d, &gpio, &bank, &bit, &offset);
|
||||
|
||||
status_addr = bank_reg(gpio, bank, reg_irq_status);
|
||||
|
||||
spin_lock_irqsave(&gpio->lock, flags);
|
||||
|
||||
iowrite32(bit, status_addr);
|
||||
|
||||
spin_unlock_irqrestore(&gpio->lock, flags);
|
||||
}
|
||||
|
||||
static void aspeed_sgpio_irq_set_mask(struct irq_data *d, bool set)
|
||||
{
|
||||
const struct aspeed_sgpio_bank *bank;
|
||||
struct aspeed_sgpio *gpio;
|
||||
unsigned long flags;
|
||||
u32 reg, bit;
|
||||
void __iomem *addr;
|
||||
int offset;
|
||||
|
||||
irqd_to_aspeed_sgpio_data(d, &gpio, &bank, &bit, &offset);
|
||||
addr = bank_reg(gpio, bank, reg_irq_enable);
|
||||
|
||||
spin_lock_irqsave(&gpio->lock, flags);
|
||||
|
||||
reg = ioread32(addr);
|
||||
if (set)
|
||||
reg |= bit;
|
||||
else
|
||||
reg &= ~bit;
|
||||
|
||||
iowrite32(reg, addr);
|
||||
|
||||
spin_unlock_irqrestore(&gpio->lock, flags);
|
||||
}
|
||||
|
||||
static void aspeed_sgpio_irq_mask(struct irq_data *d)
|
||||
{
|
||||
aspeed_sgpio_irq_set_mask(d, false);
|
||||
}
|
||||
|
||||
static void aspeed_sgpio_irq_unmask(struct irq_data *d)
|
||||
{
|
||||
aspeed_sgpio_irq_set_mask(d, true);
|
||||
}
|
||||
|
||||
static int aspeed_sgpio_set_type(struct irq_data *d, unsigned int type)
|
||||
{
|
||||
u32 type0 = 0;
|
||||
u32 type1 = 0;
|
||||
u32 type2 = 0;
|
||||
u32 bit, reg;
|
||||
const struct aspeed_sgpio_bank *bank;
|
||||
irq_flow_handler_t handler;
|
||||
struct aspeed_sgpio *gpio;
|
||||
unsigned long flags;
|
||||
void __iomem *addr;
|
||||
int offset;
|
||||
|
||||
irqd_to_aspeed_sgpio_data(d, &gpio, &bank, &bit, &offset);
|
||||
|
||||
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;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&gpio->lock, flags);
|
||||
|
||||
addr = bank_reg(gpio, bank, reg_irq_type0);
|
||||
reg = ioread32(addr);
|
||||
reg = (reg & ~bit) | type0;
|
||||
iowrite32(reg, addr);
|
||||
|
||||
addr = bank_reg(gpio, bank, reg_irq_type1);
|
||||
reg = ioread32(addr);
|
||||
reg = (reg & ~bit) | type1;
|
||||
iowrite32(reg, addr);
|
||||
|
||||
addr = bank_reg(gpio, bank, reg_irq_type2);
|
||||
reg = ioread32(addr);
|
||||
reg = (reg & ~bit) | type2;
|
||||
iowrite32(reg, addr);
|
||||
|
||||
spin_unlock_irqrestore(&gpio->lock, flags);
|
||||
|
||||
irq_set_handler_locked(d, handler);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void aspeed_sgpio_irq_handler(struct irq_desc *desc)
|
||||
{
|
||||
struct gpio_chip *gc = irq_desc_get_handler_data(desc);
|
||||
struct irq_chip *ic = irq_desc_get_chip(desc);
|
||||
struct aspeed_sgpio *data = gpiochip_get_data(gc);
|
||||
unsigned int i, p, girq;
|
||||
unsigned long reg;
|
||||
|
||||
chained_irq_enter(ic, desc);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(aspeed_sgpio_banks); i++) {
|
||||
const struct aspeed_sgpio_bank *bank = &aspeed_sgpio_banks[i];
|
||||
|
||||
reg = ioread32(bank_reg(data, bank, reg_irq_status));
|
||||
|
||||
for_each_set_bit(p, ®, 32) {
|
||||
girq = irq_find_mapping(gc->irq.domain, i * 32 + p);
|
||||
generic_handle_irq(girq);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
chained_irq_exit(ic, desc);
|
||||
}
|
||||
|
||||
static struct irq_chip aspeed_sgpio_irqchip = {
|
||||
.name = "aspeed-sgpio",
|
||||
.irq_ack = aspeed_sgpio_irq_ack,
|
||||
.irq_mask = aspeed_sgpio_irq_mask,
|
||||
.irq_unmask = aspeed_sgpio_irq_unmask,
|
||||
.irq_set_type = aspeed_sgpio_set_type,
|
||||
};
|
||||
|
||||
static int aspeed_sgpio_setup_irqs(struct aspeed_sgpio *gpio,
|
||||
struct platform_device *pdev)
|
||||
{
|
||||
int rc, i;
|
||||
const struct aspeed_sgpio_bank *bank;
|
||||
struct gpio_irq_chip *irq;
|
||||
|
||||
rc = platform_get_irq(pdev, 0);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
gpio->irq = rc;
|
||||
|
||||
/* Disable IRQ and clear Interrupt status registers for all SPGIO Pins. */
|
||||
for (i = 0; i < ARRAY_SIZE(aspeed_sgpio_banks); i++) {
|
||||
bank = &aspeed_sgpio_banks[i];
|
||||
/* disable irq enable bits */
|
||||
iowrite32(0x00000000, bank_reg(gpio, bank, reg_irq_enable));
|
||||
/* clear status bits */
|
||||
iowrite32(0xffffffff, bank_reg(gpio, bank, reg_irq_status));
|
||||
}
|
||||
|
||||
irq = &gpio->chip.irq;
|
||||
irq->chip = &aspeed_sgpio_irqchip;
|
||||
irq->handler = handle_bad_irq;
|
||||
irq->default_type = IRQ_TYPE_NONE;
|
||||
irq->parent_handler = aspeed_sgpio_irq_handler;
|
||||
irq->parent_handler_data = gpio;
|
||||
irq->parents = &gpio->irq;
|
||||
irq->num_parents = 1;
|
||||
|
||||
/* set IRQ settings and Enable Interrupt */
|
||||
for (i = 0; i < ARRAY_SIZE(aspeed_sgpio_banks); i++) {
|
||||
bank = &aspeed_sgpio_banks[i];
|
||||
/* set falling or level-low irq */
|
||||
iowrite32(0x00000000, bank_reg(gpio, bank, reg_irq_type0));
|
||||
/* trigger type is edge */
|
||||
iowrite32(0x00000000, bank_reg(gpio, bank, reg_irq_type1));
|
||||
/* dual edge trigger mode. */
|
||||
iowrite32(0xffffffff, bank_reg(gpio, bank, reg_irq_type2));
|
||||
/* enable irq */
|
||||
iowrite32(0xffffffff, bank_reg(gpio, bank, reg_irq_enable));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id aspeed_sgpio_of_table[] = {
|
||||
{ .compatible = "aspeed,ast2400-sgpio" },
|
||||
{ .compatible = "aspeed,ast2500-sgpio" },
|
||||
{}
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(of, aspeed_sgpio_of_table);
|
||||
|
||||
static int __init aspeed_sgpio_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct aspeed_sgpio *gpio;
|
||||
u32 nr_gpios, sgpio_freq, sgpio_clk_div;
|
||||
int rc;
|
||||
unsigned long apb_freq;
|
||||
|
||||
gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL);
|
||||
if (!gpio)
|
||||
return -ENOMEM;
|
||||
|
||||
gpio->base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(gpio->base))
|
||||
return PTR_ERR(gpio->base);
|
||||
|
||||
rc = of_property_read_u32(pdev->dev.of_node, "ngpios", &nr_gpios);
|
||||
if (rc < 0) {
|
||||
dev_err(&pdev->dev, "Could not read ngpios property\n");
|
||||
return -EINVAL;
|
||||
} else if (nr_gpios > MAX_NR_SGPIO) {
|
||||
dev_err(&pdev->dev, "Number of GPIOs exceeds the maximum of %d: %d\n",
|
||||
MAX_NR_SGPIO, nr_gpios);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
rc = of_property_read_u32(pdev->dev.of_node, "bus-frequency", &sgpio_freq);
|
||||
if (rc < 0) {
|
||||
dev_err(&pdev->dev, "Could not read bus-frequency property\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
gpio->pclk = devm_clk_get(&pdev->dev, NULL);
|
||||
if (IS_ERR(gpio->pclk)) {
|
||||
dev_err(&pdev->dev, "devm_clk_get failed\n");
|
||||
return PTR_ERR(gpio->pclk);
|
||||
}
|
||||
|
||||
apb_freq = clk_get_rate(gpio->pclk);
|
||||
|
||||
/*
|
||||
* From the datasheet,
|
||||
* SGPIO period = 1/PCLK * 2 * (GPIO254[31:16] + 1)
|
||||
* period = 2 * (GPIO254[31:16] + 1) / PCLK
|
||||
* frequency = 1 / (2 * (GPIO254[31:16] + 1) / PCLK)
|
||||
* frequency = PCLK / (2 * (GPIO254[31:16] + 1))
|
||||
* frequency * 2 * (GPIO254[31:16] + 1) = PCLK
|
||||
* GPIO254[31:16] = PCLK / (frequency * 2) - 1
|
||||
*/
|
||||
if (sgpio_freq == 0)
|
||||
return -EINVAL;
|
||||
|
||||
sgpio_clk_div = (apb_freq / (sgpio_freq * 2)) - 1;
|
||||
|
||||
if (sgpio_clk_div > (1 << 16) - 1)
|
||||
return -EINVAL;
|
||||
|
||||
iowrite32(FIELD_PREP(ASPEED_SGPIO_CLK_DIV_MASK, sgpio_clk_div) |
|
||||
FIELD_PREP(ASPEED_SGPIO_PINS_MASK, (nr_gpios / 8)) |
|
||||
ASPEED_SGPIO_ENABLE,
|
||||
gpio->base + ASPEED_SGPIO_CTRL);
|
||||
|
||||
spin_lock_init(&gpio->lock);
|
||||
|
||||
gpio->chip.parent = &pdev->dev;
|
||||
gpio->chip.ngpio = nr_gpios;
|
||||
gpio->chip.direction_input = aspeed_sgpio_dir_in;
|
||||
gpio->chip.direction_output = aspeed_sgpio_dir_out;
|
||||
gpio->chip.get_direction = aspeed_sgpio_get_direction;
|
||||
gpio->chip.request = NULL;
|
||||
gpio->chip.free = NULL;
|
||||
gpio->chip.get = aspeed_sgpio_get;
|
||||
gpio->chip.set = aspeed_sgpio_set;
|
||||
gpio->chip.set_config = NULL;
|
||||
gpio->chip.label = dev_name(&pdev->dev);
|
||||
gpio->chip.base = -1;
|
||||
|
||||
/* set all SGPIO pins as input (1). */
|
||||
memset(gpio->dir_in, 0xff, sizeof(gpio->dir_in));
|
||||
|
||||
aspeed_sgpio_setup_irqs(gpio, pdev);
|
||||
|
||||
rc = devm_gpiochip_add_data(&pdev->dev, &gpio->chip, gpio);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver aspeed_sgpio_driver = {
|
||||
.driver = {
|
||||
.name = KBUILD_MODNAME,
|
||||
.of_match_table = aspeed_sgpio_of_table,
|
||||
},
|
||||
};
|
||||
|
||||
module_platform_driver_probe(aspeed_sgpio_driver, aspeed_sgpio_probe);
|
||||
MODULE_DESCRIPTION("Aspeed Serial GPIO Driver");
|
||||
MODULE_LICENSE("GPL");
|
|
@ -1455,6 +1455,20 @@ static void byt_gpio_irq_handler(struct irq_desc *desc)
|
|||
chip->irq_eoi(data);
|
||||
}
|
||||
|
||||
static void byt_init_irq_valid_mask(struct gpio_chip *chip,
|
||||
unsigned long *valid_mask,
|
||||
unsigned int ngpios)
|
||||
{
|
||||
/*
|
||||
* FIXME: currently the valid_mask is filled in as part of
|
||||
* initializing the irq_chip below in byt_gpio_irq_init_hw().
|
||||
* when converting this driver to the new way of passing the
|
||||
* gpio_irq_chip along when adding the gpio_chip, move the
|
||||
* mask initialization into this callback instead. Right now
|
||||
* this callback is here to make sure the mask gets allocated.
|
||||
*/
|
||||
}
|
||||
|
||||
static void byt_gpio_irq_init_hw(struct byt_gpio *vg)
|
||||
{
|
||||
struct gpio_chip *gc = &vg->chip;
|
||||
|
@ -1525,7 +1539,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.init_valid_mask = byt_init_irq_valid_mask;
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
vg->saved_context = devm_kcalloc(&vg->pdev->dev, gc->ngpio,
|
||||
|
|
|
@ -1543,6 +1543,30 @@ static const struct dmi_system_id chv_no_valid_mask[] = {
|
|||
{}
|
||||
};
|
||||
|
||||
static void chv_init_irq_valid_mask(struct gpio_chip *chip,
|
||||
unsigned long *valid_mask,
|
||||
unsigned int ngpios)
|
||||
{
|
||||
struct chv_pinctrl *pctrl = gpiochip_get_data(chip);
|
||||
const struct chv_community *community = pctrl->community;
|
||||
int i;
|
||||
|
||||
/* Do not add GPIOs that can only generate GPEs to the IRQ domain */
|
||||
for (i = 0; i < community->npins; i++) {
|
||||
const struct pinctrl_pin_desc *desc;
|
||||
u32 intsel;
|
||||
|
||||
desc = &community->pins[i];
|
||||
|
||||
intsel = readl(chv_padreg(pctrl, desc->number, CHV_PADCTRL0));
|
||||
intsel &= CHV_PADCTRL0_INTSEL_MASK;
|
||||
intsel >>= CHV_PADCTRL0_INTSEL_SHIFT;
|
||||
|
||||
if (intsel >= community->nirqs)
|
||||
clear_bit(i, valid_mask);
|
||||
}
|
||||
}
|
||||
|
||||
static int chv_gpio_probe(struct chv_pinctrl *pctrl, int irq)
|
||||
{
|
||||
const struct chv_gpio_pinrange *range;
|
||||
|
@ -1557,7 +1581,8 @@ 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;
|
||||
if (need_valid_mask)
|
||||
chip->irq.init_valid_mask = chv_init_irq_valid_mask;
|
||||
|
||||
ret = devm_gpiochip_add_data(pctrl->dev, chip, pctrl);
|
||||
if (ret) {
|
||||
|
@ -1576,21 +1601,6 @@ static int chv_gpio_probe(struct chv_pinctrl *pctrl, int irq)
|
|||
}
|
||||
}
|
||||
|
||||
/* Do not add GPIOs that can only generate GPEs to the IRQ domain */
|
||||
for (i = 0; i < community->npins; i++) {
|
||||
const struct pinctrl_pin_desc *desc;
|
||||
u32 intsel;
|
||||
|
||||
desc = &community->pins[i];
|
||||
|
||||
intsel = readl(chv_padreg(pctrl, desc->number, CHV_PADCTRL0));
|
||||
intsel &= CHV_PADCTRL0_INTSEL_MASK;
|
||||
intsel >>= CHV_PADCTRL0_INTSEL_SHIFT;
|
||||
|
||||
if (need_valid_mask && intsel >= community->nirqs)
|
||||
clear_bit(i, chip->irq.valid_mask);
|
||||
}
|
||||
|
||||
/*
|
||||
* The same set of machines in chv_no_valid_mask[] have incorrectly
|
||||
* configured GPIOs that generate spurious interrupts so we use
|
||||
|
|
|
@ -585,12 +585,24 @@ static int stmfx_pinctrl_gpio_function_enable(struct stmfx_pinctrl *pctl)
|
|||
return stmfx_function_enable(pctl->stmfx, func);
|
||||
}
|
||||
|
||||
static int stmfx_pinctrl_gpio_init_valid_mask(struct gpio_chip *gc,
|
||||
unsigned long *valid_mask,
|
||||
unsigned int ngpios)
|
||||
{
|
||||
struct stmfx_pinctrl *pctl = gpiochip_get_data(gc);
|
||||
u32 n;
|
||||
|
||||
for_each_clear_bit(n, &pctl->gpio_valid_mask, ngpios)
|
||||
clear_bit(n, valid_mask);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int stmfx_pinctrl_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct stmfx *stmfx = dev_get_drvdata(pdev->dev.parent);
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
struct stmfx_pinctrl *pctl;
|
||||
u32 n;
|
||||
int irq, ret;
|
||||
|
||||
pctl = devm_kzalloc(stmfx->dev, sizeof(*pctl), GFP_KERNEL);
|
||||
|
@ -650,7 +662,7 @@ static int stmfx_pinctrl_probe(struct platform_device *pdev)
|
|||
pctl->gpio_chip.ngpio = pctl->pctl_desc.npins;
|
||||
pctl->gpio_chip.can_sleep = true;
|
||||
pctl->gpio_chip.of_node = np;
|
||||
pctl->gpio_chip.need_valid_mask = true;
|
||||
pctl->gpio_chip.init_valid_mask = stmfx_pinctrl_gpio_init_valid_mask;
|
||||
|
||||
ret = devm_gpiochip_add_data(pctl->dev, &pctl->gpio_chip, pctl);
|
||||
if (ret) {
|
||||
|
@ -668,8 +680,6 @@ static int stmfx_pinctrl_probe(struct platform_device *pdev)
|
|||
pctl->irq_chip.irq_set_type = stmfx_pinctrl_irq_set_type;
|
||||
pctl->irq_chip.irq_bus_lock = stmfx_pinctrl_irq_bus_lock;
|
||||
pctl->irq_chip.irq_bus_sync_unlock = stmfx_pinctrl_irq_bus_sync_unlock;
|
||||
for_each_clear_bit(n, &pctl->gpio_valid_mask, pctl->gpio_chip.ngpio)
|
||||
clear_bit(n, pctl->gpio_chip.valid_mask);
|
||||
|
||||
ret = gpiochip_irqchip_add_nested(&pctl->gpio_chip, &pctl->irq_chip,
|
||||
0, handle_bad_irq, IRQ_TYPE_NONE);
|
||||
|
|
|
@ -138,6 +138,7 @@ config PINCTRL_QCOM_SPMI_PMIC
|
|||
select PINMUX
|
||||
select PINCONF
|
||||
select GENERIC_PINCONF
|
||||
select GPIOLIB_IRQCHIP
|
||||
select IRQ_DOMAIN_HIERARCHY
|
||||
help
|
||||
This is the pinctrl, pinmux, pinconf and gpiolib driver for the
|
||||
|
|
|
@ -593,24 +593,25 @@ static void msm_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
|
|||
#define msm_gpio_dbg_show NULL
|
||||
#endif
|
||||
|
||||
static int msm_gpio_init_valid_mask(struct gpio_chip *chip)
|
||||
static int msm_gpio_init_valid_mask(struct gpio_chip *gc,
|
||||
unsigned long *valid_mask,
|
||||
unsigned int ngpios)
|
||||
{
|
||||
struct msm_pinctrl *pctrl = gpiochip_get_data(chip);
|
||||
struct msm_pinctrl *pctrl = gpiochip_get_data(gc);
|
||||
int ret;
|
||||
unsigned int len, i;
|
||||
unsigned int max_gpios = pctrl->soc->ngpios;
|
||||
const int *reserved = pctrl->soc->reserved_gpios;
|
||||
u16 *tmp;
|
||||
|
||||
/* Driver provided reserved list overrides DT and ACPI */
|
||||
if (reserved) {
|
||||
bitmap_fill(chip->valid_mask, max_gpios);
|
||||
bitmap_fill(valid_mask, ngpios);
|
||||
for (i = 0; reserved[i] >= 0; i++) {
|
||||
if (i >= max_gpios || reserved[i] >= max_gpios) {
|
||||
if (i >= ngpios || reserved[i] >= ngpios) {
|
||||
dev_err(pctrl->dev, "invalid list of reserved GPIOs\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
clear_bit(reserved[i], chip->valid_mask);
|
||||
clear_bit(reserved[i], valid_mask);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -622,7 +623,7 @@ static int msm_gpio_init_valid_mask(struct gpio_chip *chip)
|
|||
if (ret < 0)
|
||||
return 0;
|
||||
|
||||
if (ret > max_gpios)
|
||||
if (ret > ngpios)
|
||||
return -EINVAL;
|
||||
|
||||
tmp = kmalloc_array(len, sizeof(*tmp), GFP_KERNEL);
|
||||
|
@ -635,9 +636,9 @@ static int msm_gpio_init_valid_mask(struct gpio_chip *chip)
|
|||
goto out;
|
||||
}
|
||||
|
||||
bitmap_zero(chip->valid_mask, max_gpios);
|
||||
bitmap_zero(valid_mask, ngpios);
|
||||
for (i = 0; i < len; i++)
|
||||
set_bit(tmp[i], chip->valid_mask);
|
||||
set_bit(tmp[i], valid_mask);
|
||||
|
||||
out:
|
||||
kfree(tmp);
|
||||
|
@ -653,7 +654,6 @@ static const struct gpio_chip msm_gpio_template = {
|
|||
.request = gpiochip_generic_request,
|
||||
.free = gpiochip_generic_free,
|
||||
.dbg_show = msm_gpio_dbg_show,
|
||||
.init_valid_mask = msm_gpio_init_valid_mask,
|
||||
};
|
||||
|
||||
/* For dual-edge interrupts in software, since some hardware has no
|
||||
|
@ -1015,7 +1015,8 @@ static int msm_gpio_init(struct msm_pinctrl *pctrl)
|
|||
chip->parent = pctrl->dev;
|
||||
chip->owner = THIS_MODULE;
|
||||
chip->of_node = pctrl->dev->of_node;
|
||||
chip->need_valid_mask = msm_gpio_needs_valid_mask(pctrl);
|
||||
if (msm_gpio_needs_valid_mask(pctrl))
|
||||
chip->init_valid_mask = msm_gpio_init_valid_mask;
|
||||
|
||||
pctrl->irq_chip.name = "msmgpio";
|
||||
pctrl->irq_chip.irq_enable = msm_gpio_irq_enable;
|
||||
|
|
|
@ -170,8 +170,6 @@ struct pmic_gpio_state {
|
|||
struct regmap *map;
|
||||
struct pinctrl_dev *ctrl;
|
||||
struct gpio_chip chip;
|
||||
struct fwnode_handle *fwnode;
|
||||
struct irq_domain *domain;
|
||||
};
|
||||
|
||||
static const struct pinconf_generic_params pmic_gpio_bindings[] = {
|
||||
|
@ -751,23 +749,6 @@ static int pmic_gpio_of_xlate(struct gpio_chip *chip,
|
|||
return gpio_desc->args[0] - PMIC_GPIO_PHYSICAL_OFFSET;
|
||||
}
|
||||
|
||||
static int pmic_gpio_to_irq(struct gpio_chip *chip, unsigned pin)
|
||||
{
|
||||
struct pmic_gpio_state *state = gpiochip_get_data(chip);
|
||||
struct irq_fwspec fwspec;
|
||||
|
||||
fwspec.fwnode = state->fwnode;
|
||||
fwspec.param_count = 2;
|
||||
fwspec.param[0] = pin + PMIC_GPIO_PHYSICAL_OFFSET;
|
||||
/*
|
||||
* Set the type to a safe value temporarily. This will be overwritten
|
||||
* later with the proper value by irq_set_type.
|
||||
*/
|
||||
fwspec.param[1] = IRQ_TYPE_EDGE_RISING;
|
||||
|
||||
return irq_create_fwspec_mapping(&fwspec);
|
||||
}
|
||||
|
||||
static void pmic_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
|
||||
{
|
||||
struct pmic_gpio_state *state = gpiochip_get_data(chip);
|
||||
|
@ -787,7 +768,6 @@ static const struct gpio_chip pmic_gpio_gpio_template = {
|
|||
.request = gpiochip_generic_request,
|
||||
.free = gpiochip_generic_free,
|
||||
.of_xlate = pmic_gpio_of_xlate,
|
||||
.to_irq = pmic_gpio_to_irq,
|
||||
.dbg_show = pmic_gpio_dbg_show,
|
||||
};
|
||||
|
||||
|
@ -964,45 +944,23 @@ static int pmic_gpio_domain_translate(struct irq_domain *domain,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int pmic_gpio_domain_alloc(struct irq_domain *domain, unsigned int virq,
|
||||
unsigned int nr_irqs, void *data)
|
||||
static unsigned int pmic_gpio_child_offset_to_irq(struct gpio_chip *chip,
|
||||
unsigned int offset)
|
||||
{
|
||||
struct pmic_gpio_state *state = container_of(domain->host_data,
|
||||
struct pmic_gpio_state,
|
||||
chip);
|
||||
struct irq_fwspec *fwspec = data;
|
||||
struct irq_fwspec parent_fwspec;
|
||||
irq_hw_number_t hwirq;
|
||||
unsigned int type;
|
||||
int ret, i;
|
||||
|
||||
ret = pmic_gpio_domain_translate(domain, fwspec, &hwirq, &type);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
for (i = 0; i < nr_irqs; i++)
|
||||
irq_domain_set_info(domain, virq + i, hwirq + i,
|
||||
&pmic_gpio_irq_chip, state,
|
||||
handle_level_irq, NULL, NULL);
|
||||
|
||||
parent_fwspec.fwnode = domain->parent->fwnode;
|
||||
parent_fwspec.param_count = 4;
|
||||
parent_fwspec.param[0] = 0;
|
||||
parent_fwspec.param[1] = hwirq + 0xc0;
|
||||
parent_fwspec.param[2] = 0;
|
||||
parent_fwspec.param[3] = fwspec->param[1];
|
||||
|
||||
return irq_domain_alloc_irqs_parent(domain, virq, nr_irqs,
|
||||
&parent_fwspec);
|
||||
return offset + PMIC_GPIO_PHYSICAL_OFFSET;
|
||||
}
|
||||
|
||||
static const struct irq_domain_ops pmic_gpio_domain_ops = {
|
||||
.activate = gpiochip_irq_domain_activate,
|
||||
.alloc = pmic_gpio_domain_alloc,
|
||||
.deactivate = gpiochip_irq_domain_deactivate,
|
||||
.free = irq_domain_free_irqs_common,
|
||||
.translate = pmic_gpio_domain_translate,
|
||||
};
|
||||
static int pmic_gpio_child_to_parent_hwirq(struct gpio_chip *chip,
|
||||
unsigned int child_hwirq,
|
||||
unsigned int child_type,
|
||||
unsigned int *parent_hwirq,
|
||||
unsigned int *parent_type)
|
||||
{
|
||||
*parent_hwirq = child_hwirq + 0xc0;
|
||||
*parent_type = child_type;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pmic_gpio_probe(struct platform_device *pdev)
|
||||
{
|
||||
|
@ -1013,6 +971,7 @@ static int pmic_gpio_probe(struct platform_device *pdev)
|
|||
struct pinctrl_desc *pctrldesc;
|
||||
struct pmic_gpio_pad *pad, *pads;
|
||||
struct pmic_gpio_state *state;
|
||||
struct gpio_irq_chip *girq;
|
||||
int ret, npins, i;
|
||||
u32 reg;
|
||||
|
||||
|
@ -1092,19 +1051,21 @@ static int pmic_gpio_probe(struct platform_device *pdev)
|
|||
if (!parent_domain)
|
||||
return -ENXIO;
|
||||
|
||||
state->fwnode = of_node_to_fwnode(state->dev->of_node);
|
||||
state->domain = irq_domain_create_hierarchy(parent_domain, 0,
|
||||
state->chip.ngpio,
|
||||
state->fwnode,
|
||||
&pmic_gpio_domain_ops,
|
||||
&state->chip);
|
||||
if (!state->domain)
|
||||
return -ENODEV;
|
||||
girq = &state->chip.irq;
|
||||
girq->chip = &pmic_gpio_irq_chip;
|
||||
girq->default_type = IRQ_TYPE_NONE;
|
||||
girq->handler = handle_level_irq;
|
||||
girq->fwnode = of_node_to_fwnode(state->dev->of_node);
|
||||
girq->parent_domain = parent_domain;
|
||||
girq->child_to_parent_hwirq = pmic_gpio_child_to_parent_hwirq;
|
||||
girq->populate_parent_fwspec = gpiochip_populate_parent_fwspec_fourcell;
|
||||
girq->child_offset_to_irq = pmic_gpio_child_offset_to_irq;
|
||||
girq->child_irq_domain_ops.translate = pmic_gpio_domain_translate;
|
||||
|
||||
ret = gpiochip_add_data(&state->chip, state);
|
||||
if (ret) {
|
||||
dev_err(state->dev, "can't add gpio chip\n");
|
||||
goto err_chip_add_data;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1130,8 +1091,6 @@ static int pmic_gpio_probe(struct platform_device *pdev)
|
|||
|
||||
err_range:
|
||||
gpiochip_remove(&state->chip);
|
||||
err_chip_add_data:
|
||||
irq_domain_remove(state->domain);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -1140,7 +1099,6 @@ static int pmic_gpio_remove(struct platform_device *pdev)
|
|||
struct pmic_gpio_state *state = platform_get_drvdata(pdev);
|
||||
|
||||
gpiochip_remove(&state->chip);
|
||||
irq_domain_remove(state->domain);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -152,6 +152,13 @@ static const struct x86_cpu_id int0002_cpu_ids[] = {
|
|||
{}
|
||||
};
|
||||
|
||||
static void int0002_init_irq_valid_mask(struct gpio_chip *chip,
|
||||
unsigned long *valid_mask,
|
||||
unsigned int ngpios)
|
||||
{
|
||||
bitmap_clear(valid_mask, 0, GPE0A_PME_B0_VIRT_GPIO_PIN);
|
||||
}
|
||||
|
||||
static int int0002_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
|
@ -184,7 +191,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.init_valid_mask = int0002_init_irq_valid_mask;
|
||||
|
||||
ret = devm_gpiochip_add_data(&pdev->dev, chip, NULL);
|
||||
if (ret) {
|
||||
|
@ -192,8 +199,6 @@ static int int0002_probe(struct platform_device *pdev)
|
|||
return ret;
|
||||
}
|
||||
|
||||
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
|
||||
* to gpiochip_set_chained_irqchip, because the irq is shared.
|
||||
|
|
|
@ -994,62 +994,11 @@ void __acpi_handle_debug(struct _ddebug *descriptor, acpi_handle handle, const c
|
|||
#endif
|
||||
#endif
|
||||
|
||||
struct acpi_gpio_params {
|
||||
unsigned int crs_entry_index;
|
||||
unsigned int line_index;
|
||||
bool active_low;
|
||||
};
|
||||
|
||||
struct acpi_gpio_mapping {
|
||||
const char *name;
|
||||
const struct acpi_gpio_params *data;
|
||||
unsigned int size;
|
||||
|
||||
/* Ignore IoRestriction field */
|
||||
#define ACPI_GPIO_QUIRK_NO_IO_RESTRICTION BIT(0)
|
||||
/*
|
||||
* When ACPI GPIO mapping table is in use the index parameter inside it
|
||||
* refers to the GPIO resource in _CRS method. That index has no
|
||||
* distinction of actual type of the resource. When consumer wants to
|
||||
* get GpioIo type explicitly, this quirk may be used.
|
||||
*/
|
||||
#define ACPI_GPIO_QUIRK_ONLY_GPIOIO BIT(1)
|
||||
|
||||
unsigned int quirks;
|
||||
};
|
||||
|
||||
#if defined(CONFIG_ACPI) && defined(CONFIG_GPIOLIB)
|
||||
int acpi_dev_add_driver_gpios(struct acpi_device *adev,
|
||||
const struct acpi_gpio_mapping *gpios);
|
||||
|
||||
static inline void acpi_dev_remove_driver_gpios(struct acpi_device *adev)
|
||||
{
|
||||
if (adev)
|
||||
adev->driver_gpios = NULL;
|
||||
}
|
||||
|
||||
int devm_acpi_dev_add_driver_gpios(struct device *dev,
|
||||
const struct acpi_gpio_mapping *gpios);
|
||||
void devm_acpi_dev_remove_driver_gpios(struct device *dev);
|
||||
|
||||
bool acpi_gpio_get_irq_resource(struct acpi_resource *ares,
|
||||
struct acpi_resource_gpio **agpio);
|
||||
int acpi_dev_gpio_irq_get(struct acpi_device *adev, int index);
|
||||
#else
|
||||
static inline int acpi_dev_add_driver_gpios(struct acpi_device *adev,
|
||||
const struct acpi_gpio_mapping *gpios)
|
||||
{
|
||||
return -ENXIO;
|
||||
}
|
||||
static inline void acpi_dev_remove_driver_gpios(struct acpi_device *adev) {}
|
||||
|
||||
static inline int devm_acpi_dev_add_driver_gpios(struct device *dev,
|
||||
const struct acpi_gpio_mapping *gpios)
|
||||
{
|
||||
return -ENXIO;
|
||||
}
|
||||
static inline void devm_acpi_dev_remove_driver_gpios(struct device *dev) {}
|
||||
|
||||
static inline bool acpi_gpio_get_irq_resource(struct acpi_resource *ares,
|
||||
struct acpi_resource_gpio **agpio)
|
||||
{
|
||||
|
|
|
@ -221,19 +221,6 @@ static inline int gpio_to_irq(unsigned gpio)
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
static inline int gpiochip_lock_as_irq(struct gpio_chip *chip,
|
||||
unsigned int offset)
|
||||
{
|
||||
WARN_ON(1);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static inline void gpiochip_unlock_as_irq(struct gpio_chip *chip,
|
||||
unsigned int offset)
|
||||
{
|
||||
WARN_ON(1);
|
||||
}
|
||||
|
||||
static inline int irq_to_gpio(unsigned irq)
|
||||
{
|
||||
/* irq can never have been returned from gpio_to_irq() */
|
||||
|
|
|
@ -170,18 +170,8 @@ struct gpio_desc *gpio_to_desc(unsigned gpio);
|
|||
int desc_to_gpio(const struct gpio_desc *desc);
|
||||
|
||||
/* Child properties interface */
|
||||
struct device_node;
|
||||
struct fwnode_handle;
|
||||
|
||||
struct gpio_desc *gpiod_get_from_of_node(struct device_node *node,
|
||||
const char *propname, int index,
|
||||
enum gpiod_flags dflags,
|
||||
const char *label);
|
||||
struct gpio_desc *devm_gpiod_get_from_of_node(struct device *dev,
|
||||
struct device_node *node,
|
||||
const char *propname, int index,
|
||||
enum gpiod_flags dflags,
|
||||
const char *label);
|
||||
struct gpio_desc *fwnode_get_named_gpiod(struct fwnode_handle *fwnode,
|
||||
const char *propname, int index,
|
||||
enum gpiod_flags dflags,
|
||||
|
@ -530,28 +520,8 @@ static inline int desc_to_gpio(const struct gpio_desc *desc)
|
|||
}
|
||||
|
||||
/* Child properties interface */
|
||||
struct device_node;
|
||||
struct fwnode_handle;
|
||||
|
||||
static inline
|
||||
struct gpio_desc *gpiod_get_from_of_node(struct device_node *node,
|
||||
const char *propname, int index,
|
||||
enum gpiod_flags dflags,
|
||||
const char *label)
|
||||
{
|
||||
return ERR_PTR(-ENOSYS);
|
||||
}
|
||||
|
||||
static inline
|
||||
struct gpio_desc *devm_gpiod_get_from_of_node(struct device *dev,
|
||||
struct device_node *node,
|
||||
const char *propname, int index,
|
||||
enum gpiod_flags dflags,
|
||||
const char *label)
|
||||
{
|
||||
return ERR_PTR(-ENOSYS);
|
||||
}
|
||||
|
||||
static inline
|
||||
struct gpio_desc *fwnode_get_named_gpiod(struct fwnode_handle *fwnode,
|
||||
const char *propname, int index,
|
||||
|
@ -584,6 +554,111 @@ struct gpio_desc *devm_fwnode_get_gpiod_from_child(struct device *dev,
|
|||
flags, label);
|
||||
}
|
||||
|
||||
#if IS_ENABLED(CONFIG_GPIOLIB) && IS_ENABLED(CONFIG_OF_GPIO)
|
||||
struct device_node;
|
||||
|
||||
struct gpio_desc *gpiod_get_from_of_node(struct device_node *node,
|
||||
const char *propname, int index,
|
||||
enum gpiod_flags dflags,
|
||||
const char *label);
|
||||
|
||||
#else /* CONFIG_GPIOLIB && CONFIG_OF_GPIO */
|
||||
|
||||
struct device_node;
|
||||
|
||||
static inline
|
||||
struct gpio_desc *gpiod_get_from_of_node(struct device_node *node,
|
||||
const char *propname, int index,
|
||||
enum gpiod_flags dflags,
|
||||
const char *label)
|
||||
{
|
||||
return ERR_PTR(-ENOSYS);
|
||||
}
|
||||
|
||||
#endif /* CONFIG_GPIOLIB && CONFIG_OF_GPIO */
|
||||
|
||||
#ifdef CONFIG_GPIOLIB
|
||||
struct device_node;
|
||||
|
||||
struct gpio_desc *devm_gpiod_get_from_of_node(struct device *dev,
|
||||
struct device_node *node,
|
||||
const char *propname, int index,
|
||||
enum gpiod_flags dflags,
|
||||
const char *label);
|
||||
|
||||
#else /* CONFIG_GPIOLIB */
|
||||
|
||||
struct device_node;
|
||||
|
||||
static inline
|
||||
struct gpio_desc *devm_gpiod_get_from_of_node(struct device *dev,
|
||||
struct device_node *node,
|
||||
const char *propname, int index,
|
||||
enum gpiod_flags dflags,
|
||||
const char *label)
|
||||
{
|
||||
return ERR_PTR(-ENOSYS);
|
||||
}
|
||||
|
||||
#endif /* CONFIG_GPIOLIB */
|
||||
|
||||
struct acpi_gpio_params {
|
||||
unsigned int crs_entry_index;
|
||||
unsigned int line_index;
|
||||
bool active_low;
|
||||
};
|
||||
|
||||
struct acpi_gpio_mapping {
|
||||
const char *name;
|
||||
const struct acpi_gpio_params *data;
|
||||
unsigned int size;
|
||||
|
||||
/* Ignore IoRestriction field */
|
||||
#define ACPI_GPIO_QUIRK_NO_IO_RESTRICTION BIT(0)
|
||||
/*
|
||||
* When ACPI GPIO mapping table is in use the index parameter inside it
|
||||
* refers to the GPIO resource in _CRS method. That index has no
|
||||
* distinction of actual type of the resource. When consumer wants to
|
||||
* get GpioIo type explicitly, this quirk may be used.
|
||||
*/
|
||||
#define ACPI_GPIO_QUIRK_ONLY_GPIOIO BIT(1)
|
||||
|
||||
unsigned int quirks;
|
||||
};
|
||||
|
||||
#if IS_ENABLED(CONFIG_GPIOLIB) && IS_ENABLED(CONFIG_ACPI)
|
||||
|
||||
struct acpi_device;
|
||||
|
||||
int acpi_dev_add_driver_gpios(struct acpi_device *adev,
|
||||
const struct acpi_gpio_mapping *gpios);
|
||||
void acpi_dev_remove_driver_gpios(struct acpi_device *adev);
|
||||
|
||||
int devm_acpi_dev_add_driver_gpios(struct device *dev,
|
||||
const struct acpi_gpio_mapping *gpios);
|
||||
void devm_acpi_dev_remove_driver_gpios(struct device *dev);
|
||||
|
||||
#else /* CONFIG_GPIOLIB && CONFIG_ACPI */
|
||||
|
||||
struct acpi_device;
|
||||
|
||||
static inline int acpi_dev_add_driver_gpios(struct acpi_device *adev,
|
||||
const struct acpi_gpio_mapping *gpios)
|
||||
{
|
||||
return -ENXIO;
|
||||
}
|
||||
static inline void acpi_dev_remove_driver_gpios(struct acpi_device *adev) {}
|
||||
|
||||
static inline int devm_acpi_dev_add_driver_gpios(struct device *dev,
|
||||
const struct acpi_gpio_mapping *gpios)
|
||||
{
|
||||
return -ENXIO;
|
||||
}
|
||||
static inline void devm_acpi_dev_remove_driver_gpios(struct device *dev) {}
|
||||
|
||||
#endif /* CONFIG_GPIOLIB && CONFIG_ACPI */
|
||||
|
||||
|
||||
#if IS_ENABLED(CONFIG_GPIOLIB) && IS_ENABLED(CONFIG_GPIO_SYSFS)
|
||||
|
||||
int gpiod_export(struct gpio_desc *desc, bool direction_may_change);
|
||||
|
|
|
@ -20,9 +20,8 @@ struct module;
|
|||
enum gpiod_flags;
|
||||
enum gpio_lookup_flags;
|
||||
|
||||
#ifdef CONFIG_GPIOLIB
|
||||
struct gpio_chip;
|
||||
|
||||
#ifdef CONFIG_GPIOLIB_IRQCHIP
|
||||
/**
|
||||
* struct gpio_irq_chip - GPIO interrupt controller
|
||||
*/
|
||||
|
@ -49,6 +48,84 @@ struct gpio_irq_chip {
|
|||
*/
|
||||
const struct irq_domain_ops *domain_ops;
|
||||
|
||||
#ifdef CONFIG_IRQ_DOMAIN_HIERARCHY
|
||||
/**
|
||||
* @fwnode:
|
||||
*
|
||||
* Firmware node corresponding to this gpiochip/irqchip, necessary
|
||||
* for hierarchical irqdomain support.
|
||||
*/
|
||||
struct fwnode_handle *fwnode;
|
||||
|
||||
/**
|
||||
* @parent_domain:
|
||||
*
|
||||
* If non-NULL, will be set as the parent of this GPIO interrupt
|
||||
* controller's IRQ domain to establish a hierarchical interrupt
|
||||
* domain. The presence of this will activate the hierarchical
|
||||
* interrupt support.
|
||||
*/
|
||||
struct irq_domain *parent_domain;
|
||||
|
||||
/**
|
||||
* @child_to_parent_hwirq:
|
||||
*
|
||||
* This callback translates a child hardware IRQ offset to a parent
|
||||
* hardware IRQ offset on a hierarchical interrupt chip. The child
|
||||
* hardware IRQs correspond to the GPIO index 0..ngpio-1 (see the
|
||||
* ngpio field of struct gpio_chip) and the corresponding parent
|
||||
* hardware IRQ and type (such as IRQ_TYPE_*) shall be returned by
|
||||
* the driver. The driver can calculate this from an offset or using
|
||||
* a lookup table or whatever method is best for this chip. Return
|
||||
* 0 on successful translation in the driver.
|
||||
*
|
||||
* If some ranges of hardware IRQs do not have a corresponding parent
|
||||
* HWIRQ, return -EINVAL, but also make sure to fill in @valid_mask and
|
||||
* @need_valid_mask to make these GPIO lines unavailable for
|
||||
* translation.
|
||||
*/
|
||||
int (*child_to_parent_hwirq)(struct gpio_chip *chip,
|
||||
unsigned int child_hwirq,
|
||||
unsigned int child_type,
|
||||
unsigned int *parent_hwirq,
|
||||
unsigned int *parent_type);
|
||||
|
||||
/**
|
||||
* @populate_parent_fwspec:
|
||||
*
|
||||
* This optional callback populates the &struct irq_fwspec for the
|
||||
* parent's IRQ domain. If this is not specified, then
|
||||
* &gpiochip_populate_parent_fwspec_twocell will be used. A four-cell
|
||||
* variant named &gpiochip_populate_parent_fwspec_fourcell is also
|
||||
* available.
|
||||
*/
|
||||
void (*populate_parent_fwspec)(struct gpio_chip *chip,
|
||||
struct irq_fwspec *fwspec,
|
||||
unsigned int parent_hwirq,
|
||||
unsigned int parent_type);
|
||||
|
||||
/**
|
||||
* @child_offset_to_irq:
|
||||
*
|
||||
* This optional callback is used to translate the child's GPIO line
|
||||
* offset on the GPIO chip to an IRQ number for the GPIO to_irq()
|
||||
* callback. If this is not specified, then a default callback will be
|
||||
* provided that returns the line offset.
|
||||
*/
|
||||
unsigned int (*child_offset_to_irq)(struct gpio_chip *chip,
|
||||
unsigned int pin);
|
||||
|
||||
/**
|
||||
* @child_irq_domain_ops:
|
||||
*
|
||||
* The IRQ domain operations that will be used for this GPIO IRQ
|
||||
* chip. If no operations are provided, then default callbacks will
|
||||
* be populated to setup the IRQ hierarchy. Some drivers need to
|
||||
* supply their own translate function.
|
||||
*/
|
||||
struct irq_domain_ops child_irq_domain_ops;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @handler:
|
||||
*
|
||||
|
@ -125,11 +202,17 @@ struct gpio_irq_chip {
|
|||
bool threaded;
|
||||
|
||||
/**
|
||||
* @need_valid_mask:
|
||||
*
|
||||
* If set core allocates @valid_mask with all bits set to one.
|
||||
* @init_valid_mask: optional routine to initialize @valid_mask, to be
|
||||
* used if not all GPIO lines are valid interrupts. Sometimes some
|
||||
* lines just cannot fire interrupts, and this routine, when defined,
|
||||
* is passed a bitmap in "valid_mask" and it will have ngpios
|
||||
* bits from 0..(ngpios-1) set to "1" as in valid. The callback can
|
||||
* then directly set some bits to "0" if they cannot be used for
|
||||
* interrupts.
|
||||
*/
|
||||
bool need_valid_mask;
|
||||
void (*init_valid_mask)(struct gpio_chip *chip,
|
||||
unsigned long *valid_mask,
|
||||
unsigned int ngpios);
|
||||
|
||||
/**
|
||||
* @valid_mask:
|
||||
|
@ -161,7 +244,6 @@ struct gpio_irq_chip {
|
|||
*/
|
||||
void (*irq_disable)(struct irq_data *data);
|
||||
};
|
||||
#endif /* CONFIG_GPIOLIB_IRQCHIP */
|
||||
|
||||
/**
|
||||
* struct gpio_chip - abstract a GPIO controller
|
||||
|
@ -282,7 +364,9 @@ struct gpio_chip {
|
|||
void (*dbg_show)(struct seq_file *s,
|
||||
struct gpio_chip *chip);
|
||||
|
||||
int (*init_valid_mask)(struct gpio_chip *chip);
|
||||
int (*init_valid_mask)(struct gpio_chip *chip,
|
||||
unsigned long *valid_mask,
|
||||
unsigned int ngpios);
|
||||
|
||||
int base;
|
||||
u16 ngpio;
|
||||
|
@ -320,15 +404,6 @@ struct gpio_chip {
|
|||
struct gpio_irq_chip irq;
|
||||
#endif /* CONFIG_GPIOLIB_IRQCHIP */
|
||||
|
||||
/**
|
||||
* @need_valid_mask:
|
||||
*
|
||||
* If set core allocates @valid_mask with all its values initialized
|
||||
* with init_valid_mask() or set to one if init_valid_mask() is not
|
||||
* defined
|
||||
*/
|
||||
bool need_valid_mask;
|
||||
|
||||
/**
|
||||
* @valid_mask:
|
||||
*
|
||||
|
@ -421,9 +496,6 @@ extern int devm_gpiochip_add_data(struct device *dev, struct gpio_chip *chip,
|
|||
extern struct gpio_chip *gpiochip_find(void *data,
|
||||
int (*match)(struct gpio_chip *chip, void *data));
|
||||
|
||||
/* lock/unlock as IRQ */
|
||||
int gpiochip_lock_as_irq(struct gpio_chip *chip, unsigned int offset);
|
||||
void gpiochip_unlock_as_irq(struct gpio_chip *chip, unsigned int offset);
|
||||
bool gpiochip_line_is_irq(struct gpio_chip *chip, unsigned int offset);
|
||||
int gpiochip_reqres_irq(struct gpio_chip *chip, unsigned int offset);
|
||||
void gpiochip_relres_irq(struct gpio_chip *chip, unsigned int offset);
|
||||
|
@ -441,15 +513,40 @@ bool gpiochip_line_is_valid(const struct gpio_chip *chip, unsigned int offset);
|
|||
/* get driver data */
|
||||
void *gpiochip_get_data(struct gpio_chip *chip);
|
||||
|
||||
struct gpio_chip *gpiod_to_chip(const struct gpio_desc *desc);
|
||||
|
||||
struct bgpio_pdata {
|
||||
const char *label;
|
||||
int base;
|
||||
int ngpio;
|
||||
};
|
||||
|
||||
#if IS_ENABLED(CONFIG_GPIO_GENERIC)
|
||||
#ifdef CONFIG_IRQ_DOMAIN_HIERARCHY
|
||||
|
||||
void gpiochip_populate_parent_fwspec_twocell(struct gpio_chip *chip,
|
||||
struct irq_fwspec *fwspec,
|
||||
unsigned int parent_hwirq,
|
||||
unsigned int parent_type);
|
||||
void gpiochip_populate_parent_fwspec_fourcell(struct gpio_chip *chip,
|
||||
struct irq_fwspec *fwspec,
|
||||
unsigned int parent_hwirq,
|
||||
unsigned int parent_type);
|
||||
|
||||
#else
|
||||
|
||||
static inline void gpiochip_populate_parent_fwspec_twocell(struct gpio_chip *chip,
|
||||
struct irq_fwspec *fwspec,
|
||||
unsigned int parent_hwirq,
|
||||
unsigned int parent_type)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void gpiochip_populate_parent_fwspec_fourcell(struct gpio_chip *chip,
|
||||
struct irq_fwspec *fwspec,
|
||||
unsigned int parent_hwirq,
|
||||
unsigned int parent_type)
|
||||
{
|
||||
}
|
||||
|
||||
#endif /* CONFIG_IRQ_DOMAIN_HIERARCHY */
|
||||
|
||||
int bgpio_init(struct gpio_chip *gc, struct device *dev,
|
||||
unsigned long sz, void __iomem *dat, void __iomem *set,
|
||||
|
@ -463,10 +560,6 @@ int bgpio_init(struct gpio_chip *gc, struct device *dev,
|
|||
#define BGPIOF_READ_OUTPUT_REG_SET BIT(4) /* reg_set stores output value */
|
||||
#define BGPIOF_NO_OUTPUT BIT(5) /* only input */
|
||||
|
||||
#endif /* CONFIG_GPIO_GENERIC */
|
||||
|
||||
#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);
|
||||
|
@ -555,15 +648,11 @@ static inline int gpiochip_irqchip_add_nested(struct gpio_chip *gpiochip,
|
|||
}
|
||||
#endif /* CONFIG_LOCKDEP */
|
||||
|
||||
#endif /* CONFIG_GPIOLIB_IRQCHIP */
|
||||
|
||||
int gpiochip_generic_request(struct gpio_chip *chip, unsigned offset);
|
||||
void gpiochip_generic_free(struct gpio_chip *chip, unsigned offset);
|
||||
int gpiochip_generic_config(struct gpio_chip *chip, unsigned offset,
|
||||
unsigned long config);
|
||||
|
||||
#ifdef CONFIG_PINCTRL
|
||||
|
||||
/**
|
||||
* struct gpio_pin_range - pin range controlled by a gpio chip
|
||||
* @node: list for maintaining set of pin ranges, used internally
|
||||
|
@ -576,6 +665,8 @@ struct gpio_pin_range {
|
|||
struct pinctrl_gpio_range range;
|
||||
};
|
||||
|
||||
#ifdef CONFIG_PINCTRL
|
||||
|
||||
int gpiochip_add_pin_range(struct gpio_chip *chip, const char *pinctl_name,
|
||||
unsigned int gpio_offset, unsigned int pin_offset,
|
||||
unsigned int npins);
|
||||
|
@ -586,8 +677,6 @@ void gpiochip_remove_pin_ranges(struct gpio_chip *chip);
|
|||
|
||||
#else /* ! CONFIG_PINCTRL */
|
||||
|
||||
struct pinctrl_dev;
|
||||
|
||||
static inline int
|
||||
gpiochip_add_pin_range(struct gpio_chip *chip, const char *pinctl_name,
|
||||
unsigned int gpio_offset, unsigned int pin_offset,
|
||||
|
@ -619,6 +708,15 @@ void gpiochip_free_own_desc(struct gpio_desc *desc);
|
|||
void devprop_gpiochip_set_names(struct gpio_chip *chip,
|
||||
const struct fwnode_handle *fwnode);
|
||||
|
||||
#ifdef CONFIG_GPIOLIB
|
||||
|
||||
/* lock/unlock as IRQ */
|
||||
int gpiochip_lock_as_irq(struct gpio_chip *chip, unsigned int offset);
|
||||
void gpiochip_unlock_as_irq(struct gpio_chip *chip, unsigned int offset);
|
||||
|
||||
|
||||
struct gpio_chip *gpiod_to_chip(const struct gpio_desc *desc);
|
||||
|
||||
#else /* CONFIG_GPIOLIB */
|
||||
|
||||
static inline struct gpio_chip *gpiod_to_chip(const struct gpio_desc *desc)
|
||||
|
@ -628,6 +726,18 @@ static inline struct gpio_chip *gpiod_to_chip(const struct gpio_desc *desc)
|
|||
return ERR_PTR(-ENODEV);
|
||||
}
|
||||
|
||||
static inline int gpiochip_lock_as_irq(struct gpio_chip *chip,
|
||||
unsigned int offset)
|
||||
{
|
||||
WARN_ON(1);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static inline void gpiochip_unlock_as_irq(struct gpio_chip *chip,
|
||||
unsigned int offset)
|
||||
{
|
||||
WARN_ON(1);
|
||||
}
|
||||
#endif /* CONFIG_GPIOLIB */
|
||||
|
||||
#endif
|
||||
#endif /* __LINUX_GPIO_DRIVER_H */
|
||||
|
|
|
@ -61,10 +61,6 @@ static inline int of_mm_gpiochip_add(struct device_node *np,
|
|||
}
|
||||
extern void of_mm_gpiochip_remove(struct of_mm_gpio_chip *mm_gc);
|
||||
|
||||
extern int of_gpio_simple_xlate(struct gpio_chip *gc,
|
||||
const struct of_phandle_args *gpiospec,
|
||||
u32 *flags);
|
||||
|
||||
#else /* CONFIG_OF_GPIO */
|
||||
|
||||
/* Drivers may not strictly depend on the GPIO support, so let them link. */
|
||||
|
@ -77,13 +73,6 @@ static inline int of_get_named_gpio_flags(struct device_node *np,
|
|||
return -ENOSYS;
|
||||
}
|
||||
|
||||
static inline int of_gpio_simple_xlate(struct gpio_chip *gc,
|
||||
const struct of_phandle_args *gpiospec,
|
||||
u32 *flags)
|
||||
{
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_OF_GPIO */
|
||||
|
||||
/**
|
||||
|
|
|
@ -50,7 +50,4 @@ struct htc_egpio_platform_data {
|
|||
int num_chips;
|
||||
};
|
||||
|
||||
/* Determine the wakeup irq, to be called during early resume */
|
||||
extern int htc_egpio_get_wakeup_irq(struct device *dev);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/slab.h>
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
*/
|
||||
|
||||
#include <linux/dmi.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/slab.h>
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
* Mengdong Lin <mengdong.lin@intel.com>
|
||||
*/
|
||||
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
|
Loading…
Reference in New Issue