Skip to content
Snippets Groups Projects
Commit a409ed15 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
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
  ...
parents 345b17ac 7ac55488
Branches
No related tags found
No related merge requests found
Showing
with 697 additions and 223 deletions
...@@ -48,6 +48,7 @@ properties: ...@@ -48,6 +48,7 @@ properties:
- nxp,pcal6416 - nxp,pcal6416
- nxp,pcal6524 - nxp,pcal6524
- nxp,pcal9535 - nxp,pcal9535
- nxp,pcal9554b
- nxp,pcal9555a - nxp,pcal9555a
- onnn,cat9554 - onnn,cat9554
- onnn,pca9654 - onnn,pca9654
......
...@@ -13,6 +13,7 @@ Required properties: ...@@ -13,6 +13,7 @@ Required properties:
- gpio-controller : Marks the device node as a GPIO controller. - gpio-controller : Marks the device node as a GPIO controller.
Optional properties: Optional properties:
- clocks : Input clock specifier. Refer to common clock bindings.
- interrupts : Interrupt mapping for GPIO IRQ. - interrupts : Interrupt mapping for GPIO IRQ.
- xlnx,all-inputs : if n-th bit is setup, GPIO-n is input - 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 - xlnx,dout-default : if n-th bit is 1, GPIO-n default value is 1
...@@ -29,6 +30,7 @@ Example: ...@@ -29,6 +30,7 @@ Example:
gpio: gpio@40000000 { gpio: gpio@40000000 {
#gpio-cells = <2>; #gpio-cells = <2>;
compatible = "xlnx,xps-gpio-1.00.a"; compatible = "xlnx,xps-gpio-1.00.a";
clocks = <&clkc25>;
gpio-controller ; gpio-controller ;
interrupt-parent = <&microblaze_0_intc>; interrupt-parent = <&microblaze_0_intc>;
interrupts = < 6 2 >; interrupts = < 6 2 >;
......
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>;
};
# 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>;
};
...
# 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 ...@@ -440,18 +440,20 @@ For details refer to Documentation/firmware-guide/acpi/gpio-properties.rst
Interacting With the Legacy GPIO Subsystem Interacting With the Legacy GPIO Subsystem
========================================== ==========================================
Many kernel subsystems still handle GPIOs using the legacy integer-based Many kernel subsystems and drivers still handle GPIOs using the legacy
interface. Although it is strongly encouraged to upgrade them to the safer integer-based interface. It is strongly recommended to update these to the new
descriptor-based API, the following two functions allow you to convert a GPIO gpiod interface. For cases where both interfaces need to be used, the following
descriptor into the GPIO integer namespace and vice-versa:: 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) int desc_to_gpio(const struct gpio_desc *desc)
struct gpio_desc *gpio_to_desc(unsigned gpio) struct gpio_desc *gpio_to_desc(unsigned gpio)
The GPIO number returned by desc_to_gpio() can be safely used as long as the The GPIO number returned by desc_to_gpio() can safely be used as a parameter of
GPIO descriptor has not been freed. All the same, a GPIO number passed to the gpio\_*() functions for as long as the GPIO descriptor `desc` is not freed.
gpio_to_desc() must have been properly acquired, and usage of the returned GPIO All the same, a GPIO number passed to gpio_to_desc() must first be properly
descriptor is only possible after the GPIO number has been released. 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 Freeing a GPIO obtained by one API with the other API is forbidden and an
unchecked error. unchecked error.
...@@ -416,7 +416,8 @@ The preferred way to set up the helpers is to fill in the ...@@ -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. 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 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 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 .. code-block:: c
...@@ -452,7 +453,46 @@ is a typical example of a cascaded interrupt handler using gpio_irq_chip: ...@@ -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); 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: In this case the typical set-up will look like this:
.. code-block:: c .. code-block:: c
...@@ -493,32 +533,13 @@ the parent hardware irq from a child (i.e. this gpio chip) hardware irq. ...@@ -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 As always it is good to look at examples in the kernel tree for advice
on how to find the required pieces. 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 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 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 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 .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 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 from this mask. The mask can be filled in the init_valid_mask() callback
gpiochip_irqchip_add_nested() is called. that is part of the struct gpio_irq_chip.
To use the helpers please keep the following in mind: To use the helpers please keep the following in mind:
......
...@@ -2146,8 +2146,10 @@ L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) ...@@ -2146,8 +2146,10 @@ L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
S: Maintained S: Maintained
W: http://linux-chenxing.org/ W: http://linux-chenxing.org/
F: Documentation/devicetree/bindings/arm/mstar/* F: Documentation/devicetree/bindings/arm/mstar/*
F: Documentation/devicetree/bindings/gpio/mstar,msc313-gpio.yaml
F: arch/arm/boot/dts/mstar-* F: arch/arm/boot/dts/mstar-*
F: arch/arm/mach-mstar/ F: arch/arm/mach-mstar/
F: drivers/gpio/gpio-msc313.c
F: include/dt-bindings/gpio/msc313-gpio.h F: include/dt-bindings/gpio/msc313-gpio.h
   
ARM/NEC MOBILEPRO 900/c MACHINE SUPPORT ARM/NEC MOBILEPRO 900/c MACHINE SUPPORT
...@@ -7548,6 +7550,7 @@ M: Andy Shevchenko <andriy.shevchenko@linux.intel.com> ...@@ -7548,6 +7550,7 @@ M: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
L: linux-gpio@vger.kernel.org L: linux-gpio@vger.kernel.org
L: linux-acpi@vger.kernel.org L: linux-acpi@vger.kernel.org
S: Maintained 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: Documentation/firmware-guide/acpi/gpio-properties.rst
F: drivers/gpio/gpiolib-acpi.c F: drivers/gpio/gpiolib-acpi.c
F: drivers/gpio/gpiolib-acpi.h F: drivers/gpio/gpiolib-acpi.h
...@@ -7981,6 +7984,12 @@ L: dmaengine@vger.kernel.org ...@@ -7981,6 +7984,12 @@ L: dmaengine@vger.kernel.org
S: Maintained S: Maintained
F: drivers/dma/hisi_dma.c 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) HISILICON HIGH PERFORMANCE RSA ENGINE DRIVER (HPRE)
M: Zaibo Xu <xuzaibo@huawei.com> M: Zaibo Xu <xuzaibo@huawei.com>
L: linux-crypto@vger.kernel.org L: linux-crypto@vger.kernel.org
...@@ -19500,6 +19509,16 @@ S: Maintained ...@@ -19500,6 +19509,16 @@ S: Maintained
F: Documentation/devicetree/bindings/net/can/xilinx_can.txt F: Documentation/devicetree/bindings/net/can/xilinx_can.txt
F: drivers/net/can/xilinx_can.c 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 XILINX SD-FEC IP CORES
M: Derek Kiernan <derek.kiernan@xilinx.com> M: Derek Kiernan <derek.kiernan@xilinx.com>
M: Dragan Cvetic <dragan.cvetic@xilinx.com> M: Dragan Cvetic <dragan.cvetic@xilinx.com>
......
...@@ -59,8 +59,9 @@ config DEBUG_GPIO ...@@ -59,8 +59,9 @@ config DEBUG_GPIO
that are most common when setting up new platforms or boards. that are most common when setting up new platforms or boards.
config GPIO_SYSFS config GPIO_SYSFS
bool "/sys/class/gpio/... (sysfs interface)" bool "/sys/class/gpio/... (sysfs interface)" if EXPERT
depends on SYSFS depends on SYSFS
select GPIO_CDEV # We need to encourage the new ABI
help help
Say Y here to add the legacy sysfs interface for GPIOs. Say Y here to add the legacy sysfs interface for GPIOs.
...@@ -255,6 +256,7 @@ config GPIO_EP93XX ...@@ -255,6 +256,7 @@ config GPIO_EP93XX
config GPIO_EXAR config GPIO_EXAR
tristate "Support for GPIO pins on XR17V352/354/358" tristate "Support for GPIO pins on XR17V352/354/358"
depends on SERIAL_8250_EXAR depends on SERIAL_8250_EXAR
select REGMAP_MMIO
help help
Selecting this option will enable handling of GPIO pins present Selecting this option will enable handling of GPIO pins present
on Exar XR17V352/354/358 chips. on Exar XR17V352/354/358 chips.
...@@ -296,6 +298,17 @@ config GPIO_GRGPIO ...@@ -296,6 +298,17 @@ config GPIO_GRGPIO
Select this to support Aeroflex Gaisler GRGPIO cores from the GRLIB Select this to support Aeroflex Gaisler GRGPIO cores from the GRLIB
VHDL IP core library. 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 config GPIO_HLWD
tristate "Nintendo Wii (Hollywood) GPIO" tristate "Nintendo Wii (Hollywood) GPIO"
depends on OF_GPIO depends on OF_GPIO
...@@ -737,6 +750,17 @@ config GPIO_AMD_FCH ...@@ -737,6 +750,17 @@ config GPIO_AMD_FCH
Note: This driver doesn't registers itself automatically, as it Note: This driver doesn't registers itself automatically, as it
needs to be provided with platform specific configuration. needs to be provided with platform specific configuration.
(See eg. CONFIG_PCENGINES_APU2.) (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 endmenu
menu "Port-mapped I/O GPIO drivers" menu "Port-mapped I/O GPIO drivers"
...@@ -1590,6 +1614,8 @@ config GPIO_VIPERBOARD ...@@ -1590,6 +1614,8 @@ config GPIO_VIPERBOARD
endmenu endmenu
menu "Virtual GPIO drivers"
config GPIO_AGGREGATOR config GPIO_AGGREGATOR
tristate "GPIO Aggregator" tristate "GPIO Aggregator"
help help
...@@ -1613,4 +1639,6 @@ config GPIO_MOCKUP ...@@ -1613,4 +1639,6 @@ config GPIO_MOCKUP
tools/testing/selftests/gpio/gpio-mockup.sh. Reference the usage in tools/testing/selftests/gpio/gpio-mockup.sh. Reference the usage in
it. it.
endmenu
endif endif
...@@ -63,6 +63,7 @@ obj-$(CONFIG_GPIO_GE_FPGA) += gpio-ge.o ...@@ -63,6 +63,7 @@ obj-$(CONFIG_GPIO_GE_FPGA) += gpio-ge.o
obj-$(CONFIG_GPIO_GPIO_MM) += gpio-gpio-mm.o obj-$(CONFIG_GPIO_GPIO_MM) += gpio-gpio-mm.o
obj-$(CONFIG_GPIO_GRGPIO) += gpio-grgpio.o obj-$(CONFIG_GPIO_GRGPIO) += gpio-grgpio.o
obj-$(CONFIG_GPIO_GW_PLD) += gpio-gw-pld.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_GPIO_HLWD) += gpio-hlwd.o
obj-$(CONFIG_HTC_EGPIO) += gpio-htc-egpio.o obj-$(CONFIG_HTC_EGPIO) += gpio-htc-egpio.o
obj-$(CONFIG_GPIO_ICH) += gpio-ich.o obj-$(CONFIG_GPIO_ICH) += gpio-ich.o
...@@ -101,6 +102,7 @@ obj-$(CONFIG_GPIO_MOCKUP) += gpio-mockup.o ...@@ -101,6 +102,7 @@ obj-$(CONFIG_GPIO_MOCKUP) += gpio-mockup.o
obj-$(CONFIG_GPIO_MOXTET) += gpio-moxtet.o obj-$(CONFIG_GPIO_MOXTET) += gpio-moxtet.o
obj-$(CONFIG_GPIO_MPC5200) += gpio-mpc5200.o obj-$(CONFIG_GPIO_MPC5200) += gpio-mpc5200.o
obj-$(CONFIG_GPIO_MPC8XXX) += gpio-mpc8xxx.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_MSIC) += gpio-msic.o
obj-$(CONFIG_GPIO_MT7621) += gpio-mt7621.o obj-$(CONFIG_GPIO_MT7621) += gpio-mt7621.o
obj-$(CONFIG_GPIO_MVEBU) += gpio-mvebu.o obj-$(CONFIG_GPIO_MVEBU) += gpio-mvebu.o
......
...@@ -129,58 +129,9 @@ GPIOLIB irqchip ...@@ -129,58 +129,9 @@ GPIOLIB irqchip
The GPIOLIB irqchip is a helper irqchip for "simple cases" that should The GPIOLIB irqchip is a helper irqchip for "simple cases" that should
try to cover any generic kind of irqchip cascaded from a GPIO. 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 - Look over and identify any remaining easily converted drivers and
dry-code conversions to gpiolib irqchip for maintainers to test 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 Increase integration with pin control
...@@ -191,3 +142,39 @@ use of the global GPIO numbers. Once the above is complete, it may ...@@ -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 make sense to simply join the subsystems into one and make pin
multiplexing, pin configuration, GPIO, etc selectable options in one multiplexing, pin configuration, GPIO, etc selectable options in one
and the same pin control and GPIO subsystem. 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) ...@@ -132,8 +132,7 @@ static void idi_48_irq_mask(struct irq_data *data)
outb(idi48gpio->cos_enb, idi48gpio->base + 7); outb(idi48gpio->cos_enb, idi48gpio->base + 7);
raw_spin_unlock_irqrestore(&idi48gpio->lock, raw_spin_unlock_irqrestore(&idi48gpio->lock, flags);
flags);
} }
return; return;
...@@ -166,8 +165,7 @@ static void idi_48_irq_unmask(struct irq_data *data) ...@@ -166,8 +165,7 @@ static void idi_48_irq_unmask(struct irq_data *data)
outb(idi48gpio->cos_enb, idi48gpio->base + 7); outb(idi48gpio->cos_enb, idi48gpio->base + 7);
raw_spin_unlock_irqrestore(&idi48gpio->lock, raw_spin_unlock_irqrestore(&idi48gpio->lock, flags);
flags);
} }
return; return;
......
// SPDX-License-Identifier: GPL-2.0
/* /*
* GPIO driver for AMD 8111 south bridges * GPIO driver for AMD 8111 south bridges
* *
...@@ -20,10 +21,6 @@ ...@@ -20,10 +21,6 @@
* Hardware driver for Intel i810 Random Number Generator (RNG) * Hardware driver for Intel i810 Random Number Generator (RNG)
* Copyright 2000,2001 Jeff Garzik <jgarzik@pobox.com> * Copyright 2000,2001 Jeff Garzik <jgarzik@pobox.com>
* Copyright 2000,2001 Philipp Rumpf <prumpf@mandrakesoft.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/ioport.h>
#include <linux/module.h> #include <linux/module.h>
...@@ -179,7 +176,6 @@ static int __init amd_gpio_init(void) ...@@ -179,7 +176,6 @@ static int __init amd_gpio_init(void)
struct pci_dev *pdev = NULL; struct pci_dev *pdev = NULL;
const struct pci_device_id *ent; const struct pci_device_id *ent;
/* We look for our device - AMD South Bridge /* We look for our device - AMD South Bridge
* I don't know about a system with two such bridges, * I don't know about a system with two such bridges,
* so we can assume that there is max. one device. * so we can assume that there is max. one device.
...@@ -223,11 +219,10 @@ static int __init amd_gpio_init(void) ...@@ -223,11 +219,10 @@ static int __init amd_gpio_init(void)
spin_lock_init(&gp.lock); 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); err = gpiochip_add_data(&gp.chip, &gp);
if (err) { if (err) {
printk(KERN_ERR "GPIO registering failed (%d)\n", dev_err(&pdev->dev, "GPIO registering failed (%d)\n", err);
err);
ioport_unmap(gp.pm); ioport_unmap(gp.pm);
goto out; goto out;
} }
......
...@@ -123,6 +123,7 @@ static int ath79_gpio_irq_set_type(struct irq_data *data, ...@@ -123,6 +123,7 @@ static int ath79_gpio_irq_set_type(struct irq_data *data,
switch (flow_type) { switch (flow_type) {
case IRQ_TYPE_EDGE_RISING: case IRQ_TYPE_EDGE_RISING:
polarity |= mask; polarity |= mask;
fallthrough;
case IRQ_TYPE_EDGE_FALLING: case IRQ_TYPE_EDGE_FALLING:
case IRQ_TYPE_EDGE_BOTH: case IRQ_TYPE_EDGE_BOTH:
break; break;
......
...@@ -175,13 +175,13 @@ static int bt8xxgpio_probe(struct pci_dev *dev, ...@@ -175,13 +175,13 @@ static int bt8xxgpio_probe(struct pci_dev *dev,
err = pci_enable_device(dev); err = pci_enable_device(dev);
if (err) { if (err) {
printk(KERN_ERR "bt8xxgpio: Can't enable device.\n"); dev_err(&dev->dev, "can't enable device.\n");
return err; return err;
} }
if (!devm_request_mem_region(&dev->dev, pci_resource_start(dev, 0), if (!devm_request_mem_region(&dev->dev, pci_resource_start(dev, 0),
pci_resource_len(dev, 0), pci_resource_len(dev, 0),
"bt8xxgpio")) { "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)); (unsigned long long)pci_resource_start(dev, 0));
err = -EBUSY; err = -EBUSY;
goto err_disable; goto err_disable;
...@@ -191,7 +191,7 @@ static int bt8xxgpio_probe(struct pci_dev *dev, ...@@ -191,7 +191,7 @@ static int bt8xxgpio_probe(struct pci_dev *dev,
bg->mmio = devm_ioremap(&dev->dev, pci_resource_start(dev, 0), 0x1000); bg->mmio = devm_ioremap(&dev->dev, pci_resource_start(dev, 0), 0x1000);
if (!bg->mmio) { if (!bg->mmio) {
printk(KERN_ERR "bt8xxgpio: ioremap() failed\n"); dev_err(&dev->dev, "ioremap() failed\n");
err = -EIO; err = -EIO;
goto err_disable; goto err_disable;
} }
...@@ -207,7 +207,7 @@ static int bt8xxgpio_probe(struct pci_dev *dev, ...@@ -207,7 +207,7 @@ static int bt8xxgpio_probe(struct pci_dev *dev,
bt8xxgpio_gpio_setup(bg); bt8xxgpio_gpio_setup(bg);
err = gpiochip_add_data(&bg->gpio, bg); err = gpiochip_add_data(&bg->gpio, bg);
if (err) { if (err) {
printk(KERN_ERR "bt8xxgpio: Failed to register GPIOs\n"); dev_err(&dev->dev, "failed to register GPIOs\n");
goto err_disable; goto err_disable;
} }
......
...@@ -345,12 +345,8 @@ static int cs5535_gpio_probe(struct platform_device *pdev) ...@@ -345,12 +345,8 @@ static int cs5535_gpio_probe(struct platform_device *pdev)
mask_orig, mask); mask_orig, mask);
/* finally, register with the generic GPIO API */ /* finally, register with the generic GPIO API */
err = devm_gpiochip_add_data(&pdev->dev, &cs5535_gpio_chip.chip, return devm_gpiochip_add_data(&pdev->dev, &cs5535_gpio_chip.chip,
&cs5535_gpio_chip); &cs5535_gpio_chip);
if (err)
return err;
return 0;
} }
static struct platform_driver cs5535_gpio_driver = { static struct platform_driver cs5535_gpio_driver = {
......
...@@ -616,10 +616,9 @@ static int dwapb_get_reset(struct dwapb_gpio *gpio) ...@@ -616,10 +616,9 @@ static int dwapb_get_reset(struct dwapb_gpio *gpio)
int err; int err;
gpio->rst = devm_reset_control_get_optional_shared(gpio->dev, NULL); gpio->rst = devm_reset_control_get_optional_shared(gpio->dev, NULL);
if (IS_ERR(gpio->rst)) { if (IS_ERR(gpio->rst))
dev_err(gpio->dev, "Cannot get reset descriptor\n"); return dev_err_probe(gpio->dev, PTR_ERR(gpio->rst),
return PTR_ERR(gpio->rst); "Cannot get reset descriptor\n");
}
err = reset_control_deassert(gpio->rst); err = reset_control_deassert(gpio->rst);
if (err) { if (err) {
......
...@@ -4,14 +4,17 @@ ...@@ -4,14 +4,17 @@
* *
* Copyright (C) 2015 Sudip Mukherjee <sudip.mukherjee@codethink.co.uk> * Copyright (C) 2015 Sudip Mukherjee <sudip.mukherjee@codethink.co.uk>
*/ */
#include <linux/bitops.h> #include <linux/bitops.h>
#include <linux/device.h> #include <linux/device.h>
#include <linux/gpio/driver.h> #include <linux/gpio/driver.h>
#include <linux/idr.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/pci.h> #include <linux/pci.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/regmap.h>
#define EXAR_OFFSET_MPIOLVL_LO 0x90 #define EXAR_OFFSET_MPIOLVL_LO 0x90
#define EXAR_OFFSET_MPIOSEL_LO 0x93 #define EXAR_OFFSET_MPIOSEL_LO 0x93
...@@ -24,60 +27,39 @@ static DEFINE_IDA(ida_index); ...@@ -24,60 +27,39 @@ static DEFINE_IDA(ida_index);
struct exar_gpio_chip { struct exar_gpio_chip {
struct gpio_chip gpio_chip; struct gpio_chip gpio_chip;
struct mutex lock; struct regmap *regmap;
int index; int index;
void __iomem *regs;
char name[20]; char name[20];
unsigned int first_pin; unsigned int first_pin;
}; };
static void exar_update(struct gpio_chip *chip, unsigned int reg, int val, static unsigned int
unsigned int offset) exar_offset_to_sel_addr(struct exar_gpio_chip *exar_gpio, unsigned int offset)
{ {
struct exar_gpio_chip *exar_gpio = gpiochip_get_data(chip); return (offset + exar_gpio->first_pin) / 8 ? EXAR_OFFSET_MPIOSEL_HI
int temp; : EXAR_OFFSET_MPIOSEL_LO;
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);
} }
static int exar_set_direction(struct gpio_chip *chip, int direction, static unsigned int
unsigned int offset) exar_offset_to_lvl_addr(struct exar_gpio_chip *exar_gpio, unsigned int offset)
{ {
struct exar_gpio_chip *exar_gpio = gpiochip_get_data(chip); return (offset + exar_gpio->first_pin) / 8 ? EXAR_OFFSET_MPIOLVL_HI
unsigned int addr = (offset + exar_gpio->first_pin) / 8 ? : EXAR_OFFSET_MPIOLVL_LO;
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;
} }
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); return (offset + exar_gpio->first_pin) % 8;
int value;
mutex_lock(&exar_gpio->lock);
value = readb(exar_gpio->regs + reg);
mutex_unlock(&exar_gpio->lock);
return value;
} }
static int exar_get_direction(struct gpio_chip *chip, unsigned int offset) static int exar_get_direction(struct gpio_chip *chip, unsigned int offset)
{ {
struct exar_gpio_chip *exar_gpio = gpiochip_get_data(chip); struct exar_gpio_chip *exar_gpio = gpiochip_get_data(chip);
unsigned int addr = (offset + exar_gpio->first_pin) / 8 ? unsigned int addr = exar_offset_to_sel_addr(exar_gpio, offset);
EXAR_OFFSET_MPIOSEL_HI : EXAR_OFFSET_MPIOSEL_LO; unsigned int bit = exar_offset_to_bit(exar_gpio, offset);
unsigned int bit = (offset + exar_gpio->first_pin) % 8;
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_IN;
return GPIO_LINE_DIRECTION_OUT; return GPIO_LINE_DIRECTION_OUT;
...@@ -86,39 +68,66 @@ static int exar_get_direction(struct gpio_chip *chip, unsigned int offset) ...@@ -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) static int exar_get_value(struct gpio_chip *chip, unsigned int offset)
{ {
struct exar_gpio_chip *exar_gpio = gpiochip_get_data(chip); struct exar_gpio_chip *exar_gpio = gpiochip_get_data(chip);
unsigned int addr = (offset + exar_gpio->first_pin) / 8 ? unsigned int addr = exar_offset_to_lvl_addr(exar_gpio, offset);
EXAR_OFFSET_MPIOLVL_HI : EXAR_OFFSET_MPIOLVL_LO; unsigned int bit = exar_offset_to_bit(exar_gpio, offset);
unsigned int bit = (offset + exar_gpio->first_pin) % 8;
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, static void exar_set_value(struct gpio_chip *chip, unsigned int offset,
int value) int value)
{ {
struct exar_gpio_chip *exar_gpio = gpiochip_get_data(chip); struct exar_gpio_chip *exar_gpio = gpiochip_get_data(chip);
unsigned int addr = (offset + exar_gpio->first_pin) / 8 ? unsigned int addr = exar_offset_to_lvl_addr(exar_gpio, offset);
EXAR_OFFSET_MPIOLVL_HI : EXAR_OFFSET_MPIOLVL_LO; unsigned int bit = exar_offset_to_bit(exar_gpio, offset);
unsigned int bit = (offset + exar_gpio->first_pin) % 8;
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, static int exar_direction_output(struct gpio_chip *chip, unsigned int offset,
int value) 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); 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) 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) 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; struct exar_gpio_chip *exar_gpio;
u32 first_pin, ngpios; u32 first_pin, ngpios;
void __iomem *p; void __iomem *p;
...@@ -132,30 +141,37 @@ static int gpio_exar_probe(struct platform_device *pdev) ...@@ -132,30 +141,37 @@ static int gpio_exar_probe(struct platform_device *pdev)
if (!p) if (!p)
return -ENOMEM; return -ENOMEM;
ret = device_property_read_u32(&pdev->dev, "exar,first-pin", ret = device_property_read_u32(dev, "exar,first-pin", &first_pin);
&first_pin);
if (ret) if (ret)
return ret; return ret;
ret = device_property_read_u32(&pdev->dev, "ngpios", &ngpios); ret = device_property_read_u32(dev, "ngpios", &ngpios);
if (ret) if (ret)
return 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) if (!exar_gpio)
return -ENOMEM; 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); index = ida_alloc(&ida_index, GFP_KERNEL);
if (index < 0) { if (index < 0)
ret = index; return index;
goto err_mutex_destroy;
} 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); sprintf(exar_gpio->name, "exar_gpio%d", index);
exar_gpio->gpio_chip.label = exar_gpio->name; 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_output = exar_direction_output;
exar_gpio->gpio_chip.direction_input = exar_direction_input; exar_gpio->gpio_chip.direction_input = exar_direction_input;
exar_gpio->gpio_chip.get_direction = exar_get_direction; exar_gpio->gpio_chip.get_direction = exar_get_direction;
...@@ -163,39 +179,20 @@ static int gpio_exar_probe(struct platform_device *pdev) ...@@ -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.set = exar_set_value;
exar_gpio->gpio_chip.base = -1; exar_gpio->gpio_chip.base = -1;
exar_gpio->gpio_chip.ngpio = ngpios; exar_gpio->gpio_chip.ngpio = ngpios;
exar_gpio->regs = p;
exar_gpio->index = index; exar_gpio->index = index;
exar_gpio->first_pin = first_pin; exar_gpio->first_pin = first_pin;
ret = devm_gpiochip_add_data(&pdev->dev, ret = devm_gpiochip_add_data(dev, &exar_gpio->gpio_chip, exar_gpio);
&exar_gpio->gpio_chip, exar_gpio);
if (ret) if (ret)
goto err_destroy;
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; 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); platform_set_drvdata(pdev, exar_gpio);
mutex_destroy(&exar_gpio->lock);
return 0; return 0;
} }
static struct platform_driver gpio_exar_driver = { static struct platform_driver gpio_exar_driver = {
.probe = gpio_exar_probe, .probe = gpio_exar_probe,
.remove = gpio_exar_remove,
.driver = { .driver = {
.name = DRIVER_NAME, .name = DRIVER_NAME,
}, },
......
// 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 @@ ...@@ -15,6 +15,7 @@
#include <linux/irq.h> #include <linux/irq.h>
#include <linux/irq_sim.h> #include <linux/irq_sim.h>
#include <linux/irqdomain.h> #include <linux/irqdomain.h>
#include <linux/mod_devicetable.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/property.h> #include <linux/property.h>
...@@ -460,9 +461,16 @@ static int gpio_mockup_probe(struct platform_device *pdev) ...@@ -460,9 +461,16 @@ static int gpio_mockup_probe(struct platform_device *pdev)
return 0; 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 = { static struct platform_driver gpio_mockup_driver = {
.driver = { .driver = {
.name = "gpio-mockup", .name = "gpio-mockup",
.of_match_table = gpio_mockup_of_match,
}, },
.probe = gpio_mockup_probe, .probe = gpio_mockup_probe,
}; };
...@@ -556,8 +564,7 @@ static int __init gpio_mockup_init(void) ...@@ -556,8 +564,7 @@ static int __init gpio_mockup_init(void)
{ {
int i, num_chips, err; int i, num_chips, err;
if ((gpio_mockup_num_ranges < 2) || if ((gpio_mockup_num_ranges % 2) ||
(gpio_mockup_num_ranges % 2) ||
(gpio_mockup_num_ranges > GPIO_MOCKUP_MAX_RANGES)) (gpio_mockup_num_ranges > GPIO_MOCKUP_MAX_RANGES))
return -EINVAL; return -EINVAL;
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment