This is the bulk of the GPIO changes for the v5.11 kernel cycle:
Core changes: - Retired the old set-up function for GPIO IRQ chips. All chips now use the template struct gpio_irq_chip and pass that to the core to be set up alongside the gpio_chip. We can finally get rid of the old cruft. - Some refactoring and clean up of the core code. - Support edge event timestamps to be stamped using REALTIME (wall clock) timestamps. We have found solid use cases for this, so we support it. New drivers: - MStar MSC313 GPIO driver. - HiSilicon GPIO driver. Driver improvements: - The PCA953x driver now also supports the NXP PCAL9554B/C chips. - The mockup driver can now be probed from the device tree which is pretty useful for virtual prototyping of devices. - The Rcar driver now supports .get_multiple() - The MXC driver dropped some legacy and became a pure device tree client. - The Exar driver was moved over to the IDA interface for enumerating, and also switched over to using regmap for register access. -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEElDRnuGcz/wPCXQWMQRCzN7AZXXMFAl/b0r0ACgkQQRCzN7AZ XXPRIQ/+P2VxypIIi8o5ZJLt/UN1CPGbh10WCl9yR95pM7Ekxocsa05MMAyPCbCA SzDSo4wfrbVLd+C8oqGyLcyxR4A8LQDoc/MaBUC60SDr/BY2eu6bRCs9UttWUPUN 59H0r/dMAcSpIXwB9A7dKmF7Ps1Lz9naeZiGV8vw8hmuN4h3RtsWd10h8WDhByoq RA099lNKs6pFpx61hvn+6mr8ewkm6RFh9q9/eg+zU0gVeaXpYLO6zHTnRS3dARIg 9qLZ54mRUAeybpUCi+CpleUM7qQI8wYHB7pJutAXByWVACie91P5youJv2JvMgs3 rvYyjRkHkM+EtpyXStv5zzfIi0JF746zWeeQmrR3bYy7prnIjjkUgIZb2Jmqu0p2 R0PAOmylociuSsEpARIqlGebqMKlmpsekuhJsf8x53le3nM4B2qC6fVEXFfYrp2L sTfxeejmIFBBLLSSbfBFQOk3La9YBURGsidqgA2lQXL1ZSVhV6UrfblyLET6cOgs y4ORYCV4SxeErUhePkA0GXjnu00nC9iD2Too6sTF+oRIirXX3R4SBbgoHKBEhMNe /CWjYduwg7SkqwdeaBpZNU9jpFqq8Rny6nid13FMFORJWAszECzxcBIUaN55S/98 Z8QD0DJNo9nJZdtwT7OYE+x7/QcxgIHClU5MsrXS4yf3SlZHbAk= =nrFU -----END PGP SIGNATURE----- Merge tag 'gpio-v5.11-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 the GPIO changes for the v5.11 kernel cycle: Core changes: - Retired the old set-up function for GPIO IRQ chips. All chips now use the template struct gpio_irq_chip and pass that to the core to be set up alongside the gpio_chip. We can finally get rid of the old cruft. - Some refactoring and clean up of the core code. - Support edge event timestamps to be stamped using REALTIME (wall clock) timestamps. We have found solid use cases for this, so we support it. New drivers: - MStar MSC313 GPIO driver. - HiSilicon GPIO driver. Driver improvements: - The PCA953x driver now also supports the NXP PCAL9554B/C chips. - The mockup driver can now be probed from the device tree which is pretty useful for virtual prototyping of devices. - The Rcar driver now supports .get_multiple() - The MXC driver dropped some legacy and became a pure device tree client. - The Exar driver was moved over to the IDA interface for enumerating, and also switched over to using regmap for register access" * tag 'gpio-v5.11-1' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-gpio: (87 commits) MAINTAINERS: Remove reference to non-existing file gpio: hisi: Do not require ACPI for COMPILE_TEST MAINTAINERS: Add maintainer for HiSilicon GPIO driver gpio: gpio-hisi: Add HiSilicon GPIO support gpio: cs5535: Simplify the return expression of cs5535_gpio_probe() gpiolib: irq hooks: fix recursion in gpiochip_irq_unmask dt-bindings: mt7621-gpio: convert bindings to YAML format gpiolib: cdev: Flag invalid GPIOs as used gpio: put virtual gpio device into their own submenu drivers: gpio: amd8111: use SPDX-License-Identifier drivers: gpio: amd8111: prefer dev_err()/dev_info() over raw printk drivers: gpio: bt8xx: prefer dev_err()/dev_warn() over of raw printk gpio: Add TODO item for debugfs interface gpio: just plain warning when nonexisting gpio requested tools: gpio: add option to report wall-clock time to gpio-event-mon tools: gpio: add support for reporting realtime event clock to lsgpio gpiolib: cdev: allow edge event timestamps to be configured as REALTIME gpio: msc313: MStar MSC313 GPIO driver dt-bindings: gpio: Binding for MStar MSC313 GPIO controller dt-bindings: gpio: Add a binding header for the MSC313 GPIO driver ...
This commit is contained in:
Коммит
a409ed156a
|
@ -48,6 +48,7 @@ properties:
|
|||
- nxp,pcal6416
|
||||
- nxp,pcal6524
|
||||
- nxp,pcal9535
|
||||
- nxp,pcal9554b
|
||||
- nxp,pcal9555a
|
||||
- onnn,cat9554
|
||||
- onnn,pca9654
|
||||
|
|
|
@ -13,6 +13,7 @@ Required properties:
|
|||
- gpio-controller : Marks the device node as a GPIO controller.
|
||||
|
||||
Optional properties:
|
||||
- clocks : Input clock specifier. Refer to common clock bindings.
|
||||
- interrupts : Interrupt mapping for GPIO IRQ.
|
||||
- xlnx,all-inputs : if n-th bit is setup, GPIO-n is input
|
||||
- xlnx,dout-default : if n-th bit is 1, GPIO-n default value is 1
|
||||
|
@ -29,6 +30,7 @@ Example:
|
|||
gpio: gpio@40000000 {
|
||||
#gpio-cells = <2>;
|
||||
compatible = "xlnx,xps-gpio-1.00.a";
|
||||
clocks = <&clkc25>;
|
||||
gpio-controller ;
|
||||
interrupt-parent = <µblaze_0_intc>;
|
||||
interrupts = < 6 2 >;
|
||||
|
|
|
@ -1,35 +0,0 @@
|
|||
Mediatek MT7621 SoC GPIO controller bindings
|
||||
|
||||
The IP core used inside these SoCs has 3 banks of 32 GPIOs each.
|
||||
The registers of all the banks are interwoven inside one single IO range.
|
||||
We load one GPIO controller instance per bank. Also the GPIO controller can receive
|
||||
interrupts on any of the GPIOs, either edge or level. It then interrupts the CPU
|
||||
using GIC INT12.
|
||||
|
||||
Required properties for the top level node:
|
||||
- #gpio-cells : Should be two. The first cell is the GPIO pin number and the
|
||||
second cell specifies GPIO flags, as defined in <dt-bindings/gpio/gpio.h>.
|
||||
Only the GPIO_ACTIVE_HIGH and GPIO_ACTIVE_LOW flags are supported.
|
||||
- #interrupt-cells : Specifies the number of cells needed to encode an
|
||||
interrupt. Should be 2. The first cell defines the interrupt number,
|
||||
the second encodes the trigger flags encoded as described in
|
||||
Documentation/devicetree/bindings/interrupt-controller/interrupts.txt
|
||||
- compatible:
|
||||
- "mediatek,mt7621-gpio" for Mediatek controllers
|
||||
- reg : Physical base address and length of the controller's registers
|
||||
- interrupt-parent : phandle of the parent interrupt controller.
|
||||
- interrupts : Interrupt specifier for the controllers interrupt.
|
||||
- interrupt-controller : Mark the device node as an interrupt controller.
|
||||
- gpio-controller : Marks the device node as a GPIO controller.
|
||||
|
||||
Example:
|
||||
gpio@600 {
|
||||
#gpio-cells = <2>;
|
||||
#interrupt-cells = <2>;
|
||||
compatible = "mediatek,mt7621-gpio";
|
||||
gpio-controller;
|
||||
interrupt-controller;
|
||||
reg = <0x600 0x100>;
|
||||
interrupt-parent = <&gic>;
|
||||
interrupts = <GIC_SHARED 12 IRQ_TYPE_LEVEL_HIGH>;
|
||||
};
|
|
@ -0,0 +1,72 @@
|
|||
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/gpio/mediatek,mt7621-gpio.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Mediatek MT7621 SoC GPIO controller
|
||||
|
||||
maintainers:
|
||||
- Sergio Paracuellos <sergio.paracuellos@gmail.com>
|
||||
|
||||
description: |
|
||||
The IP core used inside these SoCs has 3 banks of 32 GPIOs each.
|
||||
The registers of all the banks are interwoven inside one single IO range.
|
||||
We load one GPIO controller instance per bank. Also the GPIO controller can receive
|
||||
interrupts on any of the GPIOs, either edge or level. It then interrupts the CPU
|
||||
using GIC INT12.
|
||||
|
||||
properties:
|
||||
$nodename:
|
||||
pattern: "^gpio@[0-9a-f]+$"
|
||||
|
||||
compatible:
|
||||
const: mediatek,mt7621-gpio
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
"#gpio-cells":
|
||||
const: 2
|
||||
|
||||
gpio-controller: true
|
||||
gpio-ranges: true
|
||||
|
||||
interrupt-controller: true
|
||||
|
||||
"#interrupt-cells":
|
||||
const: 2
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- "#gpio-cells"
|
||||
- gpio-controller
|
||||
- gpio-ranges
|
||||
- interrupt-controller
|
||||
- "#interrupt-cells"
|
||||
- interrupts
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/gpio/gpio.h>
|
||||
#include <dt-bindings/interrupt-controller/mips-gic.h>
|
||||
|
||||
gpio@600 {
|
||||
compatible = "mediatek,mt7621-gpio";
|
||||
reg = <0x600 0x100>;
|
||||
#gpio-cells = <2>;
|
||||
gpio-controller;
|
||||
gpio-ranges = <&pinctrl 0 0 95>;
|
||||
interrupt-controller;
|
||||
#interrupt-cells = <2>;
|
||||
interrupt-parent = <&gic>;
|
||||
interrupts = <GIC_SHARED 12 IRQ_TYPE_LEVEL_HIGH>;
|
||||
};
|
||||
|
||||
...
|
|
@ -0,0 +1,59 @@
|
|||
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/gpio/mstar,msc313-gpio.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: MStar/SigmaStar GPIO controller
|
||||
|
||||
maintainers:
|
||||
- Daniel Palmer <daniel@thingy.jp>
|
||||
|
||||
properties:
|
||||
$nodename:
|
||||
pattern: "^gpio@[0-9a-f]+$"
|
||||
|
||||
compatible:
|
||||
const: mstar,msc313-gpio
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
gpio-controller: true
|
||||
|
||||
"#gpio-cells":
|
||||
const: 2
|
||||
|
||||
gpio-ranges: true
|
||||
|
||||
interrupt-controller: true
|
||||
|
||||
"#interrupt-cells":
|
||||
const: 2
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- gpio-controller
|
||||
- "#gpio-cells"
|
||||
- interrupt-controller
|
||||
- "#interrupt-cells"
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/gpio/msc313-gpio.h>
|
||||
|
||||
gpio: gpio@207800 {
|
||||
compatible = "mstar,msc313e-gpio";
|
||||
#gpio-cells = <2>;
|
||||
reg = <0x207800 0x200>;
|
||||
gpio-controller;
|
||||
gpio-ranges = <&pinctrl 0 36 22>,
|
||||
<&pinctrl 22 63 4>,
|
||||
<&pinctrl 26 68 6>;
|
||||
#interrupt-cells = <2>;
|
||||
interrupt-controller;
|
||||
interrupt-parent = <&intc_fiq>;
|
||||
};
|
|
@ -440,18 +440,20 @@ For details refer to Documentation/firmware-guide/acpi/gpio-properties.rst
|
|||
|
||||
Interacting With the Legacy GPIO Subsystem
|
||||
==========================================
|
||||
Many kernel subsystems still handle GPIOs using the legacy integer-based
|
||||
interface. Although it is strongly encouraged to upgrade them to the safer
|
||||
descriptor-based API, the following two functions allow you to convert a GPIO
|
||||
descriptor into the GPIO integer namespace and vice-versa::
|
||||
Many kernel subsystems and drivers still handle GPIOs using the legacy
|
||||
integer-based interface. It is strongly recommended to update these to the new
|
||||
gpiod interface. For cases where both interfaces need to be used, the following
|
||||
two functions allow to convert a GPIO descriptor into the GPIO integer namespace
|
||||
and vice-versa::
|
||||
|
||||
int desc_to_gpio(const struct gpio_desc *desc)
|
||||
struct gpio_desc *gpio_to_desc(unsigned gpio)
|
||||
|
||||
The GPIO number returned by desc_to_gpio() can be safely used as long as the
|
||||
GPIO descriptor has not been freed. All the same, a GPIO number passed to
|
||||
gpio_to_desc() must have been properly acquired, and usage of the returned GPIO
|
||||
descriptor is only possible after the GPIO number has been released.
|
||||
The GPIO number returned by desc_to_gpio() can safely be used as a parameter of
|
||||
the gpio\_*() functions for as long as the GPIO descriptor `desc` is not freed.
|
||||
All the same, a GPIO number passed to gpio_to_desc() must first be properly
|
||||
acquired using e.g. gpio_request_one(), and the returned GPIO descriptor is only
|
||||
considered valid until that GPIO number is released using gpio_free().
|
||||
|
||||
Freeing a GPIO obtained by one API with the other API is forbidden and an
|
||||
unchecked error.
|
||||
|
|
|
@ -416,7 +416,8 @@ The preferred way to set up the helpers is to fill in the
|
|||
struct gpio_irq_chip inside struct gpio_chip before adding the gpio_chip.
|
||||
If you do this, the additional irq_chip will be set up by gpiolib at the
|
||||
same time as setting up the rest of the GPIO functionality. The following
|
||||
is a typical example of a cascaded interrupt handler using gpio_irq_chip:
|
||||
is a typical example of a chained cascaded interrupt handler using
|
||||
the gpio_irq_chip:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
|
@ -452,7 +453,46 @@ is a typical example of a cascaded interrupt handler using gpio_irq_chip:
|
|||
|
||||
return devm_gpiochip_add_data(dev, &g->gc, g);
|
||||
|
||||
The helper support using hierarchical interrupt controllers as well.
|
||||
The helper supports using threaded interrupts as well. Then you just request
|
||||
the interrupt separately and go with it:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
/* 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;
|
||||
|
||||
ret = devm_request_threaded_irq(dev, irq, NULL,
|
||||
irq_thread_fn, IRQF_ONESHOT, "my-chip", g);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Get a pointer to the gpio_irq_chip */
|
||||
girq = &g->gc.irq;
|
||||
girq->chip = &g->irq;
|
||||
/* 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_bad_irq;
|
||||
|
||||
return devm_gpiochip_add_data(dev, &g->gc, g);
|
||||
|
||||
The helper supports using hierarchical interrupt controllers as well.
|
||||
In this case the typical set-up will look like this:
|
||||
|
||||
.. code-block:: c
|
||||
|
@ -493,32 +533,13 @@ 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-api/driver-model/design-patterns.rst)
|
||||
|
||||
- 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_nested_irqchip(): sets up a nested cascaded irq handler for a
|
||||
gpio_chip from a parent IRQ. As the parent IRQ has usually been
|
||||
explicitly requested by the driver, this does very little more than
|
||||
mark all the child IRQs as having the other IRQ as parent.
|
||||
|
||||
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() 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.
|
||||
from this mask. The mask can be filled in the init_valid_mask() callback
|
||||
that is part of the struct gpio_irq_chip.
|
||||
|
||||
To use the helpers please keep the following in mind:
|
||||
|
||||
|
|
19
MAINTAINERS
19
MAINTAINERS
|
@ -2146,8 +2146,10 @@ L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
|
|||
S: Maintained
|
||||
W: http://linux-chenxing.org/
|
||||
F: Documentation/devicetree/bindings/arm/mstar/*
|
||||
F: Documentation/devicetree/bindings/gpio/mstar,msc313-gpio.yaml
|
||||
F: arch/arm/boot/dts/mstar-*
|
||||
F: arch/arm/mach-mstar/
|
||||
F: drivers/gpio/gpio-msc313.c
|
||||
F: include/dt-bindings/gpio/msc313-gpio.h
|
||||
|
||||
ARM/NEC MOBILEPRO 900/c MACHINE SUPPORT
|
||||
|
@ -7548,6 +7550,7 @@ M: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
|
|||
L: linux-gpio@vger.kernel.org
|
||||
L: linux-acpi@vger.kernel.org
|
||||
S: Maintained
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/andy/linux-gpio-intel.git
|
||||
F: Documentation/firmware-guide/acpi/gpio-properties.rst
|
||||
F: drivers/gpio/gpiolib-acpi.c
|
||||
F: drivers/gpio/gpiolib-acpi.h
|
||||
|
@ -7981,6 +7984,12 @@ L: dmaengine@vger.kernel.org
|
|||
S: Maintained
|
||||
F: drivers/dma/hisi_dma.c
|
||||
|
||||
HISILICON GPIO DRIVER
|
||||
M: Luo Jiaxing <luojiaxing@huawei.com>
|
||||
L: linux-gpio@vger.kernel.org
|
||||
S: Maintained
|
||||
F: drivers/gpio/gpio-hisi.c
|
||||
|
||||
HISILICON HIGH PERFORMANCE RSA ENGINE DRIVER (HPRE)
|
||||
M: Zaibo Xu <xuzaibo@huawei.com>
|
||||
L: linux-crypto@vger.kernel.org
|
||||
|
@ -19500,6 +19509,16 @@ S: Maintained
|
|||
F: Documentation/devicetree/bindings/net/can/xilinx_can.txt
|
||||
F: drivers/net/can/xilinx_can.c
|
||||
|
||||
XILINX GPIO DRIVER
|
||||
M: Shubhrajyoti Datta <shubhrajyoti.datta@xilinx.com>
|
||||
R: Srinivas Neeli <srinivas.neeli@xilinx.com>
|
||||
R: Michal Simek <michal.simek@xilinx.com>
|
||||
S: Maintained
|
||||
F: Documentation/devicetree/bindings/gpio/gpio-xilinx.txt
|
||||
F: Documentation/devicetree/bindings/gpio/gpio-zynq.txt
|
||||
F: drivers/gpio/gpio-xilinx.c
|
||||
F: drivers/gpio/gpio-zynq.c
|
||||
|
||||
XILINX SD-FEC IP CORES
|
||||
M: Derek Kiernan <derek.kiernan@xilinx.com>
|
||||
M: Dragan Cvetic <dragan.cvetic@xilinx.com>
|
||||
|
|
|
@ -59,8 +59,9 @@ config DEBUG_GPIO
|
|||
that are most common when setting up new platforms or boards.
|
||||
|
||||
config GPIO_SYSFS
|
||||
bool "/sys/class/gpio/... (sysfs interface)"
|
||||
bool "/sys/class/gpio/... (sysfs interface)" if EXPERT
|
||||
depends on SYSFS
|
||||
select GPIO_CDEV # We need to encourage the new ABI
|
||||
help
|
||||
Say Y here to add the legacy sysfs interface for GPIOs.
|
||||
|
||||
|
@ -255,6 +256,7 @@ config GPIO_EP93XX
|
|||
config GPIO_EXAR
|
||||
tristate "Support for GPIO pins on XR17V352/354/358"
|
||||
depends on SERIAL_8250_EXAR
|
||||
select REGMAP_MMIO
|
||||
help
|
||||
Selecting this option will enable handling of GPIO pins present
|
||||
on Exar XR17V352/354/358 chips.
|
||||
|
@ -296,6 +298,17 @@ config GPIO_GRGPIO
|
|||
Select this to support Aeroflex Gaisler GRGPIO cores from the GRLIB
|
||||
VHDL IP core library.
|
||||
|
||||
config GPIO_HISI
|
||||
tristate "HiSilicon GPIO controller driver"
|
||||
depends on (ARM64 && ACPI) || COMPILE_TEST
|
||||
select GPIO_GENERIC
|
||||
select GPIOLIB_IRQCHIP
|
||||
help
|
||||
Say Y or M here to build support for the HiSilicon GPIO controller
|
||||
driver GPIO block.
|
||||
This GPIO controller support double-edge interrupt and multi-core
|
||||
concurrent access.
|
||||
|
||||
config GPIO_HLWD
|
||||
tristate "Nintendo Wii (Hollywood) GPIO"
|
||||
depends on OF_GPIO
|
||||
|
@ -737,6 +750,17 @@ config GPIO_AMD_FCH
|
|||
Note: This driver doesn't registers itself automatically, as it
|
||||
needs to be provided with platform specific configuration.
|
||||
(See eg. CONFIG_PCENGINES_APU2.)
|
||||
|
||||
config GPIO_MSC313
|
||||
bool "MStar MSC313 GPIO support"
|
||||
depends on ARCH_MSTARV7
|
||||
default ARCH_MSTARV7
|
||||
select GPIOLIB_IRQCHIP
|
||||
select IRQ_DOMAIN_HIERARCHY
|
||||
help
|
||||
Say Y here to support the main GPIO block on MStar/SigmaStar
|
||||
ARMv7 based SoCs.
|
||||
|
||||
endmenu
|
||||
|
||||
menu "Port-mapped I/O GPIO drivers"
|
||||
|
@ -1590,6 +1614,8 @@ config GPIO_VIPERBOARD
|
|||
|
||||
endmenu
|
||||
|
||||
menu "Virtual GPIO drivers"
|
||||
|
||||
config GPIO_AGGREGATOR
|
||||
tristate "GPIO Aggregator"
|
||||
help
|
||||
|
@ -1613,4 +1639,6 @@ config GPIO_MOCKUP
|
|||
tools/testing/selftests/gpio/gpio-mockup.sh. Reference the usage in
|
||||
it.
|
||||
|
||||
endmenu
|
||||
|
||||
endif
|
||||
|
|
|
@ -63,6 +63,7 @@ obj-$(CONFIG_GPIO_GE_FPGA) += gpio-ge.o
|
|||
obj-$(CONFIG_GPIO_GPIO_MM) += gpio-gpio-mm.o
|
||||
obj-$(CONFIG_GPIO_GRGPIO) += gpio-grgpio.o
|
||||
obj-$(CONFIG_GPIO_GW_PLD) += gpio-gw-pld.o
|
||||
obj-$(CONFIG_GPIO_HISI) += gpio-hisi.o
|
||||
obj-$(CONFIG_GPIO_HLWD) += gpio-hlwd.o
|
||||
obj-$(CONFIG_HTC_EGPIO) += gpio-htc-egpio.o
|
||||
obj-$(CONFIG_GPIO_ICH) += gpio-ich.o
|
||||
|
@ -101,6 +102,7 @@ obj-$(CONFIG_GPIO_MOCKUP) += gpio-mockup.o
|
|||
obj-$(CONFIG_GPIO_MOXTET) += gpio-moxtet.o
|
||||
obj-$(CONFIG_GPIO_MPC5200) += gpio-mpc5200.o
|
||||
obj-$(CONFIG_GPIO_MPC8XXX) += gpio-mpc8xxx.o
|
||||
obj-$(CONFIG_GPIO_MSC313) += gpio-msc313.o
|
||||
obj-$(CONFIG_GPIO_MSIC) += gpio-msic.o
|
||||
obj-$(CONFIG_GPIO_MT7621) += gpio-mt7621.o
|
||||
obj-$(CONFIG_GPIO_MVEBU) += gpio-mvebu.o
|
||||
|
|
|
@ -129,58 +129,9 @@ GPIOLIB irqchip
|
|||
The GPIOLIB irqchip is a helper irqchip for "simple cases" that should
|
||||
try to cover any generic kind of irqchip cascaded from a GPIO.
|
||||
|
||||
- Convert all the GPIOLIB_IRQCHIP users to pass an irqchip template,
|
||||
parent and flags before calling [devm_]gpiochip_add[_data]().
|
||||
Currently we set up the irqchip after setting up the gpiochip
|
||||
using gpiochip_irqchip_add() and gpiochip_set_[chained|nested]_irqchip().
|
||||
This is too complex, so convert all users over to just set up
|
||||
the irqchip before registering the gpio_chip, typical example:
|
||||
|
||||
/* 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;
|
||||
|
||||
When this is done, we will delete the old APIs for instatiating
|
||||
GPIOLIB_IRQCHIP and simplify the code.
|
||||
|
||||
- Look over and identify any remaining easily converted drivers and
|
||||
dry-code conversions to gpiolib irqchip for maintainers to test
|
||||
|
||||
- Drop gpiochip_set_chained_irqchip() when all the chained irqchips
|
||||
have been converted to the above infrastructure.
|
||||
|
||||
- Add more infrastructure to make it possible to also pass a threaded
|
||||
irqchip in struct gpio_irq_chip.
|
||||
|
||||
- Drop gpiochip_irqchip_add_nested() when all the chained irqchips
|
||||
have been converted to the above infrastructure.
|
||||
|
||||
|
||||
Increase integration with pin control
|
||||
|
||||
|
@ -191,3 +142,39 @@ use of the global GPIO numbers. Once the above is complete, it may
|
|||
make sense to simply join the subsystems into one and make pin
|
||||
multiplexing, pin configuration, GPIO, etc selectable options in one
|
||||
and the same pin control and GPIO subsystem.
|
||||
|
||||
|
||||
Debugfs in place of sysfs
|
||||
|
||||
The old sysfs code that enables simple uses of GPIOs from the
|
||||
command line is still popular despite the existance of the proper
|
||||
character device. The reason is that it is simple to use on
|
||||
root filesystems where you only have a minimal set of tools such
|
||||
as "cat", "echo" etc.
|
||||
|
||||
The old sysfs still need to be strongly deprecated and removed
|
||||
as it relies on the global GPIO numberspace that assume a strict
|
||||
order of global GPIO numbers that do not change between boots
|
||||
and is independent of probe order.
|
||||
|
||||
To solve this and provide an ABI that people can use for hacks
|
||||
and development, implement a debugfs interface to manipulate
|
||||
GPIO lines that can do everything that sysfs can do today: one
|
||||
directory per gpiochip and one file entry per line:
|
||||
|
||||
/sys/kernel/debug/gpiochip/gpiochip0
|
||||
/sys/kernel/debug/gpiochip/gpiochip0/gpio0
|
||||
/sys/kernel/debug/gpiochip/gpiochip0/gpio1
|
||||
/sys/kernel/debug/gpiochip/gpiochip0/gpio2
|
||||
/sys/kernel/debug/gpiochip/gpiochip0/gpio3
|
||||
...
|
||||
/sys/kernel/debug/gpiochip/gpiochip1
|
||||
/sys/kernel/debug/gpiochip/gpiochip1/gpio0
|
||||
/sys/kernel/debug/gpiochip/gpiochip1/gpio1
|
||||
...
|
||||
|
||||
The exact files and design of the debugfs interface can be
|
||||
discussed but the idea is to provide a low-level access point
|
||||
for debugging and hacking and to expose all lines without the
|
||||
need of any exporting. Also provide ample ammunition to shoot
|
||||
oneself in the foot, because this is debugfs after all.
|
||||
|
|
|
@ -132,8 +132,7 @@ static void idi_48_irq_mask(struct irq_data *data)
|
|||
|
||||
outb(idi48gpio->cos_enb, idi48gpio->base + 7);
|
||||
|
||||
raw_spin_unlock_irqrestore(&idi48gpio->lock,
|
||||
flags);
|
||||
raw_spin_unlock_irqrestore(&idi48gpio->lock, flags);
|
||||
}
|
||||
|
||||
return;
|
||||
|
@ -166,8 +165,7 @@ static void idi_48_irq_unmask(struct irq_data *data)
|
|||
|
||||
outb(idi48gpio->cos_enb, idi48gpio->base + 7);
|
||||
|
||||
raw_spin_unlock_irqrestore(&idi48gpio->lock,
|
||||
flags);
|
||||
raw_spin_unlock_irqrestore(&idi48gpio->lock, flags);
|
||||
}
|
||||
|
||||
return;
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* GPIO driver for AMD 8111 south bridges
|
||||
*
|
||||
|
@ -20,10 +21,6 @@
|
|||
* Hardware driver for Intel i810 Random Number Generator (RNG)
|
||||
* Copyright 2000,2001 Jeff Garzik <jgarzik@pobox.com>
|
||||
* Copyright 2000,2001 Philipp Rumpf <prumpf@mandrakesoft.com>
|
||||
*
|
||||
* This file is licensed under the terms of the GNU General Public
|
||||
* License version 2. This program is licensed "as is" without any
|
||||
* warranty of any kind, whether express or implied.
|
||||
*/
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/module.h>
|
||||
|
@ -179,7 +176,6 @@ static int __init amd_gpio_init(void)
|
|||
struct pci_dev *pdev = NULL;
|
||||
const struct pci_device_id *ent;
|
||||
|
||||
|
||||
/* We look for our device - AMD South Bridge
|
||||
* I don't know about a system with two such bridges,
|
||||
* so we can assume that there is max. one device.
|
||||
|
@ -223,11 +219,10 @@ found:
|
|||
|
||||
spin_lock_init(&gp.lock);
|
||||
|
||||
printk(KERN_INFO "AMD-8111 GPIO detected\n");
|
||||
dev_info(&pdev->dev, "AMD-8111 GPIO detected\n");
|
||||
err = gpiochip_add_data(&gp.chip, &gp);
|
||||
if (err) {
|
||||
printk(KERN_ERR "GPIO registering failed (%d)\n",
|
||||
err);
|
||||
dev_err(&pdev->dev, "GPIO registering failed (%d)\n", err);
|
||||
ioport_unmap(gp.pm);
|
||||
goto out;
|
||||
}
|
||||
|
|
|
@ -123,6 +123,7 @@ static int ath79_gpio_irq_set_type(struct irq_data *data,
|
|||
switch (flow_type) {
|
||||
case IRQ_TYPE_EDGE_RISING:
|
||||
polarity |= mask;
|
||||
fallthrough;
|
||||
case IRQ_TYPE_EDGE_FALLING:
|
||||
case IRQ_TYPE_EDGE_BOTH:
|
||||
break;
|
||||
|
|
|
@ -175,13 +175,13 @@ static int bt8xxgpio_probe(struct pci_dev *dev,
|
|||
|
||||
err = pci_enable_device(dev);
|
||||
if (err) {
|
||||
printk(KERN_ERR "bt8xxgpio: Can't enable device.\n");
|
||||
dev_err(&dev->dev, "can't enable device.\n");
|
||||
return err;
|
||||
}
|
||||
if (!devm_request_mem_region(&dev->dev, pci_resource_start(dev, 0),
|
||||
pci_resource_len(dev, 0),
|
||||
"bt8xxgpio")) {
|
||||
printk(KERN_WARNING "bt8xxgpio: Can't request iomem (0x%llx).\n",
|
||||
dev_warn(&dev->dev, "can't request iomem (0x%llx).\n",
|
||||
(unsigned long long)pci_resource_start(dev, 0));
|
||||
err = -EBUSY;
|
||||
goto err_disable;
|
||||
|
@ -191,7 +191,7 @@ static int bt8xxgpio_probe(struct pci_dev *dev,
|
|||
|
||||
bg->mmio = devm_ioremap(&dev->dev, pci_resource_start(dev, 0), 0x1000);
|
||||
if (!bg->mmio) {
|
||||
printk(KERN_ERR "bt8xxgpio: ioremap() failed\n");
|
||||
dev_err(&dev->dev, "ioremap() failed\n");
|
||||
err = -EIO;
|
||||
goto err_disable;
|
||||
}
|
||||
|
@ -207,7 +207,7 @@ static int bt8xxgpio_probe(struct pci_dev *dev,
|
|||
bt8xxgpio_gpio_setup(bg);
|
||||
err = gpiochip_add_data(&bg->gpio, bg);
|
||||
if (err) {
|
||||
printk(KERN_ERR "bt8xxgpio: Failed to register GPIOs\n");
|
||||
dev_err(&dev->dev, "failed to register GPIOs\n");
|
||||
goto err_disable;
|
||||
}
|
||||
|
||||
|
|
|
@ -345,12 +345,8 @@ static int cs5535_gpio_probe(struct platform_device *pdev)
|
|||
mask_orig, mask);
|
||||
|
||||
/* finally, register with the generic GPIO API */
|
||||
err = devm_gpiochip_add_data(&pdev->dev, &cs5535_gpio_chip.chip,
|
||||
&cs5535_gpio_chip);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
return 0;
|
||||
return devm_gpiochip_add_data(&pdev->dev, &cs5535_gpio_chip.chip,
|
||||
&cs5535_gpio_chip);
|
||||
}
|
||||
|
||||
static struct platform_driver cs5535_gpio_driver = {
|
||||
|
|
|
@ -616,10 +616,9 @@ static int dwapb_get_reset(struct dwapb_gpio *gpio)
|
|||
int err;
|
||||
|
||||
gpio->rst = devm_reset_control_get_optional_shared(gpio->dev, NULL);
|
||||
if (IS_ERR(gpio->rst)) {
|
||||
dev_err(gpio->dev, "Cannot get reset descriptor\n");
|
||||
return PTR_ERR(gpio->rst);
|
||||
}
|
||||
if (IS_ERR(gpio->rst))
|
||||
return dev_err_probe(gpio->dev, PTR_ERR(gpio->rst),
|
||||
"Cannot get reset descriptor\n");
|
||||
|
||||
err = reset_control_deassert(gpio->rst);
|
||||
if (err) {
|
||||
|
|
|
@ -4,14 +4,17 @@
|
|||
*
|
||||
* Copyright (C) 2015 Sudip Mukherjee <sudip.mukherjee@codethink.co.uk>
|
||||
*/
|
||||
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/gpio/driver.h>
|
||||
#include <linux/idr.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/regmap.h>
|
||||
|
||||
#define EXAR_OFFSET_MPIOLVL_LO 0x90
|
||||
#define EXAR_OFFSET_MPIOSEL_LO 0x93
|
||||
|
@ -24,60 +27,39 @@ static DEFINE_IDA(ida_index);
|
|||
|
||||
struct exar_gpio_chip {
|
||||
struct gpio_chip gpio_chip;
|
||||
struct mutex lock;
|
||||
struct regmap *regmap;
|
||||
int index;
|
||||
void __iomem *regs;
|
||||
char name[20];
|
||||
unsigned int first_pin;
|
||||
};
|
||||
|
||||
static void exar_update(struct gpio_chip *chip, unsigned int reg, int val,
|
||||
unsigned int offset)
|
||||
static unsigned int
|
||||
exar_offset_to_sel_addr(struct exar_gpio_chip *exar_gpio, unsigned int offset)
|
||||
{
|
||||
struct exar_gpio_chip *exar_gpio = gpiochip_get_data(chip);
|
||||
int temp;
|
||||
|
||||
mutex_lock(&exar_gpio->lock);
|
||||
temp = readb(exar_gpio->regs + reg);
|
||||
temp &= ~BIT(offset);
|
||||
if (val)
|
||||
temp |= BIT(offset);
|
||||
writeb(temp, exar_gpio->regs + reg);
|
||||
mutex_unlock(&exar_gpio->lock);
|
||||
return (offset + exar_gpio->first_pin) / 8 ? EXAR_OFFSET_MPIOSEL_HI
|
||||
: EXAR_OFFSET_MPIOSEL_LO;
|
||||
}
|
||||
|
||||
static int exar_set_direction(struct gpio_chip *chip, int direction,
|
||||
unsigned int offset)
|
||||
static unsigned int
|
||||
exar_offset_to_lvl_addr(struct exar_gpio_chip *exar_gpio, unsigned int offset)
|
||||
{
|
||||
struct exar_gpio_chip *exar_gpio = gpiochip_get_data(chip);
|
||||
unsigned int addr = (offset + exar_gpio->first_pin) / 8 ?
|
||||
EXAR_OFFSET_MPIOSEL_HI : EXAR_OFFSET_MPIOSEL_LO;
|
||||
unsigned int bit = (offset + exar_gpio->first_pin) % 8;
|
||||
|
||||
exar_update(chip, addr, direction, bit);
|
||||
return 0;
|
||||
return (offset + exar_gpio->first_pin) / 8 ? EXAR_OFFSET_MPIOLVL_HI
|
||||
: EXAR_OFFSET_MPIOLVL_LO;
|
||||
}
|
||||
|
||||
static int exar_get(struct gpio_chip *chip, unsigned int reg)
|
||||
static unsigned int
|
||||
exar_offset_to_bit(struct exar_gpio_chip *exar_gpio, unsigned int offset)
|
||||
{
|
||||
struct exar_gpio_chip *exar_gpio = gpiochip_get_data(chip);
|
||||
int value;
|
||||
|
||||
mutex_lock(&exar_gpio->lock);
|
||||
value = readb(exar_gpio->regs + reg);
|
||||
mutex_unlock(&exar_gpio->lock);
|
||||
|
||||
return value;
|
||||
return (offset + exar_gpio->first_pin) % 8;
|
||||
}
|
||||
|
||||
static int exar_get_direction(struct gpio_chip *chip, unsigned int offset)
|
||||
{
|
||||
struct exar_gpio_chip *exar_gpio = gpiochip_get_data(chip);
|
||||
unsigned int addr = (offset + exar_gpio->first_pin) / 8 ?
|
||||
EXAR_OFFSET_MPIOSEL_HI : EXAR_OFFSET_MPIOSEL_LO;
|
||||
unsigned int bit = (offset + exar_gpio->first_pin) % 8;
|
||||
unsigned int addr = exar_offset_to_sel_addr(exar_gpio, offset);
|
||||
unsigned int bit = exar_offset_to_bit(exar_gpio, offset);
|
||||
|
||||
if (exar_get(chip, addr) & BIT(bit))
|
||||
if (regmap_test_bits(exar_gpio->regmap, addr, BIT(bit)))
|
||||
return GPIO_LINE_DIRECTION_IN;
|
||||
|
||||
return GPIO_LINE_DIRECTION_OUT;
|
||||
|
@ -86,39 +68,66 @@ static int exar_get_direction(struct gpio_chip *chip, unsigned int offset)
|
|||
static int exar_get_value(struct gpio_chip *chip, unsigned int offset)
|
||||
{
|
||||
struct exar_gpio_chip *exar_gpio = gpiochip_get_data(chip);
|
||||
unsigned int addr = (offset + exar_gpio->first_pin) / 8 ?
|
||||
EXAR_OFFSET_MPIOLVL_HI : EXAR_OFFSET_MPIOLVL_LO;
|
||||
unsigned int bit = (offset + exar_gpio->first_pin) % 8;
|
||||
unsigned int addr = exar_offset_to_lvl_addr(exar_gpio, offset);
|
||||
unsigned int bit = exar_offset_to_bit(exar_gpio, offset);
|
||||
|
||||
return !!(exar_get(chip, addr) & BIT(bit));
|
||||
return !!(regmap_test_bits(exar_gpio->regmap, addr, BIT(bit)));
|
||||
}
|
||||
|
||||
static void exar_set_value(struct gpio_chip *chip, unsigned int offset,
|
||||
int value)
|
||||
{
|
||||
struct exar_gpio_chip *exar_gpio = gpiochip_get_data(chip);
|
||||
unsigned int addr = (offset + exar_gpio->first_pin) / 8 ?
|
||||
EXAR_OFFSET_MPIOLVL_HI : EXAR_OFFSET_MPIOLVL_LO;
|
||||
unsigned int bit = (offset + exar_gpio->first_pin) % 8;
|
||||
unsigned int addr = exar_offset_to_lvl_addr(exar_gpio, offset);
|
||||
unsigned int bit = exar_offset_to_bit(exar_gpio, offset);
|
||||
|
||||
exar_update(chip, addr, value, bit);
|
||||
if (value)
|
||||
regmap_set_bits(exar_gpio->regmap, addr, BIT(bit));
|
||||
else
|
||||
regmap_clear_bits(exar_gpio->regmap, addr, BIT(bit));
|
||||
}
|
||||
|
||||
static int exar_direction_output(struct gpio_chip *chip, unsigned int offset,
|
||||
int value)
|
||||
{
|
||||
struct exar_gpio_chip *exar_gpio = gpiochip_get_data(chip);
|
||||
unsigned int addr = exar_offset_to_sel_addr(exar_gpio, offset);
|
||||
unsigned int bit = exar_offset_to_bit(exar_gpio, offset);
|
||||
|
||||
exar_set_value(chip, offset, value);
|
||||
return exar_set_direction(chip, 0, offset);
|
||||
regmap_clear_bits(exar_gpio->regmap, addr, BIT(bit));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int exar_direction_input(struct gpio_chip *chip, unsigned int offset)
|
||||
{
|
||||
return exar_set_direction(chip, 1, offset);
|
||||
struct exar_gpio_chip *exar_gpio = gpiochip_get_data(chip);
|
||||
unsigned int addr = exar_offset_to_sel_addr(exar_gpio, offset);
|
||||
unsigned int bit = exar_offset_to_bit(exar_gpio, offset);
|
||||
|
||||
regmap_set_bits(exar_gpio->regmap, addr, BIT(bit));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void exar_devm_ida_free(void *data)
|
||||
{
|
||||
struct exar_gpio_chip *exar_gpio = data;
|
||||
|
||||
ida_free(&ida_index, exar_gpio->index);
|
||||
}
|
||||
|
||||
static const struct regmap_config exar_regmap_config = {
|
||||
.name = "exar-gpio",
|
||||
.reg_bits = 16,
|
||||
.val_bits = 8,
|
||||
};
|
||||
|
||||
static int gpio_exar_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct pci_dev *pcidev = to_pci_dev(pdev->dev.parent);
|
||||
struct device *dev = &pdev->dev;
|
||||
struct pci_dev *pcidev = to_pci_dev(dev->parent);
|
||||
struct exar_gpio_chip *exar_gpio;
|
||||
u32 first_pin, ngpios;
|
||||
void __iomem *p;
|
||||
|
@ -132,30 +141,37 @@ static int gpio_exar_probe(struct platform_device *pdev)
|
|||
if (!p)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = device_property_read_u32(&pdev->dev, "exar,first-pin",
|
||||
&first_pin);
|
||||
ret = device_property_read_u32(dev, "exar,first-pin", &first_pin);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = device_property_read_u32(&pdev->dev, "ngpios", &ngpios);
|
||||
ret = device_property_read_u32(dev, "ngpios", &ngpios);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
exar_gpio = devm_kzalloc(&pdev->dev, sizeof(*exar_gpio), GFP_KERNEL);
|
||||
exar_gpio = devm_kzalloc(dev, sizeof(*exar_gpio), GFP_KERNEL);
|
||||
if (!exar_gpio)
|
||||
return -ENOMEM;
|
||||
|
||||
mutex_init(&exar_gpio->lock);
|
||||
/*
|
||||
* We don't need to check the return values of mmio regmap operations (unless
|
||||
* the regmap has a clock attached which is not the case here).
|
||||
*/
|
||||
exar_gpio->regmap = devm_regmap_init_mmio(dev, p, &exar_regmap_config);
|
||||
if (IS_ERR(exar_gpio->regmap))
|
||||
return PTR_ERR(exar_gpio->regmap);
|
||||
|
||||
index = ida_simple_get(&ida_index, 0, 0, GFP_KERNEL);
|
||||
if (index < 0) {
|
||||
ret = index;
|
||||
goto err_mutex_destroy;
|
||||
}
|
||||
index = ida_alloc(&ida_index, GFP_KERNEL);
|
||||
if (index < 0)
|
||||
return index;
|
||||
|
||||
ret = devm_add_action_or_reset(dev, exar_devm_ida_free, exar_gpio);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
sprintf(exar_gpio->name, "exar_gpio%d", index);
|
||||
exar_gpio->gpio_chip.label = exar_gpio->name;
|
||||
exar_gpio->gpio_chip.parent = &pdev->dev;
|
||||
exar_gpio->gpio_chip.parent = dev;
|
||||
exar_gpio->gpio_chip.direction_output = exar_direction_output;
|
||||
exar_gpio->gpio_chip.direction_input = exar_direction_input;
|
||||
exar_gpio->gpio_chip.get_direction = exar_get_direction;
|
||||
|
@ -163,39 +179,20 @@ static int gpio_exar_probe(struct platform_device *pdev)
|
|||
exar_gpio->gpio_chip.set = exar_set_value;
|
||||
exar_gpio->gpio_chip.base = -1;
|
||||
exar_gpio->gpio_chip.ngpio = ngpios;
|
||||
exar_gpio->regs = p;
|
||||
exar_gpio->index = index;
|
||||
exar_gpio->first_pin = first_pin;
|
||||
|
||||
ret = devm_gpiochip_add_data(&pdev->dev,
|
||||
&exar_gpio->gpio_chip, exar_gpio);
|
||||
ret = devm_gpiochip_add_data(dev, &exar_gpio->gpio_chip, exar_gpio);
|
||||
if (ret)
|
||||
goto err_destroy;
|
||||
return ret;
|
||||
|
||||
platform_set_drvdata(pdev, exar_gpio);
|
||||
|
||||
return 0;
|
||||
|
||||
err_destroy:
|
||||
ida_simple_remove(&ida_index, index);
|
||||
err_mutex_destroy:
|
||||
mutex_destroy(&exar_gpio->lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int gpio_exar_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct exar_gpio_chip *exar_gpio = platform_get_drvdata(pdev);
|
||||
|
||||
ida_simple_remove(&ida_index, exar_gpio->index);
|
||||
mutex_destroy(&exar_gpio->lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver gpio_exar_driver = {
|
||||
.probe = gpio_exar_probe,
|
||||
.remove = gpio_exar_remove,
|
||||
.driver = {
|
||||
.name = DRIVER_NAME,
|
||||
},
|
||||
|
|
|
@ -0,0 +1,323 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/* Copyright (c) 2020 HiSilicon Limited. */
|
||||
#include <linux/gpio/driver.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/property.h>
|
||||
|
||||
#define HISI_GPIO_SWPORT_DR_SET_WX 0x000
|
||||
#define HISI_GPIO_SWPORT_DR_CLR_WX 0x004
|
||||
#define HISI_GPIO_SWPORT_DDR_SET_WX 0x010
|
||||
#define HISI_GPIO_SWPORT_DDR_CLR_WX 0x014
|
||||
#define HISI_GPIO_SWPORT_DDR_ST_WX 0x018
|
||||
#define HISI_GPIO_INTEN_SET_WX 0x020
|
||||
#define HISI_GPIO_INTEN_CLR_WX 0x024
|
||||
#define HISI_GPIO_INTMASK_SET_WX 0x030
|
||||
#define HISI_GPIO_INTMASK_CLR_WX 0x034
|
||||
#define HISI_GPIO_INTTYPE_EDGE_SET_WX 0x040
|
||||
#define HISI_GPIO_INTTYPE_EDGE_CLR_WX 0x044
|
||||
#define HISI_GPIO_INT_POLARITY_SET_WX 0x050
|
||||
#define HISI_GPIO_INT_POLARITY_CLR_WX 0x054
|
||||
#define HISI_GPIO_DEBOUNCE_SET_WX 0x060
|
||||
#define HISI_GPIO_DEBOUNCE_CLR_WX 0x064
|
||||
#define HISI_GPIO_INTSTATUS_WX 0x070
|
||||
#define HISI_GPIO_PORTA_EOI_WX 0x078
|
||||
#define HISI_GPIO_EXT_PORT_WX 0x080
|
||||
#define HISI_GPIO_INTCOMB_MASK_WX 0x0a0
|
||||
#define HISI_GPIO_INT_DEDGE_SET 0x0b0
|
||||
#define HISI_GPIO_INT_DEDGE_CLR 0x0b4
|
||||
#define HISI_GPIO_INT_DEDGE_ST 0x0b8
|
||||
|
||||
#define HISI_GPIO_LINE_NUM_MAX 32
|
||||
#define HISI_GPIO_DRIVER_NAME "gpio-hisi"
|
||||
|
||||
struct hisi_gpio {
|
||||
struct gpio_chip chip;
|
||||
struct device *dev;
|
||||
void __iomem *reg_base;
|
||||
unsigned int line_num;
|
||||
struct irq_chip irq_chip;
|
||||
int irq;
|
||||
};
|
||||
|
||||
static inline u32 hisi_gpio_read_reg(struct gpio_chip *chip,
|
||||
unsigned int off)
|
||||
{
|
||||
struct hisi_gpio *hisi_gpio =
|
||||
container_of(chip, struct hisi_gpio, chip);
|
||||
void __iomem *reg = hisi_gpio->reg_base + off;
|
||||
|
||||
return readl(reg);
|
||||
}
|
||||
|
||||
static inline void hisi_gpio_write_reg(struct gpio_chip *chip,
|
||||
unsigned int off, u32 val)
|
||||
{
|
||||
struct hisi_gpio *hisi_gpio =
|
||||
container_of(chip, struct hisi_gpio, chip);
|
||||
void __iomem *reg = hisi_gpio->reg_base + off;
|
||||
|
||||
writel(val, reg);
|
||||
}
|
||||
|
||||
static void hisi_gpio_set_debounce(struct gpio_chip *chip, unsigned int off,
|
||||
u32 debounce)
|
||||
{
|
||||
if (debounce)
|
||||
hisi_gpio_write_reg(chip, HISI_GPIO_DEBOUNCE_SET_WX, BIT(off));
|
||||
else
|
||||
hisi_gpio_write_reg(chip, HISI_GPIO_DEBOUNCE_CLR_WX, BIT(off));
|
||||
}
|
||||
|
||||
static int hisi_gpio_set_config(struct gpio_chip *chip, unsigned int offset,
|
||||
unsigned long config)
|
||||
{
|
||||
u32 config_para = pinconf_to_config_param(config);
|
||||
u32 config_arg;
|
||||
|
||||
switch (config_para) {
|
||||
case PIN_CONFIG_INPUT_DEBOUNCE:
|
||||
config_arg = pinconf_to_config_argument(config);
|
||||
hisi_gpio_set_debounce(chip, offset, config_arg);
|
||||
break;
|
||||
default:
|
||||
return -ENOTSUPP;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void hisi_gpio_set_ack(struct irq_data *d)
|
||||
{
|
||||
struct gpio_chip *chip = irq_data_get_irq_chip_data(d);
|
||||
|
||||
hisi_gpio_write_reg(chip, HISI_GPIO_PORTA_EOI_WX, BIT(irqd_to_hwirq(d)));
|
||||
}
|
||||
|
||||
static void hisi_gpio_irq_set_mask(struct irq_data *d)
|
||||
{
|
||||
struct gpio_chip *chip = irq_data_get_irq_chip_data(d);
|
||||
|
||||
hisi_gpio_write_reg(chip, HISI_GPIO_INTMASK_SET_WX, BIT(irqd_to_hwirq(d)));
|
||||
}
|
||||
|
||||
static void hisi_gpio_irq_clr_mask(struct irq_data *d)
|
||||
{
|
||||
struct gpio_chip *chip = irq_data_get_irq_chip_data(d);
|
||||
|
||||
hisi_gpio_write_reg(chip, HISI_GPIO_INTMASK_CLR_WX, BIT(irqd_to_hwirq(d)));
|
||||
}
|
||||
|
||||
static int hisi_gpio_irq_set_type(struct irq_data *d, u32 type)
|
||||
{
|
||||
struct gpio_chip *chip = irq_data_get_irq_chip_data(d);
|
||||
unsigned int mask = BIT(irqd_to_hwirq(d));
|
||||
|
||||
switch (type) {
|
||||
case IRQ_TYPE_EDGE_BOTH:
|
||||
hisi_gpio_write_reg(chip, HISI_GPIO_INT_DEDGE_SET, mask);
|
||||
break;
|
||||
case IRQ_TYPE_EDGE_RISING:
|
||||
hisi_gpio_write_reg(chip, HISI_GPIO_INTTYPE_EDGE_SET_WX, mask);
|
||||
hisi_gpio_write_reg(chip, HISI_GPIO_INT_POLARITY_SET_WX, mask);
|
||||
break;
|
||||
case IRQ_TYPE_EDGE_FALLING:
|
||||
hisi_gpio_write_reg(chip, HISI_GPIO_INTTYPE_EDGE_SET_WX, mask);
|
||||
hisi_gpio_write_reg(chip, HISI_GPIO_INT_POLARITY_CLR_WX, mask);
|
||||
break;
|
||||
case IRQ_TYPE_LEVEL_HIGH:
|
||||
hisi_gpio_write_reg(chip, HISI_GPIO_INTTYPE_EDGE_CLR_WX, mask);
|
||||
hisi_gpio_write_reg(chip, HISI_GPIO_INT_POLARITY_SET_WX, mask);
|
||||
break;
|
||||
case IRQ_TYPE_LEVEL_LOW:
|
||||
hisi_gpio_write_reg(chip, HISI_GPIO_INTTYPE_EDGE_CLR_WX, mask);
|
||||
hisi_gpio_write_reg(chip, HISI_GPIO_INT_POLARITY_CLR_WX, mask);
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* The dual-edge interrupt and other interrupt's registers do not
|
||||
* take effect at the same time. The registers of the two-edge
|
||||
* interrupts have higher priorities, the configuration of
|
||||
* the dual-edge interrupts must be disabled before the configuration
|
||||
* of other kind of interrupts.
|
||||
*/
|
||||
if (type != IRQ_TYPE_EDGE_BOTH) {
|
||||
unsigned int both = hisi_gpio_read_reg(chip, HISI_GPIO_INT_DEDGE_ST);
|
||||
|
||||
if (both & mask)
|
||||
hisi_gpio_write_reg(chip, HISI_GPIO_INT_DEDGE_CLR, mask);
|
||||
}
|
||||
|
||||
if (type & IRQ_TYPE_LEVEL_MASK)
|
||||
irq_set_handler_locked(d, handle_level_irq);
|
||||
else if (type & IRQ_TYPE_EDGE_BOTH)
|
||||
irq_set_handler_locked(d, handle_edge_irq);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void hisi_gpio_irq_enable(struct irq_data *d)
|
||||
{
|
||||
struct gpio_chip *chip = irq_data_get_irq_chip_data(d);
|
||||
|
||||
hisi_gpio_irq_clr_mask(d);
|
||||
hisi_gpio_write_reg(chip, HISI_GPIO_INTEN_SET_WX, BIT(irqd_to_hwirq(d)));
|
||||
}
|
||||
|
||||
static void hisi_gpio_irq_disable(struct irq_data *d)
|
||||
{
|
||||
struct gpio_chip *chip = irq_data_get_irq_chip_data(d);
|
||||
|
||||
hisi_gpio_irq_set_mask(d);
|
||||
hisi_gpio_write_reg(chip, HISI_GPIO_INTEN_CLR_WX, BIT(irqd_to_hwirq(d)));
|
||||
}
|
||||
|
||||
static void hisi_gpio_irq_handler(struct irq_desc *desc)
|
||||
{
|
||||
struct hisi_gpio *hisi_gpio = irq_desc_get_handler_data(desc);
|
||||
unsigned long irq_msk = hisi_gpio_read_reg(&hisi_gpio->chip,
|
||||
HISI_GPIO_INTSTATUS_WX);
|
||||
struct irq_chip *irq_c = irq_desc_get_chip(desc);
|
||||
int hwirq;
|
||||
|
||||
chained_irq_enter(irq_c, desc);
|
||||
for_each_set_bit(hwirq, &irq_msk, HISI_GPIO_LINE_NUM_MAX)
|
||||
generic_handle_irq(irq_find_mapping(hisi_gpio->chip.irq.domain,
|
||||
hwirq));
|
||||
chained_irq_exit(irq_c, desc);
|
||||
}
|
||||
|
||||
static void hisi_gpio_init_irq(struct hisi_gpio *hisi_gpio)
|
||||
{
|
||||
struct gpio_chip *chip = &hisi_gpio->chip;
|
||||
struct gpio_irq_chip *girq_chip = &chip->irq;
|
||||
|
||||
/* Set hooks for irq_chip */
|
||||
hisi_gpio->irq_chip.irq_ack = hisi_gpio_set_ack;
|
||||
hisi_gpio->irq_chip.irq_mask = hisi_gpio_irq_set_mask;
|
||||
hisi_gpio->irq_chip.irq_unmask = hisi_gpio_irq_clr_mask;
|
||||
hisi_gpio->irq_chip.irq_set_type = hisi_gpio_irq_set_type;
|
||||
hisi_gpio->irq_chip.irq_enable = hisi_gpio_irq_enable;
|
||||
hisi_gpio->irq_chip.irq_disable = hisi_gpio_irq_disable;
|
||||
|
||||
girq_chip->chip = &hisi_gpio->irq_chip;
|
||||
girq_chip->default_type = IRQ_TYPE_NONE;
|
||||
girq_chip->num_parents = 1;
|
||||
girq_chip->parents = &hisi_gpio->irq;
|
||||
girq_chip->parent_handler = hisi_gpio_irq_handler;
|
||||
girq_chip->parent_handler_data = hisi_gpio;
|
||||
|
||||
/* Clear Mask of GPIO controller combine IRQ */
|
||||
hisi_gpio_write_reg(chip, HISI_GPIO_INTCOMB_MASK_WX, 1);
|
||||
}
|
||||
|
||||
static const struct acpi_device_id hisi_gpio_acpi_match[] = {
|
||||
{"HISI0184", 0},
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(acpi, hisi_gpio_acpi_match);
|
||||
|
||||
static void hisi_gpio_get_pdata(struct device *dev,
|
||||
struct hisi_gpio *hisi_gpio)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct fwnode_handle *fwnode;
|
||||
int idx = 0;
|
||||
|
||||
device_for_each_child_node(dev, fwnode) {
|
||||
/* Cycle for once, no need for an array to save line_num */
|
||||
if (fwnode_property_read_u32(fwnode, "ngpios",
|
||||
&hisi_gpio->line_num)) {
|
||||
dev_err(dev,
|
||||
"failed to get number of lines for port%d and use default value instead\n",
|
||||
idx);
|
||||
hisi_gpio->line_num = HISI_GPIO_LINE_NUM_MAX;
|
||||
}
|
||||
|
||||
if (WARN_ON(hisi_gpio->line_num > HISI_GPIO_LINE_NUM_MAX))
|
||||
hisi_gpio->line_num = HISI_GPIO_LINE_NUM_MAX;
|
||||
|
||||
hisi_gpio->irq = platform_get_irq(pdev, idx);
|
||||
|
||||
dev_info(dev,
|
||||
"get hisi_gpio[%d] with %d lines\n", idx,
|
||||
hisi_gpio->line_num);
|
||||
|
||||
idx++;
|
||||
}
|
||||
}
|
||||
|
||||
static int hisi_gpio_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct hisi_gpio *hisi_gpio;
|
||||
int port_num;
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* One GPIO controller own one port currently,
|
||||
* if we get more from ACPI table, return error.
|
||||
*/
|
||||
port_num = device_get_child_node_count(dev);
|
||||
if (WARN_ON(port_num != 1))
|
||||
return -ENODEV;
|
||||
|
||||
hisi_gpio = devm_kzalloc(dev, sizeof(*hisi_gpio), GFP_KERNEL);
|
||||
if (!hisi_gpio)
|
||||
return -ENOMEM;
|
||||
|
||||
hisi_gpio->reg_base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(hisi_gpio->reg_base))
|
||||
return PTR_ERR(hisi_gpio->reg_base);
|
||||
|
||||
hisi_gpio_get_pdata(dev, hisi_gpio);
|
||||
|
||||
hisi_gpio->dev = dev;
|
||||
|
||||
ret = bgpio_init(&hisi_gpio->chip, hisi_gpio->dev, 0x4,
|
||||
hisi_gpio->reg_base + HISI_GPIO_EXT_PORT_WX,
|
||||
hisi_gpio->reg_base + HISI_GPIO_SWPORT_DR_SET_WX,
|
||||
hisi_gpio->reg_base + HISI_GPIO_SWPORT_DR_CLR_WX,
|
||||
hisi_gpio->reg_base + HISI_GPIO_SWPORT_DDR_SET_WX,
|
||||
hisi_gpio->reg_base + HISI_GPIO_SWPORT_DDR_CLR_WX,
|
||||
BGPIOF_NO_SET_ON_INPUT);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to init, ret = %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
hisi_gpio->chip.set_config = hisi_gpio_set_config;
|
||||
hisi_gpio->chip.ngpio = hisi_gpio->line_num;
|
||||
hisi_gpio->chip.bgpio_dir_unreadable = 1;
|
||||
hisi_gpio->chip.base = -1;
|
||||
|
||||
if (hisi_gpio->irq > 0)
|
||||
hisi_gpio_init_irq(hisi_gpio);
|
||||
|
||||
ret = devm_gpiochip_add_data(dev, &hisi_gpio->chip, hisi_gpio);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to register gpiochip, ret = %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver hisi_gpio_driver = {
|
||||
.driver = {
|
||||
.name = HISI_GPIO_DRIVER_NAME,
|
||||
.acpi_match_table = hisi_gpio_acpi_match,
|
||||
},
|
||||
.probe = hisi_gpio_probe,
|
||||
};
|
||||
|
||||
module_platform_driver(hisi_gpio_driver);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Luo Jiaxing <luojiaxing@huawei.com>");
|
||||
MODULE_DESCRIPTION("HiSilicon GPIO controller driver");
|
||||
MODULE_ALIAS("platform:" HISI_GPIO_DRIVER_NAME);
|
|
@ -15,6 +15,7 @@
|
|||
#include <linux/irq.h>
|
||||
#include <linux/irq_sim.h>
|
||||
#include <linux/irqdomain.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/property.h>
|
||||
|
@ -460,9 +461,16 @@ static int gpio_mockup_probe(struct platform_device *pdev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id gpio_mockup_of_match[] = {
|
||||
{ .compatible = "gpio-mockup", },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, gpio_mockup_of_match);
|
||||
|
||||
static struct platform_driver gpio_mockup_driver = {
|
||||
.driver = {
|
||||
.name = "gpio-mockup",
|
||||
.of_match_table = gpio_mockup_of_match,
|
||||
},
|
||||
.probe = gpio_mockup_probe,
|
||||
};
|
||||
|
@ -556,8 +564,7 @@ static int __init gpio_mockup_init(void)
|
|||
{
|
||||
int i, num_chips, err;
|
||||
|
||||
if ((gpio_mockup_num_ranges < 2) ||
|
||||
(gpio_mockup_num_ranges % 2) ||
|
||||
if ((gpio_mockup_num_ranges % 2) ||
|
||||
(gpio_mockup_num_ranges > GPIO_MOCKUP_MAX_RANGES))
|
||||
return -EINVAL;
|
||||
|
||||
|
|
|
@ -0,0 +1,460 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/* Copyright (C) 2020 Daniel Palmer<daniel@thingy.jp> */
|
||||
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/gpio/driver.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#include <dt-bindings/gpio/msc313-gpio.h>
|
||||
#include <dt-bindings/interrupt-controller/arm-gic.h>
|
||||
|
||||
#define DRIVER_NAME "gpio-msc313"
|
||||
|
||||
#define MSC313_GPIO_IN BIT(0)
|
||||
#define MSC313_GPIO_OUT BIT(4)
|
||||
#define MSC313_GPIO_OEN BIT(5)
|
||||
|
||||
/*
|
||||
* These bits need to be saved to correctly restore the
|
||||
* gpio state when resuming from suspend to memory.
|
||||
*/
|
||||
#define MSC313_GPIO_BITSTOSAVE (MSC313_GPIO_OUT | MSC313_GPIO_OEN)
|
||||
|
||||
/* pad names for fuart, same for all SoCs so far */
|
||||
#define MSC313_PINNAME_FUART_RX "fuart_rx"
|
||||
#define MSC313_PINNAME_FUART_TX "fuart_tx"
|
||||
#define MSC313_PINNAME_FUART_CTS "fuart_cts"
|
||||
#define MSC313_PINNAME_FUART_RTS "fuart_rts"
|
||||
|
||||
/* pad names for sr, mercury5 is different */
|
||||
#define MSC313_PINNAME_SR_IO2 "sr_io2"
|
||||
#define MSC313_PINNAME_SR_IO3 "sr_io3"
|
||||
#define MSC313_PINNAME_SR_IO4 "sr_io4"
|
||||
#define MSC313_PINNAME_SR_IO5 "sr_io5"
|
||||
#define MSC313_PINNAME_SR_IO6 "sr_io6"
|
||||
#define MSC313_PINNAME_SR_IO7 "sr_io7"
|
||||
#define MSC313_PINNAME_SR_IO8 "sr_io8"
|
||||
#define MSC313_PINNAME_SR_IO9 "sr_io9"
|
||||
#define MSC313_PINNAME_SR_IO10 "sr_io10"
|
||||
#define MSC313_PINNAME_SR_IO11 "sr_io11"
|
||||
#define MSC313_PINNAME_SR_IO12 "sr_io12"
|
||||
#define MSC313_PINNAME_SR_IO13 "sr_io13"
|
||||
#define MSC313_PINNAME_SR_IO14 "sr_io14"
|
||||
#define MSC313_PINNAME_SR_IO15 "sr_io15"
|
||||
#define MSC313_PINNAME_SR_IO16 "sr_io16"
|
||||
#define MSC313_PINNAME_SR_IO17 "sr_io17"
|
||||
|
||||
/* pad names for sd, same for all SoCs so far */
|
||||
#define MSC313_PINNAME_SD_CLK "sd_clk"
|
||||
#define MSC313_PINNAME_SD_CMD "sd_cmd"
|
||||
#define MSC313_PINNAME_SD_D0 "sd_d0"
|
||||
#define MSC313_PINNAME_SD_D1 "sd_d1"
|
||||
#define MSC313_PINNAME_SD_D2 "sd_d2"
|
||||
#define MSC313_PINNAME_SD_D3 "sd_d3"
|
||||
|
||||
/* pad names for i2c1, same for all SoCs so for */
|
||||
#define MSC313_PINNAME_I2C1_SCL "i2c1_scl"
|
||||
#define MSC313_PINNAME_I2C1_SCA "i2c1_sda"
|
||||
|
||||
/* pad names for spi0, same for all SoCs so far */
|
||||
#define MSC313_PINNAME_SPI0_CZ "spi0_cz"
|
||||
#define MSC313_PINNAME_SPI0_CK "spi0_ck"
|
||||
#define MSC313_PINNAME_SPI0_DI "spi0_di"
|
||||
#define MSC313_PINNAME_SPI0_DO "spi0_do"
|
||||
|
||||
#define FUART_NAMES \
|
||||
MSC313_PINNAME_FUART_RX, \
|
||||
MSC313_PINNAME_FUART_TX, \
|
||||
MSC313_PINNAME_FUART_CTS, \
|
||||
MSC313_PINNAME_FUART_RTS
|
||||
|
||||
#define OFF_FUART_RX 0x50
|
||||
#define OFF_FUART_TX 0x54
|
||||
#define OFF_FUART_CTS 0x58
|
||||
#define OFF_FUART_RTS 0x5c
|
||||
|
||||
#define FUART_OFFSETS \
|
||||
OFF_FUART_RX, \
|
||||
OFF_FUART_TX, \
|
||||
OFF_FUART_CTS, \
|
||||
OFF_FUART_RTS
|
||||
|
||||
#define SR_NAMES \
|
||||
MSC313_PINNAME_SR_IO2, \
|
||||
MSC313_PINNAME_SR_IO3, \
|
||||
MSC313_PINNAME_SR_IO4, \
|
||||
MSC313_PINNAME_SR_IO5, \
|
||||
MSC313_PINNAME_SR_IO6, \
|
||||
MSC313_PINNAME_SR_IO7, \
|
||||
MSC313_PINNAME_SR_IO8, \
|
||||
MSC313_PINNAME_SR_IO9, \
|
||||
MSC313_PINNAME_SR_IO10, \
|
||||
MSC313_PINNAME_SR_IO11, \
|
||||
MSC313_PINNAME_SR_IO12, \
|
||||
MSC313_PINNAME_SR_IO13, \
|
||||
MSC313_PINNAME_SR_IO14, \
|
||||
MSC313_PINNAME_SR_IO15, \
|
||||
MSC313_PINNAME_SR_IO16, \
|
||||
MSC313_PINNAME_SR_IO17
|
||||
|
||||
#define OFF_SR_IO2 0x88
|
||||
#define OFF_SR_IO3 0x8c
|
||||
#define OFF_SR_IO4 0x90
|
||||
#define OFF_SR_IO5 0x94
|
||||
#define OFF_SR_IO6 0x98
|
||||
#define OFF_SR_IO7 0x9c
|
||||
#define OFF_SR_IO8 0xa0
|
||||
#define OFF_SR_IO9 0xa4
|
||||
#define OFF_SR_IO10 0xa8
|
||||
#define OFF_SR_IO11 0xac
|
||||
#define OFF_SR_IO12 0xb0
|
||||
#define OFF_SR_IO13 0xb4
|
||||
#define OFF_SR_IO14 0xb8
|
||||
#define OFF_SR_IO15 0xbc
|
||||
#define OFF_SR_IO16 0xc0
|
||||
#define OFF_SR_IO17 0xc4
|
||||
|
||||
#define SR_OFFSETS \
|
||||
OFF_SR_IO2, \
|
||||
OFF_SR_IO3, \
|
||||
OFF_SR_IO4, \
|
||||
OFF_SR_IO5, \
|
||||
OFF_SR_IO6, \
|
||||
OFF_SR_IO7, \
|
||||
OFF_SR_IO8, \
|
||||
OFF_SR_IO9, \
|
||||
OFF_SR_IO10, \
|
||||
OFF_SR_IO11, \
|
||||
OFF_SR_IO12, \
|
||||
OFF_SR_IO13, \
|
||||
OFF_SR_IO14, \
|
||||
OFF_SR_IO15, \
|
||||
OFF_SR_IO16, \
|
||||
OFF_SR_IO17
|
||||
|
||||
#define SD_NAMES \
|
||||
MSC313_PINNAME_SD_CLK, \
|
||||
MSC313_PINNAME_SD_CMD, \
|
||||
MSC313_PINNAME_SD_D0, \
|
||||
MSC313_PINNAME_SD_D1, \
|
||||
MSC313_PINNAME_SD_D2, \
|
||||
MSC313_PINNAME_SD_D3
|
||||
|
||||
#define OFF_SD_CLK 0x140
|
||||
#define OFF_SD_CMD 0x144
|
||||
#define OFF_SD_D0 0x148
|
||||
#define OFF_SD_D1 0x14c
|
||||
#define OFF_SD_D2 0x150
|
||||
#define OFF_SD_D3 0x154
|
||||
|
||||
#define SD_OFFSETS \
|
||||
OFF_SD_CLK, \
|
||||
OFF_SD_CMD, \
|
||||
OFF_SD_D0, \
|
||||
OFF_SD_D1, \
|
||||
OFF_SD_D2, \
|
||||
OFF_SD_D3
|
||||
|
||||
#define I2C1_NAMES \
|
||||
MSC313_PINNAME_I2C1_SCL, \
|
||||
MSC313_PINNAME_I2C1_SCA
|
||||
|
||||
#define OFF_I2C1_SCL 0x188
|
||||
#define OFF_I2C1_SCA 0x18c
|
||||
|
||||
#define I2C1_OFFSETS \
|
||||
OFF_I2C1_SCL, \
|
||||
OFF_I2C1_SCA
|
||||
|
||||
#define SPI0_NAMES \
|
||||
MSC313_PINNAME_SPI0_CZ, \
|
||||
MSC313_PINNAME_SPI0_CK, \
|
||||
MSC313_PINNAME_SPI0_DI, \
|
||||
MSC313_PINNAME_SPI0_DO
|
||||
|
||||
#define OFF_SPI0_CZ 0x1c0
|
||||
#define OFF_SPI0_CK 0x1c4
|
||||
#define OFF_SPI0_DI 0x1c8
|
||||
#define OFF_SPI0_DO 0x1cc
|
||||
|
||||
#define SPI0_OFFSETS \
|
||||
OFF_SPI0_CZ, \
|
||||
OFF_SPI0_CK, \
|
||||
OFF_SPI0_DI, \
|
||||
OFF_SPI0_DO
|
||||
|
||||
struct msc313_gpio_data {
|
||||
const char * const *names;
|
||||
const unsigned int *offsets;
|
||||
const unsigned int num;
|
||||
};
|
||||
|
||||
#define MSC313_GPIO_CHIPDATA(_chip) \
|
||||
static const struct msc313_gpio_data _chip##_data = { \
|
||||
.names = _chip##_names, \
|
||||
.offsets = _chip##_offsets, \
|
||||
.num = ARRAY_SIZE(_chip##_offsets), \
|
||||
}
|
||||
|
||||
#ifdef CONFIG_MACH_INFINITY
|
||||
static const char * const msc313_names[] = {
|
||||
FUART_NAMES,
|
||||
SR_NAMES,
|
||||
SD_NAMES,
|
||||
I2C1_NAMES,
|
||||
SPI0_NAMES,
|
||||
};
|
||||
|
||||
static const unsigned int msc313_offsets[] = {
|
||||
FUART_OFFSETS,
|
||||
SR_OFFSETS,
|
||||
SD_OFFSETS,
|
||||
I2C1_OFFSETS,
|
||||
SPI0_OFFSETS,
|
||||
};
|
||||
|
||||
MSC313_GPIO_CHIPDATA(msc313);
|
||||
#endif
|
||||
|
||||
struct msc313_gpio {
|
||||
void __iomem *base;
|
||||
const struct msc313_gpio_data *gpio_data;
|
||||
u8 *saved;
|
||||
};
|
||||
|
||||
static void msc313_gpio_set(struct gpio_chip *chip, unsigned int offset, int value)
|
||||
{
|
||||
struct msc313_gpio *gpio = gpiochip_get_data(chip);
|
||||
u8 gpioreg = readb_relaxed(gpio->base + gpio->gpio_data->offsets[offset]);
|
||||
|
||||
if (value)
|
||||
gpioreg |= MSC313_GPIO_OUT;
|
||||
else
|
||||
gpioreg &= ~MSC313_GPIO_OUT;
|
||||
|
||||
writeb_relaxed(gpioreg, gpio->base + gpio->gpio_data->offsets[offset]);
|
||||
}
|
||||
|
||||
static int msc313_gpio_get(struct gpio_chip *chip, unsigned int offset)
|
||||
{
|
||||
struct msc313_gpio *gpio = gpiochip_get_data(chip);
|
||||
|
||||
return readb_relaxed(gpio->base + gpio->gpio_data->offsets[offset]) & MSC313_GPIO_IN;
|
||||
}
|
||||
|
||||
static int msc313_gpio_direction_input(struct gpio_chip *chip, unsigned int offset)
|
||||
{
|
||||
struct msc313_gpio *gpio = gpiochip_get_data(chip);
|
||||
u8 gpioreg = readb_relaxed(gpio->base + gpio->gpio_data->offsets[offset]);
|
||||
|
||||
gpioreg |= MSC313_GPIO_OEN;
|
||||
writeb_relaxed(gpioreg, gpio->base + gpio->gpio_data->offsets[offset]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int msc313_gpio_direction_output(struct gpio_chip *chip, unsigned int offset, int value)
|
||||
{
|
||||
struct msc313_gpio *gpio = gpiochip_get_data(chip);
|
||||
u8 gpioreg = readb_relaxed(gpio->base + gpio->gpio_data->offsets[offset]);
|
||||
|
||||
gpioreg &= ~MSC313_GPIO_OEN;
|
||||
if (value)
|
||||
gpioreg |= MSC313_GPIO_OUT;
|
||||
else
|
||||
gpioreg &= ~MSC313_GPIO_OUT;
|
||||
writeb_relaxed(gpioreg, gpio->base + gpio->gpio_data->offsets[offset]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* The interrupt handling happens in the parent interrupt controller,
|
||||
* we don't do anything here.
|
||||
*/
|
||||
static struct irq_chip msc313_gpio_irqchip = {
|
||||
.name = "GPIO",
|
||||
.irq_eoi = irq_chip_eoi_parent,
|
||||
.irq_mask = irq_chip_mask_parent,
|
||||
.irq_unmask = irq_chip_unmask_parent,
|
||||
.irq_set_type = irq_chip_set_type_parent,
|
||||
.irq_set_affinity = irq_chip_set_affinity_parent,
|
||||
};
|
||||
|
||||
/*
|
||||
* The parent interrupt controller needs the GIC interrupt type set to GIC_SPI
|
||||
* so we need to provide the fwspec. Essentially gpiochip_populate_parent_fwspec_twocell
|
||||
* that puts GIC_SPI into the first cell.
|
||||
*/
|
||||
static void *msc313_gpio_populate_parent_fwspec(struct gpio_chip *gc,
|
||||
unsigned int parent_hwirq,
|
||||
unsigned int parent_type)
|
||||
{
|
||||
struct irq_fwspec *fwspec;
|
||||
|
||||
fwspec = kmalloc(sizeof(*fwspec), GFP_KERNEL);
|
||||
if (!fwspec)
|
||||
return NULL;
|
||||
|
||||
fwspec->fwnode = gc->irq.parent_domain->fwnode;
|
||||
fwspec->param_count = 3;
|
||||
fwspec->param[0] = GIC_SPI;
|
||||
fwspec->param[1] = parent_hwirq;
|
||||
fwspec->param[2] = parent_type;
|
||||
|
||||
return fwspec;
|
||||
}
|
||||
|
||||
static int msc313e_gpio_child_to_parent_hwirq(struct gpio_chip *chip,
|
||||
unsigned int child,
|
||||
unsigned int child_type,
|
||||
unsigned int *parent,
|
||||
unsigned int *parent_type)
|
||||
{
|
||||
struct msc313_gpio *priv = gpiochip_get_data(chip);
|
||||
unsigned int offset = priv->gpio_data->offsets[child];
|
||||
|
||||
/*
|
||||
* only the spi0 pins have interrupts on the parent
|
||||
* on all of the known chips and so far they are all
|
||||
* mapped to the same place
|
||||
*/
|
||||
if (offset >= OFF_SPI0_CZ && offset <= OFF_SPI0_DO) {
|
||||
*parent_type = child_type;
|
||||
*parent = ((offset - OFF_SPI0_CZ) >> 2) + 28;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int msc313_gpio_probe(struct platform_device *pdev)
|
||||
{
|
||||
const struct msc313_gpio_data *match_data;
|
||||
struct msc313_gpio *gpio;
|
||||
struct gpio_chip *gpiochip;
|
||||
struct gpio_irq_chip *gpioirqchip;
|
||||
struct irq_domain *parent_domain;
|
||||
struct device_node *parent_node;
|
||||
struct device *dev = &pdev->dev;
|
||||
int ret;
|
||||
|
||||
match_data = of_device_get_match_data(dev);
|
||||
if (!match_data)
|
||||
return -EINVAL;
|
||||
|
||||
parent_node = of_irq_find_parent(dev->of_node);
|
||||
if (!parent_node)
|
||||
return -ENODEV;
|
||||
|
||||
parent_domain = irq_find_host(parent_node);
|
||||
if (!parent_domain)
|
||||
return -ENODEV;
|
||||
|
||||
gpio = devm_kzalloc(dev, sizeof(*gpio), GFP_KERNEL);
|
||||
if (!gpio)
|
||||
return -ENOMEM;
|
||||
|
||||
gpio->gpio_data = match_data;
|
||||
|
||||
gpio->saved = devm_kcalloc(dev, gpio->gpio_data->num, sizeof(*gpio->saved), GFP_KERNEL);
|
||||
if (!gpio->saved)
|
||||
return -ENOMEM;
|
||||
|
||||
gpio->base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(gpio->base))
|
||||
return PTR_ERR(gpio->base);
|
||||
|
||||
platform_set_drvdata(pdev, gpio);
|
||||
|
||||
gpiochip = devm_kzalloc(dev, sizeof(*gpiochip), GFP_KERNEL);
|
||||
if (!gpiochip)
|
||||
return -ENOMEM;
|
||||
|
||||
gpiochip->label = DRIVER_NAME;
|
||||
gpiochip->parent = dev;
|
||||
gpiochip->request = gpiochip_generic_request;
|
||||
gpiochip->free = gpiochip_generic_free;
|
||||
gpiochip->direction_input = msc313_gpio_direction_input;
|
||||
gpiochip->direction_output = msc313_gpio_direction_output;
|
||||
gpiochip->get = msc313_gpio_get;
|
||||
gpiochip->set = msc313_gpio_set;
|
||||
gpiochip->base = -1;
|
||||
gpiochip->ngpio = gpio->gpio_data->num;
|
||||
gpiochip->names = gpio->gpio_data->names;
|
||||
|
||||
gpioirqchip = &gpiochip->irq;
|
||||
gpioirqchip->chip = &msc313_gpio_irqchip;
|
||||
gpioirqchip->fwnode = of_node_to_fwnode(dev->of_node);
|
||||
gpioirqchip->parent_domain = parent_domain;
|
||||
gpioirqchip->child_to_parent_hwirq = msc313e_gpio_child_to_parent_hwirq;
|
||||
gpioirqchip->populate_parent_alloc_arg = msc313_gpio_populate_parent_fwspec;
|
||||
gpioirqchip->handler = handle_bad_irq;
|
||||
gpioirqchip->default_type = IRQ_TYPE_NONE;
|
||||
|
||||
ret = devm_gpiochip_add_data(dev, gpiochip, gpio);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int msc313_gpio_remove(struct platform_device *pdev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id msc313_gpio_of_match[] = {
|
||||
#ifdef CONFIG_MACH_INFINITY
|
||||
{
|
||||
.compatible = "mstar,msc313-gpio",
|
||||
.data = &msc313_data,
|
||||
},
|
||||
#endif
|
||||
{ }
|
||||
};
|
||||
|
||||
/*
|
||||
* The GPIO controller loses the state of the registers when the
|
||||
* SoC goes into suspend to memory mode so we need to save some
|
||||
* of the register bits before suspending and put it back when resuming
|
||||
*/
|
||||
static int __maybe_unused msc313_gpio_suspend(struct device *dev)
|
||||
{
|
||||
struct msc313_gpio *gpio = dev_get_drvdata(dev);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < gpio->gpio_data->num; i++)
|
||||
gpio->saved[i] = readb_relaxed(gpio->base + gpio->gpio_data->offsets[i]) & MSC313_GPIO_BITSTOSAVE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __maybe_unused msc313_gpio_resume(struct device *dev)
|
||||
{
|
||||
struct msc313_gpio *gpio = dev_get_drvdata(dev);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < gpio->gpio_data->num; i++)
|
||||
writeb_relaxed(gpio->saved[i], gpio->base + gpio->gpio_data->offsets[i]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(msc313_gpio_ops, msc313_gpio_suspend, msc313_gpio_resume);
|
||||
|
||||
static struct platform_driver msc313_gpio_driver = {
|
||||
.driver = {
|
||||
.name = DRIVER_NAME,
|
||||
.of_match_table = msc313_gpio_of_match,
|
||||
.pm = &msc313_gpio_ops,
|
||||
},
|
||||
.probe = msc313_gpio_probe,
|
||||
.remove = msc313_gpio_remove,
|
||||
};
|
||||
|
||||
builtin_platform_driver(msc313_gpio_driver);
|
|
@ -78,8 +78,7 @@
|
|||
|
||||
/*
|
||||
* The Armada XP has per-CPU registers for interrupt cause, interrupt
|
||||
* mask and interrupt level mask. Those are relative to the
|
||||
* percpu_membase.
|
||||
* mask and interrupt level mask. Those are in percpu_regs range.
|
||||
*/
|
||||
#define GPIO_EDGE_CAUSE_ARMADAXP_OFF(cpu) ((cpu) * 0x4)
|
||||
#define GPIO_EDGE_MASK_ARMADAXP_OFF(cpu) (0x10 + (cpu) * 0x4)
|
||||
|
@ -93,7 +92,7 @@
|
|||
#define MVEBU_MAX_GPIO_PER_BANK 32
|
||||
|
||||
struct mvebu_pwm {
|
||||
void __iomem *membase;
|
||||
struct regmap *regs;
|
||||
unsigned long clk_rate;
|
||||
struct gpio_desc *gpiod;
|
||||
struct pwm_chip chip;
|
||||
|
@ -279,17 +278,17 @@ mvebu_gpio_write_level_mask(struct mvebu_gpio_chip *mvchip, u32 val)
|
|||
}
|
||||
|
||||
/*
|
||||
* Functions returning addresses of individual registers for a given
|
||||
* Functions returning offsets of individual registers for a given
|
||||
* PWM controller.
|
||||
*/
|
||||
static void __iomem *mvebu_pwmreg_blink_on_duration(struct mvebu_pwm *mvpwm)
|
||||
static unsigned int mvebu_pwmreg_blink_on_duration(struct mvebu_pwm *mvpwm)
|
||||
{
|
||||
return mvpwm->membase + PWM_BLINK_ON_DURATION_OFF;
|
||||
return PWM_BLINK_ON_DURATION_OFF;
|
||||
}
|
||||
|
||||
static void __iomem *mvebu_pwmreg_blink_off_duration(struct mvebu_pwm *mvpwm)
|
||||
static unsigned int mvebu_pwmreg_blink_off_duration(struct mvebu_pwm *mvpwm)
|
||||
{
|
||||
return mvpwm->membase + PWM_BLINK_OFF_DURATION_OFF;
|
||||
return PWM_BLINK_OFF_DURATION_OFF;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -600,6 +599,13 @@ static void mvebu_gpio_irq_handler(struct irq_desc *desc)
|
|||
chained_irq_exit(chip, desc);
|
||||
}
|
||||
|
||||
static const struct regmap_config mvebu_gpio_regmap_config = {
|
||||
.reg_bits = 32,
|
||||
.reg_stride = 4,
|
||||
.val_bits = 32,
|
||||
.fast_io = true,
|
||||
};
|
||||
|
||||
/*
|
||||
* Functions implementing the pwm_chip methods
|
||||
*/
|
||||
|
@ -660,9 +666,8 @@ static void mvebu_pwm_get_state(struct pwm_chip *chip,
|
|||
|
||||
spin_lock_irqsave(&mvpwm->lock, flags);
|
||||
|
||||
val = (unsigned long long)
|
||||
readl_relaxed(mvebu_pwmreg_blink_on_duration(mvpwm));
|
||||
val *= NSEC_PER_SEC;
|
||||
regmap_read(mvpwm->regs, mvebu_pwmreg_blink_on_duration(mvpwm), &u);
|
||||
val = (unsigned long long) u * NSEC_PER_SEC;
|
||||
do_div(val, mvpwm->clk_rate);
|
||||
if (val > UINT_MAX)
|
||||
state->duty_cycle = UINT_MAX;
|
||||
|
@ -671,9 +676,8 @@ static void mvebu_pwm_get_state(struct pwm_chip *chip,
|
|||
else
|
||||
state->duty_cycle = 1;
|
||||
|
||||
val = (unsigned long long)
|
||||
readl_relaxed(mvebu_pwmreg_blink_off_duration(mvpwm));
|
||||
val *= NSEC_PER_SEC;
|
||||
regmap_read(mvpwm->regs, mvebu_pwmreg_blink_off_duration(mvpwm), &u);
|
||||
val = (unsigned long long) u * NSEC_PER_SEC;
|
||||
do_div(val, mvpwm->clk_rate);
|
||||
if (val < state->duty_cycle) {
|
||||
state->period = 1;
|
||||
|
@ -726,8 +730,8 @@ static int mvebu_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
|
|||
|
||||
spin_lock_irqsave(&mvpwm->lock, flags);
|
||||
|
||||
writel_relaxed(on, mvebu_pwmreg_blink_on_duration(mvpwm));
|
||||
writel_relaxed(off, mvebu_pwmreg_blink_off_duration(mvpwm));
|
||||
regmap_write(mvpwm->regs, mvebu_pwmreg_blink_on_duration(mvpwm), on);
|
||||
regmap_write(mvpwm->regs, mvebu_pwmreg_blink_off_duration(mvpwm), off);
|
||||
if (state->enabled)
|
||||
mvebu_gpio_blink(&mvchip->chip, pwm->hwpwm, 1);
|
||||
else
|
||||
|
@ -752,10 +756,10 @@ static void __maybe_unused mvebu_pwm_suspend(struct mvebu_gpio_chip *mvchip)
|
|||
|
||||
regmap_read(mvchip->regs, GPIO_BLINK_CNT_SELECT_OFF + mvchip->offset,
|
||||
&mvpwm->blink_select);
|
||||
mvpwm->blink_on_duration =
|
||||
readl_relaxed(mvebu_pwmreg_blink_on_duration(mvpwm));
|
||||
mvpwm->blink_off_duration =
|
||||
readl_relaxed(mvebu_pwmreg_blink_off_duration(mvpwm));
|
||||
regmap_read(mvpwm->regs, mvebu_pwmreg_blink_on_duration(mvpwm),
|
||||
&mvpwm->blink_on_duration);
|
||||
regmap_read(mvpwm->regs, mvebu_pwmreg_blink_off_duration(mvpwm),
|
||||
&mvpwm->blink_off_duration);
|
||||
}
|
||||
|
||||
static void __maybe_unused mvebu_pwm_resume(struct mvebu_gpio_chip *mvchip)
|
||||
|
@ -764,10 +768,10 @@ static void __maybe_unused mvebu_pwm_resume(struct mvebu_gpio_chip *mvchip)
|
|||
|
||||
regmap_write(mvchip->regs, GPIO_BLINK_CNT_SELECT_OFF + mvchip->offset,
|
||||
mvpwm->blink_select);
|
||||
writel_relaxed(mvpwm->blink_on_duration,
|
||||
mvebu_pwmreg_blink_on_duration(mvpwm));
|
||||
writel_relaxed(mvpwm->blink_off_duration,
|
||||
mvebu_pwmreg_blink_off_duration(mvpwm));
|
||||
regmap_write(mvpwm->regs, mvebu_pwmreg_blink_on_duration(mvpwm),
|
||||
mvpwm->blink_on_duration);
|
||||
regmap_write(mvpwm->regs, mvebu_pwmreg_blink_off_duration(mvpwm),
|
||||
mvpwm->blink_off_duration);
|
||||
}
|
||||
|
||||
static int mvebu_pwm_probe(struct platform_device *pdev,
|
||||
|
@ -776,6 +780,7 @@ static int mvebu_pwm_probe(struct platform_device *pdev,
|
|||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct mvebu_pwm *mvpwm;
|
||||
void __iomem *base;
|
||||
u32 set;
|
||||
|
||||
if (!of_device_is_compatible(mvchip->chip.of_node,
|
||||
|
@ -813,9 +818,14 @@ static int mvebu_pwm_probe(struct platform_device *pdev,
|
|||
mvchip->mvpwm = mvpwm;
|
||||
mvpwm->mvchip = mvchip;
|
||||
|
||||
mvpwm->membase = devm_platform_ioremap_resource_byname(pdev, "pwm");
|
||||
if (IS_ERR(mvpwm->membase))
|
||||
return PTR_ERR(mvpwm->membase);
|
||||
base = devm_platform_ioremap_resource_byname(pdev, "pwm");
|
||||
if (IS_ERR(base))
|
||||
return PTR_ERR(base);
|
||||
|
||||
mvpwm->regs = devm_regmap_init_mmio(&pdev->dev, base,
|
||||
&mvebu_gpio_regmap_config);
|
||||
if (IS_ERR(mvpwm->regs))
|
||||
return PTR_ERR(mvpwm->regs);
|
||||
|
||||
mvpwm->clk_rate = clk_get_rate(mvchip->clk);
|
||||
if (!mvpwm->clk_rate) {
|
||||
|
@ -1022,13 +1032,6 @@ static int mvebu_gpio_resume(struct platform_device *pdev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static const struct regmap_config mvebu_gpio_regmap_config = {
|
||||
.reg_bits = 32,
|
||||
.reg_stride = 4,
|
||||
.val_bits = 32,
|
||||
.fast_io = true,
|
||||
};
|
||||
|
||||
static int mvebu_gpio_probe_raw(struct platform_device *pdev,
|
||||
struct mvebu_gpio_chip *mvchip)
|
||||
{
|
||||
|
|
|
@ -24,13 +24,6 @@
|
|||
#include <linux/of_device.h>
|
||||
#include <linux/bug.h>
|
||||
|
||||
enum mxc_gpio_hwtype {
|
||||
IMX1_GPIO, /* runs on i.mx1 */
|
||||
IMX21_GPIO, /* runs on i.mx21 and i.mx27 */
|
||||
IMX31_GPIO, /* runs on i.mx31 */
|
||||
IMX35_GPIO, /* runs on all other i.mx */
|
||||
};
|
||||
|
||||
/* device type dependent stuff */
|
||||
struct mxc_gpio_hwdata {
|
||||
unsigned dr_reg;
|
||||
|
@ -68,6 +61,7 @@ struct mxc_gpio_port {
|
|||
u32 both_edges;
|
||||
struct mxc_gpio_reg_saved gpio_saved_reg;
|
||||
bool power_off;
|
||||
const struct mxc_gpio_hwdata *hwdata;
|
||||
};
|
||||
|
||||
static struct mxc_gpio_hwdata imx1_imx21_gpio_hwdata = {
|
||||
|
@ -115,48 +109,27 @@ static struct mxc_gpio_hwdata imx35_gpio_hwdata = {
|
|||
.fall_edge = 0x03,
|
||||
};
|
||||
|
||||
static enum mxc_gpio_hwtype mxc_gpio_hwtype;
|
||||
static struct mxc_gpio_hwdata *mxc_gpio_hwdata;
|
||||
#define GPIO_DR (port->hwdata->dr_reg)
|
||||
#define GPIO_GDIR (port->hwdata->gdir_reg)
|
||||
#define GPIO_PSR (port->hwdata->psr_reg)
|
||||
#define GPIO_ICR1 (port->hwdata->icr1_reg)
|
||||
#define GPIO_ICR2 (port->hwdata->icr2_reg)
|
||||
#define GPIO_IMR (port->hwdata->imr_reg)
|
||||
#define GPIO_ISR (port->hwdata->isr_reg)
|
||||
#define GPIO_EDGE_SEL (port->hwdata->edge_sel_reg)
|
||||
|
||||
#define GPIO_DR (mxc_gpio_hwdata->dr_reg)
|
||||
#define GPIO_GDIR (mxc_gpio_hwdata->gdir_reg)
|
||||
#define GPIO_PSR (mxc_gpio_hwdata->psr_reg)
|
||||
#define GPIO_ICR1 (mxc_gpio_hwdata->icr1_reg)
|
||||
#define GPIO_ICR2 (mxc_gpio_hwdata->icr2_reg)
|
||||
#define GPIO_IMR (mxc_gpio_hwdata->imr_reg)
|
||||
#define GPIO_ISR (mxc_gpio_hwdata->isr_reg)
|
||||
#define GPIO_EDGE_SEL (mxc_gpio_hwdata->edge_sel_reg)
|
||||
|
||||
#define GPIO_INT_LOW_LEV (mxc_gpio_hwdata->low_level)
|
||||
#define GPIO_INT_HIGH_LEV (mxc_gpio_hwdata->high_level)
|
||||
#define GPIO_INT_RISE_EDGE (mxc_gpio_hwdata->rise_edge)
|
||||
#define GPIO_INT_FALL_EDGE (mxc_gpio_hwdata->fall_edge)
|
||||
#define GPIO_INT_LOW_LEV (port->hwdata->low_level)
|
||||
#define GPIO_INT_HIGH_LEV (port->hwdata->high_level)
|
||||
#define GPIO_INT_RISE_EDGE (port->hwdata->rise_edge)
|
||||
#define GPIO_INT_FALL_EDGE (port->hwdata->fall_edge)
|
||||
#define GPIO_INT_BOTH_EDGES 0x4
|
||||
|
||||
static const struct platform_device_id mxc_gpio_devtype[] = {
|
||||
{
|
||||
.name = "imx1-gpio",
|
||||
.driver_data = IMX1_GPIO,
|
||||
}, {
|
||||
.name = "imx21-gpio",
|
||||
.driver_data = IMX21_GPIO,
|
||||
}, {
|
||||
.name = "imx31-gpio",
|
||||
.driver_data = IMX31_GPIO,
|
||||
}, {
|
||||
.name = "imx35-gpio",
|
||||
.driver_data = IMX35_GPIO,
|
||||
}, {
|
||||
/* sentinel */
|
||||
}
|
||||
};
|
||||
|
||||
static const struct of_device_id mxc_gpio_dt_ids[] = {
|
||||
{ .compatible = "fsl,imx1-gpio", .data = &mxc_gpio_devtype[IMX1_GPIO], },
|
||||
{ .compatible = "fsl,imx21-gpio", .data = &mxc_gpio_devtype[IMX21_GPIO], },
|
||||
{ .compatible = "fsl,imx31-gpio", .data = &mxc_gpio_devtype[IMX31_GPIO], },
|
||||
{ .compatible = "fsl,imx35-gpio", .data = &mxc_gpio_devtype[IMX35_GPIO], },
|
||||
{ .compatible = "fsl,imx7d-gpio", .data = &mxc_gpio_devtype[IMX35_GPIO], },
|
||||
{ .compatible = "fsl,imx1-gpio", .data = &imx1_imx21_gpio_hwdata },
|
||||
{ .compatible = "fsl,imx21-gpio", .data = &imx1_imx21_gpio_hwdata },
|
||||
{ .compatible = "fsl,imx31-gpio", .data = &imx31_gpio_hwdata },
|
||||
{ .compatible = "fsl,imx35-gpio", .data = &imx35_gpio_hwdata },
|
||||
{ .compatible = "fsl,imx7d-gpio", .data = &imx35_gpio_hwdata },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, mxc_gpio_dt_ids);
|
||||
|
@ -372,36 +345,6 @@ static int mxc_gpio_init_gc(struct mxc_gpio_port *port, int irq_base)
|
|||
return rv;
|
||||
}
|
||||
|
||||
static void mxc_gpio_get_hw(struct platform_device *pdev)
|
||||
{
|
||||
const struct of_device_id *of_id =
|
||||
of_match_device(mxc_gpio_dt_ids, &pdev->dev);
|
||||
enum mxc_gpio_hwtype hwtype;
|
||||
|
||||
if (of_id)
|
||||
pdev->id_entry = of_id->data;
|
||||
hwtype = pdev->id_entry->driver_data;
|
||||
|
||||
if (mxc_gpio_hwtype) {
|
||||
/*
|
||||
* The driver works with a reasonable presupposition,
|
||||
* that is all gpio ports must be the same type when
|
||||
* running on one soc.
|
||||
*/
|
||||
BUG_ON(mxc_gpio_hwtype != hwtype);
|
||||
return;
|
||||
}
|
||||
|
||||
if (hwtype == IMX35_GPIO)
|
||||
mxc_gpio_hwdata = &imx35_gpio_hwdata;
|
||||
else if (hwtype == IMX31_GPIO)
|
||||
mxc_gpio_hwdata = &imx31_gpio_hwdata;
|
||||
else
|
||||
mxc_gpio_hwdata = &imx1_imx21_gpio_hwdata;
|
||||
|
||||
mxc_gpio_hwtype = hwtype;
|
||||
}
|
||||
|
||||
static int mxc_gpio_to_irq(struct gpio_chip *gc, unsigned offset)
|
||||
{
|
||||
struct mxc_gpio_port *port = gpiochip_get_data(gc);
|
||||
|
@ -417,14 +360,14 @@ static int mxc_gpio_probe(struct platform_device *pdev)
|
|||
int irq_base;
|
||||
int err;
|
||||
|
||||
mxc_gpio_get_hw(pdev);
|
||||
|
||||
port = devm_kzalloc(&pdev->dev, sizeof(*port), GFP_KERNEL);
|
||||
if (!port)
|
||||
return -ENOMEM;
|
||||
|
||||
port->dev = &pdev->dev;
|
||||
|
||||
port->hwdata = device_get_match_data(&pdev->dev);
|
||||
|
||||
port->base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(port->base))
|
||||
return PTR_ERR(port->base);
|
||||
|
@ -461,7 +404,7 @@ static int mxc_gpio_probe(struct platform_device *pdev)
|
|||
writel(0, port->base + GPIO_IMR);
|
||||
writel(~0, port->base + GPIO_ISR);
|
||||
|
||||
if (mxc_gpio_hwtype == IMX21_GPIO) {
|
||||
if (of_device_is_compatible(np, "fsl,imx21-gpio")) {
|
||||
/*
|
||||
* Setup one handler for all GPIO interrupts. Actually setting
|
||||
* the handler is needed only once, but doing it for every port
|
||||
|
@ -596,7 +539,6 @@ static struct platform_driver mxc_gpio_driver = {
|
|||
.suppress_bind_attrs = true,
|
||||
},
|
||||
.probe = mxc_gpio_probe,
|
||||
.id_table = mxc_gpio_devtype,
|
||||
};
|
||||
|
||||
static int __init gpio_mxc_init(void)
|
||||
|
|
|
@ -254,19 +254,6 @@ static int mxs_gpio_get_direction(struct gpio_chip *gc, unsigned offset)
|
|||
return GPIO_LINE_DIRECTION_IN;
|
||||
}
|
||||
|
||||
static const struct platform_device_id mxs_gpio_ids[] = {
|
||||
{
|
||||
.name = "imx23-gpio",
|
||||
.driver_data = IMX23_GPIO,
|
||||
}, {
|
||||
.name = "imx28-gpio",
|
||||
.driver_data = IMX28_GPIO,
|
||||
}, {
|
||||
/* sentinel */
|
||||
}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(platform, mxs_gpio_ids);
|
||||
|
||||
static const struct of_device_id mxs_gpio_dt_ids[] = {
|
||||
{ .compatible = "fsl,imx23-gpio", .data = (void *) IMX23_GPIO, },
|
||||
{ .compatible = "fsl,imx28-gpio", .data = (void *) IMX28_GPIO, },
|
||||
|
@ -370,7 +357,6 @@ static struct platform_driver mxs_gpio_driver = {
|
|||
.suppress_bind_attrs = true,
|
||||
},
|
||||
.probe = mxs_gpio_probe,
|
||||
.id_table = mxs_gpio_ids,
|
||||
};
|
||||
|
||||
static int __init mxs_gpio_init(void)
|
||||
|
|
|
@ -1049,11 +1049,8 @@ static int omap_gpio_chip_init(struct gpio_bank *bank, struct irq_chip *irqc)
|
|||
irq->first = irq_base;
|
||||
|
||||
ret = gpiochip_add_data(&bank->chip, bank);
|
||||
if (ret) {
|
||||
dev_err(bank->chip.parent,
|
||||
"Could not register gpio chip %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
if (ret)
|
||||
return dev_err_probe(bank->chip.parent, ret, "Could not register gpio chip\n");
|
||||
|
||||
ret = devm_request_irq(bank->chip.parent, bank->irq,
|
||||
omap_gpio_irq_handler,
|
||||
|
|
|
@ -32,6 +32,11 @@ struct gpio_rcar_bank_info {
|
|||
u32 intmsk;
|
||||
};
|
||||
|
||||
struct gpio_rcar_info {
|
||||
bool has_outdtsel;
|
||||
bool has_both_edge_trigger;
|
||||
};
|
||||
|
||||
struct gpio_rcar_priv {
|
||||
void __iomem *base;
|
||||
spinlock_t lock;
|
||||
|
@ -40,24 +45,23 @@ struct gpio_rcar_priv {
|
|||
struct irq_chip irq_chip;
|
||||
unsigned int irq_parent;
|
||||
atomic_t wakeup_path;
|
||||
bool has_outdtsel;
|
||||
bool has_both_edge_trigger;
|
||||
struct gpio_rcar_info info;
|
||||
struct gpio_rcar_bank_info bank_info;
|
||||
};
|
||||
|
||||
#define IOINTSEL 0x00 /* General IO/Interrupt Switching Register */
|
||||
#define INOUTSEL 0x04 /* General Input/Output Switching Register */
|
||||
#define OUTDT 0x08 /* General Output Register */
|
||||
#define INDT 0x0c /* General Input Register */
|
||||
#define INTDT 0x10 /* Interrupt Display Register */
|
||||
#define INTCLR 0x14 /* Interrupt Clear Register */
|
||||
#define INTMSK 0x18 /* Interrupt Mask Register */
|
||||
#define MSKCLR 0x1c /* Interrupt Mask Clear Register */
|
||||
#define POSNEG 0x20 /* Positive/Negative Logic Select Register */
|
||||
#define EDGLEVEL 0x24 /* Edge/level Select Register */
|
||||
#define FILONOFF 0x28 /* Chattering Prevention On/Off Register */
|
||||
#define OUTDTSEL 0x40 /* Output Data Select Register */
|
||||
#define BOTHEDGE 0x4c /* One Edge/Both Edge Select Register */
|
||||
#define IOINTSEL 0x00 /* General IO/Interrupt Switching Register */
|
||||
#define INOUTSEL 0x04 /* General Input/Output Switching Register */
|
||||
#define OUTDT 0x08 /* General Output Register */
|
||||
#define INDT 0x0c /* General Input Register */
|
||||
#define INTDT 0x10 /* Interrupt Display Register */
|
||||
#define INTCLR 0x14 /* Interrupt Clear Register */
|
||||
#define INTMSK 0x18 /* Interrupt Mask Register */
|
||||
#define MSKCLR 0x1c /* Interrupt Mask Clear Register */
|
||||
#define POSNEG 0x20 /* Positive/Negative Logic Select Register */
|
||||
#define EDGLEVEL 0x24 /* Edge/level Select Register */
|
||||
#define FILONOFF 0x28 /* Chattering Prevention On/Off Register */
|
||||
#define OUTDTSEL 0x40 /* Output Data Select Register */
|
||||
#define BOTHEDGE 0x4c /* One Edge/Both Edge Select Register */
|
||||
|
||||
#define RCAR_MAX_GPIO_PER_BANK 32
|
||||
|
||||
|
@ -123,7 +127,7 @@ static void gpio_rcar_config_interrupt_input_mode(struct gpio_rcar_priv *p,
|
|||
gpio_rcar_modify_bit(p, EDGLEVEL, hwirq, !level_trigger);
|
||||
|
||||
/* Select one edge or both edges in BOTHEDGE */
|
||||
if (p->has_both_edge_trigger)
|
||||
if (p->info.has_both_edge_trigger)
|
||||
gpio_rcar_modify_bit(p, BOTHEDGE, hwirq, both);
|
||||
|
||||
/* Select "Interrupt Input Mode" in IOINTSEL */
|
||||
|
@ -162,7 +166,7 @@ static int gpio_rcar_irq_set_type(struct irq_data *d, unsigned int type)
|
|||
false);
|
||||
break;
|
||||
case IRQ_TYPE_EDGE_BOTH:
|
||||
if (!p->has_both_edge_trigger)
|
||||
if (!p->info.has_both_edge_trigger)
|
||||
return -EINVAL;
|
||||
gpio_rcar_config_interrupt_input_mode(p, hwirq, true, false,
|
||||
true);
|
||||
|
@ -238,7 +242,7 @@ static void gpio_rcar_config_general_input_output_mode(struct gpio_chip *chip,
|
|||
gpio_rcar_modify_bit(p, INOUTSEL, gpio, output);
|
||||
|
||||
/* Select General Output Register to output data in OUTDTSEL */
|
||||
if (p->has_outdtsel && output)
|
||||
if (p->info.has_outdtsel && output)
|
||||
gpio_rcar_modify_bit(p, OUTDTSEL, gpio, false);
|
||||
|
||||
spin_unlock_irqrestore(&p->lock, flags);
|
||||
|
@ -295,14 +299,44 @@ static int gpio_rcar_direction_input(struct gpio_chip *chip, unsigned offset)
|
|||
|
||||
static int gpio_rcar_get(struct gpio_chip *chip, unsigned offset)
|
||||
{
|
||||
struct gpio_rcar_priv *p = gpiochip_get_data(chip);
|
||||
u32 bit = BIT(offset);
|
||||
|
||||
/* testing on r8a7790 shows that INDT does not show correct pin state
|
||||
* when configured as output, so use OUTDT in case of output pins */
|
||||
if (gpio_rcar_read(gpiochip_get_data(chip), INOUTSEL) & bit)
|
||||
return !!(gpio_rcar_read(gpiochip_get_data(chip), OUTDT) & bit);
|
||||
if (gpio_rcar_read(p, INOUTSEL) & bit)
|
||||
return !!(gpio_rcar_read(p, OUTDT) & bit);
|
||||
else
|
||||
return !!(gpio_rcar_read(gpiochip_get_data(chip), INDT) & bit);
|
||||
return !!(gpio_rcar_read(p, INDT) & bit);
|
||||
}
|
||||
|
||||
static int gpio_rcar_get_multiple(struct gpio_chip *chip, unsigned long *mask,
|
||||
unsigned long *bits)
|
||||
{
|
||||
struct gpio_rcar_priv *p = gpiochip_get_data(chip);
|
||||
u32 bankmask, outputs, m, val = 0;
|
||||
unsigned long flags;
|
||||
|
||||
bankmask = mask[0] & GENMASK(chip->ngpio - 1, 0);
|
||||
if (chip->valid_mask)
|
||||
bankmask &= chip->valid_mask[0];
|
||||
|
||||
if (!bankmask)
|
||||
return 0;
|
||||
|
||||
spin_lock_irqsave(&p->lock, flags);
|
||||
outputs = gpio_rcar_read(p, INOUTSEL);
|
||||
m = outputs & bankmask;
|
||||
if (m)
|
||||
val |= gpio_rcar_read(p, OUTDT) & m;
|
||||
|
||||
m = ~outputs & bankmask;
|
||||
if (m)
|
||||
val |= gpio_rcar_read(p, INDT) & m;
|
||||
spin_unlock_irqrestore(&p->lock, flags);
|
||||
|
||||
bits[0] = val;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void gpio_rcar_set(struct gpio_chip *chip, unsigned offset, int value)
|
||||
|
@ -346,11 +380,6 @@ static int gpio_rcar_direction_output(struct gpio_chip *chip, unsigned offset,
|
|||
return 0;
|
||||
}
|
||||
|
||||
struct gpio_rcar_info {
|
||||
bool has_outdtsel;
|
||||
bool has_both_edge_trigger;
|
||||
};
|
||||
|
||||
static const struct gpio_rcar_info gpio_rcar_info_gen1 = {
|
||||
.has_outdtsel = false,
|
||||
.has_both_edge_trigger = false,
|
||||
|
@ -417,8 +446,7 @@ static int gpio_rcar_parse_dt(struct gpio_rcar_priv *p, unsigned int *npins)
|
|||
int ret;
|
||||
|
||||
info = of_device_get_match_data(p->dev);
|
||||
p->has_outdtsel = info->has_outdtsel;
|
||||
p->has_both_edge_trigger = info->has_both_edge_trigger;
|
||||
p->info = *info;
|
||||
|
||||
ret = of_parse_phandle_with_fixed_args(np, "gpio-ranges", 3, 0, &args);
|
||||
*npins = ret == 0 ? args.args[2] : RCAR_MAX_GPIO_PER_BANK;
|
||||
|
@ -479,6 +507,7 @@ static int gpio_rcar_probe(struct platform_device *pdev)
|
|||
gpio_chip->get_direction = gpio_rcar_get_direction;
|
||||
gpio_chip->direction_input = gpio_rcar_direction_input;
|
||||
gpio_chip->get = gpio_rcar_get;
|
||||
gpio_chip->get_multiple = gpio_rcar_get_multiple;
|
||||
gpio_chip->direction_output = gpio_rcar_direction_output;
|
||||
gpio_chip->set = gpio_rcar_set;
|
||||
gpio_chip->set_multiple = gpio_rcar_set_multiple;
|
||||
|
@ -552,7 +581,7 @@ static int gpio_rcar_suspend(struct device *dev)
|
|||
p->bank_info.intmsk = gpio_rcar_read(p, INTMSK);
|
||||
p->bank_info.posneg = gpio_rcar_read(p, POSNEG);
|
||||
p->bank_info.edglevel = gpio_rcar_read(p, EDGLEVEL);
|
||||
if (p->has_both_edge_trigger)
|
||||
if (p->info.has_both_edge_trigger)
|
||||
p->bank_info.bothedge = gpio_rcar_read(p, BOTHEDGE);
|
||||
|
||||
if (atomic_read(&p->wakeup_path))
|
||||
|
|
|
@ -29,7 +29,6 @@
|
|||
#define SIFIVE_GPIO_OUTPUT_XOR 0x40
|
||||
|
||||
#define SIFIVE_GPIO_MAX 32
|
||||
#define SIFIVE_GPIO_IRQ_OFFSET 7
|
||||
|
||||
struct sifive_gpio {
|
||||
void __iomem *base;
|
||||
|
@ -37,7 +36,7 @@ struct sifive_gpio {
|
|||
struct regmap *regs;
|
||||
unsigned long irq_state;
|
||||
unsigned int trigger[SIFIVE_GPIO_MAX];
|
||||
unsigned int irq_parent[SIFIVE_GPIO_MAX];
|
||||
unsigned int irq_number[SIFIVE_GPIO_MAX];
|
||||
};
|
||||
|
||||
static void sifive_gpio_set_ie(struct sifive_gpio *chip, unsigned int offset)
|
||||
|
@ -128,6 +127,16 @@ static void sifive_gpio_irq_eoi(struct irq_data *d)
|
|||
irq_chip_eoi_parent(d);
|
||||
}
|
||||
|
||||
static int sifive_gpio_irq_set_affinity(struct irq_data *data,
|
||||
const struct cpumask *dest,
|
||||
bool force)
|
||||
{
|
||||
if (data->parent_data)
|
||||
return irq_chip_set_affinity_parent(data, dest, force);
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static struct irq_chip sifive_gpio_irqchip = {
|
||||
.name = "sifive-gpio",
|
||||
.irq_set_type = sifive_gpio_irq_set_type,
|
||||
|
@ -136,6 +145,7 @@ static struct irq_chip sifive_gpio_irqchip = {
|
|||
.irq_enable = sifive_gpio_irq_enable,
|
||||
.irq_disable = sifive_gpio_irq_disable,
|
||||
.irq_eoi = sifive_gpio_irq_eoi,
|
||||
.irq_set_affinity = sifive_gpio_irq_set_affinity,
|
||||
};
|
||||
|
||||
static int sifive_gpio_child_to_parent_hwirq(struct gpio_chip *gc,
|
||||
|
@ -144,8 +154,12 @@ static int sifive_gpio_child_to_parent_hwirq(struct gpio_chip *gc,
|
|||
unsigned int *parent,
|
||||
unsigned int *parent_type)
|
||||
{
|
||||
struct sifive_gpio *chip = gpiochip_get_data(gc);
|
||||
struct irq_data *d = irq_get_irq_data(chip->irq_number[child]);
|
||||
|
||||
*parent_type = IRQ_TYPE_NONE;
|
||||
*parent = child + SIFIVE_GPIO_IRQ_OFFSET;
|
||||
*parent = irqd_to_hwirq(d);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -165,7 +179,7 @@ static int sifive_gpio_probe(struct platform_device *pdev)
|
|||
struct irq_domain *parent;
|
||||
struct gpio_irq_chip *girq;
|
||||
struct sifive_gpio *chip;
|
||||
int ret, ngpio;
|
||||
int ret, ngpio, i;
|
||||
|
||||
chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL);
|
||||
if (!chip)
|
||||
|
@ -200,6 +214,9 @@ static int sifive_gpio_probe(struct platform_device *pdev)
|
|||
return -ENODEV;
|
||||
}
|
||||
|
||||
for (i = 0; i < ngpio; i++)
|
||||
chip->irq_number[i] = platform_get_irq(pdev, i);
|
||||
|
||||
ret = bgpio_init(&chip->gc, dev, 4,
|
||||
chip->base + SIFIVE_GPIO_INPUT_VAL,
|
||||
chip->base + SIFIVE_GPIO_OUTPUT_VAL,
|
||||
|
|
|
@ -474,15 +474,6 @@ 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;
|
||||
|
@ -520,6 +511,7 @@ static int stmpe_gpio_probe(struct platform_device *pdev)
|
|||
girq->default_type = IRQ_TYPE_NONE;
|
||||
girq->handler = handle_simple_irq;
|
||||
girq->threaded = true;
|
||||
girq->init_valid_mask = stmpe_init_irq_valid_mask;
|
||||
}
|
||||
|
||||
ret = gpiochip_add_data(&stmpe_gpio->chip, stmpe_gpio);
|
||||
|
|
|
@ -61,8 +61,16 @@ struct tegra_gpio_info;
|
|||
struct tegra_gpio_bank {
|
||||
unsigned int bank;
|
||||
unsigned int irq;
|
||||
spinlock_t lvl_lock[4];
|
||||
spinlock_t dbc_lock[4]; /* Lock for updating debounce count register */
|
||||
|
||||
/*
|
||||
* IRQ-core code uses raw locking, and thus, nested locking also
|
||||
* should be raw in order not to trip spinlock debug warnings.
|
||||
*/
|
||||
raw_spinlock_t lvl_lock[4];
|
||||
|
||||
/* Lock for updating debounce count register */
|
||||
spinlock_t dbc_lock[4];
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
u32 cnf[4];
|
||||
u32 out[4];
|
||||
|
@ -334,14 +342,14 @@ static int tegra_gpio_irq_set_type(struct irq_data *d, unsigned int type)
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&bank->lvl_lock[port], flags);
|
||||
raw_spin_lock_irqsave(&bank->lvl_lock[port], flags);
|
||||
|
||||
val = tegra_gpio_readl(tgi, GPIO_INT_LVL(tgi, gpio));
|
||||
val &= ~(GPIO_INT_LVL_MASK << GPIO_BIT(gpio));
|
||||
val |= lvl_type << GPIO_BIT(gpio);
|
||||
tegra_gpio_writel(tgi, val, GPIO_INT_LVL(tgi, gpio));
|
||||
|
||||
spin_unlock_irqrestore(&bank->lvl_lock[port], flags);
|
||||
raw_spin_unlock_irqrestore(&bank->lvl_lock[port], flags);
|
||||
|
||||
tegra_gpio_mask_write(tgi, GPIO_MSK_OE(tgi, gpio), gpio, 0);
|
||||
tegra_gpio_enable(tgi, gpio);
|
||||
|
@ -560,6 +568,9 @@ static const struct dev_pm_ops tegra_gpio_pm_ops = {
|
|||
SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(tegra_gpio_suspend, tegra_gpio_resume)
|
||||
};
|
||||
|
||||
static struct lock_class_key gpio_lock_class;
|
||||
static struct lock_class_key gpio_request_class;
|
||||
|
||||
static int tegra_gpio_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct tegra_gpio_info *tgi;
|
||||
|
@ -661,6 +672,7 @@ static int tegra_gpio_probe(struct platform_device *pdev)
|
|||
bank = &tgi->bank_info[GPIO_BANK(gpio)];
|
||||
|
||||
irq_set_chip_data(irq, bank);
|
||||
irq_set_lockdep_class(irq, &gpio_lock_class, &gpio_request_class);
|
||||
irq_set_chip_and_handler(irq, &tgi->ic, handle_simple_irq);
|
||||
}
|
||||
|
||||
|
@ -671,7 +683,7 @@ static int tegra_gpio_probe(struct platform_device *pdev)
|
|||
tegra_gpio_irq_handler, bank);
|
||||
|
||||
for (j = 0; j < 4; j++) {
|
||||
spin_lock_init(&bank->lvl_lock[j]);
|
||||
raw_spin_lock_init(&bank->lvl_lock[j]);
|
||||
spin_lock_init(&bank->dbc_lock[j]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -444,6 +444,16 @@ static int tegra186_irq_set_wake(struct irq_data *data, unsigned int on)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int tegra186_irq_set_affinity(struct irq_data *data,
|
||||
const struct cpumask *dest,
|
||||
bool force)
|
||||
{
|
||||
if (data->parent_data)
|
||||
return irq_chip_set_affinity_parent(data, dest, force);
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static void tegra186_gpio_irq(struct irq_desc *desc)
|
||||
{
|
||||
struct tegra_gpio *gpio = irq_desc_get_handler_data(desc);
|
||||
|
@ -690,6 +700,7 @@ static int tegra186_gpio_probe(struct platform_device *pdev)
|
|||
gpio->intc.irq_unmask = tegra186_irq_unmask;
|
||||
gpio->intc.irq_set_type = tegra186_irq_set_type;
|
||||
gpio->intc.irq_set_wake = tegra186_irq_set_wake;
|
||||
gpio->intc.irq_set_affinity = tegra186_irq_set_affinity;
|
||||
|
||||
irq = &gpio->gpio.irq;
|
||||
irq->chip = &gpio->intc;
|
||||
|
|
|
@ -6,13 +6,14 @@
|
|||
*/
|
||||
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/gpio/driver.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/gpio/driver.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
/* Register Offset Definitions */
|
||||
|
@ -38,6 +39,7 @@
|
|||
* @gpio_state: GPIO state shadow register
|
||||
* @gpio_dir: GPIO direction shadow register
|
||||
* @gpio_lock: Lock used for synchronization
|
||||
* @clk: clock resource for this driver
|
||||
*/
|
||||
struct xgpio_instance {
|
||||
struct gpio_chip gc;
|
||||
|
@ -46,6 +48,7 @@ struct xgpio_instance {
|
|||
u32 gpio_state[2];
|
||||
u32 gpio_dir[2];
|
||||
spinlock_t gpio_lock[2];
|
||||
struct clk *clk;
|
||||
};
|
||||
|
||||
static inline int xgpio_index(struct xgpio_instance *chip, int gpio)
|
||||
|
@ -256,6 +259,23 @@ static void xgpio_save_regs(struct xgpio_instance *chip)
|
|||
chip->gpio_dir[1]);
|
||||
}
|
||||
|
||||
/**
|
||||
* xgpio_remove - Remove method for the GPIO device.
|
||||
* @pdev: pointer to the platform device
|
||||
*
|
||||
* This function remove gpiochips and frees all the allocated resources.
|
||||
*
|
||||
* Return: 0 always
|
||||
*/
|
||||
static int xgpio_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct xgpio_instance *gpio = platform_get_drvdata(pdev);
|
||||
|
||||
clk_disable_unprepare(gpio->clk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* xgpio_of_probe - Probe method for the GPIO device.
|
||||
* @pdev: pointer to the platform device
|
||||
|
@ -278,7 +298,8 @@ static int xgpio_probe(struct platform_device *pdev)
|
|||
platform_set_drvdata(pdev, chip);
|
||||
|
||||
/* Update GPIO state shadow register with default value */
|
||||
of_property_read_u32(np, "xlnx,dout-default", &chip->gpio_state[0]);
|
||||
if (of_property_read_u32(np, "xlnx,dout-default", &chip->gpio_state[0]))
|
||||
chip->gpio_state[0] = 0x0;
|
||||
|
||||
/* Update GPIO direction shadow register with default value */
|
||||
if (of_property_read_u32(np, "xlnx,tri-default", &chip->gpio_dir[0]))
|
||||
|
@ -298,8 +319,9 @@ static int xgpio_probe(struct platform_device *pdev)
|
|||
|
||||
if (is_dual) {
|
||||
/* Update GPIO state shadow register with default value */
|
||||
of_property_read_u32(np, "xlnx,dout-default-2",
|
||||
&chip->gpio_state[1]);
|
||||
if (of_property_read_u32(np, "xlnx,dout-default-2",
|
||||
&chip->gpio_state[1]))
|
||||
chip->gpio_state[1] = 0x0;
|
||||
|
||||
/* Update GPIO direction shadow register with default value */
|
||||
if (of_property_read_u32(np, "xlnx,tri-default-2",
|
||||
|
@ -334,11 +356,25 @@ static int xgpio_probe(struct platform_device *pdev)
|
|||
return PTR_ERR(chip->regs);
|
||||
}
|
||||
|
||||
chip->clk = devm_clk_get_optional(&pdev->dev, NULL);
|
||||
if (IS_ERR(chip->clk)) {
|
||||
if (PTR_ERR(chip->clk) != -EPROBE_DEFER)
|
||||
dev_dbg(&pdev->dev, "Input clock not found\n");
|
||||
return PTR_ERR(chip->clk);
|
||||
}
|
||||
|
||||
status = clk_prepare_enable(chip->clk);
|
||||
if (status < 0) {
|
||||
dev_err(&pdev->dev, "Failed to prepare clk\n");
|
||||
return status;
|
||||
}
|
||||
|
||||
xgpio_save_regs(chip);
|
||||
|
||||
status = devm_gpiochip_add_data(&pdev->dev, &chip->gc, chip);
|
||||
if (status) {
|
||||
dev_err(&pdev->dev, "failed to add GPIO chip\n");
|
||||
clk_disable_unprepare(chip->clk);
|
||||
return status;
|
||||
}
|
||||
|
||||
|
@ -354,6 +390,7 @@ MODULE_DEVICE_TABLE(of, xgpio_of_match);
|
|||
|
||||
static struct platform_driver xgpio_plat_driver = {
|
||||
.probe = xgpio_probe,
|
||||
.remove = xgpio_remove,
|
||||
.driver = {
|
||||
.name = "gpio-xilinx",
|
||||
.of_match_table = xgpio_of_match,
|
||||
|
|
|
@ -186,15 +186,7 @@ static int xra1403_probe(struct spi_device *spi)
|
|||
return ret;
|
||||
}
|
||||
|
||||
ret = devm_gpiochip_add_data(&spi->dev, &xra->chip, xra);
|
||||
if (ret < 0) {
|
||||
dev_err(&spi->dev, "Unable to register gpiochip\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
spi_set_drvdata(spi, xra);
|
||||
|
||||
return 0;
|
||||
return devm_gpiochip_add_data(&spi->dev, &xra->chip, xra);
|
||||
}
|
||||
|
||||
static const struct spi_device_id xra1403_ids[] = {
|
||||
|
|
|
@ -205,6 +205,68 @@ static void acpi_gpiochip_request_irqs(struct acpi_gpio_chip *acpi_gpio)
|
|||
acpi_gpiochip_request_irq(acpi_gpio, event);
|
||||
}
|
||||
|
||||
static enum gpiod_flags
|
||||
acpi_gpio_to_gpiod_flags(const struct acpi_resource_gpio *agpio, int polarity)
|
||||
{
|
||||
/* GpioInt() implies input configuration */
|
||||
if (agpio->connection_type == ACPI_RESOURCE_GPIO_TYPE_INT)
|
||||
return GPIOD_IN;
|
||||
|
||||
switch (agpio->io_restriction) {
|
||||
case ACPI_IO_RESTRICT_INPUT:
|
||||
return GPIOD_IN;
|
||||
case ACPI_IO_RESTRICT_OUTPUT:
|
||||
/*
|
||||
* ACPI GPIO resources don't contain an initial value for the
|
||||
* GPIO. Therefore we deduce that value from the pull field
|
||||
* and the polarity instead. If the pin is pulled up we assume
|
||||
* default to be high, if it is pulled down we assume default
|
||||
* to be low, otherwise we leave pin untouched. For active low
|
||||
* polarity values will be switched. See also
|
||||
* Documentation/firmware-guide/acpi/gpio-properties.rst.
|
||||
*/
|
||||
switch (agpio->pin_config) {
|
||||
case ACPI_PIN_CONFIG_PULLUP:
|
||||
return polarity == GPIO_ACTIVE_LOW ? GPIOD_OUT_LOW : GPIOD_OUT_HIGH;
|
||||
case ACPI_PIN_CONFIG_PULLDOWN:
|
||||
return polarity == GPIO_ACTIVE_LOW ? GPIOD_OUT_HIGH : GPIOD_OUT_LOW;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* Assume that the BIOS has configured the direction and pull
|
||||
* accordingly.
|
||||
*/
|
||||
return GPIOD_ASIS;
|
||||
}
|
||||
|
||||
static struct gpio_desc *acpi_request_own_gpiod(struct gpio_chip *chip,
|
||||
struct acpi_resource_gpio *agpio,
|
||||
unsigned int index,
|
||||
const char *label)
|
||||
{
|
||||
int polarity = GPIO_ACTIVE_HIGH;
|
||||
enum gpiod_flags flags = acpi_gpio_to_gpiod_flags(agpio, polarity);
|
||||
unsigned int pin = agpio->pin_table[index];
|
||||
struct gpio_desc *desc;
|
||||
int ret;
|
||||
|
||||
desc = gpiochip_request_own_desc(chip, pin, label, polarity, flags);
|
||||
if (IS_ERR(desc))
|
||||
return desc;
|
||||
|
||||
ret = gpio_set_debounce_timeout(desc, agpio->debounce_timeout);
|
||||
if (ret)
|
||||
gpiochip_free_own_desc(desc);
|
||||
|
||||
return ret ? ERR_PTR(ret) : desc;
|
||||
}
|
||||
|
||||
static bool acpi_gpio_in_ignore_list(const char *controller_in, int pin_in)
|
||||
{
|
||||
const char *controller, *pin_str;
|
||||
|
@ -290,8 +352,7 @@ static acpi_status acpi_gpiochip_alloc_event(struct acpi_resource *ares,
|
|||
if (!handler)
|
||||
return AE_OK;
|
||||
|
||||
desc = gpiochip_request_own_desc(chip, pin, "ACPI:Event",
|
||||
GPIO_ACTIVE_HIGH, GPIOD_IN);
|
||||
desc = acpi_request_own_gpiod(chip, agpio, 0, "ACPI:Event");
|
||||
if (IS_ERR(desc)) {
|
||||
dev_err(chip->parent,
|
||||
"Failed to request GPIO for pin 0x%04X, err %ld\n",
|
||||
|
@ -526,39 +587,6 @@ static bool acpi_get_driver_gpio_data(struct acpi_device *adev,
|
|||
return false;
|
||||
}
|
||||
|
||||
static enum gpiod_flags
|
||||
acpi_gpio_to_gpiod_flags(const struct acpi_resource_gpio *agpio)
|
||||
{
|
||||
switch (agpio->io_restriction) {
|
||||
case ACPI_IO_RESTRICT_INPUT:
|
||||
return GPIOD_IN;
|
||||
case ACPI_IO_RESTRICT_OUTPUT:
|
||||
/*
|
||||
* ACPI GPIO resources don't contain an initial value for the
|
||||
* GPIO. Therefore we deduce that value from the pull field
|
||||
* instead. If the pin is pulled up we assume default to be
|
||||
* high, if it is pulled down we assume default to be low,
|
||||
* otherwise we leave pin untouched.
|
||||
*/
|
||||
switch (agpio->pin_config) {
|
||||
case ACPI_PIN_CONFIG_PULLUP:
|
||||
return GPIOD_OUT_HIGH;
|
||||
case ACPI_PIN_CONFIG_PULLDOWN:
|
||||
return GPIOD_OUT_LOW;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* Assume that the BIOS has configured the direction and pull
|
||||
* accordingly.
|
||||
*/
|
||||
return GPIOD_ASIS;
|
||||
}
|
||||
|
||||
static int
|
||||
__acpi_gpio_update_gpiod_flags(enum gpiod_flags *flags, enum gpiod_flags update)
|
||||
{
|
||||
|
@ -633,7 +661,7 @@ int acpi_gpio_update_gpiod_lookup_flags(unsigned long *lookupflags,
|
|||
struct acpi_gpio_lookup {
|
||||
struct acpi_gpio_info info;
|
||||
int index;
|
||||
int pin_index;
|
||||
u16 pin_index;
|
||||
bool active_low;
|
||||
struct gpio_desc *desc;
|
||||
int n;
|
||||
|
@ -649,7 +677,7 @@ static int acpi_populate_gpio_lookup(struct acpi_resource *ares, void *data)
|
|||
if (!lookup->desc) {
|
||||
const struct acpi_resource_gpio *agpio = &ares->data.gpio;
|
||||
bool gpioint = agpio->connection_type == ACPI_RESOURCE_GPIO_TYPE_INT;
|
||||
int pin_index;
|
||||
u16 pin_index;
|
||||
|
||||
if (lookup->info.quirks & ACPI_GPIO_QUIRK_ONLY_GPIOIO && gpioint)
|
||||
lookup->index++;
|
||||
|
@ -664,6 +692,7 @@ static int acpi_populate_gpio_lookup(struct acpi_resource *ares, void *data)
|
|||
lookup->desc = acpi_get_gpiod(agpio->resource_source.string_ptr,
|
||||
agpio->pin_table[pin_index]);
|
||||
lookup->info.pin_config = agpio->pin_config;
|
||||
lookup->info.debounce = agpio->debounce_timeout;
|
||||
lookup->info.gpioint = gpioint;
|
||||
|
||||
/*
|
||||
|
@ -674,13 +703,13 @@ static int acpi_populate_gpio_lookup(struct acpi_resource *ares, void *data)
|
|||
* - ACPI_ACTIVE_HIGH == GPIO_ACTIVE_HIGH
|
||||
*/
|
||||
if (lookup->info.gpioint) {
|
||||
lookup->info.flags = GPIOD_IN;
|
||||
lookup->info.polarity = agpio->polarity;
|
||||
lookup->info.triggering = agpio->triggering;
|
||||
} else {
|
||||
lookup->info.flags = acpi_gpio_to_gpiod_flags(agpio);
|
||||
lookup->info.polarity = lookup->active_low;
|
||||
}
|
||||
|
||||
lookup->info.flags = acpi_gpio_to_gpiod_flags(agpio, lookup->info.polarity);
|
||||
}
|
||||
|
||||
return 1;
|
||||
|
@ -794,7 +823,7 @@ static struct gpio_desc *acpi_get_gpiod_by_index(struct acpi_device *adev,
|
|||
if (ret)
|
||||
return ERR_PTR(ret);
|
||||
|
||||
dev_dbg(&adev->dev, "GPIO: _DSD returned %s %d %d %u\n",
|
||||
dev_dbg(&adev->dev, "GPIO: _DSD returned %s %d %u %u\n",
|
||||
dev_name(&lookup.info.adev->dev), lookup.index,
|
||||
lookup.pin_index, lookup.active_low);
|
||||
} else {
|
||||
|
@ -942,6 +971,7 @@ int acpi_dev_gpio_irq_get(struct acpi_device *adev, int index)
|
|||
|
||||
if (info.gpioint && idx++ == index) {
|
||||
unsigned long lflags = GPIO_LOOKUP_FLAGS_DEFAULT;
|
||||
enum gpiod_flags dflags = GPIOD_ASIS;
|
||||
char label[32];
|
||||
int irq;
|
||||
|
||||
|
@ -952,11 +982,18 @@ int acpi_dev_gpio_irq_get(struct acpi_device *adev, int index)
|
|||
if (irq < 0)
|
||||
return irq;
|
||||
|
||||
acpi_gpio_update_gpiod_flags(&dflags, &info);
|
||||
acpi_gpio_update_gpiod_lookup_flags(&lflags, &info);
|
||||
|
||||
snprintf(label, sizeof(label), "GpioInt() %d", index);
|
||||
ret = gpiod_configure_flags(desc, label, lflags, info.flags);
|
||||
ret = gpiod_configure_flags(desc, label, lflags, dflags);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = gpio_set_debounce_timeout(desc, info.debounce);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
irq_flags = acpi_dev_get_irq_type(info.triggering,
|
||||
info.polarity);
|
||||
|
||||
|
@ -982,7 +1019,7 @@ acpi_gpio_adr_space_handler(u32 function, acpi_physical_address address,
|
|||
struct gpio_chip *chip = achip->chip;
|
||||
struct acpi_resource_gpio *agpio;
|
||||
struct acpi_resource *ares;
|
||||
int pin_index = (int)address;
|
||||
u16 pin_index = address;
|
||||
acpi_status status;
|
||||
int length;
|
||||
int i;
|
||||
|
@ -1005,7 +1042,7 @@ acpi_gpio_adr_space_handler(u32 function, acpi_physical_address address,
|
|||
return AE_BAD_PARAMETER;
|
||||
}
|
||||
|
||||
length = min(agpio->pin_table_length, (u16)(pin_index + bits));
|
||||
length = min_t(u16, agpio->pin_table_length, pin_index + bits);
|
||||
for (i = pin_index; i < length; ++i) {
|
||||
int pin = agpio->pin_table[i];
|
||||
struct acpi_gpio_connection *conn;
|
||||
|
@ -1042,23 +1079,18 @@ acpi_gpio_adr_space_handler(u32 function, acpi_physical_address address,
|
|||
}
|
||||
|
||||
if (!found) {
|
||||
enum gpiod_flags flags = acpi_gpio_to_gpiod_flags(agpio);
|
||||
const char *label = "ACPI:OpRegion";
|
||||
|
||||
desc = gpiochip_request_own_desc(chip, pin, label,
|
||||
GPIO_ACTIVE_HIGH,
|
||||
flags);
|
||||
desc = acpi_request_own_gpiod(chip, agpio, i, "ACPI:OpRegion");
|
||||
if (IS_ERR(desc)) {
|
||||
status = AE_ERROR;
|
||||
mutex_unlock(&achip->conn_lock);
|
||||
status = AE_ERROR;
|
||||
goto out;
|
||||
}
|
||||
|
||||
conn = kzalloc(sizeof(*conn), GFP_KERNEL);
|
||||
if (!conn) {
|
||||
status = AE_NO_MEMORY;
|
||||
gpiochip_free_own_desc(desc);
|
||||
mutex_unlock(&achip->conn_lock);
|
||||
status = AE_NO_MEMORY;
|
||||
goto out;
|
||||
}
|
||||
|
||||
|
@ -1070,8 +1102,7 @@ acpi_gpio_adr_space_handler(u32 function, acpi_physical_address address,
|
|||
mutex_unlock(&achip->conn_lock);
|
||||
|
||||
if (function == ACPI_WRITE)
|
||||
gpiod_set_raw_value_cansleep(desc,
|
||||
!!((1 << i) & *value));
|
||||
gpiod_set_raw_value_cansleep(desc, !!(*value & BIT(i)));
|
||||
else
|
||||
*value |= (u64)gpiod_get_raw_value_cansleep(desc) << i;
|
||||
}
|
||||
|
@ -1132,7 +1163,7 @@ acpi_gpiochip_parse_own_gpio(struct acpi_gpio_chip *achip,
|
|||
int ret;
|
||||
|
||||
*lflags = GPIO_LOOKUP_FLAGS_DEFAULT;
|
||||
*dflags = 0;
|
||||
*dflags = GPIOD_ASIS;
|
||||
*name = NULL;
|
||||
|
||||
ret = fwnode_property_read_u32_array(fwnode, "gpios", gpios,
|
||||
|
|
|
@ -18,6 +18,7 @@ struct acpi_device;
|
|||
* @pin_config: pin bias as provided by ACPI
|
||||
* @polarity: interrupt polarity as provided by ACPI
|
||||
* @triggering: triggering type as provided by ACPI
|
||||
* @debounce: debounce timeout as provided by ACPI
|
||||
* @quirks: Linux specific quirks as provided by struct acpi_gpio_mapping
|
||||
*/
|
||||
struct acpi_gpio_info {
|
||||
|
@ -27,6 +28,7 @@ struct acpi_gpio_info {
|
|||
int pin_config;
|
||||
int polarity;
|
||||
int triggering;
|
||||
unsigned int debounce;
|
||||
unsigned int quirks;
|
||||
};
|
||||
|
||||
|
|
|
@ -428,6 +428,12 @@ struct line {
|
|||
*/
|
||||
struct linereq *req;
|
||||
unsigned int irq;
|
||||
/*
|
||||
* eflags is set by edge_detector_setup(), edge_detector_stop() and
|
||||
* edge_detector_update(), which are themselves mutually exclusive,
|
||||
* and is accessed by edge_irq_thread() and debounce_work_func(),
|
||||
* which can both live with a slightly stale value.
|
||||
*/
|
||||
u64 eflags;
|
||||
/*
|
||||
* timestamp_ns and req_seqno are accessed only by
|
||||
|
@ -504,11 +510,14 @@ struct linereq {
|
|||
(GPIO_V2_LINE_FLAG_EDGE_RISING | \
|
||||
GPIO_V2_LINE_FLAG_EDGE_FALLING)
|
||||
|
||||
#define GPIO_V2_LINE_FLAG_EDGE_BOTH GPIO_V2_LINE_EDGE_FLAGS
|
||||
|
||||
#define GPIO_V2_LINE_VALID_FLAGS \
|
||||
(GPIO_V2_LINE_FLAG_ACTIVE_LOW | \
|
||||
GPIO_V2_LINE_DIRECTION_FLAGS | \
|
||||
GPIO_V2_LINE_DRIVE_FLAGS | \
|
||||
GPIO_V2_LINE_EDGE_FLAGS | \
|
||||
GPIO_V2_LINE_FLAG_EVENT_CLOCK_REALTIME | \
|
||||
GPIO_V2_LINE_BIAS_FLAGS)
|
||||
|
||||
static void linereq_put_event(struct linereq *lr,
|
||||
|
@ -529,11 +538,20 @@ static void linereq_put_event(struct linereq *lr,
|
|||
pr_debug_ratelimited("event FIFO is full - event dropped\n");
|
||||
}
|
||||
|
||||
static u64 line_event_timestamp(struct line *line)
|
||||
{
|
||||
if (test_bit(FLAG_EVENT_CLOCK_REALTIME, &line->desc->flags))
|
||||
return ktime_get_real_ns();
|
||||
|
||||
return ktime_get_ns();
|
||||
}
|
||||
|
||||
static irqreturn_t edge_irq_thread(int irq, void *p)
|
||||
{
|
||||
struct line *line = p;
|
||||
struct linereq *lr = line->req;
|
||||
struct gpio_v2_line_event le;
|
||||
u64 eflags;
|
||||
|
||||
/* Do not leak kernel stack to userspace */
|
||||
memset(&le, 0, sizeof(le));
|
||||
|
@ -546,14 +564,14 @@ static irqreturn_t edge_irq_thread(int irq, void *p)
|
|||
* which case we didn't get the timestamp from
|
||||
* edge_irq_handler().
|
||||
*/
|
||||
le.timestamp_ns = ktime_get_ns();
|
||||
le.timestamp_ns = line_event_timestamp(line);
|
||||
if (lr->num_lines != 1)
|
||||
line->req_seqno = atomic_inc_return(&lr->seqno);
|
||||
}
|
||||
line->timestamp_ns = 0;
|
||||
|
||||
if (line->eflags == (GPIO_V2_LINE_FLAG_EDGE_RISING |
|
||||
GPIO_V2_LINE_FLAG_EDGE_FALLING)) {
|
||||
eflags = READ_ONCE(line->eflags);
|
||||
if (eflags == GPIO_V2_LINE_FLAG_EDGE_BOTH) {
|
||||
int level = gpiod_get_value_cansleep(line->desc);
|
||||
|
||||
if (level)
|
||||
|
@ -562,10 +580,10 @@ static irqreturn_t edge_irq_thread(int irq, void *p)
|
|||
else
|
||||
/* Emit high-to-low event */
|
||||
le.id = GPIO_V2_LINE_EVENT_FALLING_EDGE;
|
||||
} else if (line->eflags == GPIO_V2_LINE_FLAG_EDGE_RISING) {
|
||||
} else if (eflags == GPIO_V2_LINE_FLAG_EDGE_RISING) {
|
||||
/* Emit low-to-high event */
|
||||
le.id = GPIO_V2_LINE_EVENT_RISING_EDGE;
|
||||
} else if (line->eflags == GPIO_V2_LINE_FLAG_EDGE_FALLING) {
|
||||
} else if (eflags == GPIO_V2_LINE_FLAG_EDGE_FALLING) {
|
||||
/* Emit high-to-low event */
|
||||
le.id = GPIO_V2_LINE_EVENT_FALLING_EDGE;
|
||||
} else {
|
||||
|
@ -590,7 +608,7 @@ static irqreturn_t edge_irq_handler(int irq, void *p)
|
|||
* Just store the timestamp in hardirq context so we get it as
|
||||
* close in time as possible to the actual event.
|
||||
*/
|
||||
line->timestamp_ns = ktime_get_ns();
|
||||
line->timestamp_ns = line_event_timestamp(line);
|
||||
|
||||
if (lr->num_lines != 1)
|
||||
line->req_seqno = atomic_inc_return(&lr->seqno);
|
||||
|
@ -634,6 +652,7 @@ static void debounce_work_func(struct work_struct *work)
|
|||
struct line *line = container_of(work, struct line, work.work);
|
||||
struct linereq *lr;
|
||||
int level;
|
||||
u64 eflags;
|
||||
|
||||
level = gpiod_get_raw_value_cansleep(line->desc);
|
||||
if (level < 0) {
|
||||
|
@ -647,7 +666,8 @@ static void debounce_work_func(struct work_struct *work)
|
|||
WRITE_ONCE(line->level, level);
|
||||
|
||||
/* -- edge detection -- */
|
||||
if (!line->eflags)
|
||||
eflags = READ_ONCE(line->eflags);
|
||||
if (!eflags)
|
||||
return;
|
||||
|
||||
/* switch from physical level to logical - if they differ */
|
||||
|
@ -655,15 +675,15 @@ static void debounce_work_func(struct work_struct *work)
|
|||
level = !level;
|
||||
|
||||
/* ignore edges that are not being monitored */
|
||||
if (((line->eflags == GPIO_V2_LINE_FLAG_EDGE_RISING) && !level) ||
|
||||
((line->eflags == GPIO_V2_LINE_FLAG_EDGE_FALLING) && level))
|
||||
if (((eflags == GPIO_V2_LINE_FLAG_EDGE_RISING) && !level) ||
|
||||
((eflags == GPIO_V2_LINE_FLAG_EDGE_FALLING) && level))
|
||||
return;
|
||||
|
||||
/* Do not leak kernel stack to userspace */
|
||||
memset(&le, 0, sizeof(le));
|
||||
|
||||
lr = line->req;
|
||||
le.timestamp_ns = ktime_get_ns();
|
||||
le.timestamp_ns = line_event_timestamp(line);
|
||||
le.offset = gpio_chip_hwgpio(line->desc);
|
||||
line->line_seqno++;
|
||||
le.line_seqno = line->line_seqno;
|
||||
|
@ -755,7 +775,7 @@ static void edge_detector_stop(struct line *line)
|
|||
|
||||
cancel_delayed_work_sync(&line->work);
|
||||
WRITE_ONCE(line->sw_debounced, 0);
|
||||
line->eflags = 0;
|
||||
WRITE_ONCE(line->eflags, 0);
|
||||
/* do not change line->level - see comment in debounced_value() */
|
||||
}
|
||||
|
||||
|
@ -774,7 +794,7 @@ static int edge_detector_setup(struct line *line,
|
|||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
line->eflags = eflags;
|
||||
WRITE_ONCE(line->eflags, eflags);
|
||||
if (gpio_v2_line_config_debounced(lc, line_idx)) {
|
||||
debounce_period_us = gpio_v2_line_config_debounce_period(lc, line_idx);
|
||||
ret = debounce_setup(line, debounce_period_us);
|
||||
|
@ -817,13 +837,13 @@ static int edge_detector_update(struct line *line,
|
|||
unsigned int debounce_period_us =
|
||||
gpio_v2_line_config_debounce_period(lc, line_idx);
|
||||
|
||||
if ((line->eflags == eflags) && !polarity_change &&
|
||||
if ((READ_ONCE(line->eflags) == eflags) && !polarity_change &&
|
||||
(READ_ONCE(line->desc->debounce_period_us) == debounce_period_us))
|
||||
return 0;
|
||||
|
||||
/* sw debounced and still will be...*/
|
||||
if (debounce_period_us && READ_ONCE(line->sw_debounced)) {
|
||||
line->eflags = eflags;
|
||||
WRITE_ONCE(line->eflags, eflags);
|
||||
WRITE_ONCE(line->desc->debounce_period_us, debounce_period_us);
|
||||
return 0;
|
||||
}
|
||||
|
@ -967,6 +987,9 @@ static void gpio_v2_line_config_flags_to_desc_flags(u64 flags,
|
|||
flags & GPIO_V2_LINE_FLAG_BIAS_PULL_DOWN);
|
||||
assign_bit(FLAG_BIAS_DISABLE, flagsp,
|
||||
flags & GPIO_V2_LINE_FLAG_BIAS_DISABLED);
|
||||
|
||||
assign_bit(FLAG_EVENT_CLOCK_REALTIME, flagsp,
|
||||
flags & GPIO_V2_LINE_FLAG_EVENT_CLOCK_REALTIME);
|
||||
}
|
||||
|
||||
static long linereq_get_values(struct linereq *lr, void __user *ip)
|
||||
|
@ -1479,21 +1502,10 @@ static __poll_t lineevent_poll(struct file *file,
|
|||
return events;
|
||||
}
|
||||
|
||||
static ssize_t lineevent_get_size(void)
|
||||
{
|
||||
#if defined(CONFIG_X86_64) && !defined(CONFIG_UML)
|
||||
/* i386 has no padding after 'id' */
|
||||
if (in_ia32_syscall()) {
|
||||
struct compat_gpioeevent_data {
|
||||
compat_u64 timestamp;
|
||||
u32 id;
|
||||
};
|
||||
|
||||
return sizeof(struct compat_gpioeevent_data);
|
||||
}
|
||||
#endif
|
||||
return sizeof(struct gpioevent_data);
|
||||
}
|
||||
struct compat_gpioeevent_data {
|
||||
compat_u64 timestamp;
|
||||
u32 id;
|
||||
};
|
||||
|
||||
static ssize_t lineevent_read(struct file *file,
|
||||
char __user *buf,
|
||||
|
@ -1515,7 +1527,10 @@ static ssize_t lineevent_read(struct file *file,
|
|||
* actual sizeof() and pass this as an argument to copy_to_user() to
|
||||
* drop unneeded bytes from the output.
|
||||
*/
|
||||
ge_size = lineevent_get_size();
|
||||
if (compat_need_64bit_alignment_fixup())
|
||||
ge_size = sizeof(struct compat_gpioeevent_data);
|
||||
else
|
||||
ge_size = sizeof(struct gpioevent_data);
|
||||
if (count < ge_size)
|
||||
return -EINVAL;
|
||||
|
||||
|
@ -1910,6 +1925,7 @@ static void gpio_desc_to_lineinfo(struct gpio_desc *desc,
|
|||
test_bit(FLAG_USED_AS_IRQ, &desc->flags) ||
|
||||
test_bit(FLAG_EXPORT, &desc->flags) ||
|
||||
test_bit(FLAG_SYSFS, &desc->flags) ||
|
||||
!gpiochip_line_is_valid(gc, info->offset) ||
|
||||
!ok_for_pinctrl)
|
||||
info->flags |= GPIO_V2_LINE_FLAG_USED;
|
||||
|
||||
|
@ -1938,6 +1954,9 @@ static void gpio_desc_to_lineinfo(struct gpio_desc *desc,
|
|||
if (test_bit(FLAG_EDGE_FALLING, &desc->flags))
|
||||
info->flags |= GPIO_V2_LINE_FLAG_EDGE_FALLING;
|
||||
|
||||
if (test_bit(FLAG_EVENT_CLOCK_REALTIME, &desc->flags))
|
||||
info->flags |= GPIO_V2_LINE_FLAG_EVENT_CLOCK_REALTIME;
|
||||
|
||||
debounce_period_us = READ_ONCE(desc->debounce_period_us);
|
||||
if (debounce_period_us) {
|
||||
info->attrs[num_attrs].id = GPIO_V2_LINE_ATTR_ID_DEBOUNCE;
|
||||
|
|
|
@ -246,10 +246,8 @@ struct gpio_desc *__must_check devm_gpiod_get_index_optional(struct device *dev,
|
|||
struct gpio_desc *desc;
|
||||
|
||||
desc = devm_gpiod_get_index(dev, con_id, index, flags);
|
||||
if (IS_ERR(desc)) {
|
||||
if (PTR_ERR(desc) == -ENOENT)
|
||||
return NULL;
|
||||
}
|
||||
if (gpiod_not_found(desc))
|
||||
return NULL;
|
||||
|
||||
return desc;
|
||||
}
|
||||
|
@ -308,7 +306,7 @@ devm_gpiod_get_array_optional(struct device *dev, const char *con_id,
|
|||
struct gpio_descs *descs;
|
||||
|
||||
descs = devm_gpiod_get_array(dev, con_id, flags);
|
||||
if (PTR_ERR(descs) == -ENOENT)
|
||||
if (gpiod_not_found(descs))
|
||||
return NULL;
|
||||
|
||||
return descs;
|
||||
|
@ -479,9 +477,9 @@ void devm_gpio_free(struct device *dev, unsigned int gpio)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(devm_gpio_free);
|
||||
|
||||
static void devm_gpio_chip_release(struct device *dev, void *res)
|
||||
static void devm_gpio_chip_release(void *data)
|
||||
{
|
||||
struct gpio_chip *gc = *(struct gpio_chip **)res;
|
||||
struct gpio_chip *gc = data;
|
||||
|
||||
gpiochip_remove(gc);
|
||||
}
|
||||
|
@ -507,23 +505,12 @@ int devm_gpiochip_add_data_with_key(struct device *dev, struct gpio_chip *gc, vo
|
|||
struct lock_class_key *lock_key,
|
||||
struct lock_class_key *request_key)
|
||||
{
|
||||
struct gpio_chip **ptr;
|
||||
int ret;
|
||||
|
||||
ptr = devres_alloc(devm_gpio_chip_release, sizeof(*ptr),
|
||||
GFP_KERNEL);
|
||||
if (!ptr)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = gpiochip_add_data_with_key(gc, data, lock_key, request_key);
|
||||
if (ret < 0) {
|
||||
devres_free(ptr);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
*ptr = gc;
|
||||
devres_add(dev, ptr);
|
||||
|
||||
return 0;
|
||||
return devm_add_action_or_reset(dev, devm_gpio_chip_release, gc);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(devm_gpiochip_add_data_with_key);
|
||||
|
|
|
@ -509,31 +509,31 @@ struct gpio_desc *of_find_gpio(struct device *dev, const char *con_id,
|
|||
desc = of_get_named_gpiod_flags(dev->of_node, prop_name, idx,
|
||||
&of_flags);
|
||||
|
||||
if (!IS_ERR(desc) || PTR_ERR(desc) != -ENOENT)
|
||||
if (!gpiod_not_found(desc))
|
||||
break;
|
||||
}
|
||||
|
||||
if (PTR_ERR(desc) == -ENOENT) {
|
||||
if (gpiod_not_found(desc)) {
|
||||
/* Special handling for SPI GPIOs if used */
|
||||
desc = of_find_spi_gpio(dev, con_id, &of_flags);
|
||||
}
|
||||
|
||||
if (PTR_ERR(desc) == -ENOENT) {
|
||||
if (gpiod_not_found(desc)) {
|
||||
/* This quirk looks up flags and all */
|
||||
desc = of_find_spi_cs_gpio(dev, con_id, idx, flags);
|
||||
if (!IS_ERR(desc))
|
||||
return desc;
|
||||
}
|
||||
|
||||
if (PTR_ERR(desc) == -ENOENT) {
|
||||
if (gpiod_not_found(desc)) {
|
||||
/* Special handling for regulator GPIOs if used */
|
||||
desc = of_find_regulator_gpio(dev, con_id, &of_flags);
|
||||
}
|
||||
|
||||
if (PTR_ERR(desc) == -ENOENT)
|
||||
if (gpiod_not_found(desc))
|
||||
desc = of_find_arizona_gpio(dev, con_id, &of_flags);
|
||||
|
||||
if (PTR_ERR(desc) == -ENOENT)
|
||||
if (gpiod_not_found(desc))
|
||||
desc = of_find_usb_gpio(dev, con_id, &of_flags);
|
||||
|
||||
if (IS_ERR(desc))
|
||||
|
@ -593,7 +593,7 @@ static struct gpio_desc *of_parse_own_gpio(struct device_node *np,
|
|||
|
||||
xlate_flags = 0;
|
||||
*lflags = GPIO_LOOKUP_FLAGS_DEFAULT;
|
||||
*dflags = 0;
|
||||
*dflags = GPIOD_ASIS;
|
||||
|
||||
ret = of_property_read_u32(chip_np, "#gpio-cells", &tmp);
|
||||
if (ret)
|
||||
|
|
|
@ -476,7 +476,7 @@ static ssize_t export_store(struct class *class,
|
|||
*/
|
||||
|
||||
status = gpiod_request(desc, "sysfs");
|
||||
if (status < 0) {
|
||||
if (status) {
|
||||
if (status == -EPROBE_DEFER)
|
||||
status = -ENODEV;
|
||||
goto done;
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
#include <linux/bitmap.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
|
@ -119,7 +120,7 @@ struct gpio_desc *gpio_to_desc(unsigned gpio)
|
|||
spin_unlock_irqrestore(&gpio_lock, flags);
|
||||
|
||||
if (!gpio_is_valid(gpio))
|
||||
WARN(1, "invalid GPIO %d\n", gpio);
|
||||
pr_warn("invalid GPIO %d\n", gpio);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
@ -211,7 +212,7 @@ static int gpiochip_find_base(int ngpio)
|
|||
int gpiod_get_direction(struct gpio_desc *desc)
|
||||
{
|
||||
struct gpio_chip *gc;
|
||||
unsigned offset;
|
||||
unsigned int offset;
|
||||
int ret;
|
||||
|
||||
gc = gpiod_to_chip(desc);
|
||||
|
@ -771,9 +772,11 @@ err_free_ida:
|
|||
ida_free(&gpio_ida, gdev->id);
|
||||
err_free_gdev:
|
||||
/* failures here can mean systems won't boot... */
|
||||
pr_err("%s: GPIOs %d..%d (%s) failed to register, %d\n", __func__,
|
||||
gdev->base, gdev->base + gdev->ngpio - 1,
|
||||
gc->label ? : "generic", ret);
|
||||
if (ret != -EPROBE_DEFER) {
|
||||
pr_err("%s: GPIOs %d..%d (%s) failed to register, %d\n", __func__,
|
||||
gdev->base, gdev->base + gdev->ngpio - 1,
|
||||
gc->label ? : "generic", ret);
|
||||
}
|
||||
kfree(gdev);
|
||||
return ret;
|
||||
}
|
||||
|
@ -936,67 +939,6 @@ bool gpiochip_irqchip_irq_valid(const struct gpio_chip *gc,
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(gpiochip_irqchip_irq_valid);
|
||||
|
||||
/**
|
||||
* gpiochip_set_cascaded_irqchip() - connects a cascaded irqchip to a gpiochip
|
||||
* @gc: the gpiochip to set the irqchip chain to
|
||||
* @parent_irq: the irq number corresponding to the parent IRQ for this
|
||||
* cascaded irqchip
|
||||
* @parent_handler: the parent interrupt handler for the accumulated IRQ
|
||||
* coming out of the gpiochip. If the interrupt is nested rather than
|
||||
* cascaded, pass NULL in this handler argument
|
||||
*/
|
||||
static void gpiochip_set_cascaded_irqchip(struct gpio_chip *gc,
|
||||
unsigned int parent_irq,
|
||||
irq_flow_handler_t parent_handler)
|
||||
{
|
||||
struct gpio_irq_chip *girq = &gc->irq;
|
||||
struct device *dev = &gc->gpiodev->dev;
|
||||
|
||||
if (!girq->domain) {
|
||||
chip_err(gc, "called %s before setting up irqchip\n",
|
||||
__func__);
|
||||
return;
|
||||
}
|
||||
|
||||
if (parent_handler) {
|
||||
if (gc->can_sleep) {
|
||||
chip_err(gc,
|
||||
"you cannot have chained interrupts on a chip that may sleep\n");
|
||||
return;
|
||||
}
|
||||
girq->parents = devm_kcalloc(dev, 1,
|
||||
sizeof(*girq->parents),
|
||||
GFP_KERNEL);
|
||||
if (!girq->parents) {
|
||||
chip_err(gc, "out of memory allocating parent IRQ\n");
|
||||
return;
|
||||
}
|
||||
girq->parents[0] = parent_irq;
|
||||
girq->num_parents = 1;
|
||||
/*
|
||||
* The parent irqchip is already using the chip_data for this
|
||||
* irqchip, so our callbacks simply use the handler_data.
|
||||
*/
|
||||
irq_set_chained_handler_and_data(parent_irq, parent_handler,
|
||||
gc);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* gpiochip_set_nested_irqchip() - connects a nested irqchip to a gpiochip
|
||||
* @gc: the gpiochip to set the irqchip nested handler to
|
||||
* @irqchip: the irqchip to nest to the gpiochip
|
||||
* @parent_irq: the irq number corresponding to the parent IRQ for this
|
||||
* nested irqchip
|
||||
*/
|
||||
void gpiochip_set_nested_irqchip(struct gpio_chip *gc,
|
||||
struct irq_chip *irqchip,
|
||||
unsigned int parent_irq)
|
||||
{
|
||||
gpiochip_set_cascaded_irqchip(gc, parent_irq, NULL);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(gpiochip_set_nested_irqchip);
|
||||
|
||||
#ifdef CONFIG_IRQ_DOMAIN_HIERARCHY
|
||||
|
||||
/**
|
||||
|
@ -1394,7 +1336,7 @@ void gpiochip_irq_domain_deactivate(struct irq_domain *domain,
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(gpiochip_irq_domain_deactivate);
|
||||
|
||||
static int gpiochip_to_irq(struct gpio_chip *gc, unsigned offset)
|
||||
static int gpiochip_to_irq(struct gpio_chip *gc, unsigned int offset)
|
||||
{
|
||||
struct irq_domain *domain = gc->irq.domain;
|
||||
|
||||
|
@ -1477,7 +1419,8 @@ static void gpiochip_set_irq_hooks(struct gpio_chip *gc)
|
|||
if (WARN_ON(gc->irq.irq_enable))
|
||||
return;
|
||||
/* Check if the irqchip already has this hook... */
|
||||
if (irqchip->irq_enable == gpiochip_irq_enable) {
|
||||
if (irqchip->irq_enable == gpiochip_irq_enable ||
|
||||
irqchip->irq_mask == gpiochip_irq_mask) {
|
||||
/*
|
||||
* ...and if so, give a gentle warning that this is bad
|
||||
* practice.
|
||||
|
@ -1647,98 +1590,6 @@ static void gpiochip_irqchip_remove(struct gpio_chip *gc)
|
|||
gpiochip_irqchip_free_valid_mask(gc);
|
||||
}
|
||||
|
||||
/**
|
||||
* gpiochip_irqchip_add_key() - adds an irqchip to a gpiochip
|
||||
* @gc: the gpiochip to add the irqchip to
|
||||
* @irqchip: the irqchip to add to the gpiochip
|
||||
* @first_irq: if not dynamically assigned, the base (first) IRQ to
|
||||
* allocate gpiochip irqs from
|
||||
* @handler: the irq handler to use (often a predefined irq core function)
|
||||
* @type: the default type for IRQs on this irqchip, pass IRQ_TYPE_NONE
|
||||
* to have the core avoid setting up any default type in the hardware.
|
||||
* @threaded: whether this irqchip uses a nested thread handler
|
||||
* @lock_key: lockdep class for IRQ lock
|
||||
* @request_key: lockdep class for IRQ request
|
||||
*
|
||||
* This function closely associates a certain irqchip with a certain
|
||||
* gpiochip, providing an irq domain to translate the local IRQs to
|
||||
* global irqs in the gpiolib core, and making sure that the gpiochip
|
||||
* is passed as chip data to all related functions. Driver callbacks
|
||||
* need to use gpiochip_get_data() to get their local state containers back
|
||||
* from the gpiochip passed as chip data. An irqdomain will be stored
|
||||
* in the gpiochip that shall be used by the driver to handle IRQ number
|
||||
* translation. The gpiochip will need to be initialized and registered
|
||||
* before calling this function.
|
||||
*
|
||||
* This function will handle two cell:ed simple IRQs and assumes all
|
||||
* the pins on the gpiochip can generate a unique IRQ. Everything else
|
||||
* need to be open coded.
|
||||
*/
|
||||
int gpiochip_irqchip_add_key(struct gpio_chip *gc,
|
||||
struct irq_chip *irqchip,
|
||||
unsigned int first_irq,
|
||||
irq_flow_handler_t handler,
|
||||
unsigned int type,
|
||||
bool threaded,
|
||||
struct lock_class_key *lock_key,
|
||||
struct lock_class_key *request_key)
|
||||
{
|
||||
struct device_node *of_node;
|
||||
|
||||
if (!gc || !irqchip)
|
||||
return -EINVAL;
|
||||
|
||||
if (!gc->parent) {
|
||||
chip_err(gc, "missing gpiochip .dev parent pointer\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
gc->irq.threaded = threaded;
|
||||
of_node = gc->parent->of_node;
|
||||
#ifdef CONFIG_OF_GPIO
|
||||
/*
|
||||
* If the gpiochip has an assigned OF node this takes precedence
|
||||
* FIXME: get rid of this and use gc->parent->of_node
|
||||
* everywhere
|
||||
*/
|
||||
if (gc->of_node)
|
||||
of_node = gc->of_node;
|
||||
#endif
|
||||
/*
|
||||
* Specifying a default trigger is a terrible idea if DT or ACPI is
|
||||
* used to configure the interrupts, as you may end-up with
|
||||
* conflicting triggers. Tell the user, and reset to NONE.
|
||||
*/
|
||||
if (WARN(of_node && type != IRQ_TYPE_NONE,
|
||||
"%pOF: Ignoring %d default trigger\n", of_node, type))
|
||||
type = IRQ_TYPE_NONE;
|
||||
if (has_acpi_companion(gc->parent) && type != IRQ_TYPE_NONE) {
|
||||
acpi_handle_warn(ACPI_HANDLE(gc->parent),
|
||||
"Ignoring %d default trigger\n", type);
|
||||
type = IRQ_TYPE_NONE;
|
||||
}
|
||||
|
||||
gc->irq.chip = irqchip;
|
||||
gc->irq.handler = handler;
|
||||
gc->irq.default_type = type;
|
||||
gc->to_irq = gpiochip_to_irq;
|
||||
gc->irq.lock_key = lock_key;
|
||||
gc->irq.request_key = request_key;
|
||||
gc->irq.domain = irq_domain_add_simple(of_node,
|
||||
gc->ngpio, first_irq,
|
||||
&gpiochip_domain_ops, gc);
|
||||
if (!gc->irq.domain) {
|
||||
gc->irq.chip = NULL;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
gpiochip_set_irq_hooks(gc);
|
||||
|
||||
acpi_gpiochip_request_interrupts(gc);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(gpiochip_irqchip_add_key);
|
||||
|
||||
/**
|
||||
* gpiochip_irqchip_add_domain() - adds an irqdomain to a gpiochip
|
||||
* @gc: the gpiochip to add the irqchip to
|
||||
|
@ -1788,7 +1639,7 @@ static inline void gpiochip_irqchip_free_valid_mask(struct gpio_chip *gc)
|
|||
* @gc: the gpiochip owning the GPIO
|
||||
* @offset: the offset of the GPIO to request for GPIO function
|
||||
*/
|
||||
int gpiochip_generic_request(struct gpio_chip *gc, unsigned offset)
|
||||
int gpiochip_generic_request(struct gpio_chip *gc, unsigned int offset)
|
||||
{
|
||||
#ifdef CONFIG_PINCTRL
|
||||
if (list_empty(&gc->gpiodev->pin_ranges))
|
||||
|
@ -1804,7 +1655,7 @@ EXPORT_SYMBOL_GPL(gpiochip_generic_request);
|
|||
* @gc: the gpiochip to request the gpio function for
|
||||
* @offset: the offset of the GPIO to free from GPIO function
|
||||
*/
|
||||
void gpiochip_generic_free(struct gpio_chip *gc, unsigned offset)
|
||||
void gpiochip_generic_free(struct gpio_chip *gc, unsigned int offset)
|
||||
{
|
||||
#ifdef CONFIG_PINCTRL
|
||||
if (list_empty(&gc->gpiodev->pin_ranges))
|
||||
|
@ -1821,7 +1672,7 @@ EXPORT_SYMBOL_GPL(gpiochip_generic_free);
|
|||
* @offset: the offset of the GPIO to apply the configuration
|
||||
* @config: the configuration to be applied
|
||||
*/
|
||||
int gpiochip_generic_config(struct gpio_chip *gc, unsigned offset,
|
||||
int gpiochip_generic_config(struct gpio_chip *gc, unsigned int offset,
|
||||
unsigned long config)
|
||||
{
|
||||
return pinctrl_gpio_set_config(gc->gpiodev->base + offset, config);
|
||||
|
@ -1985,11 +1836,9 @@ static int gpiod_request_commit(struct gpio_desc *desc, const char *label)
|
|||
|
||||
if (test_and_set_bit(FLAG_REQUESTED, &desc->flags) == 0) {
|
||||
desc_set_label(desc, label ? : "?");
|
||||
ret = 0;
|
||||
} else {
|
||||
kfree_const(label);
|
||||
ret = -EBUSY;
|
||||
goto done;
|
||||
goto out_free_unlock;
|
||||
}
|
||||
|
||||
if (gc->request) {
|
||||
|
@ -2002,11 +1851,10 @@ static int gpiod_request_commit(struct gpio_desc *desc, const char *label)
|
|||
ret = -EINVAL;
|
||||
spin_lock_irqsave(&gpio_lock, flags);
|
||||
|
||||
if (ret < 0) {
|
||||
if (ret) {
|
||||
desc_set_label(desc, NULL);
|
||||
kfree_const(label);
|
||||
clear_bit(FLAG_REQUESTED, &desc->flags);
|
||||
goto done;
|
||||
goto out_free_unlock;
|
||||
}
|
||||
}
|
||||
if (gc->get_direction) {
|
||||
|
@ -2015,8 +1863,12 @@ static int gpiod_request_commit(struct gpio_desc *desc, const char *label)
|
|||
gpiod_get_direction(desc);
|
||||
spin_lock_irqsave(&gpio_lock, flags);
|
||||
}
|
||||
done:
|
||||
spin_unlock_irqrestore(&gpio_lock, flags);
|
||||
return 0;
|
||||
|
||||
out_free_unlock:
|
||||
spin_unlock_irqrestore(&gpio_lock, flags);
|
||||
kfree_const(label);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -2068,7 +1920,7 @@ int gpiod_request(struct gpio_desc *desc, const char *label)
|
|||
|
||||
if (try_module_get(gdev->owner)) {
|
||||
ret = gpiod_request_commit(desc, label);
|
||||
if (ret < 0)
|
||||
if (ret)
|
||||
module_put(gdev->owner);
|
||||
else
|
||||
get_device(&gdev->dev);
|
||||
|
@ -2151,7 +2003,7 @@ void gpiod_free(struct gpio_desc *desc)
|
|||
* help with diagnostics, and knowing that the signal is used as a GPIO
|
||||
* can help avoid accidentally multiplexing it to another controller.
|
||||
*/
|
||||
const char *gpiochip_is_requested(struct gpio_chip *gc, unsigned offset)
|
||||
const char *gpiochip_is_requested(struct gpio_chip *gc, unsigned int offset)
|
||||
{
|
||||
struct gpio_desc *desc;
|
||||
|
||||
|
@ -2251,30 +2103,49 @@ static int gpio_do_set_config(struct gpio_chip *gc, unsigned int offset,
|
|||
return gc->set_config(gc, offset, config);
|
||||
}
|
||||
|
||||
static int gpio_set_config(struct gpio_desc *desc, enum pin_config_param mode)
|
||||
static int gpio_set_config_with_argument(struct gpio_desc *desc,
|
||||
enum pin_config_param mode,
|
||||
u32 argument)
|
||||
{
|
||||
struct gpio_chip *gc = desc->gdev->chip;
|
||||
unsigned long config;
|
||||
unsigned arg;
|
||||
|
||||
config = pinconf_to_config_packed(mode, argument);
|
||||
return gpio_do_set_config(gc, gpio_chip_hwgpio(desc), config);
|
||||
}
|
||||
|
||||
static int gpio_set_config_with_argument_optional(struct gpio_desc *desc,
|
||||
enum pin_config_param mode,
|
||||
u32 argument)
|
||||
{
|
||||
struct device *dev = &desc->gdev->dev;
|
||||
int gpio = gpio_chip_hwgpio(desc);
|
||||
int ret;
|
||||
|
||||
ret = gpio_set_config_with_argument(desc, mode, argument);
|
||||
if (ret != -ENOTSUPP)
|
||||
return ret;
|
||||
|
||||
switch (mode) {
|
||||
case PIN_CONFIG_BIAS_PULL_DOWN:
|
||||
case PIN_CONFIG_BIAS_PULL_UP:
|
||||
arg = 1;
|
||||
case PIN_CONFIG_PERSIST_STATE:
|
||||
dev_dbg(dev, "Persistence not supported for GPIO %d\n", gpio);
|
||||
break;
|
||||
|
||||
default:
|
||||
arg = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
config = PIN_CONF_PACKED(mode, arg);
|
||||
return gpio_do_set_config(gc, gpio_chip_hwgpio(desc), config);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gpio_set_config(struct gpio_desc *desc, enum pin_config_param mode)
|
||||
{
|
||||
return gpio_set_config_with_argument(desc, mode, 0);
|
||||
}
|
||||
|
||||
static int gpio_set_bias(struct gpio_desc *desc)
|
||||
{
|
||||
int bias = 0;
|
||||
int ret = 0;
|
||||
enum pin_config_param bias;
|
||||
unsigned int arg;
|
||||
|
||||
if (test_bit(FLAG_BIAS_DISABLE, &desc->flags))
|
||||
bias = PIN_CONFIG_BIAS_DISABLE;
|
||||
|
@ -2282,13 +2153,28 @@ static int gpio_set_bias(struct gpio_desc *desc)
|
|||
bias = PIN_CONFIG_BIAS_PULL_UP;
|
||||
else if (test_bit(FLAG_PULL_DOWN, &desc->flags))
|
||||
bias = PIN_CONFIG_BIAS_PULL_DOWN;
|
||||
else
|
||||
return 0;
|
||||
|
||||
if (bias) {
|
||||
ret = gpio_set_config(desc, bias);
|
||||
if (ret != -ENOTSUPP)
|
||||
return ret;
|
||||
switch (bias) {
|
||||
case PIN_CONFIG_BIAS_PULL_DOWN:
|
||||
case PIN_CONFIG_BIAS_PULL_UP:
|
||||
arg = 1;
|
||||
break;
|
||||
|
||||
default:
|
||||
arg = 0;
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
|
||||
return gpio_set_config_with_argument_optional(desc, bias, arg);
|
||||
}
|
||||
|
||||
int gpio_set_debounce_timeout(struct gpio_desc *desc, unsigned int debounce)
|
||||
{
|
||||
return gpio_set_config_with_argument_optional(desc,
|
||||
PIN_CONFIG_INPUT_DEBOUNCE,
|
||||
debounce);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -2510,7 +2396,7 @@ EXPORT_SYMBOL_GPL(gpiod_set_config);
|
|||
* 0 on success, %-ENOTSUPP if the controller doesn't support setting the
|
||||
* debounce time.
|
||||
*/
|
||||
int gpiod_set_debounce(struct gpio_desc *desc, unsigned debounce)
|
||||
int gpiod_set_debounce(struct gpio_desc *desc, unsigned int debounce)
|
||||
{
|
||||
unsigned long config;
|
||||
|
||||
|
@ -2529,11 +2415,6 @@ EXPORT_SYMBOL_GPL(gpiod_set_debounce);
|
|||
*/
|
||||
int gpiod_set_transitory(struct gpio_desc *desc, bool transitory)
|
||||
{
|
||||
struct gpio_chip *gc;
|
||||
unsigned long packed;
|
||||
int gpio;
|
||||
int rc;
|
||||
|
||||
VALIDATE_DESC(desc);
|
||||
/*
|
||||
* Handle FLAG_TRANSITORY first, enabling queries to gpiolib for
|
||||
|
@ -2542,21 +2423,9 @@ int gpiod_set_transitory(struct gpio_desc *desc, bool transitory)
|
|||
assign_bit(FLAG_TRANSITORY, &desc->flags, transitory);
|
||||
|
||||
/* If the driver supports it, set the persistence state now */
|
||||
gc = desc->gdev->chip;
|
||||
if (!gc->set_config)
|
||||
return 0;
|
||||
|
||||
packed = pinconf_to_config_packed(PIN_CONFIG_PERSIST_STATE,
|
||||
!transitory);
|
||||
gpio = gpio_chip_hwgpio(desc);
|
||||
rc = gpio_do_set_config(gc, gpio, packed);
|
||||
if (rc == -ENOTSUPP) {
|
||||
dev_dbg(&desc->gdev->dev, "Persistence not supported for GPIO %d\n",
|
||||
gpio);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return rc;
|
||||
return gpio_set_config_with_argument_optional(desc,
|
||||
PIN_CONFIG_PERSIST_STATE,
|
||||
!transitory);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(gpiod_set_transitory);
|
||||
|
||||
|
@ -3784,7 +3653,7 @@ struct gpio_desc *fwnode_gpiod_get_index(struct fwnode_handle *fwnode,
|
|||
|
||||
desc = fwnode_get_named_gpiod(fwnode, prop_name, index, flags,
|
||||
label);
|
||||
if (!IS_ERR(desc) || (PTR_ERR(desc) != -ENOENT))
|
||||
if (!gpiod_not_found(desc))
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -3960,7 +3829,7 @@ struct gpio_desc *__must_check gpiod_get_index(struct device *dev,
|
|||
* Either we are not using DT or ACPI, or their lookup did not return
|
||||
* a result. In that case, use platform lookup as a fallback.
|
||||
*/
|
||||
if (!desc || desc == ERR_PTR(-ENOENT)) {
|
||||
if (!desc || gpiod_not_found(desc)) {
|
||||
dev_dbg(dev, "using lookup tables for GPIO lookup\n");
|
||||
desc = gpiod_find(dev, con_id, idx, &lookupflags);
|
||||
}
|
||||
|
@ -3975,7 +3844,7 @@ struct gpio_desc *__must_check gpiod_get_index(struct device *dev,
|
|||
* the device name as label
|
||||
*/
|
||||
ret = gpiod_request(desc, con_id ? con_id : devname);
|
||||
if (ret < 0) {
|
||||
if (ret) {
|
||||
if (ret == -EBUSY && flags & GPIOD_FLAGS_BIT_NONEXCLUSIVE) {
|
||||
/*
|
||||
* This happens when there are several consumers for
|
||||
|
@ -4095,10 +3964,8 @@ struct gpio_desc *__must_check gpiod_get_index_optional(struct device *dev,
|
|||
struct gpio_desc *desc;
|
||||
|
||||
desc = gpiod_get_index(dev, con_id, index, flags);
|
||||
if (IS_ERR(desc)) {
|
||||
if (PTR_ERR(desc) == -ENOENT)
|
||||
return NULL;
|
||||
}
|
||||
if (gpiod_not_found(desc))
|
||||
return NULL;
|
||||
|
||||
return desc;
|
||||
}
|
||||
|
@ -4300,7 +4167,7 @@ struct gpio_descs *__must_check gpiod_get_array_optional(struct device *dev,
|
|||
struct gpio_descs *descs;
|
||||
|
||||
descs = gpiod_get_array(dev, con_id, flags);
|
||||
if (PTR_ERR(descs) == -ENOENT)
|
||||
if (gpiod_not_found(descs))
|
||||
return NULL;
|
||||
|
||||
return descs;
|
||||
|
|
|
@ -116,6 +116,7 @@ struct gpio_desc {
|
|||
#define FLAG_BIAS_DISABLE 15 /* GPIO has pull disabled */
|
||||
#define FLAG_EDGE_RISING 16 /* GPIO CDEV detects rising edge events */
|
||||
#define FLAG_EDGE_FALLING 17 /* GPIO CDEV detects falling edge events */
|
||||
#define FLAG_EVENT_CLOCK_REALTIME 18 /* GPIO CDEV reports REALTIME timestamps in events */
|
||||
|
||||
/* Connection label */
|
||||
const char *label;
|
||||
|
@ -130,10 +131,13 @@ struct gpio_desc {
|
|||
#endif
|
||||
};
|
||||
|
||||
#define gpiod_not_found(desc) (IS_ERR(desc) && PTR_ERR(desc) == -ENOENT)
|
||||
|
||||
int gpiod_request(struct gpio_desc *desc, const char *label);
|
||||
void gpiod_free(struct gpio_desc *desc);
|
||||
int gpiod_configure_flags(struct gpio_desc *desc, const char *con_id,
|
||||
unsigned long lflags, enum gpiod_flags dflags);
|
||||
int gpio_set_debounce_timeout(struct gpio_desc *desc, unsigned int debounce);
|
||||
int gpiod_hog(struct gpio_desc *desc, const char *name,
|
||||
unsigned long lflags, enum gpiod_flags dflags);
|
||||
|
||||
|
|
|
@ -8,8 +8,8 @@
|
|||
* The second cell contains standard flag values specified in gpio.h.
|
||||
*/
|
||||
|
||||
#ifndef _DT_BINDINGS_GPIO_TEGRA_GPIO_H
|
||||
#define _DT_BINDINGS_GPIO_TEGRA_GPIO_H
|
||||
#ifndef _DT_BINDINGS_GPIO_TEGRA186_GPIO_H
|
||||
#define _DT_BINDINGS_GPIO_TEGRA186_GPIO_H
|
||||
|
||||
#include <dt-bindings/gpio/gpio.h>
|
||||
|
||||
|
|
|
@ -158,7 +158,7 @@ int gpiod_set_raw_array_value_cansleep(unsigned int array_size,
|
|||
unsigned long *value_bitmap);
|
||||
|
||||
int gpiod_set_config(struct gpio_desc *desc, unsigned long config);
|
||||
int gpiod_set_debounce(struct gpio_desc *desc, unsigned debounce);
|
||||
int gpiod_set_debounce(struct gpio_desc *desc, unsigned int debounce);
|
||||
int gpiod_set_transitory(struct gpio_desc *desc, bool transitory);
|
||||
void gpiod_toggle_active_low(struct gpio_desc *desc);
|
||||
|
||||
|
@ -481,7 +481,7 @@ static inline int gpiod_set_config(struct gpio_desc *desc, unsigned long config)
|
|||
return -ENOSYS;
|
||||
}
|
||||
|
||||
static inline int gpiod_set_debounce(struct gpio_desc *desc, unsigned debounce)
|
||||
static inline int gpiod_set_debounce(struct gpio_desc *desc, unsigned int debounce)
|
||||
{
|
||||
/* GPIO can never have been requested */
|
||||
WARN_ON(desc);
|
||||
|
|
|
@ -621,83 +621,12 @@ int gpiochip_irq_domain_activate(struct irq_domain *domain,
|
|||
void gpiochip_irq_domain_deactivate(struct irq_domain *domain,
|
||||
struct irq_data *data);
|
||||
|
||||
void gpiochip_set_nested_irqchip(struct gpio_chip *gc,
|
||||
struct irq_chip *irqchip,
|
||||
unsigned int parent_irq);
|
||||
|
||||
int gpiochip_irqchip_add_key(struct gpio_chip *gc,
|
||||
struct irq_chip *irqchip,
|
||||
unsigned int first_irq,
|
||||
irq_flow_handler_t handler,
|
||||
unsigned int type,
|
||||
bool threaded,
|
||||
struct lock_class_key *lock_key,
|
||||
struct lock_class_key *request_key);
|
||||
|
||||
bool gpiochip_irqchip_irq_valid(const struct gpio_chip *gc,
|
||||
unsigned int offset);
|
||||
|
||||
int gpiochip_irqchip_add_domain(struct gpio_chip *gc,
|
||||
struct irq_domain *domain);
|
||||
|
||||
#ifdef CONFIG_LOCKDEP
|
||||
|
||||
/*
|
||||
* Lockdep requires that each irqchip instance be created with a
|
||||
* unique key so as to avoid unnecessary warnings. This upfront
|
||||
* boilerplate static inlines provides such a key for each
|
||||
* unique instance.
|
||||
*/
|
||||
static inline int gpiochip_irqchip_add(struct gpio_chip *gc,
|
||||
struct irq_chip *irqchip,
|
||||
unsigned int first_irq,
|
||||
irq_flow_handler_t handler,
|
||||
unsigned int type)
|
||||
{
|
||||
static struct lock_class_key lock_key;
|
||||
static struct lock_class_key request_key;
|
||||
|
||||
return gpiochip_irqchip_add_key(gc, irqchip, first_irq,
|
||||
handler, type, false,
|
||||
&lock_key, &request_key);
|
||||
}
|
||||
|
||||
static inline int gpiochip_irqchip_add_nested(struct gpio_chip *gc,
|
||||
struct irq_chip *irqchip,
|
||||
unsigned int first_irq,
|
||||
irq_flow_handler_t handler,
|
||||
unsigned int type)
|
||||
{
|
||||
|
||||
static struct lock_class_key lock_key;
|
||||
static struct lock_class_key request_key;
|
||||
|
||||
return gpiochip_irqchip_add_key(gc, irqchip, first_irq,
|
||||
handler, type, true,
|
||||
&lock_key, &request_key);
|
||||
}
|
||||
#else /* ! CONFIG_LOCKDEP */
|
||||
static inline int gpiochip_irqchip_add(struct gpio_chip *gc,
|
||||
struct irq_chip *irqchip,
|
||||
unsigned int first_irq,
|
||||
irq_flow_handler_t handler,
|
||||
unsigned int type)
|
||||
{
|
||||
return gpiochip_irqchip_add_key(gc, irqchip, first_irq,
|
||||
handler, type, false, NULL, NULL);
|
||||
}
|
||||
|
||||
static inline int gpiochip_irqchip_add_nested(struct gpio_chip *gc,
|
||||
struct irq_chip *irqchip,
|
||||
unsigned int first_irq,
|
||||
irq_flow_handler_t handler,
|
||||
unsigned int type)
|
||||
{
|
||||
return gpiochip_irqchip_add_key(gc, irqchip, first_irq,
|
||||
handler, type, true, NULL, NULL);
|
||||
}
|
||||
#endif /* CONFIG_LOCKDEP */
|
||||
|
||||
int gpiochip_generic_request(struct gpio_chip *gc, unsigned int offset);
|
||||
void gpiochip_generic_free(struct gpio_chip *gc, unsigned int offset);
|
||||
int gpiochip_generic_config(struct gpio_chip *gc, unsigned int offset,
|
||||
|
|
|
@ -65,6 +65,7 @@ struct gpiochip_info {
|
|||
* @GPIO_V2_LINE_FLAG_BIAS_PULL_UP: line has pull-up bias enabled
|
||||
* @GPIO_V2_LINE_FLAG_BIAS_PULL_DOWN: line has pull-down bias enabled
|
||||
* @GPIO_V2_LINE_FLAG_BIAS_DISABLED: line has bias disabled
|
||||
* @GPIO_V2_LINE_FLAG_EVENT_CLOCK_REALTIME: line events contain REALTIME timestamps
|
||||
*/
|
||||
enum gpio_v2_line_flag {
|
||||
GPIO_V2_LINE_FLAG_USED = _BITULL(0),
|
||||
|
@ -78,6 +79,7 @@ enum gpio_v2_line_flag {
|
|||
GPIO_V2_LINE_FLAG_BIAS_PULL_UP = _BITULL(8),
|
||||
GPIO_V2_LINE_FLAG_BIAS_PULL_DOWN = _BITULL(9),
|
||||
GPIO_V2_LINE_FLAG_BIAS_DISABLED = _BITULL(10),
|
||||
GPIO_V2_LINE_FLAG_EVENT_CLOCK_REALTIME = _BITULL(11),
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -270,9 +272,6 @@ enum gpio_v2_line_event_id {
|
|||
/**
|
||||
* struct gpio_v2_line_event - The actual event being pushed to userspace
|
||||
* @timestamp_ns: best estimate of time of event occurrence, in nanoseconds.
|
||||
* The @timestamp_ns is read from %CLOCK_MONOTONIC and is intended to allow
|
||||
* the accurate measurement of the time between events. It does not provide
|
||||
* the wall-clock time.
|
||||
* @id: event identifier with value from &enum gpio_v2_line_event_id
|
||||
* @offset: the offset of the line that triggered the event
|
||||
* @seqno: the sequence number for this event in the sequence of events for
|
||||
|
@ -280,6 +279,13 @@ enum gpio_v2_line_event_id {
|
|||
* @line_seqno: the sequence number for this event in the sequence of
|
||||
* events on this particular line
|
||||
* @padding: reserved for future use
|
||||
*
|
||||
* By default the @timestamp_ns is read from %CLOCK_MONOTONIC and is
|
||||
* intended to allow the accurate measurement of the time between events.
|
||||
* It does not provide the wall-clock time.
|
||||
*
|
||||
* If the %GPIO_V2_LINE_FLAG_EVENT_CLOCK_REALTIME flag is set then the
|
||||
* @timestamp_ns is read from %CLOCK_REALTIME.
|
||||
*/
|
||||
struct gpio_v2_line_event {
|
||||
__aligned_u64 timestamp_ns;
|
||||
|
|
|
@ -148,6 +148,7 @@ void print_usage(void)
|
|||
" -s Set line as open source\n"
|
||||
" -r Listen for rising edges\n"
|
||||
" -f Listen for falling edges\n"
|
||||
" -w Report the wall-clock time for events\n"
|
||||
" -b <n> Debounce the line with period n microseconds\n"
|
||||
" [-c <n>] Do <n> loops (optional, infinite loop if not stated)\n"
|
||||
" -? This helptext\n"
|
||||
|
@ -173,7 +174,7 @@ int main(int argc, char **argv)
|
|||
|
||||
memset(&config, 0, sizeof(config));
|
||||
config.flags = GPIO_V2_LINE_FLAG_INPUT;
|
||||
while ((c = getopt(argc, argv, "c:n:o:b:dsrf?")) != -1) {
|
||||
while ((c = getopt(argc, argv, "c:n:o:b:dsrfw?")) != -1) {
|
||||
switch (c) {
|
||||
case 'c':
|
||||
loops = strtoul(optarg, NULL, 10);
|
||||
|
@ -204,6 +205,9 @@ int main(int argc, char **argv)
|
|||
case 'f':
|
||||
config.flags |= GPIO_V2_LINE_FLAG_EDGE_FALLING;
|
||||
break;
|
||||
case 'w':
|
||||
config.flags |= GPIO_V2_LINE_FLAG_EVENT_CLOCK_REALTIME;
|
||||
break;
|
||||
case '?':
|
||||
print_usage();
|
||||
return -1;
|
||||
|
|
|
@ -65,6 +65,10 @@ struct gpio_flag flagnames[] = {
|
|||
.name = "bias-disabled",
|
||||
.mask = GPIO_V2_LINE_FLAG_BIAS_DISABLED,
|
||||
},
|
||||
{
|
||||
.name = "clock-realtime",
|
||||
.mask = GPIO_V2_LINE_FLAG_EVENT_CLOCK_REALTIME,
|
||||
},
|
||||
};
|
||||
|
||||
static void print_attributes(struct gpio_v2_line_info *info)
|
||||
|
|
Загрузка…
Ссылка в новой задаче