Commit 114b5f8f authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'gpio-v4.20-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 GPIO changes for the v4.20 series:

  Core changes:

   - A patch series from Hans Verkuil to make it possible to
     enable/disable IRQs on a GPIO line at runtime and drive GPIO lines
     as output without having to put/get them from scratch.

     The irqchip callbacks have been improved so that they can use only
     the fastpatch callbacks to enable/disable irqs like any normal
     irqchip, especially the gpiod_lock_as_irq() has been improved to be
     callable in fastpath context.

     A bunch of rework had to be done to achieve this but it is a big
     win since I never liked to restrict this to slowpath. The only call
     requireing slowpath was try_module_get() and this is kept at the
     .request_resources() slowpath callback. In the GPIO CEC driver this
     is a big win sine a single line is used for both outgoing and
     incoming traffic, and this needs to use IRQs for incoming traffic
     while actively driving the line for outgoing traffic.

   - Janusz Krzysztofik improved the GPIO array API to pass a "cookie"
     (struct gpio_array) and a bitmap for setting or getting multiple
     GPIO lines at once.

     This improvement orginated in a specific need to speed up an OMAP1
     driver and has led to a much better API and real performance gains
     when the state of the array can be used to bypass a lot of checks
     and code when we want things to go really fast.

     The previous code would minimize the number of calls down to the
     driver callbacks assuming the CPU speed was orders of magnitude
     faster than the I/O latency, but this assumption was wrong on
     several platforms: what we needed to do was to profile and improve
     the speed on the hot path of the array functions and this change is
     now completed.

   - Clean out the painful and hard to grasp BNF experiments from the
     device tree bindings. Future approaches are looking into using JSON
     schema for this purpose. (Rob Herring is floating a patch series.)

  New drivers:

   - The RCAR driver now supports r8a774a1 (RZ/G2M).

   - Synopsys GPIO via CREGs driver.

  Major improvements:

   - Modernization of the EP93xx driver to use irqdomain and other
     contemporary concepts.

   - The ingenic driver has been merged into the Ingenic pin control
     driver and removed from the GPIO subsystem.

   - Debounce support in the ftgpio010 driver"

* tag 'gpio-v4.20-1' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-gpio: (116 commits)
  gpio: Clarify kerneldoc on gpiochip_set_chained_irqchip()
  gpio: Remove unused 'irqchip' argument to gpiochip_set_cascaded_irqchip()
  gpio: Drop parent irq assignment during cascade setup
  mmc: pwrseq_simple: Fix incorrect handling of GPIO bitmap
  gpio: fix SNPS_CREG kconfig dependency warning
  gpiolib: Initialize gdev field before is used
  gpio: fix kernel-doc after devres.c file rename
  gpio: fix doc string for devm_gpiochip_add_data() to not talk about irq_chip
  gpio: syscon: Fix possible NULL ptr usage
  gpiolib: Show correct direction from the beginning
  pinctrl: msm: Use init_valid_mask exported function
  gpiolib: Add init_valid_mask exported function
  GPIO: add single-register GPIO via CREG driver
  dt-bindings: Document the Synopsys GPIO via CREG bindings
  gpio: mockup: use device properties instead of platform_data
  gpio: Slightly more helpful debugfs
  gpio: omap: Remove set but not used variable 'dev'
  gpio: omap: drop omap_gpio_list
  Accept partial 'gpio-line-names' property.
  gpio: omap: get rid of the conditional PM runtime calls
  ...
parents b0b6a28b 40f5ff4f
Specifying GPIO information for devices Specifying GPIO information for devices
============================================ =======================================
1) gpios property 1) gpios property
----------------- -----------------
Nodes that makes use of GPIOs should specify them using one or more
properties, each containing a 'gpio-list':
gpio-list ::= <single-gpio> [gpio-list]
single-gpio ::= <gpio-phandle> <gpio-specifier>
gpio-phandle : phandle to gpio controller node
gpio-specifier : Array of #gpio-cells specifying specific gpio
(controller specific)
GPIO properties should be named "[<name>-]gpios", with <name> being the purpose GPIO properties should be named "[<name>-]gpios", with <name> being the purpose
of this GPIO for the device. While a non-existent <name> is considered valid of this GPIO for the device. While a non-existent <name> is considered valid
for compatibility reasons (resolving to the "gpios" property), it is not allowed for compatibility reasons (resolving to the "gpios" property), it is not allowed
...@@ -33,33 +24,27 @@ The following example could be used to describe GPIO pins used as device enable ...@@ -33,33 +24,27 @@ The following example could be used to describe GPIO pins used as device enable
and bit-banged data signals: and bit-banged data signals:
gpio1: gpio1 { gpio1: gpio1 {
gpio-controller gpio-controller;
#gpio-cells = <2>; #gpio-cells = <2>;
}; };
gpio2: gpio2 {
gpio-controller
#gpio-cells = <1>;
};
[...] [...]
enable-gpios = <&gpio2 2>;
data-gpios = <&gpio1 12 0>, data-gpios = <&gpio1 12 0>,
<&gpio1 13 0>, <&gpio1 13 0>,
<&gpio1 14 0>, <&gpio1 14 0>,
<&gpio1 15 0>; <&gpio1 15 0>;
Note that gpio-specifier length is controller dependent. In the In the above example, &gpio1 uses 2 cells to specify a gpio. The first cell is
above example, &gpio1 uses 2 cells to specify a gpio, while &gpio2 a local offset to the GPIO line and the second cell represent consumer flags,
only uses one. such as if the consumer desire the line to be active low (inverted) or open
drain. This is the recommended practice.
gpio-specifier may encode: bank, pin position inside the bank,
whether pin is open-drain and whether pin is logically inverted.
Exact meaning of each specifier cell is controller specific, and must The exact meaning of each specifier cell is controller specific, and must be
be documented in the device tree binding for the device. documented in the device tree binding for the device, but it is strongly
recommended to use the two-cell approach.
Most controllers are however specifying a generic flag bitfield Most controllers are specifying a generic flag bitfield in the last cell, so
in the last cell, so for these, use the macros defined in for these, use the macros defined in
include/dt-bindings/gpio/gpio.h whenever possible: include/dt-bindings/gpio/gpio.h whenever possible:
Example of a node using GPIOs: Example of a node using GPIOs:
...@@ -236,46 +221,40 @@ Example of two SOC GPIO banks defined as gpio-controller nodes: ...@@ -236,46 +221,40 @@ Example of two SOC GPIO banks defined as gpio-controller nodes:
Some or all of the GPIOs provided by a GPIO controller may be routed to pins Some or all of the GPIOs provided by a GPIO controller may be routed to pins
on the package via a pin controller. This allows muxing those pins between on the package via a pin controller. This allows muxing those pins between
GPIO and other functions. GPIO and other functions. It is a fairly common practice among silicon
engineers.
2.2) Ordinary (numerical) GPIO ranges
-------------------------------------
It is useful to represent which GPIOs correspond to which pins on which pin It is useful to represent which GPIOs correspond to which pins on which pin
controllers. The gpio-ranges property described below represents this, and controllers. The gpio-ranges property described below represents this with
contains information structures as follows: a discrete set of ranges mapping pins from the pin controller local number space
to pins in the GPIO controller local number space.
gpio-range-list ::= <single-gpio-range> [gpio-range-list]
single-gpio-range ::= <numeric-gpio-range> | <named-gpio-range>
numeric-gpio-range ::=
<pinctrl-phandle> <gpio-base> <pinctrl-base> <count>
named-gpio-range ::= <pinctrl-phandle> <gpio-base> '<0 0>'
pinctrl-phandle : phandle to pin controller node
gpio-base : Base GPIO ID in the GPIO controller
pinctrl-base : Base pinctrl pin ID in the pin controller
count : The number of GPIOs/pins in this range
The "pin controller node" mentioned above must conform to the bindings
described in ../pinctrl/pinctrl-bindings.txt.
In case named gpio ranges are used (ranges with both <pinctrl-base> and
<count> set to 0), the property gpio-ranges-group-names contains one string
for every single-gpio-range in gpio-ranges:
gpiorange-names-list ::= <gpiorange-name> [gpiorange-names-list]
gpiorange-name : Name of the pingroup associated to the GPIO range in
the respective pin controller.
Elements of gpiorange-names-list corresponding to numeric ranges contain
the empty string. Elements of gpiorange-names-list corresponding to named
ranges contain the name of a pin group defined in the respective pin
controller. The number of pins/GPIOs in the range is the number of pins in
that pin group.
Previous versions of this binding required all pin controller nodes that The format is: <[pin controller phandle], [GPIO controller offset],
were referenced by any gpio-ranges property to contain a property named [pin controller offset], [number of pins]>;
#gpio-range-cells with value <3>. This requirement is now deprecated.
However, that property may still exist in older device trees for The GPIO controller offset pertains to the GPIO controller node containing the
compatibility reasons, and would still be required even in new device range definition.
trees that need to be compatible with older software.
The pin controller node referenced by the phandle must conform to the bindings
described in pinctrl/pinctrl-bindings.txt.
Each offset runs from 0 to N. It is perfectly fine to pile any number of
ranges with just one pin-to-GPIO line mapping if the ranges are concocted, but
in practice these ranges are often lumped in discrete sets.
Example:
gpio-ranges = <&foo 0 20 10>, <&bar 10 50 20>;
Example 1: This means:
- pins 20..29 on pin controller "foo" is mapped to GPIO line 0..9 and
- pins 50..69 on pin controller "bar" is mapped to GPIO line 10..29
Verbose example:
qe_pio_e: gpio-controller@1460 { qe_pio_e: gpio-controller@1460 {
#gpio-cells = <2>; #gpio-cells = <2>;
...@@ -289,7 +268,28 @@ Here, a single GPIO controller has GPIOs 0..9 routed to pin controller ...@@ -289,7 +268,28 @@ Here, a single GPIO controller has GPIOs 0..9 routed to pin controller
pinctrl1's pins 20..29, and GPIOs 10..29 routed to pin controller pinctrl2's pinctrl1's pins 20..29, and GPIOs 10..29 routed to pin controller pinctrl2's
pins 50..69. pins 50..69.
Example 2:
2.3) GPIO ranges from named pin groups
--------------------------------------
It is also possible to use pin groups for gpio ranges when pin groups are the
easiest and most convenient mapping.
Both both <pinctrl-base> and <count> must set to 0 when using named pin groups
names.
The property gpio-ranges-group-names must contain exactly one string for each
range.
Elements of gpio-ranges-group-names must contain the name of a pin group
defined in the respective pin controller. The number of pins/GPIO lines in the
range is the number of pins in that pin group. The number of pins of that
group is defined int the implementation and not in the device tree.
If numerical and named pin groups are mixed, the string corresponding to a
numerical pin range in gpio-ranges-group-names must be empty.
Example:
gpio_pio_i: gpio-controller@14b0 { gpio_pio_i: gpio-controller@14b0 {
#gpio-cells = <2>; #gpio-cells = <2>;
...@@ -306,6 +306,14 @@ Example 2: ...@@ -306,6 +306,14 @@ Example 2:
"bar"; "bar";
}; };
Here, three GPIO ranges are defined wrt. two pin controllers. pinctrl1 GPIO Here, three GPIO ranges are defined referring to two pin controllers.
ranges are defined using pin numbers whereas the GPIO ranges wrt. pinctrl2
are named "foo" and "bar". pinctrl1 GPIO ranges are defined using pin numbers whereas the GPIO ranges
in pinctrl2 are defined using the pin groups named "foo" and "bar".
Previous versions of this binding required all pin controller nodes that
were referenced by any gpio-ranges property to contain a property named
#gpio-range-cells with value <3>. This requirement is now deprecated.
However, that property may still exist in older device trees for
compatibility reasons, and would still be required even in new device
trees that need to be compatible with older software.
...@@ -4,8 +4,10 @@ Required Properties: ...@@ -4,8 +4,10 @@ Required Properties:
- compatible: should contain one or more of the following: - compatible: should contain one or more of the following:
- "renesas,gpio-r8a7743": for R8A7743 (RZ/G1M) compatible GPIO controller. - "renesas,gpio-r8a7743": for R8A7743 (RZ/G1M) compatible GPIO controller.
- "renesas,gpio-r8a7744": for R8A7744 (RZ/G1N) compatible GPIO controller.
- "renesas,gpio-r8a7745": for R8A7745 (RZ/G1E) compatible GPIO controller. - "renesas,gpio-r8a7745": for R8A7745 (RZ/G1E) compatible GPIO controller.
- "renesas,gpio-r8a77470": for R8A77470 (RZ/G1C) compatible GPIO controller. - "renesas,gpio-r8a77470": for R8A77470 (RZ/G1C) compatible GPIO controller.
- "renesas,gpio-r8a774a1": for R8A774A1 (RZ/G2M) compatible GPIO controller.
- "renesas,gpio-r8a7778": for R8A7778 (R-Car M1) compatible GPIO controller. - "renesas,gpio-r8a7778": for R8A7778 (R-Car M1) compatible GPIO controller.
- "renesas,gpio-r8a7779": for R8A7779 (R-Car H1) compatible GPIO controller. - "renesas,gpio-r8a7779": for R8A7779 (R-Car H1) compatible GPIO controller.
- "renesas,gpio-r8a7790": for R8A7790 (R-Car H2) compatible GPIO controller. - "renesas,gpio-r8a7790": for R8A7790 (R-Car H2) compatible GPIO controller.
...@@ -22,7 +24,7 @@ Required Properties: ...@@ -22,7 +24,7 @@ Required Properties:
- "renesas,gpio-r8a77995": for R8A77995 (R-Car D3) compatible GPIO controller. - "renesas,gpio-r8a77995": for R8A77995 (R-Car D3) compatible GPIO controller.
- "renesas,rcar-gen1-gpio": for a generic R-Car Gen1 GPIO controller. - "renesas,rcar-gen1-gpio": for a generic R-Car Gen1 GPIO controller.
- "renesas,rcar-gen2-gpio": for a generic R-Car Gen2 or RZ/G1 GPIO controller. - "renesas,rcar-gen2-gpio": for a generic R-Car Gen2 or RZ/G1 GPIO controller.
- "renesas,rcar-gen3-gpio": for a generic R-Car Gen3 GPIO controller. - "renesas,rcar-gen3-gpio": for a generic R-Car Gen3 or RZ/G2 GPIO controller.
- "renesas,gpio-rcar": deprecated. - "renesas,gpio-rcar": deprecated.
When compatible with the generic version nodes must list the When compatible with the generic version nodes must list the
...@@ -38,7 +40,7 @@ Required Properties: ...@@ -38,7 +40,7 @@ Required Properties:
- #gpio-cells: Should be 2. The first cell is the GPIO number and the second - #gpio-cells: Should be 2. The first cell is the GPIO number and the second
cell specifies GPIO flags, as defined in <dt-bindings/gpio/gpio.h>. Only the cell specifies GPIO flags, as defined in <dt-bindings/gpio/gpio.h>. Only the
GPIO_ACTIVE_HIGH and GPIO_ACTIVE_LOW flags are supported. GPIO_ACTIVE_HIGH and GPIO_ACTIVE_LOW flags are supported.
- gpio-ranges: Range of pins managed by the GPIO controller. - gpio-ranges: See gpio.txt.
Optional properties: Optional properties:
...@@ -46,35 +48,44 @@ Optional properties: ...@@ -46,35 +48,44 @@ Optional properties:
mandatory if the hardware implements a controllable functional clock for mandatory if the hardware implements a controllable functional clock for
the GPIO instance. the GPIO instance.
Please refer to gpio.txt in this directory for details of gpio-ranges property - gpio-reserved-ranges: See gpio.txt.
and the common GPIO bindings used by client devices.
Please refer to gpio.txt in this directory for the common GPIO bindings used by
client devices.
The GPIO controller also acts as an interrupt controller. It uses the default The GPIO controller also acts as an interrupt controller. It uses the default
two cells specifier as described in Documentation/devicetree/bindings/ two cells specifier as described in Documentation/devicetree/bindings/
interrupt-controller/interrupts.txt. interrupt-controller/interrupts.txt.
Example: R8A7779 (R-Car H1) GPIO controller nodes Example: R8A77470 (RZ/G1C) GPIO controller nodes
gpio0: gpio@ffc40000 { gpio0: gpio@e6050000 {
compatible = "renesas,gpio-r8a7779", "renesas,rcar-gen1-gpio"; compatible = "renesas,gpio-r8a77470",
reg = <0xffc40000 0x2c>; "renesas,rcar-gen2-gpio";
interrupt-parent = <&gic>; reg = <0 0xe6050000 0 0x50>;
interrupts = <0 141 0x4>; interrupts = <GIC_SPI 4 IRQ_TYPE_LEVEL_HIGH>;
#gpio-cells = <2>; #gpio-cells = <2>;
gpio-controller; gpio-controller;
gpio-ranges = <&pfc 0 0 32>; gpio-ranges = <&pfc 0 0 23>;
interrupt-controller;
#interrupt-cells = <2>; #interrupt-cells = <2>;
interrupt-controller;
clocks = <&cpg CPG_MOD 912>;
power-domains = <&sysc R8A77470_PD_ALWAYS_ON>;
resets = <&cpg 912>;
}; };
... ...
gpio6: gpio@ffc46000 { gpio3: gpio@e6053000 {
compatible = "renesas,gpio-r8a7779", "renesas,rcar-gen1-gpio"; compatible = "renesas,gpio-r8a77470",
reg = <0xffc46000 0x2c>; "renesas,rcar-gen2-gpio";
interrupt-parent = <&gic>; reg = <0 0xe6053000 0 0x50>;
interrupts = <0 147 0x4>; interrupts = <GIC_SPI 7 IRQ_TYPE_LEVEL_HIGH>;
#gpio-cells = <2>; #gpio-cells = <2>;
gpio-controller; gpio-controller;
gpio-ranges = <&pfc 0 192 9>; gpio-ranges = <&pfc 0 96 30>;
interrupt-controller; gpio-reserved-ranges = <17 10>;
#interrupt-cells = <2>; #interrupt-cells = <2>;
interrupt-controller;
clocks = <&cpg CPG_MOD 909>;
power-domains = <&sysc R8A77470_PD_ALWAYS_ON>;
resets = <&cpg 909>;
}; };
Synopsys GPIO via CREG (Control REGisters) driver
Required properties:
- compatible : "snps,creg-gpio-hsdk" or "snps,creg-gpio-axs10x".
- reg : Exactly one register range with length 0x4.
- #gpio-cells : Since the generic GPIO binding is used, the
amount of cells must be specified as 2. The first cell is the
pin number, the second cell is used to specify optional parameters:
See "gpio-specifier" in .../devicetree/bindings/gpio/gpio.txt.
- gpio-controller : Marks the device node as a GPIO controller.
- ngpios: Number of GPIO pins.
Example:
gpio: gpio@f00014b0 {
compatible = "snps,creg-gpio-hsdk";
reg = <0xf00014b0 0x4>;
gpio-controller;
#gpio-cells = <2>;
ngpios = <2>;
};
...@@ -193,3 +193,27 @@ And the table can be added to the board code as follows:: ...@@ -193,3 +193,27 @@ And the table can be added to the board code as follows::
The line will be hogged as soon as the gpiochip is created or - in case the The line will be hogged as soon as the gpiochip is created or - in case the
chip was created earlier - when the hog table is registered. chip was created earlier - when the hog table is registered.
Arrays of pins
--------------
In addition to requesting pins belonging to a function one by one, a device may
also request an array of pins assigned to the function. The way those pins are
mapped to the device determines if the array qualifies for fast bitmap
processing. If yes, a bitmap is passed over get/set array functions directly
between a caller and a respective .get/set_multiple() callback of a GPIO chip.
In order to qualify for fast bitmap processing, the array must meet the
following requirements:
- pin hardware number of array member 0 must also be 0,
- pin hardware numbers of consecutive array members which belong to the same
chip as member 0 does must also match their array indexes.
Otherwise fast bitmap processing path is not used in order to avoid consecutive
pins which belong to the same chip but are not in hardware order being processed
separately.
If the array applies for fast bitmap processing path, pins which belong to
different chips than member 0 does, as well as those with indexes different from
their hardware pin numbers, are excluded from the fast path, both input and
output. Moreover, open drain and open source pins are excluded from fast bitmap
output processing.
...@@ -109,9 +109,11 @@ For a function using multiple GPIOs all of those can be obtained with one call:: ...@@ -109,9 +109,11 @@ For a function using multiple GPIOs all of those can be obtained with one call::
enum gpiod_flags flags) enum gpiod_flags flags)
This function returns a struct gpio_descs which contains an array of This function returns a struct gpio_descs which contains an array of
descriptors:: descriptors. It also contains a pointer to a gpiolib private structure which,
if passed back to get/set array functions, may speed up I/O proocessing::
struct gpio_descs { struct gpio_descs {
struct gpio_array *info;
unsigned int ndescs; unsigned int ndescs;
struct gpio_desc *desc[]; struct gpio_desc *desc[];
} }
...@@ -323,29 +325,37 @@ The following functions get or set the values of an array of GPIOs:: ...@@ -323,29 +325,37 @@ The following functions get or set the values of an array of GPIOs::
int gpiod_get_array_value(unsigned int array_size, int gpiod_get_array_value(unsigned int array_size,
struct gpio_desc **desc_array, struct gpio_desc **desc_array,
int *value_array); struct gpio_array *array_info,
unsigned long *value_bitmap);
int gpiod_get_raw_array_value(unsigned int array_size, int gpiod_get_raw_array_value(unsigned int array_size,
struct gpio_desc **desc_array, struct gpio_desc **desc_array,
int *value_array); struct gpio_array *array_info,
unsigned long *value_bitmap);
int gpiod_get_array_value_cansleep(unsigned int array_size, int gpiod_get_array_value_cansleep(unsigned int array_size,
struct gpio_desc **desc_array, struct gpio_desc **desc_array,
int *value_array); struct gpio_array *array_info,
unsigned long *value_bitmap);
int gpiod_get_raw_array_value_cansleep(unsigned int array_size, int gpiod_get_raw_array_value_cansleep(unsigned int array_size,
struct gpio_desc **desc_array, struct gpio_desc **desc_array,
int *value_array); struct gpio_array *array_info,
unsigned long *value_bitmap);
void gpiod_set_array_value(unsigned int array_size, int gpiod_set_array_value(unsigned int array_size,
struct gpio_desc **desc_array, struct gpio_desc **desc_array,
int *value_array) struct gpio_array *array_info,
void gpiod_set_raw_array_value(unsigned int array_size, unsigned long *value_bitmap)
int gpiod_set_raw_array_value(unsigned int array_size,
struct gpio_desc **desc_array, struct gpio_desc **desc_array,
int *value_array) struct gpio_array *array_info,
void gpiod_set_array_value_cansleep(unsigned int array_size, unsigned long *value_bitmap)
int gpiod_set_array_value_cansleep(unsigned int array_size,
struct gpio_desc **desc_array, struct gpio_desc **desc_array,
int *value_array) struct gpio_array *array_info,
void gpiod_set_raw_array_value_cansleep(unsigned int array_size, unsigned long *value_bitmap)
int gpiod_set_raw_array_value_cansleep(unsigned int array_size,
struct gpio_desc **desc_array, struct gpio_desc **desc_array,
int *value_array) struct gpio_array *array_info,
unsigned long *value_bitmap)
The array can be an arbitrary set of GPIOs. The functions will try to access The array can be an arbitrary set of GPIOs. The functions will try to access
GPIOs belonging to the same bank or chip simultaneously if supported by the GPIOs belonging to the same bank or chip simultaneously if supported by the
...@@ -356,8 +366,9 @@ accessed sequentially. ...@@ -356,8 +366,9 @@ accessed sequentially.
The functions take three arguments: The functions take three arguments:
* array_size - the number of array elements * array_size - the number of array elements
* desc_array - an array of GPIO descriptors * desc_array - an array of GPIO descriptors
* value_array - an array to store the GPIOs' values (get) or * array_info - optional information obtained from gpiod_array_get()
an array of values to assign to the GPIOs (set) * value_bitmap - a bitmap to store the GPIOs' values (get) or
a bitmap of values to assign to the GPIOs (set)
The descriptor array can be obtained using the gpiod_get_array() function The descriptor array can be obtained using the gpiod_get_array() function
or one of its variants. If the group of descriptors returned by that function or one of its variants. If the group of descriptors returned by that function
...@@ -366,16 +377,25 @@ the struct gpio_descs returned by gpiod_get_array():: ...@@ -366,16 +377,25 @@ the struct gpio_descs returned by gpiod_get_array()::
struct gpio_descs *my_gpio_descs = gpiod_get_array(...); struct gpio_descs *my_gpio_descs = gpiod_get_array(...);
gpiod_set_array_value(my_gpio_descs->ndescs, my_gpio_descs->desc, gpiod_set_array_value(my_gpio_descs->ndescs, my_gpio_descs->desc,
my_gpio_values); my_gpio_descs->info, my_gpio_value_bitmap);
It is also possible to access a completely arbitrary array of descriptors. The It is also possible to access a completely arbitrary array of descriptors. The
descriptors may be obtained using any combination of gpiod_get() and descriptors may be obtained using any combination of gpiod_get() and
gpiod_get_array(). Afterwards the array of descriptors has to be setup gpiod_get_array(). Afterwards the array of descriptors has to be setup
manually before it can be passed to one of the above functions. manually before it can be passed to one of the above functions. In that case,
array_info should be set to NULL.
Note that for optimal performance GPIOs belonging to the same chip should be Note that for optimal performance GPIOs belonging to the same chip should be
contiguous within the array of descriptors. contiguous within the array of descriptors.
Still better performance may be achieved if array indexes of the descriptors
match hardware pin numbers of a single chip. If an array passed to a get/set
array function matches the one obtained from gpiod_get_array() and array_info
associated with the array is also passed, the function may take a fast bitmap
processing path, passing the value_bitmap argument directly to the respective
.get/set_multiple() callback of the chip. That allows for utilization of GPIO
banks as data I/O ports without much loss of performance.
The return value of gpiod_get_array_value() and its variants is 0 on success The return value of gpiod_get_array_value() and its variants is 0 on success
or negative on error. Note the difference to gpiod_get_value(), which returns or negative on error. Note the difference to gpiod_get_value(), which returns
0 or 1 on success to convey the GPIO value. With the array functions, the GPIO 0 or 1 on success to convey the GPIO value. With the array functions, the GPIO
......
...@@ -374,7 +374,28 @@ When implementing an irqchip inside a GPIO driver, these two functions should ...@@ -374,7 +374,28 @@ When implementing an irqchip inside a GPIO driver, these two functions should
typically be called in the .startup() and .shutdown() callbacks from the typically be called in the .startup() and .shutdown() callbacks from the
irqchip. irqchip.
When using the gpiolib irqchip helpers, these callback are automatically When using the gpiolib irqchip helpers, these callbacks are automatically
assigned.
Disabling and enabling IRQs
---------------------------
When a GPIO is used as an IRQ signal, then gpiolib also needs to know if
the IRQ is enabled or disabled. In order to inform gpiolib about this,
a driver should call::
void gpiochip_disable_irq(struct gpio_chip *chip, unsigned int offset)
This allows drivers to drive the GPIO as an output while the IRQ is
disabled. When the IRQ is enabled again, a driver should call::
void gpiochip_enable_irq(struct gpio_chip *chip, unsigned int offset)
When implementing an irqchip inside a GPIO driver, these two functions should
typically be called in the .irq_disable() and .irq_enable() callbacks from the
irqchip.
When using the gpiolib irqchip helpers, these callbacks are automatically
assigned. assigned.
Real-Time compliance for GPIO IRQ chips Real-Time compliance for GPIO IRQ chips
......
...@@ -38,7 +38,7 @@ Device tree support ...@@ -38,7 +38,7 @@ Device tree support
Device-managed API Device-managed API
================== ==================
.. kernel-doc:: drivers/gpio/devres.c .. kernel-doc:: drivers/gpio/gpiolib-devres.c
:export: :export:
sysfs helpers sysfs helpers
......
...@@ -7396,6 +7396,12 @@ T: git https://github.com/intel/gvt-linux.git ...@@ -7396,6 +7396,12 @@ T: git https://github.com/intel/gvt-linux.git
S: Supported S: Supported
F: drivers/gpu/drm/i915/gvt/ F: drivers/gpu/drm/i915/gvt/
INTEL PMIC GPIO DRIVER
R: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
S: Maintained
F: drivers/gpio/gpio-*cove.c
F: drivers/gpio/gpio-msic.c
INTEL HID EVENT DRIVER INTEL HID EVENT DRIVER
M: Alex Hung <alex.hung@canonical.com> M: Alex Hung <alex.hung@canonical.com>
L: platform-driver-x86@vger.kernel.org L: platform-driver-x86@vger.kernel.org
...@@ -13352,6 +13358,7 @@ M: Uwe Kleine-König <u.kleine-koenig@pengutronix.de> ...@@ -13352,6 +13358,7 @@ M: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
R: Pengutronix Kernel Team <kernel@pengutronix.de> R: Pengutronix Kernel Team <kernel@pengutronix.de>
S: Supported S: Supported
F: drivers/siox/* F: drivers/siox/*
F: drivers/gpio/gpio-siox.c
F: include/trace/events/siox.h F: include/trace/events/siox.h
SIS 190 ETHERNET DRIVER SIS 190 ETHERNET DRIVER
...@@ -14079,6 +14086,12 @@ S: Supported ...@@ -14079,6 +14086,12 @@ S: Supported
F: drivers/reset/reset-axs10x.c F: drivers/reset/reset-axs10x.c
F: Documentation/devicetree/bindings/reset/snps,axs10x-reset.txt F: Documentation/devicetree/bindings/reset/snps,axs10x-reset.txt
SYNOPSYS CREG GPIO DRIVER
M: Eugeniy Paltsev <Eugeniy.Paltsev@synopsys.com>
S: Maintained
F: drivers/gpio/gpio-creg-snps.c
F: Documentation/devicetree/bindings/gpio/snps,creg-gpio.txt
SYNOPSYS DESIGNWARE 8250 UART DRIVER SYNOPSYS DESIGNWARE 8250 UART DRIVER
R: Andy Shevchenko <andriy.shevchenko@linux.intel.com> R: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
S: Maintained S: Maintained
......
...@@ -130,10 +130,10 @@ static struct platform_device davinci_fb_device = { ...@@ -130,10 +130,10 @@ static struct platform_device davinci_fb_device = {
}; };
static const struct gpio_led ntosd2_leds[] = { static const struct gpio_led ntosd2_leds[] = {
{ .name = "led1_green", .gpio = GPIO(10), }, { .name = "led1_green", .gpio = 10, },
{ .name = "led1_red", .gpio = GPIO(11), }, { .name = "led1_red", .gpio = 11, },
{ .name = "led2_green", .gpio = GPIO(12), }, { .name = "led2_green", .gpio = 12, },
{ .name = "led2_red", .gpio = GPIO(13), }, { .name = "led2_red", .gpio = 13, },
}; };
static struct gpio_led_platform_data ntosd2_leds_data = { static struct gpio_led_platform_data ntosd2_leds_data = {
......
...@@ -141,6 +141,15 @@ EXPORT_SYMBOL_GPL(ep93xx_chip_revision); ...@@ -141,6 +141,15 @@ EXPORT_SYMBOL_GPL(ep93xx_chip_revision);
*************************************************************************/ *************************************************************************/
static struct resource ep93xx_gpio_resource[] = { static struct resource ep93xx_gpio_resource[] = {
DEFINE_RES_MEM(EP93XX_GPIO_PHYS_BASE, 0xcc), DEFINE_RES_MEM(EP93XX_GPIO_PHYS_BASE, 0xcc),
DEFINE_RES_IRQ(IRQ_EP93XX_GPIO_AB),
DEFINE_RES_IRQ(IRQ_EP93XX_GPIO0MUX),
DEFINE_RES_IRQ(IRQ_EP93XX_GPIO1MUX),
DEFINE_RES_IRQ(IRQ_EP93XX_GPIO2MUX),
DEFINE_RES_IRQ(IRQ_EP93XX_GPIO3MUX),
DEFINE_RES_IRQ(IRQ_EP93XX_GPIO4MUX),
DEFINE_RES_IRQ(IRQ_EP93XX_GPIO5MUX),
DEFINE_RES_IRQ(IRQ_EP93XX_GPIO6MUX),
DEFINE_RES_IRQ(IRQ_EP93XX_GPIO7MUX),
}; };
static struct platform_device ep93xx_gpio_device = { static struct platform_device ep93xx_gpio_device = {
......
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
* published by the Free Software Foundation. * published by the Free Software Foundation.
*/ */
#include <linux/cpu_pm.h>
#include <linux/suspend.h> #include <linux/suspend.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/proc_fs.h> #include <linux/proc_fs.h>
...@@ -29,8 +30,6 @@ ...@@ -29,8 +30,6 @@
#include <linux/clk-provider.h> #include <linux/clk-provider.h>
#include <linux/irq.h> #include <linux/irq.h>
#include <linux/time.h> #include <linux/time.h>
#include <linux/gpio.h>
#include <linux/platform_data/gpio-omap.h>
#include <asm/fncpy.h> #include <asm/fncpy.h>
...@@ -87,7 +86,7 @@ static int omap2_enter_full_retention(void) ...@@ -87,7 +86,7 @@ static int omap2_enter_full_retention(void)
l = omap_ctrl_readl(OMAP2_CONTROL_DEVCONF0) | OMAP24XX_USBSTANDBYCTRL; l = omap_ctrl_readl(OMAP2_CONTROL_DEVCONF0) | OMAP24XX_USBSTANDBYCTRL;
omap_ctrl_writel(l, OMAP2_CONTROL_DEVCONF0); omap_ctrl_writel(l, OMAP2_CONTROL_DEVCONF0);
omap2_gpio_prepare_for_idle(0); cpu_cluster_pm_enter();
/* One last check for pending IRQs to avoid extra latency due /* One last check for pending IRQs to avoid extra latency due
* to sleeping unnecessarily. */ * to sleeping unnecessarily. */
...@@ -100,7 +99,7 @@ static int omap2_enter_full_retention(void) ...@@ -100,7 +99,7 @@ static int omap2_enter_full_retention(void)
OMAP_SDRC_REGADDR(SDRC_POWER)); OMAP_SDRC_REGADDR(SDRC_POWER));
no_sleep: no_sleep:
omap2_gpio_resume_after_idle(); cpu_cluster_pm_exit();
clk_enable(osc_ck); clk_enable(osc_ck);
......
...@@ -18,19 +18,18 @@ ...@@ -18,19 +18,18 @@
* published by the Free Software Foundation. * published by the Free Software Foundation.
*/ */
#include <linux/cpu_pm.h>
#include <linux/pm.h> #include <linux/pm.h>
#include <linux/suspend.h> #include <linux/suspend.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/list.h> #include <linux/list.h>
#include <linux/err.h> #include <linux/err.h>
#include <linux/gpio.h>
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/omap-dma.h> #include <linux/omap-dma.h>
#include <linux/omap-gpmc.h> #include <linux/omap-gpmc.h>
#include <linux/platform_data/gpio-omap.h>
#include <trace/events/power.h> #include <trace/events/power.h>
...@@ -197,7 +196,6 @@ void omap_sram_idle(void) ...@@ -197,7 +196,6 @@ void omap_sram_idle(void)
int mpu_next_state = PWRDM_POWER_ON; int mpu_next_state = PWRDM_POWER_ON;
int per_next_state = PWRDM_POWER_ON; int per_next_state = PWRDM_POWER_ON;
int core_next_state = PWRDM_POWER_ON; int core_next_state = PWRDM_POWER_ON;
int per_going_off;
u32 sdrc_pwr = 0; u32 sdrc_pwr = 0;
mpu_next_state = pwrdm_read_next_pwrst(mpu_pwrdm); mpu_next_state = pwrdm_read_next_pwrst(mpu_pwrdm);
...@@ -227,10 +225,8 @@ void omap_sram_idle(void) ...@@ -227,10 +225,8 @@ void omap_sram_idle(void)
pwrdm_pre_transition(NULL); pwrdm_pre_transition(NULL);
/* PER */ /* PER */
if (per_next_state < PWRDM_POWER_ON) { if (per_next_state == PWRDM_POWER_OFF)
per_going_off = (per_next_state == PWRDM_POWER_OFF) ? 1 : 0; cpu_cluster_pm_enter();
omap2_gpio_prepare_for_idle(per_going_off);
}
/* CORE */ /* CORE */
if (core_next_state < PWRDM_POWER_ON) { if (core_next_state < PWRDM_POWER_ON) {
...@@ -295,8 +291,8 @@ void omap_sram_idle(void) ...@@ -295,8 +291,8 @@ void omap_sram_idle(void)
pwrdm_post_transition(NULL); pwrdm_post_transition(NULL);
/* PER */ /* PER */
if (per_next_state < PWRDM_POWER_ON) if (per_next_state == PWRDM_POWER_OFF)
omap2_gpio_resume_after_idle(); cpu_cluster_pm_exit();
} }
static void omap3_pm_idle(void) static void omap3_pm_idle(void)
......
...@@ -51,12 +51,4 @@ typedef enum { ...@@ -51,12 +51,4 @@ typedef enum {
extern void vr41xx_set_irq_level(unsigned int pin, irq_level_t level); extern void vr41xx_set_irq_level(unsigned int pin, irq_level_t level);
typedef enum {
GPIO_PULL_DOWN,
GPIO_PULL_UP,
GPIO_PULL_DISABLE,
} gpio_pull_t;
extern int vr41xx_gpio_pullupdown(unsigned int pin, gpio_pull_t pull);
#endif /* __NEC_VR41XX_GIU_H */ #endif /* __NEC_VR41XX_GIU_H */
...@@ -24,7 +24,6 @@ ...@@ -24,7 +24,6 @@
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/leds.h> #include <linux/leds.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/platform_data/gpio-ts5500.h>
#include <linux/platform_data/max197.h> #include <linux/platform_data/max197.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/slab.h> #include <linux/slab.h>
......
...@@ -62,20 +62,15 @@ static void hd44780_strobe_gpio(struct hd44780 *hd) ...@@ -62,20 +62,15 @@ static void hd44780_strobe_gpio(struct hd44780 *hd)
/* write to an LCD panel register in 8 bit GPIO mode */ /* write to an LCD panel register in 8 bit GPIO mode */
static void hd44780_write_gpio8(struct hd44780 *hd, u8 val, unsigned int rs) static void hd44780_write_gpio8(struct hd44780 *hd, u8 val, unsigned int rs)
{ {
int values[10]; /* for DATA[0-7], RS, RW */ DECLARE_BITMAP(values, 10); /* for DATA[0-7], RS, RW */
unsigned int i, n; unsigned int n;
for (i = 0; i < 8; i++) values[0] = val;
values[PIN_DATA0 + i] = !!(val & BIT(i)); __assign_bit(8, values, rs);
values[PIN_CTRL_RS] = rs; n = hd->pins[PIN_CTRL_RW] ? 10 : 9;
n = 9;
if (hd->pins[PIN_CTRL_RW]) {
values[PIN_CTRL_RW] = 0;
n++;
}
/* Present the data to the port */ /* Present the data to the port */
gpiod_set_array_value_cansleep(n, &hd->pins[PIN_DATA0], values); gpiod_set_array_value_cansleep(n, &hd->pins[PIN_DATA0], NULL, values);
hd44780_strobe_gpio(hd); hd44780_strobe_gpio(hd);
} }
...@@ -83,32 +78,25 @@ static void hd44780_write_gpio8(struct hd44780 *hd, u8 val, unsigned int rs) ...@@ -83,32 +78,25 @@ static void hd44780_write_gpio8(struct hd44780 *hd, u8 val, unsigned int rs)
/* write to an LCD panel register in 4 bit GPIO mode */ /* write to an LCD panel register in 4 bit GPIO mode */
static void hd44780_write_gpio4(struct hd44780 *hd, u8 val, unsigned int rs) static void hd44780_write_gpio4(struct hd44780 *hd, u8 val, unsigned int rs)
{ {
int values[10]; /* for DATA[0-7], RS, RW, but DATA[0-3] is unused */ DECLARE_BITMAP(values, 6); /* for DATA[4-7], RS, RW */
unsigned int i, n; unsigned int n;
/* High nibble + RS, RW */ /* High nibble + RS, RW */
for (i = 4; i < 8; i++) values[0] = val >> 4;
values[PIN_DATA0 + i] = !!(val & BIT(i)); __assign_bit(4, values, rs);
values[PIN_CTRL_RS] = rs; n = hd->pins[PIN_CTRL_RW] ? 6 : 5;
n = 5;
if (hd->pins[PIN_CTRL_RW]) {
values[PIN_CTRL_RW] = 0;
n++;
}
/* Present the data to the port */ /* Present the data to the port */
gpiod_set_array_value_cansleep(n, &hd->pins[PIN_DATA4], gpiod_set_array_value_cansleep(n, &hd->pins[PIN_DATA4], NULL, values);
&values[PIN_DATA4]);
hd44780_strobe_gpio(hd); hd44780_strobe_gpio(hd);
/* Low nibble */ /* Low nibble */
for (i = 0; i < 4; i++) values[0] &= ~0x0fUL;
values[PIN_DATA4 + i] = !!(val & BIT(i)); values[0] |= val & 0x0f;
/* Present the data to the port */ /* Present the data to the port */
gpiod_set_array_value_cansleep(n, &hd->pins[PIN_DATA4], gpiod_set_array_value_cansleep(n, &hd->pins[PIN_DATA4], NULL, values);
&values[PIN_DATA4]);
hd44780_strobe_gpio(hd); hd44780_strobe_gpio(hd);
} }
...@@ -155,23 +143,16 @@ static void hd44780_write_cmd_gpio4(struct charlcd *lcd, int cmd) ...@@ -155,23 +143,16 @@ static void hd44780_write_cmd_gpio4(struct charlcd *lcd, int cmd)
/* Send 4-bits of a command to the LCD panel in raw 4 bit GPIO mode */ /* Send 4-bits of a command to the LCD panel in raw 4 bit GPIO mode */
static void hd44780_write_cmd_raw_gpio4(struct charlcd *lcd, int cmd) static void hd44780_write_cmd_raw_gpio4(struct charlcd *lcd, int cmd)
{ {
int values[10]; /* for DATA[0-7], RS, RW, but DATA[0-3] is unused */ DECLARE_BITMAP(values, 6); /* for DATA[4-7], RS, RW */
struct hd44780 *hd = lcd->drvdata; struct hd44780 *hd = lcd->drvdata;
unsigned int i, n; unsigned int n;
/* Command nibble + RS, RW */ /* Command nibble + RS, RW */
for (i = 0; i < 4; i++) values[0] = cmd & 0x0f;
values[PIN_DATA4 + i] = !!(cmd & BIT(i)); n = hd->pins[PIN_CTRL_RW] ? 6 : 5;
values[PIN_CTRL_RS] = 0;
n = 5;
if (hd->pins[PIN_CTRL_RW]) {
values[PIN_CTRL_RW] = 0;
n++;
}
/* Present the data to the port */ /* Present the data to the port */
gpiod_set_array_value_cansleep(n, &hd->pins[PIN_DATA4], gpiod_set_array_value_cansleep(n, &hd->pins[PIN_DATA4], NULL, values);
&values[PIN_DATA4]);
hd44780_strobe_gpio(hd); hd44780_strobe_gpio(hd);
} }
......
...@@ -110,13 +110,12 @@ static void ts_nbus_set_direction(struct ts_nbus *ts_nbus, int direction) ...@@ -110,13 +110,12 @@ static void ts_nbus_set_direction(struct ts_nbus *ts_nbus, int direction)
*/ */
static void ts_nbus_reset_bus(struct ts_nbus *ts_nbus) static void ts_nbus_reset_bus(struct ts_nbus *ts_nbus)
{ {
int i; DECLARE_BITMAP(values, 8);
int values[8];
for (i = 0; i < 8; i++) values[0] = 0;
values[i] = 0;
gpiod_set_array_value_cansleep(8, ts_nbus->data->desc, values); gpiod_set_array_value_cansleep(8, ts_nbus->data->desc,
ts_nbus->data->info, values);
gpiod_set_value_cansleep(ts_nbus->csn, 0); gpiod_set_value_cansleep(ts_nbus->csn, 0);
gpiod_set_value_cansleep(ts_nbus->strobe, 0); gpiod_set_value_cansleep(ts_nbus->strobe, 0);
gpiod_set_value_cansleep(ts_nbus->ale, 0); gpiod_set_value_cansleep(ts_nbus->ale, 0);
...@@ -157,16 +156,11 @@ static int ts_nbus_read_byte(struct ts_nbus *ts_nbus, u8 *val) ...@@ -157,16 +156,11 @@ static int ts_nbus_read_byte(struct ts_nbus *ts_nbus, u8 *val)
static void ts_nbus_write_byte(struct ts_nbus *ts_nbus, u8 byte) static void ts_nbus_write_byte(struct ts_nbus *ts_nbus, u8 byte)
{ {
struct gpio_descs *gpios = ts_nbus->data; struct gpio_descs *gpios = ts_nbus->data;
int i; DECLARE_BITMAP(values, 8);
int values[8];
for (i = 0; i < 8; i++) values[0] = byte;
if (byte & BIT(i))
values[i] = 1;
else
values[i] = 0;
gpiod_set_array_value_cansleep(8, gpios->desc, values); gpiod_set_array_value_cansleep(8, gpios->desc, gpios->info, values);
} }
/* /*
......
...@@ -200,6 +200,7 @@ config GPIO_EP93XX ...@@ -200,6 +200,7 @@ config GPIO_EP93XX
def_bool y def_bool y
depends on ARCH_EP93XX depends on ARCH_EP93XX
select GPIO_GENERIC select GPIO_GENERIC
select GPIOLIB_IRQCHIP
config GPIO_EXAR config GPIO_EXAR
tristate "Support for GPIO pins on XR17V352/354/358" tristate "Support for GPIO pins on XR17V352/354/358"
...@@ -428,6 +429,24 @@ config GPIO_REG ...@@ -428,6 +429,24 @@ config GPIO_REG
A 32-bit single register GPIO fixed in/out implementation. This A 32-bit single register GPIO fixed in/out implementation. This
can be used to represent any register as a set of GPIO signals. can be used to represent any register as a set of GPIO signals.
config GPIO_SIOX
tristate "SIOX GPIO support"
depends on SIOX
select GPIOLIB_IRQCHIP
help
Say yes here to support SIOX I/O devices. These are units connected
via a SIOX bus and have a number of fixed-direction I/O lines.
config GPIO_SNPS_CREG
bool "Synopsys GPIO via CREG (Control REGisters) driver"
depends on ARC || COMPILE_TEST
depends on OF_GPIO
help
This driver supports GPIOs via CREG on various Synopsys SoCs.
This is a single-register MMIO GPIO driver for complex cases
where only several fields in register belong to GPIO lines and
each GPIO line owns a field with different length and on/off value.
config GPIO_SPEAR_SPICS config GPIO_SPEAR_SPICS
bool "ST SPEAr13xx SPI Chip Select as GPIO support" bool "ST SPEAr13xx SPI Chip Select as GPIO support"
depends on PLAT_SPEAR depends on PLAT_SPEAR
...@@ -469,6 +488,7 @@ config GPIO_SYSCON ...@@ -469,6 +488,7 @@ config GPIO_SYSCON
config GPIO_TB10X config GPIO_TB10X
bool bool
select GPIO_GENERIC
select GENERIC_IRQ_CHIP select GENERIC_IRQ_CHIP
select OF_GPIO select OF_GPIO
......
...@@ -3,8 +3,8 @@ ...@@ -3,8 +3,8 @@
ccflags-$(CONFIG_DEBUG_GPIO) += -DDEBUG ccflags-$(CONFIG_DEBUG_GPIO) += -DDEBUG
obj-$(CONFIG_GPIOLIB) += devres.o
obj-$(CONFIG_GPIOLIB) += gpiolib.o obj-$(CONFIG_GPIOLIB) += gpiolib.o
obj-$(CONFIG_GPIOLIB) += gpiolib-devres.o
obj-$(CONFIG_GPIOLIB) += gpiolib-legacy.o obj-$(CONFIG_GPIOLIB) += gpiolib-legacy.o
obj-$(CONFIG_GPIOLIB) += gpiolib-devprop.o obj-$(CONFIG_GPIOLIB) += gpiolib-devprop.o
obj-$(CONFIG_OF_GPIO) += gpiolib-of.o obj-$(CONFIG_OF_GPIO) += gpiolib-of.o
...@@ -110,6 +110,7 @@ obj-$(CONFIG_GPIO_REG) += gpio-reg.o ...@@ -110,6 +110,7 @@ obj-$(CONFIG_GPIO_REG) += gpio-reg.o
obj-$(CONFIG_ARCH_SA1100) += gpio-sa1100.o obj-$(CONFIG_ARCH_SA1100) += gpio-sa1100.o
obj-$(CONFIG_GPIO_SCH) += gpio-sch.o obj-$(CONFIG_GPIO_SCH) += gpio-sch.o
obj-$(CONFIG_GPIO_SCH311X) += gpio-sch311x.o obj-$(CONFIG_GPIO_SCH311X) += gpio-sch311x.o
obj-$(CONFIG_GPIO_SNPS_CREG) += gpio-creg-snps.o
obj-$(CONFIG_GPIO_SODAVILLE) += gpio-sodaville.o obj-$(CONFIG_GPIO_SODAVILLE) += gpio-sodaville.o
obj-$(CONFIG_GPIO_SPEAR_SPICS) += gpio-spear-spics.o obj-$(CONFIG_GPIO_SPEAR_SPICS) += gpio-spear-spics.o
obj-$(CONFIG_GPIO_SPRD) += gpio-sprd.o obj-$(CONFIG_GPIO_SPRD) += gpio-sprd.o
...@@ -124,6 +125,7 @@ obj-$(CONFIG_GPIO_TEGRA186) += gpio-tegra186.o ...@@ -124,6 +125,7 @@ obj-$(CONFIG_GPIO_TEGRA186) += gpio-tegra186.o
obj-$(CONFIG_GPIO_THUNDERX) += gpio-thunderx.o obj-$(CONFIG_GPIO_THUNDERX) += gpio-thunderx.o
obj-$(CONFIG_GPIO_TIMBERDALE) += gpio-timberdale.o obj-$(CONFIG_GPIO_TIMBERDALE) += gpio-timberdale.o
obj-$(CONFIG_GPIO_PALMAS) += gpio-palmas.o obj-$(CONFIG_GPIO_PALMAS) += gpio-palmas.o
obj-$(CONFIG_GPIO_SIOX) += gpio-siox.o
obj-$(CONFIG_GPIO_TPIC2810) += gpio-tpic2810.o obj-$(CONFIG_GPIO_TPIC2810) += gpio-tpic2810.o
obj-$(CONFIG_GPIO_TPS65086) += gpio-tps65086.o obj-$(CONFIG_GPIO_TPS65086) += gpio-tps65086.o
obj-$(CONFIG_GPIO_TPS65218) += gpio-tps65218.o obj-$(CONFIG_GPIO_TPS65218) += gpio-tps65218.o
......
...@@ -172,7 +172,7 @@ static struct platform_driver adp5520_gpio_driver = { ...@@ -172,7 +172,7 @@ static struct platform_driver adp5520_gpio_driver = {
module_platform_driver(adp5520_gpio_driver); module_platform_driver(adp5520_gpio_driver);
MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>"); MODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>");
MODULE_DESCRIPTION("GPIO ADP5520 Driver"); MODULE_DESCRIPTION("GPIO ADP5520 Driver");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:adp5520-gpio"); MODULE_ALIAS("platform:adp5520-gpio");
...@@ -494,6 +494,6 @@ static struct i2c_driver adp5588_gpio_driver = { ...@@ -494,6 +494,6 @@ static struct i2c_driver adp5588_gpio_driver = {
module_i2c_driver(adp5588_gpio_driver); module_i2c_driver(adp5588_gpio_driver);
MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>"); MODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>");
MODULE_DESCRIPTION("GPIO ADP5588 Driver"); MODULE_DESCRIPTION("GPIO ADP5588 Driver");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
...@@ -373,6 +373,7 @@ static void bcm_kona_gpio_irq_mask(struct irq_data *d) ...@@ -373,6 +373,7 @@ static void bcm_kona_gpio_irq_mask(struct irq_data *d)
val = readl(reg_base + GPIO_INT_MASK(bank_id)); val = readl(reg_base + GPIO_INT_MASK(bank_id));
val |= BIT(bit); val |= BIT(bit);
writel(val, reg_base + GPIO_INT_MASK(bank_id)); writel(val, reg_base + GPIO_INT_MASK(bank_id));
gpiochip_disable_irq(&kona_gpio->gpio_chip, gpio);
raw_spin_unlock_irqrestore(&kona_gpio->lock, flags); raw_spin_unlock_irqrestore(&kona_gpio->lock, flags);
} }
...@@ -394,6 +395,7 @@ static void bcm_kona_gpio_irq_unmask(struct irq_data *d) ...@@ -394,6 +395,7 @@ static void bcm_kona_gpio_irq_unmask(struct irq_data *d)
val = readl(reg_base + GPIO_INT_MSKCLR(bank_id)); val = readl(reg_base + GPIO_INT_MSKCLR(bank_id));
val |= BIT(bit); val |= BIT(bit);
writel(val, reg_base + GPIO_INT_MSKCLR(bank_id)); writel(val, reg_base + GPIO_INT_MSKCLR(bank_id));
gpiochip_enable_irq(&kona_gpio->gpio_chip, gpio);
raw_spin_unlock_irqrestore(&kona_gpio->lock, flags); raw_spin_unlock_irqrestore(&kona_gpio->lock, flags);
} }
...@@ -485,23 +487,15 @@ static void bcm_kona_gpio_irq_handler(struct irq_desc *desc) ...@@ -485,23 +487,15 @@ static void bcm_kona_gpio_irq_handler(struct irq_desc *desc)
static int bcm_kona_gpio_irq_reqres(struct irq_data *d) static int bcm_kona_gpio_irq_reqres(struct irq_data *d)
{ {
struct bcm_kona_gpio *kona_gpio = irq_data_get_irq_chip_data(d); struct bcm_kona_gpio *kona_gpio = irq_data_get_irq_chip_data(d);
int ret;
ret = gpiochip_lock_as_irq(&kona_gpio->gpio_chip, d->hwirq); return gpiochip_reqres_irq(&kona_gpio->gpio_chip, d->hwirq);
if (ret) {
dev_err(kona_gpio->gpio_chip.parent,
"unable to lock HW IRQ %lu for IRQ\n",
d->hwirq);
return ret;
}
return 0;
} }
static void bcm_kona_gpio_irq_relres(struct irq_data *d) static void bcm_kona_gpio_irq_relres(struct irq_data *d)
{ {
struct bcm_kona_gpio *kona_gpio = irq_data_get_irq_chip_data(d); struct bcm_kona_gpio *kona_gpio = irq_data_get_irq_chip_data(d);
gpiochip_unlock_as_irq(&kona_gpio->gpio_chip, d->hwirq); gpiochip_relres_irq(&kona_gpio->gpio_chip, d->hwirq);
} }
static struct irq_chip bcm_gpio_irq_chip = { static struct irq_chip bcm_gpio_irq_chip = {
......
...@@ -664,6 +664,18 @@ static int brcmstb_gpio_probe(struct platform_device *pdev) ...@@ -664,6 +664,18 @@ static int brcmstb_gpio_probe(struct platform_device *pdev)
struct brcmstb_gpio_bank *bank; struct brcmstb_gpio_bank *bank;
struct gpio_chip *gc; struct gpio_chip *gc;
/*
* If bank_width is 0, then there is an empty bank in the
* register block. Special handling for this case.
*/
if (bank_width == 0) {
dev_dbg(dev, "Width 0 found: Empty bank @ %d\n",
num_banks);
num_banks++;
gpio_base += MAX_GPIO_PER_BANK;
continue;
}
bank = devm_kzalloc(dev, sizeof(*bank), GFP_KERNEL); bank = devm_kzalloc(dev, sizeof(*bank), GFP_KERNEL);
if (!bank) { if (!bank) {
err = -ENOMEM; err = -ENOMEM;
...@@ -740,9 +752,6 @@ static int brcmstb_gpio_probe(struct platform_device *pdev) ...@@ -740,9 +752,6 @@ static int brcmstb_gpio_probe(struct platform_device *pdev)
goto fail; goto fail;
} }
dev_info(dev, "Registered %d banks (GPIO(s): %d-%d)\n",
num_banks, priv->gpio_base, gpio_base - 1);
if (priv->parent_wake_irq && need_wakeup_event) if (priv->parent_wake_irq && need_wakeup_event)
pm_wakeup_event(dev, 0); pm_wakeup_event(dev, 0);
......
// SPDX-License-Identifier: GPL-2.0+
//
// Synopsys CREG (Control REGisters) GPIO driver
//
// Copyright (C) 2018 Synopsys
// Author: Eugeniy Paltsev <Eugeniy.Paltsev@synopsys.com>
#include <linux/gpio/driver.h>
#include <linux/io.h>
#include <linux/of.h>
#include <linux/of_platform.h>
#define MAX_GPIO 32
struct creg_layout {
u8 ngpio;
u8 shift[MAX_GPIO];
u8 on[MAX_GPIO];
u8 off[MAX_GPIO];
u8 bit_per_gpio[MAX_GPIO];
};
struct creg_gpio {
struct gpio_chip gc;
void __iomem *regs;
spinlock_t lock;
const struct creg_layout *layout;
};
static void creg_gpio_set(struct gpio_chip *gc, unsigned int offset, int val)
{
struct creg_gpio *hcg = gpiochip_get_data(gc);
const struct creg_layout *layout = hcg->layout;
u32 reg, reg_shift, value;
unsigned long flags;
int i;
value = val ? hcg->layout->on[offset] : hcg->layout->off[offset];
reg_shift = layout->shift[offset];
for (i = 0; i < offset; i++)
reg_shift += layout->bit_per_gpio[i] + layout->shift[i];
spin_lock_irqsave(&hcg->lock, flags);
reg = readl(hcg->regs);
reg &= ~(GENMASK(layout->bit_per_gpio[i] - 1, 0) << reg_shift);
reg |= (value << reg_shift);
writel(reg, hcg->regs);
spin_unlock_irqrestore(&hcg->lock, flags);
}
static int creg_gpio_dir_out(struct gpio_chip *gc, unsigned int offset, int val)
{
creg_gpio_set(gc, offset, val);
return 0;
}
static int creg_gpio_validate_pg(struct device *dev, struct creg_gpio *hcg,
int i)
{
const struct creg_layout *layout = hcg->layout;
if (layout->bit_per_gpio[i] < 1 || layout->bit_per_gpio[i] > 8)
return -EINVAL;
/* Check that on valiue fits it's placeholder */
if (GENMASK(31, layout->bit_per_gpio[i]) & layout->on[i])
return -EINVAL;
/* Check that off valiue fits it's placeholder */
if (GENMASK(31, layout->bit_per_gpio[i]) & layout->off[i])
return -EINVAL;
if (layout->on[i] == layout->off[i])
return -EINVAL;
return 0;
}
static int creg_gpio_validate(struct device *dev, struct creg_gpio *hcg,
u32 ngpios)
{
u32 reg_len = 0;
int i;
if (hcg->layout->ngpio < 1 || hcg->layout->ngpio > MAX_GPIO)
return -EINVAL;
if (ngpios < 1 || ngpios > hcg->layout->ngpio) {
dev_err(dev, "ngpios must be in [1:%u]\n", hcg->layout->ngpio);
return -EINVAL;
}
for (i = 0; i < hcg->layout->ngpio; i++) {
if (creg_gpio_validate_pg(dev, hcg, i))
return -EINVAL;
reg_len += hcg->layout->shift[i] + hcg->layout->bit_per_gpio[i];
}
/* Check that we fit in 32 bit register */
if (reg_len > 32)
return -EINVAL;
return 0;
}
static const struct creg_layout hsdk_cs_ctl = {
.ngpio = 10,
.shift = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
.off = { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 },
.on = { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 },
.bit_per_gpio = { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 }
};
static const struct creg_layout axs10x_flsh_cs_ctl = {
.ngpio = 1,
.shift = { 0 },
.off = { 1 },
.on = { 3 },
.bit_per_gpio = { 2 }
};
static const struct of_device_id creg_gpio_ids[] = {
{
.compatible = "snps,creg-gpio-axs10x",
.data = &axs10x_flsh_cs_ctl
}, {
.compatible = "snps,creg-gpio-hsdk",
.data = &hsdk_cs_ctl
}, { /* sentinel */ }
};
static int creg_gpio_probe(struct platform_device *pdev)
{
const struct of_device_id *match;
struct device *dev = &pdev->dev;
struct creg_gpio *hcg;
struct resource *mem;
u32 ngpios;
int ret;
hcg = devm_kzalloc(dev, sizeof(struct creg_gpio), GFP_KERNEL);
if (!hcg)
return -ENOMEM;
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
hcg->regs = devm_ioremap_resource(dev, mem);
if (IS_ERR(hcg->regs))
return PTR_ERR(hcg->regs);
match = of_match_node(creg_gpio_ids, pdev->dev.of_node);
hcg->layout = match->data;
if (!hcg->layout)
return -EINVAL;
ret = of_property_read_u32(dev->of_node, "ngpios", &ngpios);
if (ret)
return ret;
ret = creg_gpio_validate(dev, hcg, ngpios);
if (ret)
return ret;
spin_lock_init(&hcg->lock);
hcg->gc.label = dev_name(dev);
hcg->gc.base = -1;
hcg->gc.ngpio = ngpios;
hcg->gc.set = creg_gpio_set;
hcg->gc.direction_output = creg_gpio_dir_out;
hcg->gc.of_node = dev->of_node;
ret = devm_gpiochip_add_data(dev, &hcg->gc, hcg);
if (ret)
return ret;
dev_info(dev, "GPIO controller with %d gpios probed\n", ngpios);
return 0;
}
static struct platform_driver creg_gpio_snps_driver = {
.driver = {
.name = "snps-creg-gpio",
.of_match_table = creg_gpio_ids,
},
.probe = creg_gpio_probe,
};
builtin_platform_driver(creg_gpio_snps_driver);
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
* the Free Software Foundation; either version 2 of the License, or * the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version. * (at your option) any later version.
*/ */
#include <linux/gpio/driver.h> #include <linux/gpio/driver.h>
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/kernel.h> #include <linux/kernel.h>
...@@ -24,6 +25,12 @@ ...@@ -24,6 +25,12 @@
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/platform_data/gpio-davinci.h> #include <linux/platform_data/gpio-davinci.h>
#include <linux/irqchip/chained_irq.h> #include <linux/irqchip/chained_irq.h>
#include <linux/spinlock.h>
#include <asm-generic/gpio.h>
#define MAX_REGS_BANKS 5
#define MAX_INT_PER_BANK 32
struct davinci_gpio_regs { struct davinci_gpio_regs {
u32 dir; u32 dir;
...@@ -41,11 +48,31 @@ struct davinci_gpio_regs { ...@@ -41,11 +48,31 @@ struct davinci_gpio_regs {
typedef struct irq_chip *(*gpio_get_irq_chip_cb_t)(unsigned int irq); typedef struct irq_chip *(*gpio_get_irq_chip_cb_t)(unsigned int irq);
#define BINTEN 0x8 /* GPIO Interrupt Per-Bank Enable Register */ #define BINTEN 0x8 /* GPIO Interrupt Per-Bank Enable Register */
#define MAX_LABEL_SIZE 20
static void __iomem *gpio_base; static void __iomem *gpio_base;
static unsigned int offset_array[5] = {0x10, 0x38, 0x60, 0x88, 0xb0}; static unsigned int offset_array[5] = {0x10, 0x38, 0x60, 0x88, 0xb0};
struct davinci_gpio_irq_data {
void __iomem *regs;
struct davinci_gpio_controller *chip;
int bank_num;
};
struct davinci_gpio_controller {
struct gpio_chip chip;
struct irq_domain *irq_domain;
/* Serialize access to GPIO registers */
spinlock_t lock;
void __iomem *regs[MAX_REGS_BANKS];
int gpio_unbanked;
int irqs[MAX_INT_PER_BANK];
};
static inline u32 __gpio_mask(unsigned gpio)
{
return 1 << (gpio % 32);
}
static inline struct davinci_gpio_regs __iomem *irq2regs(struct irq_data *d) static inline struct davinci_gpio_regs __iomem *irq2regs(struct irq_data *d)
{ {
struct davinci_gpio_regs __iomem *g; struct davinci_gpio_regs __iomem *g;
...@@ -166,14 +193,12 @@ davinci_gpio_get_pdata(struct platform_device *pdev) ...@@ -166,14 +193,12 @@ davinci_gpio_get_pdata(struct platform_device *pdev)
static int davinci_gpio_probe(struct platform_device *pdev) static int davinci_gpio_probe(struct platform_device *pdev)
{ {
static int ctrl_num, bank_base; int bank, i, ret = 0;
int gpio, bank, i, ret = 0;
unsigned int ngpio, nbank, nirq; unsigned int ngpio, nbank, nirq;
struct davinci_gpio_controller *chips; struct davinci_gpio_controller *chips;
struct davinci_gpio_platform_data *pdata; struct davinci_gpio_platform_data *pdata;
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
struct resource *res; struct resource *res;
char label[MAX_LABEL_SIZE];
pdata = davinci_gpio_get_pdata(pdev); pdata = davinci_gpio_get_pdata(pdev);
if (!pdata) { if (!pdata) {
...@@ -207,10 +232,7 @@ static int davinci_gpio_probe(struct platform_device *pdev) ...@@ -207,10 +232,7 @@ static int davinci_gpio_probe(struct platform_device *pdev)
else else
nirq = DIV_ROUND_UP(ngpio, 16); nirq = DIV_ROUND_UP(ngpio, 16);
nbank = DIV_ROUND_UP(ngpio, 32); chips = devm_kzalloc(dev, sizeof(*chips), GFP_KERNEL);
chips = devm_kcalloc(dev,
nbank, sizeof(struct davinci_gpio_controller),
GFP_KERNEL);
if (!chips) if (!chips)
return -ENOMEM; return -ENOMEM;
...@@ -228,10 +250,7 @@ static int davinci_gpio_probe(struct platform_device *pdev) ...@@ -228,10 +250,7 @@ static int davinci_gpio_probe(struct platform_device *pdev)
} }
} }
snprintf(label, MAX_LABEL_SIZE, "davinci_gpio.%d", ctrl_num++); chips->chip.label = dev_name(dev);
chips->chip.label = devm_kstrdup(dev, label, GFP_KERNEL);
if (!chips->chip.label)
return -ENOMEM;
chips->chip.direction_input = davinci_direction_in; chips->chip.direction_input = davinci_direction_in;
chips->chip.get = davinci_gpio_get; chips->chip.get = davinci_gpio_get;
...@@ -239,7 +258,7 @@ static int davinci_gpio_probe(struct platform_device *pdev) ...@@ -239,7 +258,7 @@ static int davinci_gpio_probe(struct platform_device *pdev)
chips->chip.set = davinci_gpio_set; chips->chip.set = davinci_gpio_set;
chips->chip.ngpio = ngpio; chips->chip.ngpio = ngpio;
chips->chip.base = bank_base; chips->chip.base = -1;
#ifdef CONFIG_OF_GPIO #ifdef CONFIG_OF_GPIO
chips->chip.of_gpio_n_cells = 2; chips->chip.of_gpio_n_cells = 2;
...@@ -252,28 +271,21 @@ static int davinci_gpio_probe(struct platform_device *pdev) ...@@ -252,28 +271,21 @@ static int davinci_gpio_probe(struct platform_device *pdev)
} }
#endif #endif
spin_lock_init(&chips->lock); spin_lock_init(&chips->lock);
bank_base += ngpio;
for (gpio = 0, bank = 0; gpio < ngpio; gpio += 32, bank++) nbank = DIV_ROUND_UP(ngpio, 32);
for (bank = 0; bank < nbank; bank++)
chips->regs[bank] = gpio_base + offset_array[bank]; chips->regs[bank] = gpio_base + offset_array[bank];
ret = devm_gpiochip_add_data(dev, &chips->chip, chips); ret = devm_gpiochip_add_data(dev, &chips->chip, chips);
if (ret) if (ret)
goto err; return ret;
platform_set_drvdata(pdev, chips); platform_set_drvdata(pdev, chips);
ret = davinci_gpio_irq_setup(pdev); ret = davinci_gpio_irq_setup(pdev);
if (ret) if (ret)
goto err; return ret;
return 0; return 0;
err:
/* Revert the static variable increments */
ctrl_num--;
bank_base -= ngpio;
return ret;
} }
/*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/
......
// SPDX-License-Identifier: GPL-2.0
/* /*
* Generic EP93xx GPIO handling * Generic EP93xx GPIO handling
* *
...@@ -6,10 +7,6 @@ ...@@ -6,10 +7,6 @@
* *
* Based on code originally from: * Based on code originally from:
* linux/arch/arm/mach-ep93xx/core.c * linux/arch/arm/mach-ep93xx/core.c
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/ */
#include <linux/init.h> #include <linux/init.h>
...@@ -19,16 +16,26 @@ ...@@ -19,16 +16,26 @@
#include <linux/irq.h> #include <linux/irq.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/gpio/driver.h> #include <linux/gpio/driver.h>
/* FIXME: this is here for gpio_to_irq() - get rid of this! */ #include <linux/bitops.h>
#include <linux/gpio.h>
#define EP93XX_GPIO_F_INT_STATUS 0x5c
#define EP93XX_GPIO_A_INT_STATUS 0xa0
#define EP93XX_GPIO_B_INT_STATUS 0xbc
/* Maximum value for gpio line identifiers */
#define EP93XX_GPIO_LINE_MAX 63
#include <mach/hardware.h> /* Maximum value for irq capable line identifiers */
#include <mach/gpio-ep93xx.h> #define EP93XX_GPIO_LINE_MAX_IRQ 23
#define irq_to_gpio(irq) ((irq) - gpio_to_irq(0)) /*
* Static mapping of GPIO bank F IRQS:
* F0..F7 (16..24) to irq 80..87.
*/
#define EP93XX_GPIO_F_IRQ_BASE 80
struct ep93xx_gpio { struct ep93xx_gpio {
void __iomem *mmio_base; void __iomem *base;
struct gpio_chip gc[8]; struct gpio_chip gc[8];
}; };
...@@ -48,27 +55,45 @@ static const u8 eoi_register_offset[3] = { 0x98, 0xb4, 0x54 }; ...@@ -48,27 +55,45 @@ static const u8 eoi_register_offset[3] = { 0x98, 0xb4, 0x54 };
static const u8 int_en_register_offset[3] = { 0x9c, 0xb8, 0x58 }; static const u8 int_en_register_offset[3] = { 0x9c, 0xb8, 0x58 };
static const u8 int_debounce_register_offset[3] = { 0xa8, 0xc4, 0x64 }; static const u8 int_debounce_register_offset[3] = { 0xa8, 0xc4, 0x64 };
static void ep93xx_gpio_update_int_params(unsigned port) static void ep93xx_gpio_update_int_params(struct ep93xx_gpio *epg, unsigned port)
{ {
BUG_ON(port > 2); BUG_ON(port > 2);
writeb_relaxed(0, EP93XX_GPIO_REG(int_en_register_offset[port])); writeb_relaxed(0, epg->base + int_en_register_offset[port]);
writeb_relaxed(gpio_int_type2[port], writeb_relaxed(gpio_int_type2[port],
EP93XX_GPIO_REG(int_type2_register_offset[port])); epg->base + int_type2_register_offset[port]);
writeb_relaxed(gpio_int_type1[port], writeb_relaxed(gpio_int_type1[port],
EP93XX_GPIO_REG(int_type1_register_offset[port])); epg->base + int_type1_register_offset[port]);
writeb(gpio_int_unmasked[port] & gpio_int_enabled[port], writeb(gpio_int_unmasked[port] & gpio_int_enabled[port],
EP93XX_GPIO_REG(int_en_register_offset[port])); epg->base + int_en_register_offset[port]);
}
static int ep93xx_gpio_port(struct gpio_chip *gc)
{
struct ep93xx_gpio *epg = gpiochip_get_data(gc);
int port = 0;
while (port < ARRAY_SIZE(epg->gc) && gc != &epg->gc[port])
port++;
/* This should not happen but is there as a last safeguard */
if (port == ARRAY_SIZE(epg->gc)) {
pr_crit("can't find the GPIO port\n");
return 0;
}
return port;
} }
static void ep93xx_gpio_int_debounce(unsigned int irq, bool enable) static void ep93xx_gpio_int_debounce(struct gpio_chip *gc,
unsigned int offset, bool enable)
{ {
int line = irq_to_gpio(irq); struct ep93xx_gpio *epg = gpiochip_get_data(gc);
int port = line >> 3; int port = ep93xx_gpio_port(gc);
int port_mask = 1 << (line & 7); int port_mask = BIT(offset);
if (enable) if (enable)
gpio_int_debounce[port] |= port_mask; gpio_int_debounce[port] |= port_mask;
...@@ -76,29 +101,36 @@ static void ep93xx_gpio_int_debounce(unsigned int irq, bool enable) ...@@ -76,29 +101,36 @@ static void ep93xx_gpio_int_debounce(unsigned int irq, bool enable)
gpio_int_debounce[port] &= ~port_mask; gpio_int_debounce[port] &= ~port_mask;
writeb(gpio_int_debounce[port], writeb(gpio_int_debounce[port],
EP93XX_GPIO_REG(int_debounce_register_offset[port])); epg->base + int_debounce_register_offset[port]);
} }
static void ep93xx_gpio_ab_irq_handler(struct irq_desc *desc) static void ep93xx_gpio_ab_irq_handler(struct irq_desc *desc)
{ {
unsigned char status; struct gpio_chip *gc = irq_desc_get_handler_data(desc);
int i; struct ep93xx_gpio *epg = gpiochip_get_data(gc);
struct irq_chip *irqchip = irq_desc_get_chip(desc);
unsigned long stat;
int offset;
status = readb(EP93XX_GPIO_A_INT_STATUS); chained_irq_enter(irqchip, desc);
for (i = 0; i < 8; i++) {
if (status & (1 << i)) {
int gpio_irq = gpio_to_irq(EP93XX_GPIO_LINE_A(0)) + i;
generic_handle_irq(gpio_irq);
}
}
status = readb(EP93XX_GPIO_B_INT_STATUS); /*
for (i = 0; i < 8; i++) { * Dispatch the IRQs to the irqdomain of each A and B
if (status & (1 << i)) { * gpiochip irqdomains depending on what has fired.
int gpio_irq = gpio_to_irq(EP93XX_GPIO_LINE_B(0)) + i; * The tricky part is that the IRQ line is shared
generic_handle_irq(gpio_irq); * between bank A and B and each has their own gpiochip.
} */
} stat = readb(epg->base + EP93XX_GPIO_A_INT_STATUS);
for_each_set_bit(offset, &stat, 8)
generic_handle_irq(irq_find_mapping(epg->gc[0].irq.domain,
offset));
stat = readb(epg->base + EP93XX_GPIO_B_INT_STATUS);
for_each_set_bit(offset, &stat, 8)
generic_handle_irq(irq_find_mapping(epg->gc[1].irq.domain,
offset));
chained_irq_exit(irqchip, desc);
} }
static void ep93xx_gpio_f_irq_handler(struct irq_desc *desc) static void ep93xx_gpio_f_irq_handler(struct irq_desc *desc)
...@@ -106,60 +138,67 @@ static void ep93xx_gpio_f_irq_handler(struct irq_desc *desc) ...@@ -106,60 +138,67 @@ static void ep93xx_gpio_f_irq_handler(struct irq_desc *desc)
/* /*
* map discontiguous hw irq range to continuous sw irq range: * map discontiguous hw irq range to continuous sw irq range:
* *
* IRQ_EP93XX_GPIO{0..7}MUX -> gpio_to_irq(EP93XX_GPIO_LINE_F({0..7}) * IRQ_EP93XX_GPIO{0..7}MUX -> EP93XX_GPIO_LINE_F{0..7}
*/ */
struct irq_chip *irqchip = irq_desc_get_chip(desc);
unsigned int irq = irq_desc_get_irq(desc); unsigned int irq = irq_desc_get_irq(desc);
int port_f_idx = ((irq + 1) & 7) ^ 4; /* {19..22,47..50} -> {0..7} */ int port_f_idx = ((irq + 1) & 7) ^ 4; /* {19..22,47..50} -> {0..7} */
int gpio_irq = gpio_to_irq(EP93XX_GPIO_LINE_F(0)) + port_f_idx; int gpio_irq = EP93XX_GPIO_F_IRQ_BASE + port_f_idx;
chained_irq_enter(irqchip, desc);
generic_handle_irq(gpio_irq); generic_handle_irq(gpio_irq);
chained_irq_exit(irqchip, desc);
} }
static void ep93xx_gpio_irq_ack(struct irq_data *d) static void ep93xx_gpio_irq_ack(struct irq_data *d)
{ {
int line = irq_to_gpio(d->irq); struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
int port = line >> 3; struct ep93xx_gpio *epg = gpiochip_get_data(gc);
int port_mask = 1 << (line & 7); int port = ep93xx_gpio_port(gc);
int port_mask = BIT(d->irq & 7);
if (irqd_get_trigger_type(d) == IRQ_TYPE_EDGE_BOTH) { if (irqd_get_trigger_type(d) == IRQ_TYPE_EDGE_BOTH) {
gpio_int_type2[port] ^= port_mask; /* switch edge direction */ gpio_int_type2[port] ^= port_mask; /* switch edge direction */
ep93xx_gpio_update_int_params(port); ep93xx_gpio_update_int_params(epg, port);
} }
writeb(port_mask, EP93XX_GPIO_REG(eoi_register_offset[port])); writeb(port_mask, epg->base + eoi_register_offset[port]);
} }
static void ep93xx_gpio_irq_mask_ack(struct irq_data *d) static void ep93xx_gpio_irq_mask_ack(struct irq_data *d)
{ {
int line = irq_to_gpio(d->irq); struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
int port = line >> 3; struct ep93xx_gpio *epg = gpiochip_get_data(gc);
int port_mask = 1 << (line & 7); int port = ep93xx_gpio_port(gc);
int port_mask = BIT(d->irq & 7);
if (irqd_get_trigger_type(d) == IRQ_TYPE_EDGE_BOTH) if (irqd_get_trigger_type(d) == IRQ_TYPE_EDGE_BOTH)
gpio_int_type2[port] ^= port_mask; /* switch edge direction */ gpio_int_type2[port] ^= port_mask; /* switch edge direction */
gpio_int_unmasked[port] &= ~port_mask; gpio_int_unmasked[port] &= ~port_mask;
ep93xx_gpio_update_int_params(port); ep93xx_gpio_update_int_params(epg, port);
writeb(port_mask, EP93XX_GPIO_REG(eoi_register_offset[port])); writeb(port_mask, epg->base + eoi_register_offset[port]);
} }
static void ep93xx_gpio_irq_mask(struct irq_data *d) static void ep93xx_gpio_irq_mask(struct irq_data *d)
{ {
int line = irq_to_gpio(d->irq); struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
int port = line >> 3; struct ep93xx_gpio *epg = gpiochip_get_data(gc);
int port = ep93xx_gpio_port(gc);
gpio_int_unmasked[port] &= ~(1 << (line & 7)); gpio_int_unmasked[port] &= ~BIT(d->irq & 7);
ep93xx_gpio_update_int_params(port); ep93xx_gpio_update_int_params(epg, port);
} }
static void ep93xx_gpio_irq_unmask(struct irq_data *d) static void ep93xx_gpio_irq_unmask(struct irq_data *d)
{ {
int line = irq_to_gpio(d->irq); struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
int port = line >> 3; struct ep93xx_gpio *epg = gpiochip_get_data(gc);
int port = ep93xx_gpio_port(gc);
gpio_int_unmasked[port] |= 1 << (line & 7); gpio_int_unmasked[port] |= BIT(d->irq & 7);
ep93xx_gpio_update_int_params(port); ep93xx_gpio_update_int_params(epg, port);
} }
/* /*
...@@ -169,12 +208,14 @@ static void ep93xx_gpio_irq_unmask(struct irq_data *d) ...@@ -169,12 +208,14 @@ static void ep93xx_gpio_irq_unmask(struct irq_data *d)
*/ */
static int ep93xx_gpio_irq_type(struct irq_data *d, unsigned int type) static int ep93xx_gpio_irq_type(struct irq_data *d, unsigned int type)
{ {
const int gpio = irq_to_gpio(d->irq); struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
const int port = gpio >> 3; struct ep93xx_gpio *epg = gpiochip_get_data(gc);
const int port_mask = 1 << (gpio & 7); int port = ep93xx_gpio_port(gc);
int offset = d->irq & 7;
int port_mask = BIT(offset);
irq_flow_handler_t handler; irq_flow_handler_t handler;
gpio_direction_input(gpio); gc->direction_input(gc, offset);
switch (type) { switch (type) {
case IRQ_TYPE_EDGE_RISING: case IRQ_TYPE_EDGE_RISING:
...@@ -200,7 +241,7 @@ static int ep93xx_gpio_irq_type(struct irq_data *d, unsigned int type) ...@@ -200,7 +241,7 @@ static int ep93xx_gpio_irq_type(struct irq_data *d, unsigned int type)
case IRQ_TYPE_EDGE_BOTH: case IRQ_TYPE_EDGE_BOTH:
gpio_int_type1[port] |= port_mask; gpio_int_type1[port] |= port_mask;
/* set initial polarity based on current input level */ /* set initial polarity based on current input level */
if (gpio_get_value(gpio)) if (gc->get(gc, offset))
gpio_int_type2[port] &= ~port_mask; /* falling */ gpio_int_type2[port] &= ~port_mask; /* falling */
else else
gpio_int_type2[port] |= port_mask; /* rising */ gpio_int_type2[port] |= port_mask; /* rising */
...@@ -214,7 +255,7 @@ static int ep93xx_gpio_irq_type(struct irq_data *d, unsigned int type) ...@@ -214,7 +255,7 @@ static int ep93xx_gpio_irq_type(struct irq_data *d, unsigned int type)
gpio_int_enabled[port] |= port_mask; gpio_int_enabled[port] |= port_mask;
ep93xx_gpio_update_int_params(port); ep93xx_gpio_update_int_params(epg, port);
return 0; return 0;
} }
...@@ -228,35 +269,53 @@ static struct irq_chip ep93xx_gpio_irq_chip = { ...@@ -228,35 +269,53 @@ static struct irq_chip ep93xx_gpio_irq_chip = {
.irq_set_type = ep93xx_gpio_irq_type, .irq_set_type = ep93xx_gpio_irq_type,
}; };
static void ep93xx_gpio_init_irq(void) static int ep93xx_gpio_init_irq(struct platform_device *pdev,
struct ep93xx_gpio *epg)
{ {
int ab_parent_irq = platform_get_irq(pdev, 0);
struct device *dev = &pdev->dev;
int gpio_irq; int gpio_irq;
int ret;
int i;
/* The A bank */
ret = gpiochip_irqchip_add(&epg->gc[0], &ep93xx_gpio_irq_chip,
64, handle_level_irq,
IRQ_TYPE_NONE);
if (ret) {
dev_err(dev, "Could not add irqchip 0\n");
return ret;
}
gpiochip_set_chained_irqchip(&epg->gc[0], &ep93xx_gpio_irq_chip,
ab_parent_irq,
ep93xx_gpio_ab_irq_handler);
/* The B bank */
ret = gpiochip_irqchip_add(&epg->gc[1], &ep93xx_gpio_irq_chip,
72, handle_level_irq,
IRQ_TYPE_NONE);
if (ret) {
dev_err(dev, "Could not add irqchip 1\n");
return ret;
}
gpiochip_set_chained_irqchip(&epg->gc[1], &ep93xx_gpio_irq_chip,
ab_parent_irq,
ep93xx_gpio_ab_irq_handler);
for (gpio_irq = gpio_to_irq(0); /* The F bank */
gpio_irq <= gpio_to_irq(EP93XX_GPIO_LINE_MAX_IRQ); ++gpio_irq) { for (i = 0; i < 8; i++) {
gpio_irq = EP93XX_GPIO_F_IRQ_BASE + i;
irq_set_chip_data(gpio_irq, &epg->gc[5]);
irq_set_chip_and_handler(gpio_irq, &ep93xx_gpio_irq_chip, irq_set_chip_and_handler(gpio_irq, &ep93xx_gpio_irq_chip,
handle_level_irq); handle_level_irq);
irq_clear_status_flags(gpio_irq, IRQ_NOREQUEST); irq_clear_status_flags(gpio_irq, IRQ_NOREQUEST);
} }
irq_set_chained_handler(IRQ_EP93XX_GPIO_AB, for (i = 1; i <= 8; i++)
ep93xx_gpio_ab_irq_handler); irq_set_chained_handler_and_data(platform_get_irq(pdev, i),
irq_set_chained_handler(IRQ_EP93XX_GPIO0MUX, ep93xx_gpio_f_irq_handler,
ep93xx_gpio_f_irq_handler); &epg->gc[i]);
irq_set_chained_handler(IRQ_EP93XX_GPIO1MUX, return 0;
ep93xx_gpio_f_irq_handler);
irq_set_chained_handler(IRQ_EP93XX_GPIO2MUX,
ep93xx_gpio_f_irq_handler);
irq_set_chained_handler(IRQ_EP93XX_GPIO3MUX,
ep93xx_gpio_f_irq_handler);
irq_set_chained_handler(IRQ_EP93XX_GPIO4MUX,
ep93xx_gpio_f_irq_handler);
irq_set_chained_handler(IRQ_EP93XX_GPIO5MUX,
ep93xx_gpio_f_irq_handler);
irq_set_chained_handler(IRQ_EP93XX_GPIO6MUX,
ep93xx_gpio_f_irq_handler);
irq_set_chained_handler(IRQ_EP93XX_GPIO7MUX,
ep93xx_gpio_f_irq_handler);
} }
...@@ -268,68 +327,54 @@ struct ep93xx_gpio_bank { ...@@ -268,68 +327,54 @@ struct ep93xx_gpio_bank {
int data; int data;
int dir; int dir;
int base; int base;
bool has_debounce; bool has_irq;
}; };
#define EP93XX_GPIO_BANK(_label, _data, _dir, _base, _debounce) \ #define EP93XX_GPIO_BANK(_label, _data, _dir, _base, _has_irq) \
{ \ { \
.label = _label, \ .label = _label, \
.data = _data, \ .data = _data, \
.dir = _dir, \ .dir = _dir, \
.base = _base, \ .base = _base, \
.has_debounce = _debounce, \ .has_irq = _has_irq, \
} }
static struct ep93xx_gpio_bank ep93xx_gpio_banks[] = { static struct ep93xx_gpio_bank ep93xx_gpio_banks[] = {
EP93XX_GPIO_BANK("A", 0x00, 0x10, 0, true), EP93XX_GPIO_BANK("A", 0x00, 0x10, 0, true), /* Bank A has 8 IRQs */
EP93XX_GPIO_BANK("B", 0x04, 0x14, 8, true), EP93XX_GPIO_BANK("B", 0x04, 0x14, 8, true), /* Bank B has 8 IRQs */
EP93XX_GPIO_BANK("C", 0x08, 0x18, 40, false), EP93XX_GPIO_BANK("C", 0x08, 0x18, 40, false),
EP93XX_GPIO_BANK("D", 0x0c, 0x1c, 24, false), EP93XX_GPIO_BANK("D", 0x0c, 0x1c, 24, false),
EP93XX_GPIO_BANK("E", 0x20, 0x24, 32, false), EP93XX_GPIO_BANK("E", 0x20, 0x24, 32, false),
EP93XX_GPIO_BANK("F", 0x30, 0x34, 16, true), EP93XX_GPIO_BANK("F", 0x30, 0x34, 16, true), /* Bank F has 8 IRQs */
EP93XX_GPIO_BANK("G", 0x38, 0x3c, 48, false), EP93XX_GPIO_BANK("G", 0x38, 0x3c, 48, false),
EP93XX_GPIO_BANK("H", 0x40, 0x44, 56, false), EP93XX_GPIO_BANK("H", 0x40, 0x44, 56, false),
}; };
static int ep93xx_gpio_set_config(struct gpio_chip *chip, unsigned offset, static int ep93xx_gpio_set_config(struct gpio_chip *gc, unsigned offset,
unsigned long config) unsigned long config)
{ {
int gpio = chip->base + offset;
int irq = gpio_to_irq(gpio);
u32 debounce; u32 debounce;
if (pinconf_to_config_param(config) != PIN_CONFIG_INPUT_DEBOUNCE) if (pinconf_to_config_param(config) != PIN_CONFIG_INPUT_DEBOUNCE)
return -ENOTSUPP; return -ENOTSUPP;
if (irq < 0)
return -EINVAL;
debounce = pinconf_to_config_argument(config); debounce = pinconf_to_config_argument(config);
ep93xx_gpio_int_debounce(irq, debounce ? true : false); ep93xx_gpio_int_debounce(gc, offset, debounce ? true : false);
return 0; return 0;
} }
/* static int ep93xx_gpio_f_to_irq(struct gpio_chip *gc, unsigned offset)
* Map GPIO A0..A7 (0..7) to irq 64..71,
* B0..B7 (7..15) to irq 72..79, and
* F0..F7 (16..24) to irq 80..87.
*/
static int ep93xx_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
{ {
int gpio = chip->base + offset; return EP93XX_GPIO_F_IRQ_BASE + offset;
if (gpio > EP93XX_GPIO_LINE_MAX_IRQ)
return -EINVAL;
return 64 + gpio;
} }
static int ep93xx_gpio_add_bank(struct gpio_chip *gc, struct device *dev, static int ep93xx_gpio_add_bank(struct gpio_chip *gc, struct device *dev,
void __iomem *mmio_base, struct ep93xx_gpio_bank *bank) struct ep93xx_gpio *epg,
struct ep93xx_gpio_bank *bank)
{ {
void __iomem *data = mmio_base + bank->data; void __iomem *data = epg->base + bank->data;
void __iomem *dir = mmio_base + bank->dir; void __iomem *dir = epg->base + bank->dir;
int err; int err;
err = bgpio_init(gc, dev, 1, data, NULL, NULL, dir, NULL, 0); err = bgpio_init(gc, dev, 1, data, NULL, NULL, dir, NULL, 0);
...@@ -339,41 +384,41 @@ static int ep93xx_gpio_add_bank(struct gpio_chip *gc, struct device *dev, ...@@ -339,41 +384,41 @@ static int ep93xx_gpio_add_bank(struct gpio_chip *gc, struct device *dev,
gc->label = bank->label; gc->label = bank->label;
gc->base = bank->base; gc->base = bank->base;
if (bank->has_debounce) { if (bank->has_irq)
gc->set_config = ep93xx_gpio_set_config; gc->set_config = ep93xx_gpio_set_config;
gc->to_irq = ep93xx_gpio_to_irq;
}
return devm_gpiochip_add_data(dev, gc, NULL); return devm_gpiochip_add_data(dev, gc, epg);
} }
static int ep93xx_gpio_probe(struct platform_device *pdev) static int ep93xx_gpio_probe(struct platform_device *pdev)
{ {
struct ep93xx_gpio *ep93xx_gpio; struct ep93xx_gpio *epg;
struct resource *res; struct resource *res;
int i; int i;
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
ep93xx_gpio = devm_kzalloc(dev, sizeof(struct ep93xx_gpio), GFP_KERNEL); epg = devm_kzalloc(dev, sizeof(*epg), GFP_KERNEL);
if (!ep93xx_gpio) if (!epg)
return -ENOMEM; return -ENOMEM;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0); res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
ep93xx_gpio->mmio_base = devm_ioremap_resource(dev, res); epg->base = devm_ioremap_resource(dev, res);
if (IS_ERR(ep93xx_gpio->mmio_base)) if (IS_ERR(epg->base))
return PTR_ERR(ep93xx_gpio->mmio_base); return PTR_ERR(epg->base);
for (i = 0; i < ARRAY_SIZE(ep93xx_gpio_banks); i++) { for (i = 0; i < ARRAY_SIZE(ep93xx_gpio_banks); i++) {
struct gpio_chip *gc = &ep93xx_gpio->gc[i]; struct gpio_chip *gc = &epg->gc[i];
struct ep93xx_gpio_bank *bank = &ep93xx_gpio_banks[i]; struct ep93xx_gpio_bank *bank = &ep93xx_gpio_banks[i];
if (ep93xx_gpio_add_bank(gc, &pdev->dev, if (ep93xx_gpio_add_bank(gc, &pdev->dev, epg, bank))
ep93xx_gpio->mmio_base, bank))
dev_warn(&pdev->dev, "Unable to add gpio bank %s\n", dev_warn(&pdev->dev, "Unable to add gpio bank %s\n",
bank->label); bank->label);
/* Only bank F has especially funky IRQ handling */
if (i == 5)
gc->to_irq = ep93xx_gpio_f_to_irq;
} }
ep93xx_gpio_init_irq(); ep93xx_gpio_init_irq(pdev, epg);
return 0; return 0;
} }
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/bitops.h> #include <linux/bitops.h>
#include <linux/clk.h>
/* GPIO registers definition */ /* GPIO registers definition */
#define GPIO_DATA_OUT 0x00 #define GPIO_DATA_OUT 0x00
...@@ -40,11 +41,14 @@ ...@@ -40,11 +41,14 @@
* struct ftgpio_gpio - Gemini GPIO state container * struct ftgpio_gpio - Gemini GPIO state container
* @dev: containing device for this instance * @dev: containing device for this instance
* @gc: gpiochip for this instance * @gc: gpiochip for this instance
* @base: remapped I/O-memory base
* @clk: silicon clock
*/ */
struct ftgpio_gpio { struct ftgpio_gpio {
struct device *dev; struct device *dev;
struct gpio_chip gc; struct gpio_chip gc;
void __iomem *base; void __iomem *base;
struct clk *clk;
}; };
static void ftgpio_gpio_ack_irq(struct irq_data *d) static void ftgpio_gpio_ack_irq(struct irq_data *d)
...@@ -157,6 +161,73 @@ static void ftgpio_gpio_irq_handler(struct irq_desc *desc) ...@@ -157,6 +161,73 @@ static void ftgpio_gpio_irq_handler(struct irq_desc *desc)
chained_irq_exit(irqchip, desc); chained_irq_exit(irqchip, desc);
} }
static int ftgpio_gpio_set_config(struct gpio_chip *gc, unsigned int offset,
unsigned long config)
{
enum pin_config_param param = pinconf_to_config_param(config);
u32 arg = pinconf_to_config_argument(config);
struct ftgpio_gpio *g = gpiochip_get_data(gc);
unsigned long pclk_freq;
u32 deb_div;
u32 val;
if (param != PIN_CONFIG_INPUT_DEBOUNCE)
return -ENOTSUPP;
/*
* Debounce only works if interrupts are enabled. The manual
* states that if PCLK is 66 MHz, and this is set to 0x7D0, then
* PCLK is divided down to 33 kHz for the debounce timer. 0x7D0 is
* 2000 decimal, so what they mean is simply that the PCLK is
* divided by this value.
*
* As we get a debounce setting in microseconds, we calculate the
* desired period time and see if we can get a suitable debounce
* time.
*/
pclk_freq = clk_get_rate(g->clk);
deb_div = DIV_ROUND_CLOSEST(pclk_freq, arg);
/* This register is only 24 bits wide */
if (deb_div > (1 << 24))
return -ENOTSUPP;
dev_dbg(g->dev, "prescale divisor: %08x, resulting frequency %lu Hz\n",
deb_div, (pclk_freq/deb_div));
val = readl(g->base + GPIO_DEBOUNCE_PRESCALE);
if (val == deb_div) {
/*
* The debounce timer happens to already be set to the
* desireable value, what a coincidence! We can just enable
* debounce on this GPIO line and return. This happens more
* often than you think, for example when all GPIO keys
* on a system are requesting the same debounce interval.
*/
val = readl(g->base + GPIO_DEBOUNCE_EN);
val |= BIT(offset);
writel(val, g->base + GPIO_DEBOUNCE_EN);
return 0;
}
val = readl(g->base + GPIO_DEBOUNCE_EN);
if (val) {
/*
* Oh no! Someone is already using the debounce with
* another setting than what we need. Bummer.
*/
return -ENOTSUPP;
}
/* First come, first serve */
writel(deb_div, g->base + GPIO_DEBOUNCE_PRESCALE);
/* Enable debounce */
val |= BIT(offset);
writel(val, g->base + GPIO_DEBOUNCE_EN);
return 0;
}
static int ftgpio_gpio_probe(struct platform_device *pdev) static int ftgpio_gpio_probe(struct platform_device *pdev)
{ {
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
...@@ -180,6 +251,19 @@ static int ftgpio_gpio_probe(struct platform_device *pdev) ...@@ -180,6 +251,19 @@ static int ftgpio_gpio_probe(struct platform_device *pdev)
if (irq <= 0) if (irq <= 0)
return irq ? irq : -EINVAL; return irq ? irq : -EINVAL;
g->clk = devm_clk_get(dev, NULL);
if (!IS_ERR(g->clk)) {
ret = clk_prepare_enable(g->clk);
if (ret)
return ret;
} else if (PTR_ERR(g->clk) == -EPROBE_DEFER) {
/*
* Percolate deferrals, for anything else,
* just live without the clocking.
*/
return PTR_ERR(g->clk);
}
ret = bgpio_init(&g->gc, dev, 4, ret = bgpio_init(&g->gc, dev, 4,
g->base + GPIO_DATA_IN, g->base + GPIO_DATA_IN,
g->base + GPIO_DATA_SET, g->base + GPIO_DATA_SET,
...@@ -189,7 +273,7 @@ static int ftgpio_gpio_probe(struct platform_device *pdev) ...@@ -189,7 +273,7 @@ static int ftgpio_gpio_probe(struct platform_device *pdev)
0); 0);
if (ret) { if (ret) {
dev_err(dev, "unable to init generic GPIO\n"); dev_err(dev, "unable to init generic GPIO\n");
return ret; goto dis_clk;
} }
g->gc.label = "FTGPIO010"; g->gc.label = "FTGPIO010";
g->gc.base = -1; g->gc.base = -1;
...@@ -197,28 +281,50 @@ static int ftgpio_gpio_probe(struct platform_device *pdev) ...@@ -197,28 +281,50 @@ static int ftgpio_gpio_probe(struct platform_device *pdev)
g->gc.owner = THIS_MODULE; g->gc.owner = THIS_MODULE;
/* ngpio is set by bgpio_init() */ /* ngpio is set by bgpio_init() */
/* We need a silicon clock to do debounce */
if (!IS_ERR(g->clk))
g->gc.set_config = ftgpio_gpio_set_config;
ret = devm_gpiochip_add_data(dev, &g->gc, g); ret = devm_gpiochip_add_data(dev, &g->gc, g);
if (ret) if (ret)
return ret; goto dis_clk;
/* Disable, unmask and clear all interrupts */ /* Disable, unmask and clear all interrupts */
writel(0x0, g->base + GPIO_INT_EN); writel(0x0, g->base + GPIO_INT_EN);
writel(0x0, g->base + GPIO_INT_MASK); writel(0x0, g->base + GPIO_INT_MASK);
writel(~0x0, g->base + GPIO_INT_CLR); writel(~0x0, g->base + GPIO_INT_CLR);
/* Clear any use of debounce */
writel(0x0, g->base + GPIO_DEBOUNCE_EN);
ret = gpiochip_irqchip_add(&g->gc, &ftgpio_gpio_irqchip, ret = gpiochip_irqchip_add(&g->gc, &ftgpio_gpio_irqchip,
0, handle_bad_irq, 0, handle_bad_irq,
IRQ_TYPE_NONE); IRQ_TYPE_NONE);
if (ret) { if (ret) {
dev_info(dev, "could not add irqchip\n"); dev_info(dev, "could not add irqchip\n");
return ret; goto dis_clk;
} }
gpiochip_set_chained_irqchip(&g->gc, &ftgpio_gpio_irqchip, gpiochip_set_chained_irqchip(&g->gc, &ftgpio_gpio_irqchip,
irq, ftgpio_gpio_irq_handler); irq, ftgpio_gpio_irq_handler);
platform_set_drvdata(pdev, g);
dev_info(dev, "FTGPIO010 @%p registered\n", g->base); dev_info(dev, "FTGPIO010 @%p registered\n", g->base);
return 0; return 0;
dis_clk:
if (!IS_ERR(g->clk))
clk_disable_unprepare(g->clk);
return ret;
}
static int ftgpio_gpio_remove(struct platform_device *pdev)
{
struct ftgpio_gpio *g = platform_get_drvdata(pdev);
if (!IS_ERR(g->clk))
clk_disable_unprepare(g->clk);
return 0;
} }
static const struct of_device_id ftgpio_gpio_of_match[] = { static const struct of_device_id ftgpio_gpio_of_match[] = {
...@@ -240,5 +346,6 @@ static struct platform_driver ftgpio_gpio_driver = { ...@@ -240,5 +346,6 @@ static struct platform_driver ftgpio_gpio_driver = {
.of_match_table = of_match_ptr(ftgpio_gpio_of_match), .of_match_table = of_match_ptr(ftgpio_gpio_of_match),
}, },
.probe = ftgpio_gpio_probe, .probe = ftgpio_gpio_probe,
.remove = ftgpio_gpio_remove,
}; };
builtin_platform_driver(ftgpio_gpio_driver); builtin_platform_driver(ftgpio_gpio_driver);
...@@ -189,7 +189,6 @@ static void egpio_set(struct gpio_chip *chip, unsigned offset, int value) ...@@ -189,7 +189,6 @@ static void egpio_set(struct gpio_chip *chip, unsigned offset, int value)
unsigned long flag; unsigned long flag;
struct egpio_chip *egpio; struct egpio_chip *egpio;
struct egpio_info *ei; struct egpio_info *ei;
unsigned bit;
int pos; int pos;
int reg; int reg;
int shift; int shift;
...@@ -199,7 +198,6 @@ static void egpio_set(struct gpio_chip *chip, unsigned offset, int value) ...@@ -199,7 +198,6 @@ static void egpio_set(struct gpio_chip *chip, unsigned offset, int value)
egpio = gpiochip_get_data(chip); egpio = gpiochip_get_data(chip);
ei = dev_get_drvdata(egpio->dev); ei = dev_get_drvdata(egpio->dev);
bit = egpio_bit(ei, offset);
pos = egpio_pos(ei, offset); pos = egpio_pos(ei, offset);
reg = egpio->reg_start + pos; reg = egpio->reg_start + pos;
shift = pos << ei->reg_shift; shift = pos << ei->reg_shift;
...@@ -334,7 +332,13 @@ static int __init egpio_probe(struct platform_device *pdev) ...@@ -334,7 +332,13 @@ static int __init egpio_probe(struct platform_device *pdev)
ei->chip[i].is_out = pdata->chip[i].direction; ei->chip[i].is_out = pdata->chip[i].direction;
ei->chip[i].dev = &(pdev->dev); ei->chip[i].dev = &(pdev->dev);
chip = &(ei->chip[i].chip); chip = &(ei->chip[i].chip);
chip->label = "htc-egpio"; chip->label = devm_kasprintf(&pdev->dev, GFP_KERNEL,
"htc-egpio-%d",
i);
if (!chip->label) {
ret = -ENOMEM;
goto fail;
}
chip->parent = &pdev->dev; chip->parent = &pdev->dev;
chip->owner = THIS_MODULE; chip->owner = THIS_MODULE;
chip->get = egpio_get; chip->get = egpio_get;
......
...@@ -313,18 +313,21 @@ static int max3191x_set_config(struct gpio_chip *gpio, unsigned int offset, ...@@ -313,18 +313,21 @@ static int max3191x_set_config(struct gpio_chip *gpio, unsigned int offset,
static void gpiod_set_array_single_value_cansleep(unsigned int ndescs, static void gpiod_set_array_single_value_cansleep(unsigned int ndescs,
struct gpio_desc **desc, struct gpio_desc **desc,
struct gpio_array *info,
int value) int value)
{ {
int i, *values; unsigned long *values;
values = kmalloc_array(ndescs, sizeof(*values), GFP_KERNEL); values = bitmap_alloc(ndescs, GFP_KERNEL);
if (!values) if (!values)
return; return;
for (i = 0; i < ndescs; i++) if (value)
values[i] = value; bitmap_fill(values, ndescs);
else
bitmap_zero(values, ndescs);
gpiod_set_array_value_cansleep(ndescs, desc, values); gpiod_set_array_value_cansleep(ndescs, desc, info, values);
kfree(values); kfree(values);
} }
...@@ -397,7 +400,8 @@ static int max3191x_probe(struct spi_device *spi) ...@@ -397,7 +400,8 @@ static int max3191x_probe(struct spi_device *spi)
if (max3191x->modesel_pins) if (max3191x->modesel_pins)
gpiod_set_array_single_value_cansleep( gpiod_set_array_single_value_cansleep(
max3191x->modesel_pins->ndescs, max3191x->modesel_pins->ndescs,
max3191x->modesel_pins->desc, max3191x->mode); max3191x->modesel_pins->desc,
max3191x->modesel_pins->info, max3191x->mode);
max3191x->ignore_uv = device_property_read_bool(dev, max3191x->ignore_uv = device_property_read_bool(dev,
"maxim,ignore-undervoltage"); "maxim,ignore-undervoltage");
......
// SPDX-License-Identifier: GPL-2.0+
/* /*
* Generic driver for memory-mapped GPIO controllers. * Generic driver for memory-mapped GPIO controllers.
* *
* Copyright 2008 MontaVista Software, Inc. * Copyright 2008 MontaVista Software, Inc.
* Copyright 2008,2010 Anton Vorontsov <cbouatmailru@gmail.com> * Copyright 2008,2010 Anton Vorontsov <cbouatmailru@gmail.com>
* *
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* ....``.```~~~~````.`.`.`.`.```````'',,,.........`````......`....... * ....``.```~~~~````.`.`.`.`.```````'',,,.........`````......`.......
* ...`` ```````.. * ...`` ```````..
* ..The simplest form of a GPIO controller that the driver supports is`` * ..The simplest form of a GPIO controller that the driver supports is``
......
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
#include <linux/irq_sim.h> #include <linux/irq_sim.h>
#include <linux/debugfs.h> #include <linux/debugfs.h>
#include <linux/uaccess.h> #include <linux/uaccess.h>
#include <linux/property.h>
#include "gpiolib.h" #include "gpiolib.h"
...@@ -28,6 +29,8 @@ ...@@ -28,6 +29,8 @@
* of GPIO lines. * of GPIO lines.
*/ */
#define GPIO_MOCKUP_MAX_RANGES (GPIO_MOCKUP_MAX_GC * 2) #define GPIO_MOCKUP_MAX_RANGES (GPIO_MOCKUP_MAX_GC * 2)
/* Maximum of three properties + the sentinel. */
#define GPIO_MOCKUP_MAX_PROP 4
#define gpio_mockup_err(...) pr_err(GPIO_MOCKUP_NAME ": " __VA_ARGS__) #define gpio_mockup_err(...) pr_err(GPIO_MOCKUP_NAME ": " __VA_ARGS__)
...@@ -59,13 +62,6 @@ struct gpio_mockup_dbgfs_private { ...@@ -59,13 +62,6 @@ struct gpio_mockup_dbgfs_private {
int offset; int offset;
}; };
struct gpio_mockup_platform_data {
int base;
int ngpio;
int index;
bool named_lines;
};
static int gpio_mockup_ranges[GPIO_MOCKUP_MAX_RANGES]; static int gpio_mockup_ranges[GPIO_MOCKUP_MAX_RANGES];
static int gpio_mockup_num_ranges; static int gpio_mockup_num_ranges;
module_param_array(gpio_mockup_ranges, int, &gpio_mockup_num_ranges, 0400); module_param_array(gpio_mockup_ranges, int, &gpio_mockup_num_ranges, 0400);
...@@ -255,26 +251,37 @@ static int gpio_mockup_name_lines(struct device *dev, ...@@ -255,26 +251,37 @@ static int gpio_mockup_name_lines(struct device *dev,
static int gpio_mockup_probe(struct platform_device *pdev) static int gpio_mockup_probe(struct platform_device *pdev)
{ {
struct gpio_mockup_platform_data *pdata;
struct gpio_mockup_chip *chip; struct gpio_mockup_chip *chip;
struct gpio_chip *gc; struct gpio_chip *gc;
int rv, base, ngpio;
struct device *dev; struct device *dev;
char *name; const char *name;
int rv, base;
u16 ngpio;
dev = &pdev->dev; dev = &pdev->dev;
pdata = dev_get_platdata(dev);
base = pdata->base; rv = device_property_read_u32(dev, "gpio-base", &base);
ngpio = pdata->ngpio; if (rv)
base = -1;
rv = device_property_read_u16(dev, "nr-gpios", &ngpio);
if (rv)
return rv;
rv = device_property_read_string(dev, "chip-name", &name);
if (rv)
name = NULL;
chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL); chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL);
if (!chip) if (!chip)
return -ENOMEM; return -ENOMEM;
name = devm_kasprintf(dev, GFP_KERNEL, "%s-%c", if (!name) {
pdev->name, pdata->index); name = devm_kasprintf(dev, GFP_KERNEL,
"%s-%c", pdev->name, pdev->id + 'A');
if (!name) if (!name)
return -ENOMEM; return -ENOMEM;
}
gc = &chip->gc; gc = &chip->gc;
gc->base = base; gc->base = base;
...@@ -295,7 +302,7 @@ static int gpio_mockup_probe(struct platform_device *pdev) ...@@ -295,7 +302,7 @@ static int gpio_mockup_probe(struct platform_device *pdev)
if (!chip->lines) if (!chip->lines)
return -ENOMEM; return -ENOMEM;
if (pdata->named_lines) { if (device_property_read_bool(dev, "named-gpio-lines")) {
rv = gpio_mockup_name_lines(dev, chip); rv = gpio_mockup_name_lines(dev, chip);
if (rv) if (rv)
return rv; return rv;
...@@ -339,9 +346,11 @@ static void gpio_mockup_unregister_pdevs(void) ...@@ -339,9 +346,11 @@ static void gpio_mockup_unregister_pdevs(void)
static int __init gpio_mockup_init(void) static int __init gpio_mockup_init(void)
{ {
int i, num_chips, err = 0, index = 'A'; struct property_entry properties[GPIO_MOCKUP_MAX_PROP];
struct gpio_mockup_platform_data pdata; int i, prop, num_chips, err = 0, base;
struct platform_device_info pdevinfo;
struct platform_device *pdev; struct platform_device *pdev;
u16 ngpio;
if ((gpio_mockup_num_ranges < 2) || if ((gpio_mockup_num_ranges < 2) ||
(gpio_mockup_num_ranges % 2) || (gpio_mockup_num_ranges % 2) ||
...@@ -371,17 +380,28 @@ static int __init gpio_mockup_init(void) ...@@ -371,17 +380,28 @@ static int __init gpio_mockup_init(void)
} }
for (i = 0; i < num_chips; i++) { for (i = 0; i < num_chips; i++) {
pdata.index = index++; memset(properties, 0, sizeof(properties));
pdata.base = gpio_mockup_range_base(i); memset(&pdevinfo, 0, sizeof(pdevinfo));
pdata.ngpio = pdata.base < 0 prop = 0;
? gpio_mockup_range_ngpio(i)
: gpio_mockup_range_ngpio(i) - pdata.base; base = gpio_mockup_range_base(i);
pdata.named_lines = gpio_mockup_named_lines; if (base >= 0)
properties[prop++] = PROPERTY_ENTRY_U32("gpio-base",
pdev = platform_device_register_resndata(NULL, base);
GPIO_MOCKUP_NAME,
i, NULL, 0, &pdata, ngpio = base < 0 ? gpio_mockup_range_ngpio(i)
sizeof(pdata)); : gpio_mockup_range_ngpio(i) - base;
properties[prop++] = PROPERTY_ENTRY_U16("nr-gpios", ngpio);
if (gpio_mockup_named_lines)
properties[prop++] = PROPERTY_ENTRY_BOOL(
"named-gpio-lines");
pdevinfo.name = GPIO_MOCKUP_NAME;
pdevinfo.id = i;
pdevinfo.properties = properties;
pdev = platform_device_register_full(&pdevinfo);
if (IS_ERR(pdev)) { if (IS_ERR(pdev)) {
gpio_mockup_err("error registering device"); gpio_mockup_err("error registering device");
platform_driver_unregister(&gpio_mockup_driver); platform_driver_unregister(&gpio_mockup_driver);
......
...@@ -18,8 +18,6 @@ ...@@ -18,8 +18,6 @@
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/gpio/driver.h> #include <linux/gpio/driver.h>
/* FIXME: for gpio_get_value(), replace this by direct register read */
#include <linux/gpio.h>
#include <linux/module.h> #include <linux/module.h>
#define MXS_SET 0x4 #define MXS_SET 0x4
...@@ -86,7 +84,7 @@ static int mxs_gpio_set_irq_type(struct irq_data *d, unsigned int type) ...@@ -86,7 +84,7 @@ static int mxs_gpio_set_irq_type(struct irq_data *d, unsigned int type)
port->both_edges &= ~pin_mask; port->both_edges &= ~pin_mask;
switch (type) { switch (type) {
case IRQ_TYPE_EDGE_BOTH: case IRQ_TYPE_EDGE_BOTH:
val = gpio_get_value(port->gc.base + d->hwirq); val = port->gc.get(&port->gc, d->hwirq);
if (val) if (val)
edge = GPIO_INT_FALL_EDGE; edge = GPIO_INT_FALL_EDGE;
else else
......
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
#include <linux/err.h> #include <linux/err.h>
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/cpu_pm.h>
#include <linux/device.h> #include <linux/device.h>
#include <linux/pm_runtime.h> #include <linux/pm_runtime.h>
#include <linux/pm.h> #include <linux/pm.h>
...@@ -28,10 +29,10 @@ ...@@ -28,10 +29,10 @@
#include <linux/bitops.h> #include <linux/bitops.h>
#include <linux/platform_data/gpio-omap.h> #include <linux/platform_data/gpio-omap.h>
#define OFF_MODE 1
#define OMAP4_GPIO_DEBOUNCINGTIME_MASK 0xFF #define OMAP4_GPIO_DEBOUNCINGTIME_MASK 0xFF
static LIST_HEAD(omap_gpio_list); #define OMAP_GPIO_QUIRK_IDLE_REMOVE_TRIGGER BIT(2)
#define OMAP_GPIO_QUIRK_DEFERRED_WKUP_EN BIT(1)
struct gpio_regs { struct gpio_regs {
u32 irqenable1; u32 irqenable1;
...@@ -48,6 +49,13 @@ struct gpio_regs { ...@@ -48,6 +49,13 @@ struct gpio_regs {
u32 debounce_en; u32 debounce_en;
}; };
struct gpio_bank;
struct gpio_omap_funcs {
void (*idle_enable_level_quirk)(struct gpio_bank *bank);
void (*idle_disable_level_quirk)(struct gpio_bank *bank);
};
struct gpio_bank { struct gpio_bank {
struct list_head node; struct list_head node;
void __iomem *base; void __iomem *base;
...@@ -55,6 +63,7 @@ struct gpio_bank { ...@@ -55,6 +63,7 @@ struct gpio_bank {
u32 non_wakeup_gpios; u32 non_wakeup_gpios;
u32 enabled_non_wakeup_gpios; u32 enabled_non_wakeup_gpios;
struct gpio_regs context; struct gpio_regs context;
struct gpio_omap_funcs funcs;
u32 saved_datain; u32 saved_datain;
u32 level_mask; u32 level_mask;
u32 toggle_mask; u32 toggle_mask;
...@@ -62,6 +71,8 @@ struct gpio_bank { ...@@ -62,6 +71,8 @@ struct gpio_bank {
raw_spinlock_t wa_lock; raw_spinlock_t wa_lock;
struct gpio_chip chip; struct gpio_chip chip;
struct clk *dbck; struct clk *dbck;
struct notifier_block nb;
unsigned int is_suspended:1;
u32 mod_usage; u32 mod_usage;
u32 irq_usage; u32 irq_usage;
u32 dbck_enable_mask; u32 dbck_enable_mask;
...@@ -73,8 +84,8 @@ struct gpio_bank { ...@@ -73,8 +84,8 @@ struct gpio_bank {
int stride; int stride;
u32 width; u32 width;
int context_loss_count; int context_loss_count;
int power_mode;
bool workaround_enabled; bool workaround_enabled;
u32 quirks;
void (*set_dataout)(struct gpio_bank *bank, unsigned gpio, int enable); void (*set_dataout)(struct gpio_bank *bank, unsigned gpio, int enable);
void (*set_dataout_multiple)(struct gpio_bank *bank, void (*set_dataout_multiple)(struct gpio_bank *bank,
...@@ -368,10 +379,19 @@ static inline void omap_set_gpio_trigger(struct gpio_bank *bank, int gpio, ...@@ -368,10 +379,19 @@ static inline void omap_set_gpio_trigger(struct gpio_bank *bank, int gpio,
readl_relaxed(bank->base + bank->regs->fallingdetect); readl_relaxed(bank->base + bank->regs->fallingdetect);
if (likely(!(bank->non_wakeup_gpios & gpio_bit))) { if (likely(!(bank->non_wakeup_gpios & gpio_bit))) {
omap_gpio_rmw(base, bank->regs->wkup_en, gpio_bit, trigger != 0); /* Defer wkup_en register update until we idle? */
if (bank->quirks & OMAP_GPIO_QUIRK_DEFERRED_WKUP_EN) {
if (trigger)
bank->context.wake_en |= gpio_bit;
else
bank->context.wake_en &= ~gpio_bit;
} else {
omap_gpio_rmw(base, bank->regs->wkup_en, gpio_bit,
trigger != 0);
bank->context.wake_en = bank->context.wake_en =
readl_relaxed(bank->base + bank->regs->wkup_en); readl_relaxed(bank->base + bank->regs->wkup_en);
} }
}
/* This part needs to be executed always for OMAP{34xx, 44xx} */ /* This part needs to be executed always for OMAP{34xx, 44xx} */
if (!bank->regs->irqctrl) { if (!bank->regs->irqctrl) {
...@@ -682,11 +702,6 @@ static int omap_gpio_request(struct gpio_chip *chip, unsigned offset) ...@@ -682,11 +702,6 @@ static int omap_gpio_request(struct gpio_chip *chip, unsigned offset)
struct gpio_bank *bank = gpiochip_get_data(chip); struct gpio_bank *bank = gpiochip_get_data(chip);
unsigned long flags; unsigned long flags;
/*
* If this is the first gpio_request for the bank,
* enable the bank module.
*/
if (!BANK_USED(bank))
pm_runtime_get_sync(chip->parent); pm_runtime_get_sync(chip->parent);
raw_spin_lock_irqsave(&bank->lock, flags); raw_spin_lock_irqsave(&bank->lock, flags);
...@@ -711,11 +726,6 @@ static void omap_gpio_free(struct gpio_chip *chip, unsigned offset) ...@@ -711,11 +726,6 @@ static void omap_gpio_free(struct gpio_chip *chip, unsigned offset)
omap_disable_gpio_module(bank, offset); omap_disable_gpio_module(bank, offset);
raw_spin_unlock_irqrestore(&bank->lock, flags); raw_spin_unlock_irqrestore(&bank->lock, flags);
/*
* If this is the last gpio to be freed in the bank,
* disable the bank module.
*/
if (!BANK_USED(bank))
pm_runtime_put(chip->parent); pm_runtime_put(chip->parent);
} }
...@@ -741,7 +751,9 @@ static irqreturn_t omap_gpio_irq_handler(int irq, void *gpiobank) ...@@ -741,7 +751,9 @@ static irqreturn_t omap_gpio_irq_handler(int irq, void *gpiobank)
if (WARN_ON(!isr_reg)) if (WARN_ON(!isr_reg))
goto exit; goto exit;
pm_runtime_get_sync(bank->chip.parent); if (WARN_ONCE(!pm_runtime_active(bank->chip.parent),
"gpio irq%i while runtime suspended?\n", irq))
return IRQ_NONE;
while (1) { while (1) {
raw_spin_lock_irqsave(&bank->lock, lock_flags); raw_spin_lock_irqsave(&bank->lock, lock_flags);
...@@ -792,7 +804,6 @@ static irqreturn_t omap_gpio_irq_handler(int irq, void *gpiobank) ...@@ -792,7 +804,6 @@ static irqreturn_t omap_gpio_irq_handler(int irq, void *gpiobank)
} }
} }
exit: exit:
pm_runtime_put(bank->chip.parent);
return IRQ_HANDLED; return IRQ_HANDLED;
} }
...@@ -841,7 +852,6 @@ static void omap_gpio_irq_bus_lock(struct irq_data *data) ...@@ -841,7 +852,6 @@ static void omap_gpio_irq_bus_lock(struct irq_data *data)
{ {
struct gpio_bank *bank = omap_irq_data_get_bank(data); struct gpio_bank *bank = omap_irq_data_get_bank(data);
if (!BANK_USED(bank))
pm_runtime_get_sync(bank->chip.parent); pm_runtime_get_sync(bank->chip.parent);
} }
...@@ -849,11 +859,6 @@ static void gpio_irq_bus_sync_unlock(struct irq_data *data) ...@@ -849,11 +859,6 @@ static void gpio_irq_bus_sync_unlock(struct irq_data *data)
{ {
struct gpio_bank *bank = omap_irq_data_get_bank(data); struct gpio_bank *bank = omap_irq_data_get_bank(data);
/*
* If this is the last IRQ to be freed in the bank,
* disable the bank module.
*/
if (!BANK_USED(bank))
pm_runtime_put(bank->chip.parent); pm_runtime_put(bank->chip.parent);
} }
...@@ -899,6 +904,82 @@ static void omap_gpio_unmask_irq(struct irq_data *d) ...@@ -899,6 +904,82 @@ static void omap_gpio_unmask_irq(struct irq_data *d)
raw_spin_unlock_irqrestore(&bank->lock, flags); raw_spin_unlock_irqrestore(&bank->lock, flags);
} }
/*
* Only edges can generate a wakeup event to the PRCM.
*
* Therefore, ensure any wake-up capable GPIOs have
* edge-detection enabled before going idle to ensure a wakeup
* to the PRCM is generated on a GPIO transition. (c.f. 34xx
* NDA TRM 25.5.3.1)
*
* The normal values will be restored upon ->runtime_resume()
* by writing back the values saved in bank->context.
*/
static void __maybe_unused
omap2_gpio_enable_level_quirk(struct gpio_bank *bank)
{
u32 wake_low, wake_hi;
/* Enable additional edge detection for level gpios for idle */
wake_low = bank->context.leveldetect0 & bank->context.wake_en;
if (wake_low)
writel_relaxed(wake_low | bank->context.fallingdetect,
bank->base + bank->regs->fallingdetect);
wake_hi = bank->context.leveldetect1 & bank->context.wake_en;
if (wake_hi)
writel_relaxed(wake_hi | bank->context.risingdetect,
bank->base + bank->regs->risingdetect);
}
static void __maybe_unused
omap2_gpio_disable_level_quirk(struct gpio_bank *bank)
{
/* Disable edge detection for level gpios after idle */
writel_relaxed(bank->context.fallingdetect,
bank->base + bank->regs->fallingdetect);
writel_relaxed(bank->context.risingdetect,
bank->base + bank->regs->risingdetect);
}
/*
* On omap4 and later SoC variants a level interrupt with wkup_en
* enabled blocks the GPIO functional clock from idling until the GPIO
* instance has been reset. To avoid that, we must set wkup_en only for
* idle for level interrupts, and clear level registers for the duration
* of idle. The level interrupts will be still there on wakeup by their
* nature.
*/
static void __maybe_unused
omap4_gpio_enable_level_quirk(struct gpio_bank *bank)
{
/* Update wake register for idle, edge bits might be already set */
writel_relaxed(bank->context.wake_en,
bank->base + bank->regs->wkup_en);
/* Clear level registers for idle */
writel_relaxed(0, bank->base + bank->regs->leveldetect0);
writel_relaxed(0, bank->base + bank->regs->leveldetect1);
}
static void __maybe_unused
omap4_gpio_disable_level_quirk(struct gpio_bank *bank)
{
/* Restore level registers after idle */
writel_relaxed(bank->context.leveldetect0,
bank->base + bank->regs->leveldetect0);
writel_relaxed(bank->context.leveldetect1,
bank->base + bank->regs->leveldetect1);
/* Clear saved wkup_en for level, it will be set for next idle again */
bank->context.wake_en &= ~(bank->context.leveldetect0 |
bank->context.leveldetect1);
/* Update wake with only edge configuration */
writel_relaxed(bank->context.wake_en,
bank->base + bank->regs->wkup_en);
}
/*---------------------------------------------------------------------*/ /*---------------------------------------------------------------------*/
static int omap_mpuio_suspend_noirq(struct device *dev) static int omap_mpuio_suspend_noirq(struct device *dev)
...@@ -1218,6 +1299,36 @@ static int omap_gpio_chip_init(struct gpio_bank *bank, struct irq_chip *irqc) ...@@ -1218,6 +1299,36 @@ static int omap_gpio_chip_init(struct gpio_bank *bank, struct irq_chip *irqc)
return ret; return ret;
} }
static void omap_gpio_idle(struct gpio_bank *bank, bool may_lose_context);
static void omap_gpio_unidle(struct gpio_bank *bank);
static int gpio_omap_cpu_notifier(struct notifier_block *nb,
unsigned long cmd, void *v)
{
struct gpio_bank *bank;
unsigned long flags;
bank = container_of(nb, struct gpio_bank, nb);
raw_spin_lock_irqsave(&bank->lock, flags);
switch (cmd) {
case CPU_CLUSTER_PM_ENTER:
if (bank->is_suspended)
break;
omap_gpio_idle(bank, true);
break;
case CPU_CLUSTER_PM_ENTER_FAILED:
case CPU_CLUSTER_PM_EXIT:
if (bank->is_suspended)
break;
omap_gpio_unidle(bank);
break;
}
raw_spin_unlock_irqrestore(&bank->lock, flags);
return NOTIFY_OK;
}
static const struct of_device_id omap_gpio_match[]; static const struct of_device_id omap_gpio_match[];
static int omap_gpio_probe(struct platform_device *pdev) static int omap_gpio_probe(struct platform_device *pdev)
...@@ -1256,6 +1367,7 @@ static int omap_gpio_probe(struct platform_device *pdev) ...@@ -1256,6 +1367,7 @@ static int omap_gpio_probe(struct platform_device *pdev)
irqc->irq_bus_sync_unlock = gpio_irq_bus_sync_unlock, irqc->irq_bus_sync_unlock = gpio_irq_bus_sync_unlock,
irqc->name = dev_name(&pdev->dev); irqc->name = dev_name(&pdev->dev);
irqc->flags = IRQCHIP_MASK_ON_SUSPEND; irqc->flags = IRQCHIP_MASK_ON_SUSPEND;
irqc->parent_device = dev;
bank->irq = platform_get_irq(pdev, 0); bank->irq = platform_get_irq(pdev, 0);
if (bank->irq <= 0) { if (bank->irq <= 0) {
...@@ -1270,6 +1382,7 @@ static int omap_gpio_probe(struct platform_device *pdev) ...@@ -1270,6 +1382,7 @@ static int omap_gpio_probe(struct platform_device *pdev)
bank->chip.parent = dev; bank->chip.parent = dev;
bank->chip.owner = THIS_MODULE; bank->chip.owner = THIS_MODULE;
bank->dbck_flag = pdata->dbck_flag; bank->dbck_flag = pdata->dbck_flag;
bank->quirks = pdata->quirks;
bank->stride = pdata->bank_stride; bank->stride = pdata->bank_stride;
bank->width = pdata->bank_width; bank->width = pdata->bank_width;
bank->is_mpuio = pdata->is_mpuio; bank->is_mpuio = pdata->is_mpuio;
...@@ -1278,6 +1391,7 @@ static int omap_gpio_probe(struct platform_device *pdev) ...@@ -1278,6 +1391,7 @@ static int omap_gpio_probe(struct platform_device *pdev)
#ifdef CONFIG_OF_GPIO #ifdef CONFIG_OF_GPIO
bank->chip.of_node = of_node_get(node); bank->chip.of_node = of_node_get(node);
#endif #endif
if (node) { if (node) {
if (!of_property_read_bool(node, "ti,gpio-always-on")) if (!of_property_read_bool(node, "ti,gpio-always-on"))
bank->loses_context = true; bank->loses_context = true;
...@@ -1298,6 +1412,18 @@ static int omap_gpio_probe(struct platform_device *pdev) ...@@ -1298,6 +1412,18 @@ static int omap_gpio_probe(struct platform_device *pdev)
omap_set_gpio_dataout_mask_multiple; omap_set_gpio_dataout_mask_multiple;
} }
if (bank->quirks & OMAP_GPIO_QUIRK_DEFERRED_WKUP_EN) {
bank->funcs.idle_enable_level_quirk =
omap4_gpio_enable_level_quirk;
bank->funcs.idle_disable_level_quirk =
omap4_gpio_disable_level_quirk;
} else if (bank->quirks & OMAP_GPIO_QUIRK_IDLE_REMOVE_TRIGGER) {
bank->funcs.idle_enable_level_quirk =
omap2_gpio_enable_level_quirk;
bank->funcs.idle_disable_level_quirk =
omap2_gpio_disable_level_quirk;
}
raw_spin_lock_init(&bank->lock); raw_spin_lock_init(&bank->lock);
raw_spin_lock_init(&bank->wa_lock); raw_spin_lock_init(&bank->wa_lock);
...@@ -1322,7 +1448,6 @@ static int omap_gpio_probe(struct platform_device *pdev) ...@@ -1322,7 +1448,6 @@ static int omap_gpio_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, bank); platform_set_drvdata(pdev, bank);
pm_runtime_enable(dev); pm_runtime_enable(dev);
pm_runtime_irq_safe(dev);
pm_runtime_get_sync(dev); pm_runtime_get_sync(dev);
if (bank->is_mpuio) if (bank->is_mpuio)
...@@ -1341,9 +1466,13 @@ static int omap_gpio_probe(struct platform_device *pdev) ...@@ -1341,9 +1466,13 @@ static int omap_gpio_probe(struct platform_device *pdev)
omap_gpio_show_rev(bank); omap_gpio_show_rev(bank);
pm_runtime_put(dev); if (bank->funcs.idle_enable_level_quirk &&
bank->funcs.idle_disable_level_quirk) {
bank->nb.notifier_call = gpio_omap_cpu_notifier;
cpu_pm_register_notifier(&bank->nb);
}
list_add_tail(&bank->node, &omap_gpio_list); pm_runtime_put(dev);
return 0; return 0;
} }
...@@ -1352,6 +1481,8 @@ static int omap_gpio_remove(struct platform_device *pdev) ...@@ -1352,6 +1481,8 @@ static int omap_gpio_remove(struct platform_device *pdev)
{ {
struct gpio_bank *bank = platform_get_drvdata(pdev); struct gpio_bank *bank = platform_get_drvdata(pdev);
if (bank->nb.notifier_call)
cpu_pm_unregister_notifier(&bank->nb);
list_del(&bank->node); list_del(&bank->node);
gpiochip_remove(&bank->chip); gpiochip_remove(&bank->chip);
pm_runtime_disable(&pdev->dev); pm_runtime_disable(&pdev->dev);
...@@ -1361,48 +1492,22 @@ static int omap_gpio_remove(struct platform_device *pdev) ...@@ -1361,48 +1492,22 @@ static int omap_gpio_remove(struct platform_device *pdev)
return 0; return 0;
} }
#ifdef CONFIG_ARCH_OMAP2PLUS
#if defined(CONFIG_PM)
static void omap_gpio_restore_context(struct gpio_bank *bank); static void omap_gpio_restore_context(struct gpio_bank *bank);
static int omap_gpio_runtime_suspend(struct device *dev) static void omap_gpio_idle(struct gpio_bank *bank, bool may_lose_context)
{ {
struct platform_device *pdev = to_platform_device(dev); struct device *dev = bank->chip.parent;
struct gpio_bank *bank = platform_get_drvdata(pdev);
u32 l1 = 0, l2 = 0; u32 l1 = 0, l2 = 0;
unsigned long flags;
u32 wake_low, wake_hi;
raw_spin_lock_irqsave(&bank->lock, flags);
/* if (bank->funcs.idle_enable_level_quirk)
* Only edges can generate a wakeup event to the PRCM. bank->funcs.idle_enable_level_quirk(bank);
*
* Therefore, ensure any wake-up capable GPIOs have
* edge-detection enabled before going idle to ensure a wakeup
* to the PRCM is generated on a GPIO transition. (c.f. 34xx
* NDA TRM 25.5.3.1)
*
* The normal values will be restored upon ->runtime_resume()
* by writing back the values saved in bank->context.
*/
wake_low = bank->context.leveldetect0 & bank->context.wake_en;
if (wake_low)
writel_relaxed(wake_low | bank->context.fallingdetect,
bank->base + bank->regs->fallingdetect);
wake_hi = bank->context.leveldetect1 & bank->context.wake_en;
if (wake_hi)
writel_relaxed(wake_hi | bank->context.risingdetect,
bank->base + bank->regs->risingdetect);
if (!bank->enabled_non_wakeup_gpios) if (!bank->enabled_non_wakeup_gpios)
goto update_gpio_context_count; goto update_gpio_context_count;
if (bank->power_mode != OFF_MODE) { if (!may_lose_context)
bank->power_mode = 0;
goto update_gpio_context_count; goto update_gpio_context_count;
}
/* /*
* If going to OFF, remove triggering for all * If going to OFF, remove triggering for all
* non-wakeup GPIOs. Otherwise spurious IRQs will be * non-wakeup GPIOs. Otherwise spurious IRQs will be
...@@ -1427,23 +1532,16 @@ static int omap_gpio_runtime_suspend(struct device *dev) ...@@ -1427,23 +1532,16 @@ static int omap_gpio_runtime_suspend(struct device *dev)
bank->get_context_loss_count(dev); bank->get_context_loss_count(dev);
omap_gpio_dbck_disable(bank); omap_gpio_dbck_disable(bank);
raw_spin_unlock_irqrestore(&bank->lock, flags);
return 0;
} }
static void omap_gpio_init_context(struct gpio_bank *p); static void omap_gpio_init_context(struct gpio_bank *p);
static int omap_gpio_runtime_resume(struct device *dev) static void omap_gpio_unidle(struct gpio_bank *bank)
{ {
struct platform_device *pdev = to_platform_device(dev); struct device *dev = bank->chip.parent;
struct gpio_bank *bank = platform_get_drvdata(pdev);
u32 l = 0, gen, gen0, gen1; u32 l = 0, gen, gen0, gen1;
unsigned long flags;
int c; int c;
raw_spin_lock_irqsave(&bank->lock, flags);
/* /*
* On the first resume during the probe, the context has not * On the first resume during the probe, the context has not
* been initialised and so initialise it now. Also initialise * been initialised and so initialise it now. Also initialise
...@@ -1459,16 +1557,8 @@ static int omap_gpio_runtime_resume(struct device *dev) ...@@ -1459,16 +1557,8 @@ static int omap_gpio_runtime_resume(struct device *dev)
omap_gpio_dbck_enable(bank); omap_gpio_dbck_enable(bank);
/* if (bank->funcs.idle_disable_level_quirk)
* In ->runtime_suspend(), level-triggered, wakeup-enabled bank->funcs.idle_disable_level_quirk(bank);
* GPIOs were set to edge trigger also in order to be able to
* generate a PRCM wakeup. Here we restore the
* pre-runtime_suspend() values for edge triggering.
*/
writel_relaxed(bank->context.fallingdetect,
bank->base + bank->regs->fallingdetect);
writel_relaxed(bank->context.risingdetect,
bank->base + bank->regs->risingdetect);
if (bank->loses_context) { if (bank->loses_context) {
if (!bank->get_context_loss_count) { if (!bank->get_context_loss_count) {
...@@ -1478,16 +1568,13 @@ static int omap_gpio_runtime_resume(struct device *dev) ...@@ -1478,16 +1568,13 @@ static int omap_gpio_runtime_resume(struct device *dev)
if (c != bank->context_loss_count) { if (c != bank->context_loss_count) {
omap_gpio_restore_context(bank); omap_gpio_restore_context(bank);
} else { } else {
raw_spin_unlock_irqrestore(&bank->lock, flags); return;
return 0;
} }
} }
} }
if (!bank->workaround_enabled) { if (!bank->workaround_enabled)
raw_spin_unlock_irqrestore(&bank->lock, flags); return;
return 0;
}
l = readl_relaxed(bank->base + bank->regs->datain); l = readl_relaxed(bank->base + bank->regs->datain);
...@@ -1540,41 +1627,8 @@ static int omap_gpio_runtime_resume(struct device *dev) ...@@ -1540,41 +1627,8 @@ static int omap_gpio_runtime_resume(struct device *dev)
} }
bank->workaround_enabled = false; bank->workaround_enabled = false;
raw_spin_unlock_irqrestore(&bank->lock, flags);
return 0;
}
#endif /* CONFIG_PM */
#if IS_BUILTIN(CONFIG_GPIO_OMAP)
void omap2_gpio_prepare_for_idle(int pwr_mode)
{
struct gpio_bank *bank;
list_for_each_entry(bank, &omap_gpio_list, node) {
if (!BANK_USED(bank) || !bank->loses_context)
continue;
bank->power_mode = pwr_mode;
pm_runtime_put_sync_suspend(bank->chip.parent);
}
} }
void omap2_gpio_resume_after_idle(void)
{
struct gpio_bank *bank;
list_for_each_entry(bank, &omap_gpio_list, node) {
if (!BANK_USED(bank) || !bank->loses_context)
continue;
pm_runtime_get_sync(bank->chip.parent);
}
}
#endif
#if defined(CONFIG_PM)
static void omap_gpio_init_context(struct gpio_bank *p) static void omap_gpio_init_context(struct gpio_bank *p)
{ {
struct omap_gpio_reg_offs *regs = p->regs; struct omap_gpio_reg_offs *regs = p->regs;
...@@ -1631,17 +1685,57 @@ static void omap_gpio_restore_context(struct gpio_bank *bank) ...@@ -1631,17 +1685,57 @@ static void omap_gpio_restore_context(struct gpio_bank *bank)
writel_relaxed(bank->context.irqenable2, writel_relaxed(bank->context.irqenable2,
bank->base + bank->regs->irqenable2); bank->base + bank->regs->irqenable2);
} }
#endif /* CONFIG_PM */
#else
#define omap_gpio_runtime_suspend NULL
#define omap_gpio_runtime_resume NULL
static inline void omap_gpio_init_context(struct gpio_bank *p) {}
#endif
static int __maybe_unused omap_gpio_runtime_suspend(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct gpio_bank *bank = platform_get_drvdata(pdev);
unsigned long flags;
int error = 0;
raw_spin_lock_irqsave(&bank->lock, flags);
/* Must be idled only by CPU_CLUSTER_PM_ENTER? */
if (bank->irq_usage) {
error = -EBUSY;
goto unlock;
}
omap_gpio_idle(bank, true);
bank->is_suspended = true;
unlock:
raw_spin_unlock_irqrestore(&bank->lock, flags);
return error;
}
static int __maybe_unused omap_gpio_runtime_resume(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct gpio_bank *bank = platform_get_drvdata(pdev);
unsigned long flags;
int error = 0;
raw_spin_lock_irqsave(&bank->lock, flags);
/* Must be unidled only by CPU_CLUSTER_PM_ENTER? */
if (bank->irq_usage) {
error = -EBUSY;
goto unlock;
}
omap_gpio_unidle(bank);
bank->is_suspended = false;
unlock:
raw_spin_unlock_irqrestore(&bank->lock, flags);
return error;
}
#ifdef CONFIG_ARCH_OMAP2PLUS
static const struct dev_pm_ops gpio_pm_ops = { static const struct dev_pm_ops gpio_pm_ops = {
SET_RUNTIME_PM_OPS(omap_gpio_runtime_suspend, omap_gpio_runtime_resume, SET_RUNTIME_PM_OPS(omap_gpio_runtime_suspend, omap_gpio_runtime_resume,
NULL) NULL)
}; };
#else
static const struct dev_pm_ops gpio_pm_ops;
#endif /* CONFIG_ARCH_OMAP2PLUS */
#if defined(CONFIG_OF) #if defined(CONFIG_OF)
static struct omap_gpio_reg_offs omap2_gpio_regs = { static struct omap_gpio_reg_offs omap2_gpio_regs = {
...@@ -1690,6 +1784,11 @@ static struct omap_gpio_reg_offs omap4_gpio_regs = { ...@@ -1690,6 +1784,11 @@ static struct omap_gpio_reg_offs omap4_gpio_regs = {
.fallingdetect = OMAP4_GPIO_FALLINGDETECT, .fallingdetect = OMAP4_GPIO_FALLINGDETECT,
}; };
/*
* Note that omap2 does not currently support idle modes with context loss so
* no need to add OMAP_GPIO_QUIRK_IDLE_REMOVE_TRIGGER quirk flag to save
* and restore context.
*/
static const struct omap_gpio_platform_data omap2_pdata = { static const struct omap_gpio_platform_data omap2_pdata = {
.regs = &omap2_gpio_regs, .regs = &omap2_gpio_regs,
.bank_width = 32, .bank_width = 32,
...@@ -1700,12 +1799,15 @@ static const struct omap_gpio_platform_data omap3_pdata = { ...@@ -1700,12 +1799,15 @@ static const struct omap_gpio_platform_data omap3_pdata = {
.regs = &omap2_gpio_regs, .regs = &omap2_gpio_regs,
.bank_width = 32, .bank_width = 32,
.dbck_flag = true, .dbck_flag = true,
.quirks = OMAP_GPIO_QUIRK_IDLE_REMOVE_TRIGGER,
}; };
static const struct omap_gpio_platform_data omap4_pdata = { static const struct omap_gpio_platform_data omap4_pdata = {
.regs = &omap4_gpio_regs, .regs = &omap4_gpio_regs,
.bank_width = 32, .bank_width = 32,
.dbck_flag = true, .dbck_flag = true,
.quirks = OMAP_GPIO_QUIRK_IDLE_REMOVE_TRIGGER |
OMAP_GPIO_QUIRK_DEFERRED_WKUP_EN,
}; };
static const struct of_device_id omap_gpio_match[] = { static const struct of_device_id omap_gpio_match[] = {
......
...@@ -776,6 +776,9 @@ static int pxa_gpio_suspend(void) ...@@ -776,6 +776,9 @@ static int pxa_gpio_suspend(void)
struct pxa_gpio_bank *c; struct pxa_gpio_bank *c;
int gpio; int gpio;
if (!pchip)
return 0;
for_each_gpio_bank(gpio, c, pchip) { for_each_gpio_bank(gpio, c, pchip) {
c->saved_gplr = readl_relaxed(c->regbase + GPLR_OFFSET); c->saved_gplr = readl_relaxed(c->regbase + GPLR_OFFSET);
c->saved_gpdr = readl_relaxed(c->regbase + GPDR_OFFSET); c->saved_gpdr = readl_relaxed(c->regbase + GPDR_OFFSET);
...@@ -794,6 +797,9 @@ static void pxa_gpio_resume(void) ...@@ -794,6 +797,9 @@ static void pxa_gpio_resume(void)
struct pxa_gpio_bank *c; struct pxa_gpio_bank *c;
int gpio; int gpio;
if (!pchip)
return;
for_each_gpio_bank(gpio, c, pchip) { for_each_gpio_bank(gpio, c, pchip) {
/* restore level with set/clear */ /* restore level with set/clear */
writel_relaxed(c->saved_gplr, c->regbase + GPSR_OFFSET); writel_relaxed(c->saved_gplr, c->regbase + GPSR_OFFSET);
......
...@@ -321,6 +321,9 @@ static void gpio_rcar_set_multiple(struct gpio_chip *chip, unsigned long *mask, ...@@ -321,6 +321,9 @@ static void gpio_rcar_set_multiple(struct gpio_chip *chip, unsigned long *mask,
u32 val, bankmask; u32 val, bankmask;
bankmask = mask[0] & GENMASK(chip->ngpio - 1, 0); bankmask = mask[0] & GENMASK(chip->ngpio - 1, 0);
if (chip->valid_mask)
bankmask &= chip->valid_mask[0];
if (!bankmask) if (!bankmask)
return; return;
...@@ -558,6 +561,9 @@ static int gpio_rcar_resume(struct device *dev) ...@@ -558,6 +561,9 @@ static int gpio_rcar_resume(struct device *dev)
u32 mask; u32 mask;
for (offset = 0; offset < p->gpio_chip.ngpio; offset++) { for (offset = 0; offset < p->gpio_chip.ngpio; offset++) {
if (!gpiochip_line_is_valid(&p->gpio_chip, offset))
continue;
mask = BIT(offset); mask = BIT(offset);
/* I/O pin */ /* I/O pin */
if (!(p->bank_info.iointsel & mask)) { if (!(p->bank_info.iointsel & mask)) {
......
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2015-2018 Pengutronix, Uwe Kleine-König <kernel@pengutronix.de>
*/
#include <linux/module.h>
#include <linux/siox.h>
#include <linux/gpio/driver.h>
#include <linux/of.h>
struct gpio_siox_ddata {
struct gpio_chip gchip;
struct irq_chip ichip;
struct mutex lock;
u8 setdata[1];
u8 getdata[3];
spinlock_t irqlock;
u32 irq_enable;
u32 irq_status;
u32 irq_type[20];
};
/*
* Note that this callback only sets the value that is clocked out in the next
* cycle.
*/
static int gpio_siox_set_data(struct siox_device *sdevice, u8 status, u8 buf[])
{
struct gpio_siox_ddata *ddata = dev_get_drvdata(&sdevice->dev);
mutex_lock(&ddata->lock);
buf[0] = ddata->setdata[0];
mutex_unlock(&ddata->lock);
return 0;
}
static int gpio_siox_get_data(struct siox_device *sdevice, const u8 buf[])
{
struct gpio_siox_ddata *ddata = dev_get_drvdata(&sdevice->dev);
size_t offset;
u32 trigger;
mutex_lock(&ddata->lock);
spin_lock_irq(&ddata->irqlock);
for (offset = 0; offset < 12; ++offset) {
unsigned int bitpos = 11 - offset;
unsigned int gpiolevel = buf[bitpos / 8] & (1 << bitpos % 8);
unsigned int prev_level =
ddata->getdata[bitpos / 8] & (1 << (bitpos % 8));
u32 irq_type = ddata->irq_type[offset];
if (gpiolevel) {
if ((irq_type & IRQ_TYPE_LEVEL_HIGH) ||
((irq_type & IRQ_TYPE_EDGE_RISING) && !prev_level))
ddata->irq_status |= 1 << offset;
} else {
if ((irq_type & IRQ_TYPE_LEVEL_LOW) ||
((irq_type & IRQ_TYPE_EDGE_FALLING) && prev_level))
ddata->irq_status |= 1 << offset;
}
}
trigger = ddata->irq_status & ddata->irq_enable;
spin_unlock_irq(&ddata->irqlock);
ddata->getdata[0] = buf[0];
ddata->getdata[1] = buf[1];
ddata->getdata[2] = buf[2];
mutex_unlock(&ddata->lock);
for (offset = 0; offset < 12; ++offset) {
if (trigger & (1 << offset)) {
struct irq_domain *irqdomain = ddata->gchip.irq.domain;
unsigned int irq = irq_find_mapping(irqdomain, offset);
/*
* Conceptually handle_nested_irq should call the flow
* handler of the irq chip. But it doesn't, so we have
* to clean the irq_status here.
*/
spin_lock_irq(&ddata->irqlock);
ddata->irq_status &= ~(1 << offset);
spin_unlock_irq(&ddata->irqlock);
handle_nested_irq(irq);
}
}
return 0;
}
static void gpio_siox_irq_ack(struct irq_data *d)
{
struct irq_chip *ic = irq_data_get_irq_chip(d);
struct gpio_siox_ddata *ddata =
container_of(ic, struct gpio_siox_ddata, ichip);
spin_lock_irq(&ddata->irqlock);
ddata->irq_status &= ~(1 << d->hwirq);
spin_unlock_irq(&ddata->irqlock);
}
static void gpio_siox_irq_mask(struct irq_data *d)
{
struct irq_chip *ic = irq_data_get_irq_chip(d);
struct gpio_siox_ddata *ddata =
container_of(ic, struct gpio_siox_ddata, ichip);
spin_lock_irq(&ddata->irqlock);
ddata->irq_enable &= ~(1 << d->hwirq);
spin_unlock_irq(&ddata->irqlock);
}
static void gpio_siox_irq_unmask(struct irq_data *d)
{
struct irq_chip *ic = irq_data_get_irq_chip(d);
struct gpio_siox_ddata *ddata =
container_of(ic, struct gpio_siox_ddata, ichip);
spin_lock_irq(&ddata->irqlock);
ddata->irq_enable |= 1 << d->hwirq;
spin_unlock_irq(&ddata->irqlock);
}
static int gpio_siox_irq_set_type(struct irq_data *d, u32 type)
{
struct irq_chip *ic = irq_data_get_irq_chip(d);
struct gpio_siox_ddata *ddata =
container_of(ic, struct gpio_siox_ddata, ichip);
spin_lock_irq(&ddata->irqlock);
ddata->irq_type[d->hwirq] = type;
spin_unlock_irq(&ddata->irqlock);
return 0;
}
static int gpio_siox_get(struct gpio_chip *chip, unsigned int offset)
{
struct gpio_siox_ddata *ddata =
container_of(chip, struct gpio_siox_ddata, gchip);
int ret;
mutex_lock(&ddata->lock);
if (offset >= 12) {
unsigned int bitpos = 19 - offset;
ret = ddata->setdata[0] & (1 << bitpos);
} else {
unsigned int bitpos = 11 - offset;
ret = ddata->getdata[bitpos / 8] & (1 << (bitpos % 8));
}
mutex_unlock(&ddata->lock);
return ret;
}
static void gpio_siox_set(struct gpio_chip *chip,
unsigned int offset, int value)
{
struct gpio_siox_ddata *ddata =
container_of(chip, struct gpio_siox_ddata, gchip);
u8 mask = 1 << (19 - offset);
mutex_lock(&ddata->lock);
if (value)
ddata->setdata[0] |= mask;
else
ddata->setdata[0] &= ~mask;
mutex_unlock(&ddata->lock);
}
static int gpio_siox_direction_input(struct gpio_chip *chip,
unsigned int offset)
{
if (offset >= 12)
return -EINVAL;
return 0;
}
static int gpio_siox_direction_output(struct gpio_chip *chip,
unsigned int offset, int value)
{
if (offset < 12)
return -EINVAL;
gpio_siox_set(chip, offset, value);
return 0;
}
static int gpio_siox_get_direction(struct gpio_chip *chip, unsigned int offset)
{
if (offset < 12)
return 1; /* input */
else
return 0; /* output */
}
static int gpio_siox_probe(struct siox_device *sdevice)
{
struct gpio_siox_ddata *ddata;
int ret;
ddata = devm_kzalloc(&sdevice->dev, sizeof(*ddata), GFP_KERNEL);
if (!ddata)
return -ENOMEM;
dev_set_drvdata(&sdevice->dev, ddata);
mutex_init(&ddata->lock);
spin_lock_init(&ddata->irqlock);
ddata->gchip.base = -1;
ddata->gchip.can_sleep = 1;
ddata->gchip.parent = &sdevice->dev;
ddata->gchip.owner = THIS_MODULE;
ddata->gchip.get = gpio_siox_get;
ddata->gchip.set = gpio_siox_set;
ddata->gchip.direction_input = gpio_siox_direction_input;
ddata->gchip.direction_output = gpio_siox_direction_output;
ddata->gchip.get_direction = gpio_siox_get_direction;
ddata->gchip.ngpio = 20;
ddata->ichip.name = "siox-gpio";
ddata->ichip.irq_ack = gpio_siox_irq_ack;
ddata->ichip.irq_mask = gpio_siox_irq_mask;
ddata->ichip.irq_unmask = gpio_siox_irq_unmask;
ddata->ichip.irq_set_type = gpio_siox_irq_set_type;
ret = gpiochip_add(&ddata->gchip);
if (ret) {
dev_err(&sdevice->dev,
"Failed to register gpio chip (%d)\n", ret);
goto err_gpiochip;
}
ret = gpiochip_irqchip_add(&ddata->gchip, &ddata->ichip,
0, handle_level_irq, IRQ_TYPE_EDGE_RISING);
if (ret) {
dev_err(&sdevice->dev,
"Failed to register irq chip (%d)\n", ret);
err_gpiochip:
gpiochip_remove(&ddata->gchip);
}
return ret;
}
static int gpio_siox_remove(struct siox_device *sdevice)
{
struct gpio_siox_ddata *ddata = dev_get_drvdata(&sdevice->dev);
gpiochip_remove(&ddata->gchip);
return 0;
}
static struct siox_driver gpio_siox_driver = {
.probe = gpio_siox_probe,
.remove = gpio_siox_remove,
.set_data = gpio_siox_set_data,
.get_data = gpio_siox_get_data,
.driver = {
.name = "gpio-siox",
},
};
static int __init gpio_siox_init(void)
{
return siox_driver_register(&gpio_siox_driver);
}
module_init(gpio_siox_init);
static void __exit gpio_siox_exit(void)
{
siox_driver_unregister(&gpio_siox_driver);
}
module_exit(gpio_siox_exit);
MODULE_AUTHOR("Uwe Kleine-Koenig <u.kleine-koenig@pengutronix.de>");
MODULE_DESCRIPTION("SIOX gpio driver");
MODULE_LICENSE("GPL v2");
...@@ -122,7 +122,7 @@ static int syscon_gpio_dir_out(struct gpio_chip *chip, unsigned offset, int val) ...@@ -122,7 +122,7 @@ static int syscon_gpio_dir_out(struct gpio_chip *chip, unsigned offset, int val)
BIT(offs % SYSCON_REG_BITS)); BIT(offs % SYSCON_REG_BITS));
} }
priv->data->set(chip, offset, val); chip->set(chip, offset, val);
return 0; return 0;
} }
......
...@@ -45,14 +45,12 @@ ...@@ -45,14 +45,12 @@
/** /**
* @spinlock: used for atomic read/modify/write of registers
* @base: register base address * @base: register base address
* @domain: IRQ domain of GPIO generated interrupts managed by this controller * @domain: IRQ domain of GPIO generated interrupts managed by this controller
* @irq: Interrupt line of parent interrupt controller * @irq: Interrupt line of parent interrupt controller
* @gc: gpio_chip structure associated to this GPIO controller * @gc: gpio_chip structure associated to this GPIO controller
*/ */
struct tb10x_gpio { struct tb10x_gpio {
spinlock_t spinlock;
void __iomem *base; void __iomem *base;
struct irq_domain *domain; struct irq_domain *domain;
int irq; int irq;
...@@ -76,60 +74,14 @@ static inline void tb10x_set_bits(struct tb10x_gpio *gpio, unsigned int offs, ...@@ -76,60 +74,14 @@ static inline void tb10x_set_bits(struct tb10x_gpio *gpio, unsigned int offs,
u32 r; u32 r;
unsigned long flags; unsigned long flags;
spin_lock_irqsave(&gpio->spinlock, flags); spin_lock_irqsave(&gpio->gc.bgpio_lock, flags);
r = tb10x_reg_read(gpio, offs); r = tb10x_reg_read(gpio, offs);
r = (r & ~mask) | (val & mask); r = (r & ~mask) | (val & mask);
tb10x_reg_write(gpio, offs, r); tb10x_reg_write(gpio, offs, r);
spin_unlock_irqrestore(&gpio->spinlock, flags); spin_unlock_irqrestore(&gpio->gc.bgpio_lock, flags);
}
static int tb10x_gpio_direction_in(struct gpio_chip *chip, unsigned offset)
{
struct tb10x_gpio *tb10x_gpio = gpiochip_get_data(chip);
int mask = BIT(offset);
int val = TB10X_GPIO_DIR_IN << offset;
tb10x_set_bits(tb10x_gpio, OFFSET_TO_REG_DDR, mask, val);
return 0;
}
static int tb10x_gpio_get(struct gpio_chip *chip, unsigned offset)
{
struct tb10x_gpio *tb10x_gpio = gpiochip_get_data(chip);
int val;
val = tb10x_reg_read(tb10x_gpio, OFFSET_TO_REG_DATA);
if (val & BIT(offset))
return 1;
else
return 0;
}
static void tb10x_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
{
struct tb10x_gpio *tb10x_gpio = gpiochip_get_data(chip);
int mask = BIT(offset);
int val = value << offset;
tb10x_set_bits(tb10x_gpio, OFFSET_TO_REG_DATA, mask, val);
}
static int tb10x_gpio_direction_out(struct gpio_chip *chip,
unsigned offset, int value)
{
struct tb10x_gpio *tb10x_gpio = gpiochip_get_data(chip);
int mask = BIT(offset);
int val = TB10X_GPIO_DIR_OUT << offset;
tb10x_gpio_set(chip, offset, value);
tb10x_set_bits(tb10x_gpio, OFFSET_TO_REG_DDR, mask, val);
return 0;
} }
static int tb10x_gpio_to_irq(struct gpio_chip *chip, unsigned offset) static int tb10x_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
...@@ -169,72 +121,85 @@ static int tb10x_gpio_probe(struct platform_device *pdev) ...@@ -169,72 +121,85 @@ static int tb10x_gpio_probe(struct platform_device *pdev)
{ {
struct tb10x_gpio *tb10x_gpio; struct tb10x_gpio *tb10x_gpio;
struct resource *mem; struct resource *mem;
struct device_node *dn = pdev->dev.of_node; struct device *dev = &pdev->dev;
struct device_node *np = dev->of_node;
int ret = -EBUSY; int ret = -EBUSY;
u32 ngpio; u32 ngpio;
if (!dn) if (!np)
return -EINVAL; return -EINVAL;
if (of_property_read_u32(dn, "abilis,ngpio", &ngpio)) if (of_property_read_u32(np, "abilis,ngpio", &ngpio))
return -EINVAL; return -EINVAL;
tb10x_gpio = devm_kzalloc(&pdev->dev, sizeof(*tb10x_gpio), GFP_KERNEL); tb10x_gpio = devm_kzalloc(dev, sizeof(*tb10x_gpio), GFP_KERNEL);
if (tb10x_gpio == NULL) if (tb10x_gpio == NULL)
return -ENOMEM; return -ENOMEM;
spin_lock_init(&tb10x_gpio->spinlock);
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
tb10x_gpio->base = devm_ioremap_resource(&pdev->dev, mem); tb10x_gpio->base = devm_ioremap_resource(dev, mem);
if (IS_ERR(tb10x_gpio->base)) if (IS_ERR(tb10x_gpio->base))
return PTR_ERR(tb10x_gpio->base); return PTR_ERR(tb10x_gpio->base);
tb10x_gpio->gc.label = tb10x_gpio->gc.label =
devm_kasprintf(&pdev->dev, GFP_KERNEL, "%pOF", pdev->dev.of_node); devm_kasprintf(dev, GFP_KERNEL, "%pOF", pdev->dev.of_node);
if (!tb10x_gpio->gc.label) if (!tb10x_gpio->gc.label)
return -ENOMEM; return -ENOMEM;
tb10x_gpio->gc.parent = &pdev->dev; /*
* Initialize generic GPIO with one single register for reading and setting
* the lines, no special set or clear registers and a data direction register
* wher 1 means "output".
*/
ret = bgpio_init(&tb10x_gpio->gc, dev, 4,
tb10x_gpio->base + OFFSET_TO_REG_DATA,
NULL,
NULL,
tb10x_gpio->base + OFFSET_TO_REG_DDR,
NULL,
0);
if (ret) {
dev_err(dev, "unable to init generic GPIO\n");
return ret;
}
tb10x_gpio->gc.base = -1;
tb10x_gpio->gc.parent = dev;
tb10x_gpio->gc.owner = THIS_MODULE; tb10x_gpio->gc.owner = THIS_MODULE;
tb10x_gpio->gc.direction_input = tb10x_gpio_direction_in; /*
tb10x_gpio->gc.get = tb10x_gpio_get; * ngpio is set by bgpio_init() but we override it, this .request()
tb10x_gpio->gc.direction_output = tb10x_gpio_direction_out; * callback also overrides the one set up by generic GPIO.
tb10x_gpio->gc.set = tb10x_gpio_set; */
tb10x_gpio->gc.ngpio = ngpio;
tb10x_gpio->gc.request = gpiochip_generic_request; tb10x_gpio->gc.request = gpiochip_generic_request;
tb10x_gpio->gc.free = gpiochip_generic_free; tb10x_gpio->gc.free = gpiochip_generic_free;
tb10x_gpio->gc.base = -1;
tb10x_gpio->gc.ngpio = ngpio;
tb10x_gpio->gc.can_sleep = false;
ret = devm_gpiochip_add_data(&pdev->dev, &tb10x_gpio->gc, tb10x_gpio); ret = devm_gpiochip_add_data(dev, &tb10x_gpio->gc, tb10x_gpio);
if (ret < 0) { if (ret < 0) {
dev_err(&pdev->dev, "Could not add gpiochip.\n"); dev_err(dev, "Could not add gpiochip.\n");
return ret; return ret;
} }
platform_set_drvdata(pdev, tb10x_gpio); platform_set_drvdata(pdev, tb10x_gpio);
if (of_find_property(dn, "interrupt-controller", NULL)) { if (of_find_property(np, "interrupt-controller", NULL)) {
struct irq_chip_generic *gc; struct irq_chip_generic *gc;
ret = platform_get_irq(pdev, 0); ret = platform_get_irq(pdev, 0);
if (ret < 0) { if (ret < 0) {
dev_err(&pdev->dev, "No interrupt specified.\n"); dev_err(dev, "No interrupt specified.\n");
return ret; return ret;
} }
tb10x_gpio->gc.to_irq = tb10x_gpio_to_irq; tb10x_gpio->gc.to_irq = tb10x_gpio_to_irq;
tb10x_gpio->irq = ret; tb10x_gpio->irq = ret;
ret = devm_request_irq(&pdev->dev, ret, tb10x_gpio_irq_cascade, ret = devm_request_irq(dev, ret, tb10x_gpio_irq_cascade,
IRQF_TRIGGER_NONE | IRQF_SHARED, IRQF_TRIGGER_NONE | IRQF_SHARED,
dev_name(&pdev->dev), tb10x_gpio); dev_name(dev), tb10x_gpio);
if (ret != 0) if (ret != 0)
return ret; return ret;
tb10x_gpio->domain = irq_domain_add_linear(dn, tb10x_gpio->domain = irq_domain_add_linear(np,
tb10x_gpio->gc.ngpio, tb10x_gpio->gc.ngpio,
&irq_generic_chip_ops, NULL); &irq_generic_chip_ops, NULL);
if (!tb10x_gpio->domain) { if (!tb10x_gpio->domain) {
......
// SPDX-License-Identifier: GPL-2.0
/* /*
* Copyright (C) 2015 Texas Instruments Incorporated - http://www.ti.com/ * Copyright (C) 2015 Texas Instruments Incorporated - http://www.ti.com/
* Andrew F. Davis <afd@ti.com> * Andrew F. Davis <afd@ti.com>
* *
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed "as is" WITHOUT ANY WARRANTY of any
* kind, whether expressed or implied; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License version 2 for more details.
*
* Based on the TPS65912 driver * Based on the TPS65912 driver
*/ */
#include <linux/gpio.h> #include <linux/gpio/driver.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
......
// SPDX-License-Identifier: GPL-2.0
/* /*
* TI TPS6586x GPIO driver * TI TPS6586x GPIO driver
* *
...@@ -7,22 +8,10 @@ ...@@ -7,22 +8,10 @@
* Based on tps6586x.c * Based on tps6586x.c
* Copyright (c) 2010 CompuLab Ltd. * Copyright (c) 2010 CompuLab Ltd.
* Mike Rapoport <mike@compulab.co.il> * Mike Rapoport <mike@compulab.co.il>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/gpio.h> #include <linux/gpio/driver.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/mfd/tps6586x.h> #include <linux/mfd/tps6586x.h>
......
// SPDX-License-Identifier: GPL-2.0+
/* /*
* TI TPS6591x GPIO driver * TI TPS6591x GPIO driver
* *
...@@ -5,18 +6,12 @@ ...@@ -5,18 +6,12 @@
* *
* Author: Graeme Gregory <gg@slimlogic.co.uk> * Author: Graeme Gregory <gg@slimlogic.co.uk>
* Author: Jorge Eduardo Candelaria <jedu@slimlogic.co.uk> * Author: Jorge Eduardo Candelaria <jedu@slimlogic.co.uk>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
*/ */
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/gpio.h> #include <linux/gpio/driver.h>
#include <linux/i2c.h> #include <linux/i2c.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/mfd/tps65910.h> #include <linux/mfd/tps65910.h>
......
// SPDX-License-Identifier: GPL-2.0
/* /*
* GPIO driver for TI TPS65912x PMICs * GPIO driver for TI TPS65912x PMICs
* *
* Copyright (C) 2015 Texas Instruments Incorporated - http://www.ti.com/ * Copyright (C) 2015 Texas Instruments Incorporated - http://www.ti.com/
* Andrew F. Davis <afd@ti.com> * Andrew F. Davis <afd@ti.com>
* *
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed "as is" WITHOUT ANY WARRANTY of any
* kind, whether expressed or implied; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License version 2 for more details.
*
* Based on the Arizona GPIO driver and the previous TPS65912 driver by * Based on the Arizona GPIO driver and the previous TPS65912 driver by
* Margarita Olaya Cabrera <magi@slimlogic.co.uk> * Margarita Olaya Cabrera <magi@slimlogic.co.uk>
*/ */
#include <linux/gpio.h> #include <linux/gpio/driver.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
...@@ -40,9 +32,9 @@ static int tps65912_gpio_get_direction(struct gpio_chip *gc, ...@@ -40,9 +32,9 @@ static int tps65912_gpio_get_direction(struct gpio_chip *gc,
return ret; return ret;
if (val & GPIO_CFG_MASK) if (val & GPIO_CFG_MASK)
return GPIOF_DIR_OUT; return 0;
else else
return GPIOF_DIR_IN; return 1;
} }
static int tps65912_gpio_direction_input(struct gpio_chip *gc, unsigned offset) static int tps65912_gpio_direction_input(struct gpio_chip *gc, unsigned offset)
......
// SPDX-License-Identifier: GPL-2.0
/* /*
* Digital I/O driver for Technologic Systems TS-5500 * Digital I/O driver for Technologic Systems TS-5500
* *
...@@ -16,17 +17,12 @@ ...@@ -16,17 +17,12 @@
* TS-5600: * TS-5600:
* Documentation: http://wiki.embeddedarm.com/wiki/TS-5600 * Documentation: http://wiki.embeddedarm.com/wiki/TS-5600
* Blocks: LCD port (identical to TS-5500 LCD). * Blocks: LCD port (identical to TS-5500 LCD).
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/ */
#include <linux/bitops.h> #include <linux/bitops.h>
#include <linux/gpio.h> #include <linux/gpio/driver.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/platform_data/gpio-ts5500.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/slab.h> #include <linux/slab.h>
...@@ -318,7 +314,6 @@ static void ts5500_disable_irq(struct ts5500_priv *priv) ...@@ -318,7 +314,6 @@ static void ts5500_disable_irq(struct ts5500_priv *priv)
static int ts5500_dio_probe(struct platform_device *pdev) static int ts5500_dio_probe(struct platform_device *pdev)
{ {
enum ts5500_blocks block = platform_get_device_id(pdev)->driver_data; enum ts5500_blocks block = platform_get_device_id(pdev)->driver_data;
struct ts5500_dio_platform_data *pdata = dev_get_platdata(&pdev->dev);
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
const char *name = dev_name(dev); const char *name = dev_name(dev);
struct ts5500_priv *priv; struct ts5500_priv *priv;
...@@ -349,10 +344,6 @@ static int ts5500_dio_probe(struct platform_device *pdev) ...@@ -349,10 +344,6 @@ static int ts5500_dio_probe(struct platform_device *pdev)
priv->gpio_chip.set = ts5500_gpio_set; priv->gpio_chip.set = ts5500_gpio_set;
priv->gpio_chip.to_irq = ts5500_gpio_to_irq; priv->gpio_chip.to_irq = ts5500_gpio_to_irq;
priv->gpio_chip.base = -1; priv->gpio_chip.base = -1;
if (pdata) {
priv->gpio_chip.base = pdata->base;
priv->strap = pdata->strap;
}
switch (block) { switch (block) {
case TS5500_DIO1: case TS5500_DIO1:
......
// SPDX-License-Identifier: GPL-2.0+
/* /*
* Access to GPIOs on TWL4030/TPS659x0 chips * Access to GPIOs on TWL4030/TPS659x0 chips
* *
...@@ -9,20 +10,6 @@ ...@@ -9,20 +10,6 @@
* *
* Initial Code: * Initial Code:
* Andy Lowe / Nishanth Menon * Andy Lowe / Nishanth Menon
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/ */
#include <linux/module.h> #include <linux/module.h>
...@@ -30,7 +17,7 @@ ...@@ -30,7 +17,7 @@
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/kthread.h> #include <linux/kthread.h>
#include <linux/irq.h> #include <linux/irq.h>
#include <linux/gpio.h> #include <linux/gpio/driver.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/irqdomain.h> #include <linux/irqdomain.h>
...@@ -167,6 +154,23 @@ static int twl4030_set_gpio_direction(int gpio, int is_input) ...@@ -167,6 +154,23 @@ static int twl4030_set_gpio_direction(int gpio, int is_input)
return ret; return ret;
} }
static int twl4030_get_gpio_direction(int gpio)
{
u8 d_bnk = gpio >> 3;
u8 d_msk = BIT(gpio & 0x7);
u8 base = REG_GPIODATADIR1 + d_bnk;
int ret = 0;
ret = gpio_twl4030_read(base);
if (ret < 0)
return ret;
/* 1 = output, but gpiolib semantics are inverse so invert */
ret = !(ret & d_msk);
return ret;
}
static int twl4030_set_gpio_dataout(int gpio, int enable) static int twl4030_set_gpio_dataout(int gpio, int enable)
{ {
u8 d_bnk = gpio >> 3; u8 d_bnk = gpio >> 3;
...@@ -372,6 +376,28 @@ static int twl_direction_out(struct gpio_chip *chip, unsigned offset, int value) ...@@ -372,6 +376,28 @@ static int twl_direction_out(struct gpio_chip *chip, unsigned offset, int value)
return ret; return ret;
} }
static int twl_get_direction(struct gpio_chip *chip, unsigned offset)
{
struct gpio_twl4030_priv *priv = gpiochip_get_data(chip);
/*
* Default 0 = output
* LED GPIOs >= TWL4030_GPIO_MAX are always output
*/
int ret = 0;
mutex_lock(&priv->mutex);
if (offset < TWL4030_GPIO_MAX) {
ret = twl4030_get_gpio_direction(offset);
if (ret) {
mutex_unlock(&priv->mutex);
return ret;
}
}
mutex_unlock(&priv->mutex);
return ret;
}
static int twl_to_irq(struct gpio_chip *chip, unsigned offset) static int twl_to_irq(struct gpio_chip *chip, unsigned offset)
{ {
struct gpio_twl4030_priv *priv = gpiochip_get_data(chip); struct gpio_twl4030_priv *priv = gpiochip_get_data(chip);
...@@ -387,8 +413,9 @@ static const struct gpio_chip template_chip = { ...@@ -387,8 +413,9 @@ static const struct gpio_chip template_chip = {
.request = twl_request, .request = twl_request,
.free = twl_free, .free = twl_free,
.direction_input = twl_direction_in, .direction_input = twl_direction_in,
.get = twl_get,
.direction_output = twl_direction_out, .direction_output = twl_direction_out,
.get_direction = twl_get_direction,
.get = twl_get,
.set = twl_set, .set = twl_set,
.to_irq = twl_to_irq, .to_irq = twl_to_irq,
.can_sleep = true, .can_sleep = true,
......
// SPDX-License-Identifier: GPL-2.0+
/* /*
* Access to GPOs on TWL6040 chip * Access to GPOs on TWL6040 chip
* *
...@@ -6,28 +7,15 @@ ...@@ -6,28 +7,15 @@
* Authors: * Authors:
* Sergio Aguirre <saaguirre@ti.com> * Sergio Aguirre <saaguirre@ti.com>
* Peter Ujfalusi <peter.ujfalusi@ti.com> * Peter Ujfalusi <peter.ujfalusi@ti.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/ */
#include <linux/module.h> #include <linux/module.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/kthread.h> #include <linux/kthread.h>
#include <linux/irq.h> #include <linux/irq.h>
#include <linux/gpio.h> #include <linux/gpio/driver.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/bitops.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/mfd/twl6040.h> #include <linux/mfd/twl6040.h>
...@@ -41,7 +29,13 @@ static int twl6040gpo_get(struct gpio_chip *chip, unsigned offset) ...@@ -41,7 +29,13 @@ static int twl6040gpo_get(struct gpio_chip *chip, unsigned offset)
if (ret < 0) if (ret < 0)
return ret; return ret;
return (ret >> offset) & 1; return !!(ret & BIT(offset));
}
static int twl6040gpo_get_direction(struct gpio_chip *chip, unsigned offset)
{
/* This means "out" */
return 0;
} }
static int twl6040gpo_direction_out(struct gpio_chip *chip, unsigned offset, static int twl6040gpo_direction_out(struct gpio_chip *chip, unsigned offset,
...@@ -62,9 +56,9 @@ static void twl6040gpo_set(struct gpio_chip *chip, unsigned offset, int value) ...@@ -62,9 +56,9 @@ static void twl6040gpo_set(struct gpio_chip *chip, unsigned offset, int value)
return; return;
if (value) if (value)
gpoctl = ret | (1 << offset); gpoctl = ret | BIT(offset);
else else
gpoctl = ret & ~(1 << offset); gpoctl = ret & ~BIT(offset);
twl6040_reg_write(twl6040, TWL6040_REG_GPOCTL, gpoctl); twl6040_reg_write(twl6040, TWL6040_REG_GPOCTL, gpoctl);
} }
...@@ -74,6 +68,7 @@ static struct gpio_chip twl6040gpo_chip = { ...@@ -74,6 +68,7 @@ static struct gpio_chip twl6040gpo_chip = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.get = twl6040gpo_get, .get = twl6040gpo_get,
.direction_output = twl6040gpo_direction_out, .direction_output = twl6040gpo_direction_out,
.get_direction = twl6040gpo_get_direction,
.set = twl6040gpo_set, .set = twl6040gpo_set,
.can_sleep = true, .can_sleep = true,
}; };
......
// SPDX-License-Identifier: GPL-2.0+
/* /*
* Freescale vf610 GPIO support through PORT and GPIO * Freescale vf610 GPIO support through PORT and GPIO
* *
* Copyright (c) 2014 Toradex AG. * Copyright (c) 2014 Toradex AG.
* *
* Author: Stefan Agner <stefan@agner.ch>. * Author: Stefan Agner <stefan@agner.ch>.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/ */
#include <linux/bitops.h> #include <linux/bitops.h>
#include <linux/err.h> #include <linux/err.h>
#include <linux/gpio.h> #include <linux/gpio/driver.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/io.h> #include <linux/io.h>
......
// SPDX-License-Identifier: GPL-2.0+
/* /*
* Nano River Technologies viperboard GPIO lib driver * Nano River Technologies viperboard GPIO lib driver
* *
* (C) 2012 by Lemonage GmbH * (C) 2012 by Lemonage GmbH
* Author: Lars Poeschel <poeschel@lemonage.de> * Author: Lars Poeschel <poeschel@lemonage.de>
* All rights reserved. * All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
*/ */
#include <linux/kernel.h> #include <linux/kernel.h>
...@@ -19,9 +14,8 @@ ...@@ -19,9 +14,8 @@
#include <linux/types.h> #include <linux/types.h>
#include <linux/mutex.h> #include <linux/mutex.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/usb.h> #include <linux/usb.h>
#include <linux/gpio.h> #include <linux/gpio/driver.h>
#include <linux/mfd/viperboard.h> #include <linux/mfd/viperboard.h>
......
// SPDX-License-Identifier: GPL-2.0+
/* /*
* Driver for NEC VR4100 series General-purpose I/O Unit. * Driver for NEC VR4100 series General-purpose I/O Unit.
* *
* Copyright (C) 2002 MontaVista Software Inc. * Copyright (C) 2002 MontaVista Software Inc.
* Author: Yoichi Yuasa <source@mvista.com> * Author: Yoichi Yuasa <source@mvista.com>
* Copyright (C) 2003-2009 Yoichi Yuasa <yuasa@linux-mips.org> * Copyright (C) 2003-2009 Yoichi Yuasa <yuasa@linux-mips.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/ */
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/gpio.h> #include <linux/gpio/driver.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/io.h> #include <linux/io.h>
...@@ -384,44 +371,6 @@ static int giu_set_direction(struct gpio_chip *chip, unsigned pin, int dir) ...@@ -384,44 +371,6 @@ static int giu_set_direction(struct gpio_chip *chip, unsigned pin, int dir)
return 0; return 0;
} }
int vr41xx_gpio_pullupdown(unsigned int pin, gpio_pull_t pull)
{
u16 reg, mask;
unsigned long flags;
if ((giu_flags & GPIO_HAS_PULLUPDOWN_IO) != GPIO_HAS_PULLUPDOWN_IO)
return -EPERM;
if (pin >= 15)
return -EINVAL;
mask = 1 << pin;
spin_lock_irqsave(&giu_lock, flags);
if (pull == GPIO_PULL_UP || pull == GPIO_PULL_DOWN) {
reg = giu_read(GIUTERMUPDN);
if (pull == GPIO_PULL_UP)
reg |= mask;
else
reg &= ~mask;
giu_write(GIUTERMUPDN, reg);
reg = giu_read(GIUUSEUPDN);
reg |= mask;
giu_write(GIUUSEUPDN, reg);
} else {
reg = giu_read(GIUUSEUPDN);
reg &= ~mask;
giu_write(GIUUSEUPDN, reg);
}
spin_unlock_irqrestore(&giu_lock, flags);
return 0;
}
EXPORT_SYMBOL_GPL(vr41xx_gpio_pullupdown);
static int vr41xx_gpio_get(struct gpio_chip *chip, unsigned pin) static int vr41xx_gpio_get(struct gpio_chip *chip, unsigned pin)
{ {
u16 reg, mask; u16 reg, mask;
......
// SPDX-License-Identifier: GPL-2.0+
/* /*
* Linux GPIOlib driver for the VIA VX855 integrated southbridge GPIO * Linux GPIOlib driver for the VIA VX855 integrated southbridge GPIO
* *
...@@ -5,27 +6,10 @@ ...@@ -5,27 +6,10 @@
* Copyright (C) 2010 One Laptop per Child * Copyright (C) 2010 One Laptop per Child
* Author: Harald Welte <HaraldWelte@viatech.com> * Author: Harald Welte <HaraldWelte@viatech.com>
* All rights reserved. * All rights reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*
*/ */
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/gpio.h> #include <linux/gpio/driver.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/device.h> #include <linux/device.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
......
// SPDX-License-Identifier: GPL-2.0+
/* /*
* gpiolib support for Wolfson WM831x PMICs * gpiolib support for Wolfson WM831x PMICs
* *
...@@ -5,17 +6,12 @@ ...@@ -5,17 +6,12 @@
* *
* Author: Mark Brown <broonie@opensource.wolfsonmicro.com> * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
* *
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
*/ */
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/gpio.h> #include <linux/gpio/driver.h>
#include <linux/mfd/core.h> #include <linux/mfd/core.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/seq_file.h> #include <linux/seq_file.h>
......
// SPDX-License-Identifier: GPL-2.0+
/* /*
* gpiolib support for Wolfson WM835x PMICs * gpiolib support for Wolfson WM835x PMICs
* *
...@@ -5,17 +6,12 @@ ...@@ -5,17 +6,12 @@
* *
* Author: Mark Brown <broonie@opensource.wolfsonmicro.com> * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
* *
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
*/ */
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/gpio.h> #include <linux/gpio/driver.h>
#include <linux/mfd/core.h> #include <linux/mfd/core.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/seq_file.h> #include <linux/seq_file.h>
......
// SPDX-License-Identifier: GPL-2.0+
/* /*
* gpiolib support for Wolfson WM8994 * gpiolib support for Wolfson WM8994
* *
...@@ -5,17 +6,12 @@ ...@@ -5,17 +6,12 @@
* *
* Author: Mark Brown <broonie@opensource.wolfsonmicro.com> * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
* *
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
*/ */
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/gpio.h> #include <linux/gpio/driver.h>
#include <linux/mfd/core.h> #include <linux/mfd/core.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/seq_file.h> #include <linux/seq_file.h>
......
// SPDX-License-Identifier: GPL-2.0
/* /*
* Copyright (C) 2003-2015 Broadcom Corporation * Copyright (C) 2003-2015 Broadcom Corporation
* All Rights Reserved * All Rights Reserved
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/ */
#include <linux/gpio.h> #include <linux/gpio/driver.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/of_device.h> #include <linux/of_device.h>
#include <linux/module.h> #include <linux/module.h>
......
// SPDX-License-Identifier: GPL-2.0
/* /*
* Copyright (C) 2013 TangoTec Ltd. * Copyright (C) 2013 TangoTec Ltd.
* Author: Baruch Siach <baruch@tkos.co.il> * Author: Baruch Siach <baruch@tkos.co.il>
* *
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Driver for the Xtensa LX4 GPIO32 Option * Driver for the Xtensa LX4 GPIO32 Option
* *
* Documentation: Xtensa LX4 Microprocessor Data Book, Section 2.22 * Documentation: Xtensa LX4 Microprocessor Data Book, Section 2.22
...@@ -30,7 +27,7 @@ ...@@ -30,7 +27,7 @@
#include <linux/err.h> #include <linux/err.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/gpio.h> #include <linux/gpio/driver.h>
#include <linux/bitops.h> #include <linux/bitops.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
......
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
#include <linux/of_device.h> #include <linux/of_device.h>
#include <linux/of_gpio.h> #include <linux/of_gpio.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/gpio.h> #include <linux/gpio/driver.h>
/* /*
* Memory layout: * Memory layout:
......
// SPDX-License-Identifier: GPL-2.0
/* /*
* ACPI helpers for GPIO API * ACPI helpers for GPIO API
* *
* Copyright (C) 2012, Intel Corporation * Copyright (C) 2012, Intel Corporation
* Authors: Mathias Nyman <mathias.nyman@linux.intel.com> * Authors: Mathias Nyman <mathias.nyman@linux.intel.com>
* Mika Westerberg <mika.westerberg@linux.intel.com> * Mika Westerberg <mika.westerberg@linux.intel.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/ */
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/gpio.h>
#include <linux/gpio/consumer.h> #include <linux/gpio/consumer.h>
#include <linux/gpio/driver.h> #include <linux/gpio/driver.h>
#include <linux/gpio/machine.h> #include <linux/gpio/machine.h>
......
// SPDX-License-Identifier: GPL-2.0
/* /*
* Device property helpers for GPIO chips. * Device property helpers for GPIO chips.
* *
* Copyright (C) 2016, Intel Corporation * Copyright (C) 2016, Intel Corporation
* Author: Mika Westerberg <mika.westerberg@linux.intel.com> * Author: Mika Westerberg <mika.westerberg@linux.intel.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/ */
#include <linux/property.h> #include <linux/property.h>
...@@ -32,32 +29,29 @@ void devprop_gpiochip_set_names(struct gpio_chip *chip, ...@@ -32,32 +29,29 @@ void devprop_gpiochip_set_names(struct gpio_chip *chip,
struct gpio_device *gdev = chip->gpiodev; struct gpio_device *gdev = chip->gpiodev;
const char **names; const char **names;
int ret, i; int ret, i;
int count;
ret = fwnode_property_read_string_array(fwnode, "gpio-line-names", count = fwnode_property_read_string_array(fwnode, "gpio-line-names",
NULL, 0); NULL, 0);
if (ret < 0) if (count < 0)
return; return;
if (ret != gdev->ngpio) { if (count > gdev->ngpio)
dev_warn(&gdev->dev, count = gdev->ngpio;
"names %d do not match number of GPIOs %d\n", ret,
gdev->ngpio);
return;
}
names = kcalloc(gdev->ngpio, sizeof(*names), GFP_KERNEL); names = kcalloc(count, sizeof(*names), GFP_KERNEL);
if (!names) if (!names)
return; return;
ret = fwnode_property_read_string_array(fwnode, "gpio-line-names", ret = fwnode_property_read_string_array(fwnode, "gpio-line-names",
names, gdev->ngpio); names, count);
if (ret < 0) { if (ret < 0) {
dev_warn(&gdev->dev, "failed to read GPIO line names\n"); dev_warn(&gdev->dev, "failed to read GPIO line names\n");
kfree(names); kfree(names);
return; return;
} }
for (i = 0; i < gdev->ngpio; i++) for (i = 0; i < count; i++)
gdev->descs[i].name = names[i]; gdev->descs[i].name = names[i];
kfree(names); kfree(names);
......
/* SPDX-License-Identifier: GPL-2.0 */
/* /*
* drivers/gpio/devres.c - managed gpio resources * devres.c - managed gpio resources
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* This file is based on kernel/irq/devres.c * This file is based on kernel/irq/devres.c
* *
* Copyright (c) 2011 John Crispin <john@phrozen.org> * Copyright (c) 2011 John Crispin <john@phrozen.org>
......
// SPDX-License-Identifier: GPL-2.0
#include <linux/gpio/consumer.h> #include <linux/gpio/consumer.h>
#include <linux/gpio/driver.h> #include <linux/gpio/driver.h>
......
// SPDX-License-Identifier: GPL-2.0
/* /*
* OF helpers for the GPIO API * OF helpers for the GPIO API
* *
* Copyright (c) 2007-2008 MontaVista Software, Inc. * Copyright (c) 2007-2008 MontaVista Software, Inc.
* *
* Author: Anton Vorontsov <avorontsov@ru.mvista.com> * Author: Anton Vorontsov <avorontsov@ru.mvista.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*/ */
#include <linux/device.h> #include <linux/device.h>
...@@ -58,7 +54,8 @@ static struct gpio_desc *of_xlate_and_get_gpiod_flags(struct gpio_chip *chip, ...@@ -58,7 +54,8 @@ static struct gpio_desc *of_xlate_and_get_gpiod_flags(struct gpio_chip *chip,
} }
static void of_gpio_flags_quirks(struct device_node *np, static void of_gpio_flags_quirks(struct device_node *np,
enum of_gpio_flags *flags) enum of_gpio_flags *flags,
int index)
{ {
/* /*
* Some GPIO fixed regulator quirks. * Some GPIO fixed regulator quirks.
...@@ -92,6 +89,51 @@ static void of_gpio_flags_quirks(struct device_node *np, ...@@ -92,6 +89,51 @@ static void of_gpio_flags_quirks(struct device_node *np,
pr_info("%s uses legacy open drain flag - update the DTS if you can\n", pr_info("%s uses legacy open drain flag - update the DTS if you can\n",
of_node_full_name(np)); of_node_full_name(np));
} }
/*
* Legacy handling of SPI active high chip select. If we have a
* property named "cs-gpios" we need to inspect the child node
* to determine if the flags should have inverted semantics.
*/
if (IS_ENABLED(CONFIG_SPI_MASTER) &&
of_property_read_bool(np, "cs-gpios")) {
struct device_node *child;
u32 cs;
int ret;
for_each_child_of_node(np, child) {
ret = of_property_read_u32(child, "reg", &cs);
if (!ret)
continue;
if (cs == index) {
/*
* SPI children have active low chip selects
* by default. This can be specified negatively
* by just omitting "spi-cs-high" in the
* device node, or actively by tagging on
* GPIO_ACTIVE_LOW as flag in the device
* tree. If the line is simultaneously
* tagged as active low in the device tree
* and has the "spi-cs-high" set, we get a
* conflict and the "spi-cs-high" flag will
* take precedence.
*/
if (of_property_read_bool(np, "spi-cs-high")) {
if (*flags & OF_GPIO_ACTIVE_LOW) {
pr_warn("%s GPIO handle specifies active low - ignored\n",
of_node_full_name(np));
*flags &= ~OF_GPIO_ACTIVE_LOW;
}
} else {
if (!(*flags & OF_GPIO_ACTIVE_LOW))
pr_info("%s enforce active low on chipselect handle\n",
of_node_full_name(np));
*flags |= OF_GPIO_ACTIVE_LOW;
}
break;
}
}
}
} }
/** /**
...@@ -132,7 +174,7 @@ struct gpio_desc *of_get_named_gpiod_flags(struct device_node *np, ...@@ -132,7 +174,7 @@ struct gpio_desc *of_get_named_gpiod_flags(struct device_node *np,
goto out; goto out;
if (flags) if (flags)
of_gpio_flags_quirks(np, flags); of_gpio_flags_quirks(np, flags, index);
pr_debug("%s: parsed '%s' property of node '%pOF[%d]' - status (%d)\n", pr_debug("%s: parsed '%s' property of node '%pOF[%d]' - status (%d)\n",
__func__, propname, np, index, __func__, propname, np, index,
...@@ -349,8 +391,8 @@ static struct gpio_desc *of_parse_own_gpio(struct device_node *np, ...@@ -349,8 +391,8 @@ static struct gpio_desc *of_parse_own_gpio(struct device_node *np,
else if (of_property_read_bool(np, "output-high")) else if (of_property_read_bool(np, "output-high"))
*dflags |= GPIOD_OUT_HIGH; *dflags |= GPIOD_OUT_HIGH;
else { else {
pr_warn("GPIO line %d (%s): no hogging state specified, bailing out\n", pr_warn("GPIO line %d (%pOFn): no hogging state specified, bailing out\n",
desc_to_gpio(desc), np->name); desc_to_gpio(desc), np);
return ERR_PTR(-EINVAL); return ERR_PTR(-EINVAL);
} }
......
// SPDX-License-Identifier: GPL-2.0
#include <linux/idr.h> #include <linux/idr.h>
#include <linux/mutex.h> #include <linux/mutex.h>
#include <linux/device.h> #include <linux/device.h>
#include <linux/sysfs.h> #include <linux/sysfs.h>
#include <linux/gpio.h>
#include <linux/gpio/consumer.h> #include <linux/gpio/consumer.h>
#include <linux/gpio/driver.h> #include <linux/gpio/driver.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
...@@ -444,11 +444,6 @@ static struct attribute *gpiochip_attrs[] = { ...@@ -444,11 +444,6 @@ static struct attribute *gpiochip_attrs[] = {
}; };
ATTRIBUTE_GROUPS(gpiochip); ATTRIBUTE_GROUPS(gpiochip);
static struct gpio_desc *gpio_to_valid_desc(int gpio)
{
return gpio_is_valid(gpio) ? gpio_to_desc(gpio) : NULL;
}
/* /*
* /sys/class/gpio/export ... write-only * /sys/class/gpio/export ... write-only
* integer N ... number of GPIO to export (full access) * integer N ... number of GPIO to export (full access)
...@@ -467,7 +462,7 @@ static ssize_t export_store(struct class *class, ...@@ -467,7 +462,7 @@ static ssize_t export_store(struct class *class,
if (status < 0) if (status < 0)
goto done; goto done;
desc = gpio_to_valid_desc(gpio); desc = gpio_to_desc(gpio);
/* reject invalid GPIOs */ /* reject invalid GPIOs */
if (!desc) { if (!desc) {
pr_warn("%s: invalid GPIO %ld\n", __func__, gpio); pr_warn("%s: invalid GPIO %ld\n", __func__, gpio);
...@@ -514,7 +509,7 @@ static ssize_t unexport_store(struct class *class, ...@@ -514,7 +509,7 @@ static ssize_t unexport_store(struct class *class,
if (status < 0) if (status < 0)
goto done; goto done;
desc = gpio_to_valid_desc(gpio); desc = gpio_to_desc(gpio);
/* reject bogus commands (gpio_unexport ignores them) */ /* reject bogus commands (gpio_unexport ignores them) */
if (!desc) { if (!desc) {
pr_warn("%s: invalid GPIO %ld\n", __func__, gpio); pr_warn("%s: invalid GPIO %ld\n", __func__, gpio);
......
// SPDX-License-Identifier: GPL-2.0
#include <linux/bitmap.h> #include <linux/bitmap.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/module.h> #include <linux/module.h>
...@@ -212,13 +213,13 @@ int gpiod_get_direction(struct gpio_desc *desc) ...@@ -212,13 +213,13 @@ int gpiod_get_direction(struct gpio_desc *desc)
{ {
struct gpio_chip *chip; struct gpio_chip *chip;
unsigned offset; unsigned offset;
int status = -EINVAL; int status;
chip = gpiod_to_chip(desc); chip = gpiod_to_chip(desc);
offset = gpio_chip_hwgpio(desc); offset = gpio_chip_hwgpio(desc);
if (!chip->get_direction) if (!chip->get_direction)
return status; return -ENOTSUPP;
status = chip->get_direction(chip, offset); status = chip->get_direction(chip, offset);
if (status > 0) { if (status > 0) {
...@@ -359,7 +360,7 @@ static unsigned long *gpiochip_allocate_mask(struct gpio_chip *chip) ...@@ -359,7 +360,7 @@ static unsigned long *gpiochip_allocate_mask(struct gpio_chip *chip)
return p; return p;
} }
static int gpiochip_init_valid_mask(struct gpio_chip *gpiochip) static int gpiochip_alloc_valid_mask(struct gpio_chip *gpiochip)
{ {
#ifdef CONFIG_OF_GPIO #ifdef CONFIG_OF_GPIO
int size; int size;
...@@ -380,6 +381,14 @@ static int gpiochip_init_valid_mask(struct gpio_chip *gpiochip) ...@@ -380,6 +381,14 @@ static int gpiochip_init_valid_mask(struct gpio_chip *gpiochip)
return 0; return 0;
} }
static int gpiochip_init_valid_mask(struct gpio_chip *gpiochip)
{
if (gpiochip->init_valid_mask)
return gpiochip->init_valid_mask(gpiochip);
return 0;
}
static void gpiochip_free_valid_mask(struct gpio_chip *gpiochip) static void gpiochip_free_valid_mask(struct gpio_chip *gpiochip)
{ {
kfree(gpiochip->valid_mask); kfree(gpiochip->valid_mask);
...@@ -427,7 +436,7 @@ static long linehandle_ioctl(struct file *filep, unsigned int cmd, ...@@ -427,7 +436,7 @@ static long linehandle_ioctl(struct file *filep, unsigned int cmd,
struct linehandle_state *lh = filep->private_data; struct linehandle_state *lh = filep->private_data;
void __user *ip = (void __user *)arg; void __user *ip = (void __user *)arg;
struct gpiohandle_data ghd; struct gpiohandle_data ghd;
int vals[GPIOHANDLES_MAX]; DECLARE_BITMAP(vals, GPIOHANDLES_MAX);
int i; int i;
if (cmd == GPIOHANDLE_GET_LINE_VALUES_IOCTL) { if (cmd == GPIOHANDLE_GET_LINE_VALUES_IOCTL) {
...@@ -436,13 +445,14 @@ static long linehandle_ioctl(struct file *filep, unsigned int cmd, ...@@ -436,13 +445,14 @@ static long linehandle_ioctl(struct file *filep, unsigned int cmd,
true, true,
lh->numdescs, lh->numdescs,
lh->descs, lh->descs,
NULL,
vals); vals);
if (ret) if (ret)
return ret; return ret;
memset(&ghd, 0, sizeof(ghd)); memset(&ghd, 0, sizeof(ghd));
for (i = 0; i < lh->numdescs; i++) for (i = 0; i < lh->numdescs; i++)
ghd.values[i] = vals[i]; ghd.values[i] = test_bit(i, vals);
if (copy_to_user(ip, &ghd, sizeof(ghd))) if (copy_to_user(ip, &ghd, sizeof(ghd)))
return -EFAULT; return -EFAULT;
...@@ -461,13 +471,14 @@ static long linehandle_ioctl(struct file *filep, unsigned int cmd, ...@@ -461,13 +471,14 @@ static long linehandle_ioctl(struct file *filep, unsigned int cmd,
/* Clamp all values to [0,1] */ /* Clamp all values to [0,1] */
for (i = 0; i < lh->numdescs; i++) for (i = 0; i < lh->numdescs; i++)
vals[i] = !!ghd.values[i]; __assign_bit(i, vals, ghd.values[i]);
/* Reuse the array setting function */ /* Reuse the array setting function */
return gpiod_set_array_value_complex(false, return gpiod_set_array_value_complex(false,
true, true,
lh->numdescs, lh->numdescs,
lh->descs, lh->descs,
NULL,
vals); vals);
} }
return -EINVAL; return -EINVAL;
...@@ -812,26 +823,26 @@ static irqreturn_t lineevent_irq_thread(int irq, void *p) ...@@ -812,26 +823,26 @@ static irqreturn_t lineevent_irq_thread(int irq, void *p)
{ {
struct lineevent_state *le = p; struct lineevent_state *le = p;
struct gpioevent_data ge; struct gpioevent_data ge;
int ret, level; int ret;
/* Do not leak kernel stack to userspace */ /* Do not leak kernel stack to userspace */
memset(&ge, 0, sizeof(ge)); memset(&ge, 0, sizeof(ge));
ge.timestamp = le->timestamp; ge.timestamp = le->timestamp;
level = gpiod_get_value_cansleep(le->desc);
if (le->eflags & GPIOEVENT_REQUEST_RISING_EDGE if (le->eflags & GPIOEVENT_REQUEST_RISING_EDGE
&& le->eflags & GPIOEVENT_REQUEST_FALLING_EDGE) { && le->eflags & GPIOEVENT_REQUEST_FALLING_EDGE) {
int level = gpiod_get_value_cansleep(le->desc);
if (level) if (level)
/* Emit low-to-high event */ /* Emit low-to-high event */
ge.id = GPIOEVENT_EVENT_RISING_EDGE; ge.id = GPIOEVENT_EVENT_RISING_EDGE;
else else
/* Emit high-to-low event */ /* Emit high-to-low event */
ge.id = GPIOEVENT_EVENT_FALLING_EDGE; ge.id = GPIOEVENT_EVENT_FALLING_EDGE;
} else if (le->eflags & GPIOEVENT_REQUEST_RISING_EDGE && level) { } else if (le->eflags & GPIOEVENT_REQUEST_RISING_EDGE) {
/* Emit low-to-high event */ /* Emit low-to-high event */
ge.id = GPIOEVENT_EVENT_RISING_EDGE; ge.id = GPIOEVENT_EVENT_RISING_EDGE;
} else if (le->eflags & GPIOEVENT_REQUEST_FALLING_EDGE && !level) { } else if (le->eflags & GPIOEVENT_REQUEST_FALLING_EDGE) {
/* Emit high-to-low event */ /* Emit high-to-low event */
ge.id = GPIOEVENT_EVENT_FALLING_EDGE; ge.id = GPIOEVENT_EVENT_FALLING_EDGE;
} else { } else {
...@@ -942,7 +953,6 @@ static int lineevent_create(struct gpio_device *gdev, void __user *ip) ...@@ -942,7 +953,6 @@ static int lineevent_create(struct gpio_device *gdev, void __user *ip)
if (eflags & GPIOEVENT_REQUEST_FALLING_EDGE) if (eflags & GPIOEVENT_REQUEST_FALLING_EDGE)
irqflags |= IRQF_TRIGGER_FALLING; irqflags |= IRQF_TRIGGER_FALLING;
irqflags |= IRQF_ONESHOT; irqflags |= IRQF_ONESHOT;
irqflags |= IRQF_SHARED;
INIT_KFIFO(le->events); INIT_KFIFO(le->events);
init_waitqueue_head(&le->wait); init_waitqueue_head(&le->wait);
...@@ -1341,19 +1351,8 @@ int gpiochip_add_data_with_key(struct gpio_chip *chip, void *data, ...@@ -1341,19 +1351,8 @@ int gpiochip_add_data_with_key(struct gpio_chip *chip, void *data,
spin_unlock_irqrestore(&gpio_lock, flags); spin_unlock_irqrestore(&gpio_lock, flags);
for (i = 0; i < chip->ngpio; i++) { for (i = 0; i < chip->ngpio; i++)
struct gpio_desc *desc = &gdev->descs[i]; gdev->descs[i].gdev = gdev;
desc->gdev = gdev;
/* REVISIT: most hardware initializes GPIOs as inputs (often
* with pullups enabled) so power usage is minimized. Linux
* code should set the gpio direction first thing; but until
* it does, and in case chip->get_direction is not set, we may
* expose the wrong direction in sysfs.
*/
desc->flags = !chip->direction_input ? (1 << FLAG_IS_OUT) : 0;
}
#ifdef CONFIG_PINCTRL #ifdef CONFIG_PINCTRL
INIT_LIST_HEAD(&gdev->pin_ranges); INIT_LIST_HEAD(&gdev->pin_ranges);
...@@ -1367,7 +1366,7 @@ int gpiochip_add_data_with_key(struct gpio_chip *chip, void *data, ...@@ -1367,7 +1366,7 @@ int gpiochip_add_data_with_key(struct gpio_chip *chip, void *data,
if (status) if (status)
goto err_remove_from_list; goto err_remove_from_list;
status = gpiochip_init_valid_mask(chip); status = gpiochip_alloc_valid_mask(chip);
if (status) if (status)
goto err_remove_irqchip_mask; goto err_remove_irqchip_mask;
...@@ -1379,6 +1378,21 @@ int gpiochip_add_data_with_key(struct gpio_chip *chip, void *data, ...@@ -1379,6 +1378,21 @@ int gpiochip_add_data_with_key(struct gpio_chip *chip, void *data,
if (status) if (status)
goto err_remove_chip; goto err_remove_chip;
status = gpiochip_init_valid_mask(chip);
if (status)
goto err_remove_chip;
for (i = 0; i < chip->ngpio; i++) {
struct gpio_desc *desc = &gdev->descs[i];
if (chip->get_direction && gpiochip_line_is_valid(chip, i))
desc->flags = !chip->get_direction(chip, i) ?
(1 << FLAG_IS_OUT) : 0;
else
desc->flags = !chip->direction_input ?
(1 << FLAG_IS_OUT) : 0;
}
acpi_gpiochip_add(chip); acpi_gpiochip_add(chip);
machine_gpiochip_add(chip); machine_gpiochip_add(chip);
...@@ -1512,7 +1526,7 @@ static int devm_gpio_chip_match(struct device *dev, void *res, void *data) ...@@ -1512,7 +1526,7 @@ static int devm_gpio_chip_match(struct device *dev, void *res, void *data)
/** /**
* devm_gpiochip_add_data() - Resource manager gpiochip_add_data() * devm_gpiochip_add_data() - Resource manager gpiochip_add_data()
* @dev: the device pointer on which irq_chip belongs to. * @dev: pointer to the device that gpio_chip belongs to.
* @chip: the chip to register, with chip->base initialized * @chip: the chip to register, with chip->base initialized
* @data: driver-private data associated with this chip * @data: driver-private data associated with this chip
* *
...@@ -1649,7 +1663,6 @@ EXPORT_SYMBOL_GPL(gpiochip_irqchip_irq_valid); ...@@ -1649,7 +1663,6 @@ EXPORT_SYMBOL_GPL(gpiochip_irqchip_irq_valid);
/** /**
* gpiochip_set_cascaded_irqchip() - connects a cascaded irqchip to a gpiochip * gpiochip_set_cascaded_irqchip() - connects a cascaded irqchip to a gpiochip
* @gpiochip: the gpiochip to set the irqchip chain to * @gpiochip: the gpiochip to set the irqchip chain to
* @irqchip: the irqchip to chain to the gpiochip
* @parent_irq: the irq number corresponding to the parent IRQ for this * @parent_irq: the irq number corresponding to the parent IRQ for this
* chained irqchip * chained irqchip
* @parent_handler: the parent interrupt handler for the accumulated IRQ * @parent_handler: the parent interrupt handler for the accumulated IRQ
...@@ -1657,12 +1670,9 @@ EXPORT_SYMBOL_GPL(gpiochip_irqchip_irq_valid); ...@@ -1657,12 +1670,9 @@ EXPORT_SYMBOL_GPL(gpiochip_irqchip_irq_valid);
* cascaded, pass NULL in this handler argument * cascaded, pass NULL in this handler argument
*/ */
static void gpiochip_set_cascaded_irqchip(struct gpio_chip *gpiochip, static void gpiochip_set_cascaded_irqchip(struct gpio_chip *gpiochip,
struct irq_chip *irqchip,
unsigned int parent_irq, unsigned int parent_irq,
irq_flow_handler_t parent_handler) irq_flow_handler_t parent_handler)
{ {
unsigned int offset;
if (!gpiochip->irq.domain) { if (!gpiochip->irq.domain) {
chip_err(gpiochip, "called %s before setting up irqchip\n", chip_err(gpiochip, "called %s before setting up irqchip\n",
__func__); __func__);
...@@ -1686,14 +1696,6 @@ static void gpiochip_set_cascaded_irqchip(struct gpio_chip *gpiochip, ...@@ -1686,14 +1696,6 @@ static void gpiochip_set_cascaded_irqchip(struct gpio_chip *gpiochip,
gpiochip->irq.parents = &gpiochip->irq.parent_irq; gpiochip->irq.parents = &gpiochip->irq.parent_irq;
gpiochip->irq.num_parents = 1; gpiochip->irq.num_parents = 1;
} }
/* Set the parent IRQ for all affected IRQs */
for (offset = 0; offset < gpiochip->ngpio; offset++) {
if (!gpiochip_irqchip_irq_valid(gpiochip, offset))
continue;
irq_set_parent(irq_find_mapping(gpiochip->irq.domain, offset),
parent_irq);
}
} }
/** /**
...@@ -1703,8 +1705,7 @@ static void gpiochip_set_cascaded_irqchip(struct gpio_chip *gpiochip, ...@@ -1703,8 +1705,7 @@ static void gpiochip_set_cascaded_irqchip(struct gpio_chip *gpiochip,
* @parent_irq: the irq number corresponding to the parent IRQ for this * @parent_irq: the irq number corresponding to the parent IRQ for this
* chained irqchip * chained irqchip
* @parent_handler: the parent interrupt handler for the accumulated IRQ * @parent_handler: the parent interrupt handler for the accumulated IRQ
* coming out of the gpiochip. If the interrupt is nested rather than * coming out of the gpiochip.
* cascaded, pass NULL in this handler argument
*/ */
void gpiochip_set_chained_irqchip(struct gpio_chip *gpiochip, void gpiochip_set_chained_irqchip(struct gpio_chip *gpiochip,
struct irq_chip *irqchip, struct irq_chip *irqchip,
...@@ -1716,8 +1717,7 @@ void gpiochip_set_chained_irqchip(struct gpio_chip *gpiochip, ...@@ -1716,8 +1717,7 @@ void gpiochip_set_chained_irqchip(struct gpio_chip *gpiochip,
return; return;
} }
gpiochip_set_cascaded_irqchip(gpiochip, irqchip, parent_irq, gpiochip_set_cascaded_irqchip(gpiochip, parent_irq, parent_handler);
parent_handler);
} }
EXPORT_SYMBOL_GPL(gpiochip_set_chained_irqchip); EXPORT_SYMBOL_GPL(gpiochip_set_chained_irqchip);
...@@ -1732,8 +1732,7 @@ void gpiochip_set_nested_irqchip(struct gpio_chip *gpiochip, ...@@ -1732,8 +1732,7 @@ void gpiochip_set_nested_irqchip(struct gpio_chip *gpiochip,
struct irq_chip *irqchip, struct irq_chip *irqchip,
unsigned int parent_irq) unsigned int parent_irq)
{ {
gpiochip_set_cascaded_irqchip(gpiochip, irqchip, parent_irq, gpiochip_set_cascaded_irqchip(gpiochip, parent_irq, NULL);
NULL);
} }
EXPORT_SYMBOL_GPL(gpiochip_set_nested_irqchip); EXPORT_SYMBOL_GPL(gpiochip_set_nested_irqchip);
...@@ -1805,39 +1804,75 @@ static const struct irq_domain_ops gpiochip_domain_ops = { ...@@ -1805,39 +1804,75 @@ static const struct irq_domain_ops gpiochip_domain_ops = {
.xlate = irq_domain_xlate_twocell, .xlate = irq_domain_xlate_twocell,
}; };
static int gpiochip_to_irq(struct gpio_chip *chip, unsigned offset)
{
if (!gpiochip_irqchip_irq_valid(chip, offset))
return -ENXIO;
return irq_create_mapping(chip->irq.domain, offset);
}
static int gpiochip_irq_reqres(struct irq_data *d) static int gpiochip_irq_reqres(struct irq_data *d)
{ {
struct gpio_chip *chip = irq_data_get_irq_chip_data(d); struct gpio_chip *chip = irq_data_get_irq_chip_data(d);
int ret;
if (!try_module_get(chip->gpiodev->owner)) return gpiochip_reqres_irq(chip, d->hwirq);
return -ENODEV;
ret = gpiochip_lock_as_irq(chip, d->hwirq);
if (ret) {
chip_err(chip,
"unable to lock HW IRQ %lu for IRQ\n",
d->hwirq);
module_put(chip->gpiodev->owner);
return ret;
}
return 0;
} }
static void gpiochip_irq_relres(struct irq_data *d) static void gpiochip_irq_relres(struct irq_data *d)
{ {
struct gpio_chip *chip = irq_data_get_irq_chip_data(d); struct gpio_chip *chip = irq_data_get_irq_chip_data(d);
gpiochip_unlock_as_irq(chip, d->hwirq); gpiochip_relres_irq(chip, d->hwirq);
module_put(chip->gpiodev->owner);
} }
static int gpiochip_to_irq(struct gpio_chip *chip, unsigned offset) static void gpiochip_irq_enable(struct irq_data *d)
{ {
if (!gpiochip_irqchip_irq_valid(chip, offset)) struct gpio_chip *chip = irq_data_get_irq_chip_data(d);
return -ENXIO;
return irq_create_mapping(chip->irq.domain, offset); gpiochip_enable_irq(chip, d->hwirq);
if (chip->irq.irq_enable)
chip->irq.irq_enable(d);
else
chip->irq.chip->irq_unmask(d);
}
static void gpiochip_irq_disable(struct irq_data *d)
{
struct gpio_chip *chip = irq_data_get_irq_chip_data(d);
if (chip->irq.irq_disable)
chip->irq.irq_disable(d);
else
chip->irq.chip->irq_mask(d);
gpiochip_disable_irq(chip, d->hwirq);
}
static void gpiochip_set_irq_hooks(struct gpio_chip *gpiochip)
{
struct irq_chip *irqchip = gpiochip->irq.chip;
if (!irqchip->irq_request_resources &&
!irqchip->irq_release_resources) {
irqchip->irq_request_resources = gpiochip_irq_reqres;
irqchip->irq_release_resources = gpiochip_irq_relres;
}
if (WARN_ON(gpiochip->irq.irq_enable))
return;
/* Check if the irqchip already has this hook... */
if (irqchip->irq_enable == gpiochip_irq_enable) {
/*
* ...and if so, give a gentle warning that this is bad
* practice.
*/
chip_info(gpiochip,
"detected irqchip that is shared with multiple gpiochips: please fix the driver.\n");
return;
}
gpiochip->irq.irq_enable = irqchip->irq_enable;
gpiochip->irq.irq_disable = irqchip->irq_disable;
irqchip->irq_enable = gpiochip_irq_enable;
irqchip->irq_disable = gpiochip_irq_disable;
} }
/** /**
...@@ -1898,16 +1933,6 @@ static int gpiochip_add_irqchip(struct gpio_chip *gpiochip, ...@@ -1898,16 +1933,6 @@ static int gpiochip_add_irqchip(struct gpio_chip *gpiochip,
if (!gpiochip->irq.domain) if (!gpiochip->irq.domain)
return -EINVAL; return -EINVAL;
/*
* It is possible for a driver to override this, but only if the
* alternative functions are both implemented.
*/
if (!irqchip->irq_request_resources &&
!irqchip->irq_release_resources) {
irqchip->irq_request_resources = gpiochip_irq_reqres;
irqchip->irq_release_resources = gpiochip_irq_relres;
}
if (gpiochip->irq.parent_handler) { if (gpiochip->irq.parent_handler) {
void *data = gpiochip->irq.parent_handler_data ?: gpiochip; void *data = gpiochip->irq.parent_handler_data ?: gpiochip;
...@@ -1923,6 +1948,8 @@ static int gpiochip_add_irqchip(struct gpio_chip *gpiochip, ...@@ -1923,6 +1948,8 @@ static int gpiochip_add_irqchip(struct gpio_chip *gpiochip,
} }
} }
gpiochip_set_irq_hooks(gpiochip);
acpi_gpiochip_request_interrupts(gpiochip); acpi_gpiochip_request_interrupts(gpiochip);
return 0; return 0;
...@@ -1936,11 +1963,12 @@ static int gpiochip_add_irqchip(struct gpio_chip *gpiochip, ...@@ -1936,11 +1963,12 @@ static int gpiochip_add_irqchip(struct gpio_chip *gpiochip,
*/ */
static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip) static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip)
{ {
struct irq_chip *irqchip = gpiochip->irq.chip;
unsigned int offset; unsigned int offset;
acpi_gpiochip_free_interrupts(gpiochip); acpi_gpiochip_free_interrupts(gpiochip);
if (gpiochip->irq.chip && gpiochip->irq.parent_handler) { if (irqchip && gpiochip->irq.parent_handler) {
struct gpio_irq_chip *irq = &gpiochip->irq; struct gpio_irq_chip *irq = &gpiochip->irq;
unsigned int i; unsigned int i;
...@@ -1964,11 +1992,19 @@ static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip) ...@@ -1964,11 +1992,19 @@ static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip)
irq_domain_remove(gpiochip->irq.domain); irq_domain_remove(gpiochip->irq.domain);
} }
if (gpiochip->irq.chip) { if (irqchip) {
gpiochip->irq.chip->irq_request_resources = NULL; if (irqchip->irq_request_resources == gpiochip_irq_reqres) {
gpiochip->irq.chip->irq_release_resources = NULL; irqchip->irq_request_resources = NULL;
gpiochip->irq.chip = NULL; irqchip->irq_release_resources = NULL;
}
if (irqchip->irq_enable == gpiochip_irq_enable) {
irqchip->irq_enable = gpiochip->irq.irq_enable;
irqchip->irq_disable = gpiochip->irq.irq_disable;
}
} }
gpiochip->irq.irq_enable = NULL;
gpiochip->irq.irq_disable = NULL;
gpiochip->irq.chip = NULL;
gpiochip_irqchip_free_valid_mask(gpiochip); gpiochip_irqchip_free_valid_mask(gpiochip);
} }
...@@ -2057,15 +2093,7 @@ int gpiochip_irqchip_add_key(struct gpio_chip *gpiochip, ...@@ -2057,15 +2093,7 @@ int gpiochip_irqchip_add_key(struct gpio_chip *gpiochip,
return -EINVAL; return -EINVAL;
} }
/* gpiochip_set_irq_hooks(gpiochip);
* It is possible for a driver to override this, but only if the
* alternative functions are both implemented.
*/
if (!irqchip->irq_request_resources &&
!irqchip->irq_release_resources) {
irqchip->irq_request_resources = gpiochip_irq_reqres;
irqchip->irq_release_resources = gpiochip_irq_relres;
}
acpi_gpiochip_request_interrupts(gpiochip); acpi_gpiochip_request_interrupts(gpiochip);
...@@ -2513,19 +2541,38 @@ EXPORT_SYMBOL_GPL(gpiochip_free_own_desc); ...@@ -2513,19 +2541,38 @@ EXPORT_SYMBOL_GPL(gpiochip_free_own_desc);
int gpiod_direction_input(struct gpio_desc *desc) int gpiod_direction_input(struct gpio_desc *desc)
{ {
struct gpio_chip *chip; struct gpio_chip *chip;
int status = -EINVAL; int status = 0;
VALIDATE_DESC(desc); VALIDATE_DESC(desc);
chip = desc->gdev->chip; chip = desc->gdev->chip;
if (!chip->get || !chip->direction_input) { /*
* It is legal to have no .get() and .direction_input() specified if
* the chip is output-only, but you can't specify .direction_input()
* and not support the .get() operation, that doesn't make sense.
*/
if (!chip->get && chip->direction_input) {
gpiod_warn(desc, gpiod_warn(desc,
"%s: missing get() or direction_input() operations\n", "%s: missing get() but have direction_input()\n",
__func__); __func__);
return -EIO; return -EIO;
} }
/*
* If we have a .direction_input() callback, things are simple,
* just call it. Else we are some input-only chip so try to check the
* direction (if .get_direction() is supported) else we silently
* assume we are in input mode after this.
*/
if (chip->direction_input) {
status = chip->direction_input(chip, gpio_chip_hwgpio(desc)); status = chip->direction_input(chip, gpio_chip_hwgpio(desc));
} else if (chip->get_direction &&
(chip->get_direction(chip, gpio_chip_hwgpio(desc)) != 1)) {
gpiod_warn(desc,
"%s: missing direction_input() operation and line is output\n",
__func__);
return -EIO;
}
if (status == 0) if (status == 0)
clear_bit(FLAG_IS_OUT, &desc->flags); clear_bit(FLAG_IS_OUT, &desc->flags);
...@@ -2547,16 +2594,38 @@ static int gpiod_direction_output_raw_commit(struct gpio_desc *desc, int value) ...@@ -2547,16 +2594,38 @@ static int gpiod_direction_output_raw_commit(struct gpio_desc *desc, int value)
{ {
struct gpio_chip *gc = desc->gdev->chip; struct gpio_chip *gc = desc->gdev->chip;
int val = !!value; int val = !!value;
int ret; int ret = 0;
if (!gc->set || !gc->direction_output) { /*
* It's OK not to specify .direction_output() if the gpiochip is
* output-only, but if there is then not even a .set() operation it
* is pretty tricky to drive the output line.
*/
if (!gc->set && !gc->direction_output) {
gpiod_warn(desc, gpiod_warn(desc,
"%s: missing set() or direction_output() operations\n", "%s: missing set() and direction_output() operations\n",
__func__); __func__);
return -EIO; return -EIO;
} }
if (gc->direction_output) {
ret = gc->direction_output(gc, gpio_chip_hwgpio(desc), val); ret = gc->direction_output(gc, gpio_chip_hwgpio(desc), val);
} else {
/* Check that we are in output mode if we can */
if (gc->get_direction &&
gc->get_direction(gc, gpio_chip_hwgpio(desc))) {
gpiod_warn(desc,
"%s: missing direction_output() operation\n",
__func__);
return -EIO;
}
/*
* If we can't actively set the direction, we are some
* output-only chip, so just drive the output as desired.
*/
gc->set(gc, gpio_chip_hwgpio(desc), val);
}
if (!ret) if (!ret)
set_bit(FLAG_IS_OUT, &desc->flags); set_bit(FLAG_IS_OUT, &desc->flags);
trace_gpio_value(desc_to_gpio(desc), 0, val); trace_gpio_value(desc_to_gpio(desc), 0, val);
...@@ -2605,8 +2674,9 @@ int gpiod_direction_output(struct gpio_desc *desc, int value) ...@@ -2605,8 +2674,9 @@ int gpiod_direction_output(struct gpio_desc *desc, int value)
else else
value = !!value; value = !!value;
/* GPIOs used for IRQs shall not be set as output */ /* GPIOs used for enabled IRQs shall not be set as output */
if (test_bit(FLAG_USED_AS_IRQ, &desc->flags)) { if (test_bit(FLAG_USED_AS_IRQ, &desc->flags) &&
test_bit(FLAG_IRQ_IS_ENABLED, &desc->flags)) {
gpiod_err(desc, gpiod_err(desc,
"%s: tried to set a GPIO tied to an IRQ as output\n", "%s: tried to set a GPIO tied to an IRQ as output\n",
__func__); __func__);
...@@ -2785,9 +2855,39 @@ static int gpio_chip_get_multiple(struct gpio_chip *chip, ...@@ -2785,9 +2855,39 @@ static int gpio_chip_get_multiple(struct gpio_chip *chip,
int gpiod_get_array_value_complex(bool raw, bool can_sleep, int gpiod_get_array_value_complex(bool raw, bool can_sleep,
unsigned int array_size, unsigned int array_size,
struct gpio_desc **desc_array, struct gpio_desc **desc_array,
int *value_array) struct gpio_array *array_info,
unsigned long *value_bitmap)
{ {
int i = 0; int err, i = 0;
/*
* Validate array_info against desc_array and its size.
* It should immediately follow desc_array if both
* have been obtained from the same gpiod_get_array() call.
*/
if (array_info && array_info->desc == desc_array &&
array_size <= array_info->size &&
(void *)array_info == desc_array + array_info->size) {
if (!can_sleep)
WARN_ON(array_info->chip->can_sleep);
err = gpio_chip_get_multiple(array_info->chip,
array_info->get_mask,
value_bitmap);
if (err)
return err;
if (!raw && !bitmap_empty(array_info->invert_mask, array_size))
bitmap_xor(value_bitmap, value_bitmap,
array_info->invert_mask, array_size);
if (bitmap_full(array_info->get_mask, array_size))
return 0;
i = find_first_zero_bit(array_info->get_mask, array_size);
} else {
array_info = NULL;
}
while (i < array_size) { while (i < array_size) {
struct gpio_chip *chip = desc_array[i]->gdev->chip; struct gpio_chip *chip = desc_array[i]->gdev->chip;
...@@ -2819,6 +2919,10 @@ int gpiod_get_array_value_complex(bool raw, bool can_sleep, ...@@ -2819,6 +2919,10 @@ int gpiod_get_array_value_complex(bool raw, bool can_sleep,
__set_bit(hwgpio, mask); __set_bit(hwgpio, mask);
i++; i++;
if (array_info)
i = find_next_zero_bit(array_info->get_mask,
array_size, i);
} while ((i < array_size) && } while ((i < array_size) &&
(desc_array[i]->gdev->chip == chip)); (desc_array[i]->gdev->chip == chip));
...@@ -2829,15 +2933,20 @@ int gpiod_get_array_value_complex(bool raw, bool can_sleep, ...@@ -2829,15 +2933,20 @@ int gpiod_get_array_value_complex(bool raw, bool can_sleep,
return ret; return ret;
} }
for (j = first; j < i; j++) { for (j = first; j < i; ) {
const struct gpio_desc *desc = desc_array[j]; const struct gpio_desc *desc = desc_array[j];
int hwgpio = gpio_chip_hwgpio(desc); int hwgpio = gpio_chip_hwgpio(desc);
int value = test_bit(hwgpio, bits); int value = test_bit(hwgpio, bits);
if (!raw && test_bit(FLAG_ACTIVE_LOW, &desc->flags)) if (!raw && test_bit(FLAG_ACTIVE_LOW, &desc->flags))
value = !value; value = !value;
value_array[j] = value; __assign_bit(j, value_bitmap, value);
trace_gpio_value(desc_to_gpio(desc), 1, value); trace_gpio_value(desc_to_gpio(desc), 1, value);
j++;
if (array_info)
j = find_next_zero_bit(array_info->get_mask, i,
j);
} }
if (mask != fastpath) if (mask != fastpath)
...@@ -2896,9 +3005,10 @@ EXPORT_SYMBOL_GPL(gpiod_get_value); ...@@ -2896,9 +3005,10 @@ EXPORT_SYMBOL_GPL(gpiod_get_value);
/** /**
* gpiod_get_raw_array_value() - read raw values from an array of GPIOs * gpiod_get_raw_array_value() - read raw values from an array of GPIOs
* @array_size: number of elements in the descriptor / value arrays * @array_size: number of elements in the descriptor array / value bitmap
* @desc_array: array of GPIO descriptors whose values will be read * @desc_array: array of GPIO descriptors whose values will be read
* @value_array: array to store the read values * @array_info: information on applicability of fast bitmap processing path
* @value_bitmap: bitmap to store the read values
* *
* Read the raw values of the GPIOs, i.e. the values of the physical lines * Read the raw values of the GPIOs, i.e. the values of the physical lines
* without regard for their ACTIVE_LOW status. Return 0 in case of success, * without regard for their ACTIVE_LOW status. Return 0 in case of success,
...@@ -2908,20 +3018,24 @@ EXPORT_SYMBOL_GPL(gpiod_get_value); ...@@ -2908,20 +3018,24 @@ EXPORT_SYMBOL_GPL(gpiod_get_value);
* and it will complain if the GPIO chip functions potentially sleep. * and it will complain if the GPIO chip functions potentially sleep.
*/ */
int gpiod_get_raw_array_value(unsigned int array_size, int gpiod_get_raw_array_value(unsigned int array_size,
struct gpio_desc **desc_array, int *value_array) struct gpio_desc **desc_array,
struct gpio_array *array_info,
unsigned long *value_bitmap)
{ {
if (!desc_array) if (!desc_array)
return -EINVAL; return -EINVAL;
return gpiod_get_array_value_complex(true, false, array_size, return gpiod_get_array_value_complex(true, false, array_size,
desc_array, value_array); desc_array, array_info,
value_bitmap);
} }
EXPORT_SYMBOL_GPL(gpiod_get_raw_array_value); EXPORT_SYMBOL_GPL(gpiod_get_raw_array_value);
/** /**
* gpiod_get_array_value() - read values from an array of GPIOs * gpiod_get_array_value() - read values from an array of GPIOs
* @array_size: number of elements in the descriptor / value arrays * @array_size: number of elements in the descriptor array / value bitmap
* @desc_array: array of GPIO descriptors whose values will be read * @desc_array: array of GPIO descriptors whose values will be read
* @value_array: array to store the read values * @array_info: information on applicability of fast bitmap processing path
* @value_bitmap: bitmap to store the read values
* *
* Read the logical values of the GPIOs, i.e. taking their ACTIVE_LOW status * Read the logical values of the GPIOs, i.e. taking their ACTIVE_LOW status
* into account. Return 0 in case of success, else an error code. * into account. Return 0 in case of success, else an error code.
...@@ -2930,12 +3044,15 @@ EXPORT_SYMBOL_GPL(gpiod_get_raw_array_value); ...@@ -2930,12 +3044,15 @@ EXPORT_SYMBOL_GPL(gpiod_get_raw_array_value);
* and it will complain if the GPIO chip functions potentially sleep. * and it will complain if the GPIO chip functions potentially sleep.
*/ */
int gpiod_get_array_value(unsigned int array_size, int gpiod_get_array_value(unsigned int array_size,
struct gpio_desc **desc_array, int *value_array) struct gpio_desc **desc_array,
struct gpio_array *array_info,
unsigned long *value_bitmap)
{ {
if (!desc_array) if (!desc_array)
return -EINVAL; return -EINVAL;
return gpiod_get_array_value_complex(false, false, array_size, return gpiod_get_array_value_complex(false, false, array_size,
desc_array, value_array); desc_array, array_info,
value_bitmap);
} }
EXPORT_SYMBOL_GPL(gpiod_get_array_value); EXPORT_SYMBOL_GPL(gpiod_get_array_value);
...@@ -3028,10 +3145,37 @@ static void gpio_chip_set_multiple(struct gpio_chip *chip, ...@@ -3028,10 +3145,37 @@ static void gpio_chip_set_multiple(struct gpio_chip *chip,
int gpiod_set_array_value_complex(bool raw, bool can_sleep, int gpiod_set_array_value_complex(bool raw, bool can_sleep,
unsigned int array_size, unsigned int array_size,
struct gpio_desc **desc_array, struct gpio_desc **desc_array,
int *value_array) struct gpio_array *array_info,
unsigned long *value_bitmap)
{ {
int i = 0; int i = 0;
/*
* Validate array_info against desc_array and its size.
* It should immediately follow desc_array if both
* have been obtained from the same gpiod_get_array() call.
*/
if (array_info && array_info->desc == desc_array &&
array_size <= array_info->size &&
(void *)array_info == desc_array + array_info->size) {
if (!can_sleep)
WARN_ON(array_info->chip->can_sleep);
if (!raw && !bitmap_empty(array_info->invert_mask, array_size))
bitmap_xor(value_bitmap, value_bitmap,
array_info->invert_mask, array_size);
gpio_chip_set_multiple(array_info->chip, array_info->set_mask,
value_bitmap);
if (bitmap_full(array_info->set_mask, array_size))
return 0;
i = find_first_zero_bit(array_info->set_mask, array_size);
} else {
array_info = NULL;
}
while (i < array_size) { while (i < array_size) {
struct gpio_chip *chip = desc_array[i]->gdev->chip; struct gpio_chip *chip = desc_array[i]->gdev->chip;
unsigned long fastpath[2 * BITS_TO_LONGS(FASTPATH_NGPIO)]; unsigned long fastpath[2 * BITS_TO_LONGS(FASTPATH_NGPIO)];
...@@ -3057,9 +3201,16 @@ int gpiod_set_array_value_complex(bool raw, bool can_sleep, ...@@ -3057,9 +3201,16 @@ int gpiod_set_array_value_complex(bool raw, bool can_sleep,
do { do {
struct gpio_desc *desc = desc_array[i]; struct gpio_desc *desc = desc_array[i];
int hwgpio = gpio_chip_hwgpio(desc); int hwgpio = gpio_chip_hwgpio(desc);
int value = value_array[i]; int value = test_bit(i, value_bitmap);
if (!raw && test_bit(FLAG_ACTIVE_LOW, &desc->flags)) /*
* Pins applicable for fast input but not for
* fast output processing may have been already
* inverted inside the fast path, skip them.
*/
if (!raw && !(array_info &&
test_bit(i, array_info->invert_mask)) &&
test_bit(FLAG_ACTIVE_LOW, &desc->flags))
value = !value; value = !value;
trace_gpio_value(desc_to_gpio(desc), 0, value); trace_gpio_value(desc_to_gpio(desc), 0, value);
/* /*
...@@ -3079,6 +3230,10 @@ int gpiod_set_array_value_complex(bool raw, bool can_sleep, ...@@ -3079,6 +3230,10 @@ int gpiod_set_array_value_complex(bool raw, bool can_sleep,
count++; count++;
} }
i++; i++;
if (array_info)
i = find_next_zero_bit(array_info->set_mask,
array_size, i);
} while ((i < array_size) && } while ((i < array_size) &&
(desc_array[i]->gdev->chip == chip)); (desc_array[i]->gdev->chip == chip));
/* push collected bits to outputs */ /* push collected bits to outputs */
...@@ -3153,9 +3308,10 @@ EXPORT_SYMBOL_GPL(gpiod_set_value); ...@@ -3153,9 +3308,10 @@ EXPORT_SYMBOL_GPL(gpiod_set_value);
/** /**
* gpiod_set_raw_array_value() - assign values to an array of GPIOs * gpiod_set_raw_array_value() - assign values to an array of GPIOs
* @array_size: number of elements in the descriptor / value arrays * @array_size: number of elements in the descriptor array / value bitmap
* @desc_array: array of GPIO descriptors whose values will be assigned * @desc_array: array of GPIO descriptors whose values will be assigned
* @value_array: array of values to assign * @array_info: information on applicability of fast bitmap processing path
* @value_bitmap: bitmap of values to assign
* *
* Set the raw values of the GPIOs, i.e. the values of the physical lines * Set the raw values of the GPIOs, i.e. the values of the physical lines
* without regard for their ACTIVE_LOW status. * without regard for their ACTIVE_LOW status.
...@@ -3164,20 +3320,23 @@ EXPORT_SYMBOL_GPL(gpiod_set_value); ...@@ -3164,20 +3320,23 @@ EXPORT_SYMBOL_GPL(gpiod_set_value);
* complain if the GPIO chip functions potentially sleep. * complain if the GPIO chip functions potentially sleep.
*/ */
int gpiod_set_raw_array_value(unsigned int array_size, int gpiod_set_raw_array_value(unsigned int array_size,
struct gpio_desc **desc_array, int *value_array) struct gpio_desc **desc_array,
struct gpio_array *array_info,
unsigned long *value_bitmap)
{ {
if (!desc_array) if (!desc_array)
return -EINVAL; return -EINVAL;
return gpiod_set_array_value_complex(true, false, array_size, return gpiod_set_array_value_complex(true, false, array_size,
desc_array, value_array); desc_array, array_info, value_bitmap);
} }
EXPORT_SYMBOL_GPL(gpiod_set_raw_array_value); EXPORT_SYMBOL_GPL(gpiod_set_raw_array_value);
/** /**
* gpiod_set_array_value() - assign values to an array of GPIOs * gpiod_set_array_value() - assign values to an array of GPIOs
* @array_size: number of elements in the descriptor / value arrays * @array_size: number of elements in the descriptor array / value bitmap
* @desc_array: array of GPIO descriptors whose values will be assigned * @desc_array: array of GPIO descriptors whose values will be assigned
* @value_array: array of values to assign * @array_info: information on applicability of fast bitmap processing path
* @value_bitmap: bitmap of values to assign
* *
* Set the logical values of the GPIOs, i.e. taking their ACTIVE_LOW status * Set the logical values of the GPIOs, i.e. taking their ACTIVE_LOW status
* into account. * into account.
...@@ -3185,13 +3344,16 @@ EXPORT_SYMBOL_GPL(gpiod_set_raw_array_value); ...@@ -3185,13 +3344,16 @@ EXPORT_SYMBOL_GPL(gpiod_set_raw_array_value);
* This function should be called from contexts where we cannot sleep, and will * This function should be called from contexts where we cannot sleep, and will
* complain if the GPIO chip functions potentially sleep. * complain if the GPIO chip functions potentially sleep.
*/ */
void gpiod_set_array_value(unsigned int array_size, int gpiod_set_array_value(unsigned int array_size,
struct gpio_desc **desc_array, int *value_array) struct gpio_desc **desc_array,
struct gpio_array *array_info,
unsigned long *value_bitmap)
{ {
if (!desc_array) if (!desc_array)
return; return -EINVAL;
gpiod_set_array_value_complex(false, false, array_size, desc_array, return gpiod_set_array_value_complex(false, false, array_size,
value_array); desc_array, array_info,
value_bitmap);
} }
EXPORT_SYMBOL_GPL(gpiod_set_array_value); EXPORT_SYMBOL_GPL(gpiod_set_array_value);
...@@ -3293,6 +3455,7 @@ int gpiochip_lock_as_irq(struct gpio_chip *chip, unsigned int offset) ...@@ -3293,6 +3455,7 @@ int gpiochip_lock_as_irq(struct gpio_chip *chip, unsigned int offset)
} }
set_bit(FLAG_USED_AS_IRQ, &desc->flags); set_bit(FLAG_USED_AS_IRQ, &desc->flags);
set_bit(FLAG_IRQ_IS_ENABLED, &desc->flags);
/* /*
* If the consumer has not set up a label (such as when the * If the consumer has not set up a label (such as when the
...@@ -3323,6 +3486,7 @@ void gpiochip_unlock_as_irq(struct gpio_chip *chip, unsigned int offset) ...@@ -3323,6 +3486,7 @@ void gpiochip_unlock_as_irq(struct gpio_chip *chip, unsigned int offset)
return; return;
clear_bit(FLAG_USED_AS_IRQ, &desc->flags); clear_bit(FLAG_USED_AS_IRQ, &desc->flags);
clear_bit(FLAG_IRQ_IS_ENABLED, &desc->flags);
/* If we only had this marking, erase it */ /* If we only had this marking, erase it */
if (desc->label && !strcmp(desc->label, "interrupt")) if (desc->label && !strcmp(desc->label, "interrupt"))
...@@ -3330,6 +3494,28 @@ void gpiochip_unlock_as_irq(struct gpio_chip *chip, unsigned int offset) ...@@ -3330,6 +3494,28 @@ void gpiochip_unlock_as_irq(struct gpio_chip *chip, unsigned int offset)
} }
EXPORT_SYMBOL_GPL(gpiochip_unlock_as_irq); EXPORT_SYMBOL_GPL(gpiochip_unlock_as_irq);
void gpiochip_disable_irq(struct gpio_chip *chip, unsigned int offset)
{
struct gpio_desc *desc = gpiochip_get_desc(chip, offset);
if (!IS_ERR(desc) &&
!WARN_ON(!test_bit(FLAG_USED_AS_IRQ, &desc->flags)))
clear_bit(FLAG_IRQ_IS_ENABLED, &desc->flags);
}
EXPORT_SYMBOL_GPL(gpiochip_disable_irq);
void gpiochip_enable_irq(struct gpio_chip *chip, unsigned int offset)
{
struct gpio_desc *desc = gpiochip_get_desc(chip, offset);
if (!IS_ERR(desc) &&
!WARN_ON(!test_bit(FLAG_USED_AS_IRQ, &desc->flags))) {
WARN_ON(test_bit(FLAG_IS_OUT, &desc->flags));
set_bit(FLAG_IRQ_IS_ENABLED, &desc->flags);
}
}
EXPORT_SYMBOL_GPL(gpiochip_enable_irq);
bool gpiochip_line_is_irq(struct gpio_chip *chip, unsigned int offset) bool gpiochip_line_is_irq(struct gpio_chip *chip, unsigned int offset)
{ {
if (offset >= chip->ngpio) if (offset >= chip->ngpio)
...@@ -3339,6 +3525,30 @@ bool gpiochip_line_is_irq(struct gpio_chip *chip, unsigned int offset) ...@@ -3339,6 +3525,30 @@ bool gpiochip_line_is_irq(struct gpio_chip *chip, unsigned int offset)
} }
EXPORT_SYMBOL_GPL(gpiochip_line_is_irq); EXPORT_SYMBOL_GPL(gpiochip_line_is_irq);
int gpiochip_reqres_irq(struct gpio_chip *chip, unsigned int offset)
{
int ret;
if (!try_module_get(chip->gpiodev->owner))
return -ENODEV;
ret = gpiochip_lock_as_irq(chip, offset);
if (ret) {
chip_err(chip, "unable to lock HW IRQ %u for IRQ\n", offset);
module_put(chip->gpiodev->owner);
return ret;
}
return 0;
}
EXPORT_SYMBOL_GPL(gpiochip_reqres_irq);
void gpiochip_relres_irq(struct gpio_chip *chip, unsigned int offset)
{
gpiochip_unlock_as_irq(chip, offset);
module_put(chip->gpiodev->owner);
}
EXPORT_SYMBOL_GPL(gpiochip_relres_irq);
bool gpiochip_line_is_open_drain(struct gpio_chip *chip, unsigned int offset) bool gpiochip_line_is_open_drain(struct gpio_chip *chip, unsigned int offset)
{ {
if (offset >= chip->ngpio) if (offset >= chip->ngpio)
...@@ -3411,9 +3621,10 @@ EXPORT_SYMBOL_GPL(gpiod_get_value_cansleep); ...@@ -3411,9 +3621,10 @@ EXPORT_SYMBOL_GPL(gpiod_get_value_cansleep);
/** /**
* gpiod_get_raw_array_value_cansleep() - read raw values from an array of GPIOs * gpiod_get_raw_array_value_cansleep() - read raw values from an array of GPIOs
* @array_size: number of elements in the descriptor / value arrays * @array_size: number of elements in the descriptor array / value bitmap
* @desc_array: array of GPIO descriptors whose values will be read * @desc_array: array of GPIO descriptors whose values will be read
* @value_array: array to store the read values * @array_info: information on applicability of fast bitmap processing path
* @value_bitmap: bitmap to store the read values
* *
* Read the raw values of the GPIOs, i.e. the values of the physical lines * Read the raw values of the GPIOs, i.e. the values of the physical lines
* without regard for their ACTIVE_LOW status. Return 0 in case of success, * without regard for their ACTIVE_LOW status. Return 0 in case of success,
...@@ -3423,21 +3634,24 @@ EXPORT_SYMBOL_GPL(gpiod_get_value_cansleep); ...@@ -3423,21 +3634,24 @@ EXPORT_SYMBOL_GPL(gpiod_get_value_cansleep);
*/ */
int gpiod_get_raw_array_value_cansleep(unsigned int array_size, int gpiod_get_raw_array_value_cansleep(unsigned int array_size,
struct gpio_desc **desc_array, struct gpio_desc **desc_array,
int *value_array) struct gpio_array *array_info,
unsigned long *value_bitmap)
{ {
might_sleep_if(extra_checks); might_sleep_if(extra_checks);
if (!desc_array) if (!desc_array)
return -EINVAL; return -EINVAL;
return gpiod_get_array_value_complex(true, true, array_size, return gpiod_get_array_value_complex(true, true, array_size,
desc_array, value_array); desc_array, array_info,
value_bitmap);
} }
EXPORT_SYMBOL_GPL(gpiod_get_raw_array_value_cansleep); EXPORT_SYMBOL_GPL(gpiod_get_raw_array_value_cansleep);
/** /**
* gpiod_get_array_value_cansleep() - read values from an array of GPIOs * gpiod_get_array_value_cansleep() - read values from an array of GPIOs
* @array_size: number of elements in the descriptor / value arrays * @array_size: number of elements in the descriptor array / value bitmap
* @desc_array: array of GPIO descriptors whose values will be read * @desc_array: array of GPIO descriptors whose values will be read
* @value_array: array to store the read values * @array_info: information on applicability of fast bitmap processing path
* @value_bitmap: bitmap to store the read values
* *
* Read the logical values of the GPIOs, i.e. taking their ACTIVE_LOW status * Read the logical values of the GPIOs, i.e. taking their ACTIVE_LOW status
* into account. Return 0 in case of success, else an error code. * into account. Return 0 in case of success, else an error code.
...@@ -3446,13 +3660,15 @@ EXPORT_SYMBOL_GPL(gpiod_get_raw_array_value_cansleep); ...@@ -3446,13 +3660,15 @@ EXPORT_SYMBOL_GPL(gpiod_get_raw_array_value_cansleep);
*/ */
int gpiod_get_array_value_cansleep(unsigned int array_size, int gpiod_get_array_value_cansleep(unsigned int array_size,
struct gpio_desc **desc_array, struct gpio_desc **desc_array,
int *value_array) struct gpio_array *array_info,
unsigned long *value_bitmap)
{ {
might_sleep_if(extra_checks); might_sleep_if(extra_checks);
if (!desc_array) if (!desc_array)
return -EINVAL; return -EINVAL;
return gpiod_get_array_value_complex(false, true, array_size, return gpiod_get_array_value_complex(false, true, array_size,
desc_array, value_array); desc_array, array_info,
value_bitmap);
} }
EXPORT_SYMBOL_GPL(gpiod_get_array_value_cansleep); EXPORT_SYMBOL_GPL(gpiod_get_array_value_cansleep);
...@@ -3494,9 +3710,10 @@ EXPORT_SYMBOL_GPL(gpiod_set_value_cansleep); ...@@ -3494,9 +3710,10 @@ EXPORT_SYMBOL_GPL(gpiod_set_value_cansleep);
/** /**
* gpiod_set_raw_array_value_cansleep() - assign values to an array of GPIOs * gpiod_set_raw_array_value_cansleep() - assign values to an array of GPIOs
* @array_size: number of elements in the descriptor / value arrays * @array_size: number of elements in the descriptor array / value bitmap
* @desc_array: array of GPIO descriptors whose values will be assigned * @desc_array: array of GPIO descriptors whose values will be assigned
* @value_array: array of values to assign * @array_info: information on applicability of fast bitmap processing path
* @value_bitmap: bitmap of values to assign
* *
* Set the raw values of the GPIOs, i.e. the values of the physical lines * Set the raw values of the GPIOs, i.e. the values of the physical lines
* without regard for their ACTIVE_LOW status. * without regard for their ACTIVE_LOW status.
...@@ -3505,13 +3722,14 @@ EXPORT_SYMBOL_GPL(gpiod_set_value_cansleep); ...@@ -3505,13 +3722,14 @@ EXPORT_SYMBOL_GPL(gpiod_set_value_cansleep);
*/ */
int gpiod_set_raw_array_value_cansleep(unsigned int array_size, int gpiod_set_raw_array_value_cansleep(unsigned int array_size,
struct gpio_desc **desc_array, struct gpio_desc **desc_array,
int *value_array) struct gpio_array *array_info,
unsigned long *value_bitmap)
{ {
might_sleep_if(extra_checks); might_sleep_if(extra_checks);
if (!desc_array) if (!desc_array)
return -EINVAL; return -EINVAL;
return gpiod_set_array_value_complex(true, true, array_size, desc_array, return gpiod_set_array_value_complex(true, true, array_size, desc_array,
value_array); array_info, value_bitmap);
} }
EXPORT_SYMBOL_GPL(gpiod_set_raw_array_value_cansleep); EXPORT_SYMBOL_GPL(gpiod_set_raw_array_value_cansleep);
...@@ -3534,24 +3752,27 @@ void gpiod_add_lookup_tables(struct gpiod_lookup_table **tables, size_t n) ...@@ -3534,24 +3752,27 @@ void gpiod_add_lookup_tables(struct gpiod_lookup_table **tables, size_t n)
/** /**
* gpiod_set_array_value_cansleep() - assign values to an array of GPIOs * gpiod_set_array_value_cansleep() - assign values to an array of GPIOs
* @array_size: number of elements in the descriptor / value arrays * @array_size: number of elements in the descriptor array / value bitmap
* @desc_array: array of GPIO descriptors whose values will be assigned * @desc_array: array of GPIO descriptors whose values will be assigned
* @value_array: array of values to assign * @array_info: information on applicability of fast bitmap processing path
* @value_bitmap: bitmap of values to assign
* *
* Set the logical values of the GPIOs, i.e. taking their ACTIVE_LOW status * Set the logical values of the GPIOs, i.e. taking their ACTIVE_LOW status
* into account. * into account.
* *
* This function is to be called from contexts that can sleep. * This function is to be called from contexts that can sleep.
*/ */
void gpiod_set_array_value_cansleep(unsigned int array_size, int gpiod_set_array_value_cansleep(unsigned int array_size,
struct gpio_desc **desc_array, struct gpio_desc **desc_array,
int *value_array) struct gpio_array *array_info,
unsigned long *value_bitmap)
{ {
might_sleep_if(extra_checks); might_sleep_if(extra_checks);
if (!desc_array) if (!desc_array)
return; return -EINVAL;
gpiod_set_array_value_complex(false, true, array_size, desc_array, return gpiod_set_array_value_complex(false, true, array_size,
value_array); desc_array, array_info,
value_bitmap);
} }
EXPORT_SYMBOL_GPL(gpiod_set_array_value_cansleep); EXPORT_SYMBOL_GPL(gpiod_set_array_value_cansleep);
...@@ -4186,7 +4407,9 @@ struct gpio_descs *__must_check gpiod_get_array(struct device *dev, ...@@ -4186,7 +4407,9 @@ struct gpio_descs *__must_check gpiod_get_array(struct device *dev,
{ {
struct gpio_desc *desc; struct gpio_desc *desc;
struct gpio_descs *descs; struct gpio_descs *descs;
int count; struct gpio_array *array_info = NULL;
struct gpio_chip *chip;
int count, bitmap_size;
count = gpiod_count(dev, con_id); count = gpiod_count(dev, con_id);
if (count < 0) if (count < 0)
...@@ -4202,9 +4425,92 @@ struct gpio_descs *__must_check gpiod_get_array(struct device *dev, ...@@ -4202,9 +4425,92 @@ struct gpio_descs *__must_check gpiod_get_array(struct device *dev,
gpiod_put_array(descs); gpiod_put_array(descs);
return ERR_CAST(desc); return ERR_CAST(desc);
} }
descs->desc[descs->ndescs] = desc; descs->desc[descs->ndescs] = desc;
chip = gpiod_to_chip(desc);
/*
* If pin hardware number of array member 0 is also 0, select
* its chip as a candidate for fast bitmap processing path.
*/
if (descs->ndescs == 0 && gpio_chip_hwgpio(desc) == 0) {
struct gpio_descs *array;
bitmap_size = BITS_TO_LONGS(chip->ngpio > count ?
chip->ngpio : count);
array = kzalloc(struct_size(descs, desc, count) +
struct_size(array_info, invert_mask,
3 * bitmap_size), GFP_KERNEL);
if (!array) {
gpiod_put_array(descs);
return ERR_PTR(-ENOMEM);
}
memcpy(array, descs,
struct_size(descs, desc, descs->ndescs + 1));
kfree(descs);
descs = array;
array_info = (void *)(descs->desc + count);
array_info->get_mask = array_info->invert_mask +
bitmap_size;
array_info->set_mask = array_info->get_mask +
bitmap_size;
array_info->desc = descs->desc;
array_info->size = count;
array_info->chip = chip;
bitmap_set(array_info->get_mask, descs->ndescs,
count - descs->ndescs);
bitmap_set(array_info->set_mask, descs->ndescs,
count - descs->ndescs);
descs->info = array_info;
}
/* Unmark array members which don't belong to the 'fast' chip */
if (array_info && array_info->chip != chip) {
__clear_bit(descs->ndescs, array_info->get_mask);
__clear_bit(descs->ndescs, array_info->set_mask);
}
/*
* Detect array members which belong to the 'fast' chip
* but their pins are not in hardware order.
*/
else if (array_info &&
gpio_chip_hwgpio(desc) != descs->ndescs) {
/*
* Don't use fast path if all array members processed so
* far belong to the same chip as this one but its pin
* hardware number is different from its array index.
*/
if (bitmap_full(array_info->get_mask, descs->ndescs)) {
array_info = NULL;
} else {
__clear_bit(descs->ndescs,
array_info->get_mask);
__clear_bit(descs->ndescs,
array_info->set_mask);
}
} else if (array_info) {
/* Exclude open drain or open source from fast output */
if (gpiochip_line_is_open_drain(chip, descs->ndescs) ||
gpiochip_line_is_open_source(chip, descs->ndescs))
__clear_bit(descs->ndescs,
array_info->set_mask);
/* Identify 'fast' pins which require invertion */
if (gpiod_is_active_low(desc))
__set_bit(descs->ndescs,
array_info->invert_mask);
}
descs->ndescs++; descs->ndescs++;
} }
if (array_info)
dev_dbg(dev,
"GPIO array info: chip=%s, size=%d, get_mask=%lx, set_mask=%lx, invert_mask=%lx\n",
array_info->chip->label, array_info->size,
*array_info->get_mask, *array_info->set_mask,
*array_info->invert_mask);
return descs; return descs;
} }
EXPORT_SYMBOL_GPL(gpiod_get_array); EXPORT_SYMBOL_GPL(gpiod_get_array);
...@@ -4291,8 +4597,9 @@ static void gpiolib_dbg_show(struct seq_file *s, struct gpio_device *gdev) ...@@ -4291,8 +4597,9 @@ static void gpiolib_dbg_show(struct seq_file *s, struct gpio_device *gdev)
struct gpio_chip *chip = gdev->chip; struct gpio_chip *chip = gdev->chip;
unsigned gpio = gdev->base; unsigned gpio = gdev->base;
struct gpio_desc *gdesc = &gdev->descs[0]; struct gpio_desc *gdesc = &gdev->descs[0];
int is_out; bool is_out;
int is_irq; bool is_irq;
bool active_low;
for (i = 0; i < gdev->ngpio; i++, gpio++, gdesc++) { for (i = 0; i < gdev->ngpio; i++, gpio++, gdesc++) {
if (!test_bit(FLAG_REQUESTED, &gdesc->flags)) { if (!test_bit(FLAG_REQUESTED, &gdesc->flags)) {
...@@ -4306,11 +4613,13 @@ static void gpiolib_dbg_show(struct seq_file *s, struct gpio_device *gdev) ...@@ -4306,11 +4613,13 @@ static void gpiolib_dbg_show(struct seq_file *s, struct gpio_device *gdev)
gpiod_get_direction(gdesc); gpiod_get_direction(gdesc);
is_out = test_bit(FLAG_IS_OUT, &gdesc->flags); is_out = test_bit(FLAG_IS_OUT, &gdesc->flags);
is_irq = test_bit(FLAG_USED_AS_IRQ, &gdesc->flags); is_irq = test_bit(FLAG_USED_AS_IRQ, &gdesc->flags);
seq_printf(s, " gpio-%-3d (%-20.20s|%-20.20s) %s %s %s", active_low = test_bit(FLAG_ACTIVE_LOW, &gdesc->flags);
seq_printf(s, " gpio-%-3d (%-20.20s|%-20.20s) %s %s %s%s",
gpio, gdesc->name ? gdesc->name : "", gdesc->label, gpio, gdesc->name ? gdesc->name : "", gdesc->label,
is_out ? "out" : "in ", is_out ? "out" : "in ",
chip->get ? (chip->get(chip, i) ? "hi" : "lo") : "? ", chip->get ? (chip->get(chip, i) ? "hi" : "lo") : "? ",
is_irq ? "IRQ" : " "); is_irq ? "IRQ " : "",
active_low ? "ACTIVE LOW" : "");
seq_printf(s, "\n"); seq_printf(s, "\n");
} }
} }
......
/* SPDX-License-Identifier: GPL-2.0 */
/* /*
* Internal GPIO functions. * Internal GPIO functions.
* *
* Copyright (C) 2013, Intel Corporation * Copyright (C) 2013, Intel Corporation
* Author: Mika Westerberg <mika.westerberg@linux.intel.com> * Author: Mika Westerberg <mika.westerberg@linux.intel.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/ */
#ifndef GPIOLIB_H #ifndef GPIOLIB_H
...@@ -183,15 +180,26 @@ static inline bool acpi_can_fallback_to_crs(struct acpi_device *adev, ...@@ -183,15 +180,26 @@ static inline bool acpi_can_fallback_to_crs(struct acpi_device *adev,
} }
#endif #endif
struct gpio_array {
struct gpio_desc **desc;
unsigned int size;
struct gpio_chip *chip;
unsigned long *get_mask;
unsigned long *set_mask;
unsigned long invert_mask[];
};
struct gpio_desc *gpiochip_get_desc(struct gpio_chip *chip, u16 hwnum); struct gpio_desc *gpiochip_get_desc(struct gpio_chip *chip, u16 hwnum);
int gpiod_get_array_value_complex(bool raw, bool can_sleep, int gpiod_get_array_value_complex(bool raw, bool can_sleep,
unsigned int array_size, unsigned int array_size,
struct gpio_desc **desc_array, struct gpio_desc **desc_array,
int *value_array); struct gpio_array *array_info,
unsigned long *value_bitmap);
int gpiod_set_array_value_complex(bool raw, bool can_sleep, int gpiod_set_array_value_complex(bool raw, bool can_sleep,
unsigned int array_size, unsigned int array_size,
struct gpio_desc **desc_array, struct gpio_desc **desc_array,
int *value_array); struct gpio_array *array_info,
unsigned long *value_bitmap);
/* This is just passed between gpiolib and devres */ /* This is just passed between gpiolib and devres */
struct gpio_desc *gpiod_get_from_of_node(struct device_node *node, struct gpio_desc *gpiod_get_from_of_node(struct device_node *node,
...@@ -214,6 +222,7 @@ struct gpio_desc { ...@@ -214,6 +222,7 @@ struct gpio_desc {
#define FLAG_OPEN_DRAIN 7 /* Gpio is open drain type */ #define FLAG_OPEN_DRAIN 7 /* Gpio is open drain type */
#define FLAG_OPEN_SOURCE 8 /* Gpio is open source type */ #define FLAG_OPEN_SOURCE 8 /* Gpio is open source type */
#define FLAG_USED_AS_IRQ 9 /* GPIO is connected to an IRQ */ #define FLAG_USED_AS_IRQ 9 /* GPIO is connected to an IRQ */
#define FLAG_IRQ_IS_ENABLED 10 /* GPIO is connected to an enabled IRQ */
#define FLAG_IS_HOGGED 11 /* GPIO is hogged */ #define FLAG_IS_HOGGED 11 /* GPIO is hogged */
#define FLAG_TRANSITORY 12 /* GPIO may lose value in sleep or reset */ #define FLAG_TRANSITORY 12 /* GPIO may lose value in sleep or reset */
......
...@@ -22,18 +22,16 @@ struct gpiomux { ...@@ -22,18 +22,16 @@ struct gpiomux {
struct i2c_mux_gpio_platform_data data; struct i2c_mux_gpio_platform_data data;
unsigned gpio_base; unsigned gpio_base;
struct gpio_desc **gpios; struct gpio_desc **gpios;
int *values;
}; };
static void i2c_mux_gpio_set(const struct gpiomux *mux, unsigned val) static void i2c_mux_gpio_set(const struct gpiomux *mux, unsigned val)
{ {
int i; DECLARE_BITMAP(values, BITS_PER_TYPE(val));
for (i = 0; i < mux->data.n_gpios; i++) values[0] = val;
mux->values[i] = (val >> i) & 1;
gpiod_set_array_value_cansleep(mux->data.n_gpios, gpiod_set_array_value_cansleep(mux->data.n_gpios, mux->gpios, NULL,
mux->gpios, mux->values); values);
} }
static int i2c_mux_gpio_select(struct i2c_mux_core *muxc, u32 chan) static int i2c_mux_gpio_select(struct i2c_mux_core *muxc, u32 chan)
...@@ -182,15 +180,13 @@ static int i2c_mux_gpio_probe(struct platform_device *pdev) ...@@ -182,15 +180,13 @@ static int i2c_mux_gpio_probe(struct platform_device *pdev)
return -EPROBE_DEFER; return -EPROBE_DEFER;
muxc = i2c_mux_alloc(parent, &pdev->dev, mux->data.n_values, muxc = i2c_mux_alloc(parent, &pdev->dev, mux->data.n_values,
mux->data.n_gpios * sizeof(*mux->gpios) + mux->data.n_gpios * sizeof(*mux->gpios), 0,
mux->data.n_gpios * sizeof(*mux->values), 0,
i2c_mux_gpio_select, NULL); i2c_mux_gpio_select, NULL);
if (!muxc) { if (!muxc) {
ret = -ENOMEM; ret = -ENOMEM;
goto alloc_failed; goto alloc_failed;
} }
mux->gpios = muxc->priv; mux->gpios = muxc->priv;
mux->values = (int *)(mux->gpios + mux->data.n_gpios);
muxc->priv = mux; muxc->priv = mux;
platform_set_drvdata(pdev, muxc); platform_set_drvdata(pdev, muxc);
......
...@@ -40,17 +40,21 @@ static void mmc_pwrseq_simple_set_gpios_value(struct mmc_pwrseq_simple *pwrseq, ...@@ -40,17 +40,21 @@ static void mmc_pwrseq_simple_set_gpios_value(struct mmc_pwrseq_simple *pwrseq,
struct gpio_descs *reset_gpios = pwrseq->reset_gpios; struct gpio_descs *reset_gpios = pwrseq->reset_gpios;
if (!IS_ERR(reset_gpios)) { if (!IS_ERR(reset_gpios)) {
int i, *values; unsigned long *values;
int nvalues = reset_gpios->ndescs; int nvalues = reset_gpios->ndescs;
values = kmalloc_array(nvalues, sizeof(int), GFP_KERNEL); values = bitmap_alloc(nvalues, GFP_KERNEL);
if (!values) if (!values)
return; return;
for (i = 0; i < nvalues; i++) if (value)
values[i] = value; bitmap_fill(values, nvalues);
else
bitmap_zero(values, nvalues);
gpiod_set_array_value_cansleep(nvalues, reset_gpios->desc,
reset_gpios->info, values);
gpiod_set_array_value_cansleep(nvalues, reset_gpios->desc, values);
kfree(values); kfree(values);
} }
} }
......
...@@ -17,20 +17,18 @@ ...@@ -17,20 +17,18 @@
struct mux_gpio { struct mux_gpio {
struct gpio_descs *gpios; struct gpio_descs *gpios;
int *val;
}; };
static int mux_gpio_set(struct mux_control *mux, int state) static int mux_gpio_set(struct mux_control *mux, int state)
{ {
struct mux_gpio *mux_gpio = mux_chip_priv(mux->chip); struct mux_gpio *mux_gpio = mux_chip_priv(mux->chip);
int i; DECLARE_BITMAP(values, BITS_PER_TYPE(state));
for (i = 0; i < mux_gpio->gpios->ndescs; i++) values[0] = state;
mux_gpio->val[i] = (state >> i) & 1;
gpiod_set_array_value_cansleep(mux_gpio->gpios->ndescs, gpiod_set_array_value_cansleep(mux_gpio->gpios->ndescs,
mux_gpio->gpios->desc, mux_gpio->gpios->desc,
mux_gpio->val); mux_gpio->gpios->info, values);
return 0; return 0;
} }
...@@ -58,13 +56,11 @@ static int mux_gpio_probe(struct platform_device *pdev) ...@@ -58,13 +56,11 @@ static int mux_gpio_probe(struct platform_device *pdev)
if (pins < 0) if (pins < 0)
return pins; return pins;
mux_chip = devm_mux_chip_alloc(dev, 1, sizeof(*mux_gpio) + mux_chip = devm_mux_chip_alloc(dev, 1, sizeof(*mux_gpio));
pins * sizeof(*mux_gpio->val));
if (IS_ERR(mux_chip)) if (IS_ERR(mux_chip))
return PTR_ERR(mux_chip); return PTR_ERR(mux_chip);
mux_gpio = mux_chip_priv(mux_chip); mux_gpio = mux_chip_priv(mux_chip);
mux_gpio->val = (int *)(mux_gpio + 1);
mux_chip->ops = &mux_gpio_ops; mux_chip->ops = &mux_gpio_ops;
mux_gpio->gpios = devm_gpiod_get_array(dev, "mux", GPIOD_OUT_LOW); mux_gpio->gpios = devm_gpiod_get_array(dev, "mux", GPIOD_OUT_LOW);
......
...@@ -20,23 +20,21 @@ ...@@ -20,23 +20,21 @@
struct mdio_mux_gpio_state { struct mdio_mux_gpio_state {
struct gpio_descs *gpios; struct gpio_descs *gpios;
void *mux_handle; void *mux_handle;
int values[];
}; };
static int mdio_mux_gpio_switch_fn(int current_child, int desired_child, static int mdio_mux_gpio_switch_fn(int current_child, int desired_child,
void *data) void *data)
{ {
struct mdio_mux_gpio_state *s = data; struct mdio_mux_gpio_state *s = data;
unsigned int n; DECLARE_BITMAP(values, BITS_PER_TYPE(desired_child));
if (current_child == desired_child) if (current_child == desired_child)
return 0; return 0;
for (n = 0; n < s->gpios->ndescs; n++) values[0] = desired_child;
s->values[n] = (desired_child >> n) & 1;
gpiod_set_array_value_cansleep(s->gpios->ndescs, s->gpios->desc, gpiod_set_array_value_cansleep(s->gpios->ndescs, s->gpios->desc,
s->values); s->gpios->info, values);
return 0; return 0;
} }
...@@ -51,8 +49,7 @@ static int mdio_mux_gpio_probe(struct platform_device *pdev) ...@@ -51,8 +49,7 @@ static int mdio_mux_gpio_probe(struct platform_device *pdev)
if (IS_ERR(gpios)) if (IS_ERR(gpios))
return PTR_ERR(gpios); return PTR_ERR(gpios);
s = devm_kzalloc(&pdev->dev, struct_size(s, values, gpios->ndescs), s = devm_kzalloc(&pdev->dev, sizeof(*s), GFP_KERNEL);
GFP_KERNEL);
if (!s) { if (!s) {
gpiod_put_array(gpios); gpiod_put_array(gpios);
return -ENOMEM; return -ENOMEM;
......
...@@ -351,19 +351,20 @@ static int soc_common_pcmcia_config_skt( ...@@ -351,19 +351,20 @@ static int soc_common_pcmcia_config_skt(
if (ret == 0) { if (ret == 0) {
struct gpio_desc *descs[2]; struct gpio_desc *descs[2];
int values[2], n = 0; DECLARE_BITMAP(values, 2);
int n = 0;
if (skt->gpio_reset) { if (skt->gpio_reset) {
descs[n] = skt->gpio_reset; descs[n] = skt->gpio_reset;
values[n++] = !!(state->flags & SS_RESET); __assign_bit(n++, values, state->flags & SS_RESET);
} }
if (skt->gpio_bus_enable) { if (skt->gpio_bus_enable) {
descs[n] = skt->gpio_bus_enable; descs[n] = skt->gpio_bus_enable;
values[n++] = !!(state->flags & SS_OUTPUT_ENA); __assign_bit(n++, values, state->flags & SS_OUTPUT_ENA);
} }
if (n) if (n)
gpiod_set_array_value_cansleep(n, descs, values); gpiod_set_array_value_cansleep(n, descs, NULL, values);
/* /*
* This really needs a better solution. The IRQ * This really needs a better solution. The IRQ
......
...@@ -157,15 +157,13 @@ static const struct phy_ops gpio_usb_ops = { ...@@ -157,15 +157,13 @@ static const struct phy_ops gpio_usb_ops = {
*/ */
static void phy_mdm6600_cmd(struct phy_mdm6600 *ddata, int val) static void phy_mdm6600_cmd(struct phy_mdm6600 *ddata, int val)
{ {
int values[PHY_MDM6600_NR_CMD_LINES]; DECLARE_BITMAP(values, PHY_MDM6600_NR_CMD_LINES);
int i;
val &= (1 << PHY_MDM6600_NR_CMD_LINES) - 1; values[0] = val;
for (i = 0; i < PHY_MDM6600_NR_CMD_LINES; i++)
values[i] = (val & BIT(i)) >> i;
gpiod_set_array_value_cansleep(PHY_MDM6600_NR_CMD_LINES, gpiod_set_array_value_cansleep(PHY_MDM6600_NR_CMD_LINES,
ddata->cmd_gpios->desc, values); ddata->cmd_gpios->desc,
ddata->cmd_gpios->info, values);
} }
/** /**
...@@ -176,7 +174,7 @@ static void phy_mdm6600_status(struct work_struct *work) ...@@ -176,7 +174,7 @@ static void phy_mdm6600_status(struct work_struct *work)
{ {
struct phy_mdm6600 *ddata; struct phy_mdm6600 *ddata;
struct device *dev; struct device *dev;
int values[PHY_MDM6600_NR_STATUS_LINES]; DECLARE_BITMAP(values, PHY_MDM6600_NR_STATUS_LINES);
int error, i, val = 0; int error, i, val = 0;
ddata = container_of(work, struct phy_mdm6600, status_work.work); ddata = container_of(work, struct phy_mdm6600, status_work.work);
...@@ -184,16 +182,17 @@ static void phy_mdm6600_status(struct work_struct *work) ...@@ -184,16 +182,17 @@ static void phy_mdm6600_status(struct work_struct *work)
error = gpiod_get_array_value_cansleep(PHY_MDM6600_NR_STATUS_LINES, error = gpiod_get_array_value_cansleep(PHY_MDM6600_NR_STATUS_LINES,
ddata->status_gpios->desc, ddata->status_gpios->desc,
ddata->status_gpios->info,
values); values);
if (error) if (error)
return; return;
for (i = 0; i < PHY_MDM6600_NR_STATUS_LINES; i++) { for (i = 0; i < PHY_MDM6600_NR_STATUS_LINES; i++) {
val |= values[i] << i; val |= test_bit(i, values) << i;
dev_dbg(ddata->dev, "XXX %s: i: %i values[i]: %i val: %i\n", dev_dbg(ddata->dev, "XXX %s: i: %i values[i]: %i val: %i\n",
__func__, i, values[i], val); __func__, i, test_bit(i, values), val);
} }
ddata->status = val; ddata->status = values[0];
dev_info(dev, "modem status: %i %s\n", dev_info(dev, "modem status: %i %s\n",
ddata->status, ddata->status,
......
...@@ -601,6 +601,42 @@ static void msm_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip) ...@@ -601,6 +601,42 @@ static void msm_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
#define msm_gpio_dbg_show NULL #define msm_gpio_dbg_show NULL
#endif #endif
static int msm_gpio_init_valid_mask(struct gpio_chip *chip)
{
struct msm_pinctrl *pctrl = gpiochip_get_data(chip);
int ret;
unsigned int len, i;
unsigned int max_gpios = pctrl->soc->ngpios;
u16 *tmp;
/* The number of GPIOs in the ACPI tables */
len = ret = device_property_read_u16_array(pctrl->dev, "gpios", NULL,
0);
if (ret < 0)
return 0;
if (ret > max_gpios)
return -EINVAL;
tmp = kmalloc_array(len, sizeof(*tmp), GFP_KERNEL);
if (!tmp)
return -ENOMEM;
ret = device_property_read_u16_array(pctrl->dev, "gpios", tmp, len);
if (ret < 0) {
dev_err(pctrl->dev, "could not read list of GPIOs\n");
goto out;
}
bitmap_zero(chip->valid_mask, max_gpios);
for (i = 0; i < len; i++)
set_bit(tmp[i], chip->valid_mask);
out:
kfree(tmp);
return ret;
}
static const struct gpio_chip msm_gpio_template = { static const struct gpio_chip msm_gpio_template = {
.direction_input = msm_gpio_direction_input, .direction_input = msm_gpio_direction_input,
.direction_output = msm_gpio_direction_output, .direction_output = msm_gpio_direction_output,
...@@ -610,6 +646,7 @@ static const struct gpio_chip msm_gpio_template = { ...@@ -610,6 +646,7 @@ static const struct gpio_chip msm_gpio_template = {
.request = gpiochip_generic_request, .request = gpiochip_generic_request,
.free = gpiochip_generic_free, .free = gpiochip_generic_free,
.dbg_show = msm_gpio_dbg_show, .dbg_show = msm_gpio_dbg_show,
.init_valid_mask = msm_gpio_init_valid_mask,
}; };
/* For dual-edge interrupts in software, since some hardware has no /* For dual-edge interrupts in software, since some hardware has no
...@@ -925,41 +962,6 @@ static void msm_gpio_irq_handler(struct irq_desc *desc) ...@@ -925,41 +962,6 @@ static void msm_gpio_irq_handler(struct irq_desc *desc)
chained_irq_exit(chip, desc); chained_irq_exit(chip, desc);
} }
static int msm_gpio_init_valid_mask(struct gpio_chip *chip,
struct msm_pinctrl *pctrl)
{
int ret;
unsigned int len, i;
unsigned int max_gpios = pctrl->soc->ngpios;
u16 *tmp;
/* The number of GPIOs in the ACPI tables */
len = ret = device_property_read_u16_array(pctrl->dev, "gpios", NULL, 0);
if (ret < 0)
return 0;
if (ret > max_gpios)
return -EINVAL;
tmp = kmalloc_array(len, sizeof(*tmp), GFP_KERNEL);
if (!tmp)
return -ENOMEM;
ret = device_property_read_u16_array(pctrl->dev, "gpios", tmp, len);
if (ret < 0) {
dev_err(pctrl->dev, "could not read list of GPIOs\n");
goto out;
}
bitmap_zero(chip->valid_mask, max_gpios);
for (i = 0; i < len; i++)
set_bit(tmp[i], chip->valid_mask);
out:
kfree(tmp);
return ret;
}
static bool msm_gpio_needs_valid_mask(struct msm_pinctrl *pctrl) static bool msm_gpio_needs_valid_mask(struct msm_pinctrl *pctrl)
{ {
return device_property_read_u16_array(pctrl->dev, "gpios", NULL, 0) > 0; return device_property_read_u16_array(pctrl->dev, "gpios", NULL, 0) > 0;
...@@ -998,13 +1000,6 @@ static int msm_gpio_init(struct msm_pinctrl *pctrl) ...@@ -998,13 +1000,6 @@ static int msm_gpio_init(struct msm_pinctrl *pctrl)
return ret; return ret;
} }
ret = msm_gpio_init_valid_mask(chip, pctrl);
if (ret) {
dev_err(pctrl->dev, "Failed to setup irq valid bits\n");
gpiochip_remove(&pctrl->chip);
return ret;
}
/* /*
* For DeviceTree-supported systems, the gpio core checks the * For DeviceTree-supported systems, the gpio core checks the
* pinctrl's device node for the "gpio-ranges" property. * pinctrl's device node for the "gpio-ranges" property.
......
...@@ -202,7 +202,7 @@ static int ad7606_write_raw(struct iio_dev *indio_dev, ...@@ -202,7 +202,7 @@ static int ad7606_write_raw(struct iio_dev *indio_dev,
long mask) long mask)
{ {
struct ad7606_state *st = iio_priv(indio_dev); struct ad7606_state *st = iio_priv(indio_dev);
int values[3]; DECLARE_BITMAP(values, 3);
int ret, i; int ret, i;
switch (mask) { switch (mask) {
...@@ -227,12 +227,10 @@ static int ad7606_write_raw(struct iio_dev *indio_dev, ...@@ -227,12 +227,10 @@ static int ad7606_write_raw(struct iio_dev *indio_dev,
if (ret < 0) if (ret < 0)
return ret; return ret;
values[0] = (ret >> 0) & 1; values[0] = ret;
values[1] = (ret >> 1) & 1;
values[2] = (ret >> 2) & 1;
mutex_lock(&st->lock); mutex_lock(&st->lock);
gpiod_set_array_value(ARRAY_SIZE(values), st->gpio_os->desc, gpiod_set_array_value(3, st->gpio_os->desc, st->gpio_os->info,
values); values);
st->oversampling = val; st->oversampling = val;
mutex_unlock(&st->lock); mutex_unlock(&st->lock);
......
...@@ -40,7 +40,7 @@ void mctrl_gpio_set(struct mctrl_gpios *gpios, unsigned int mctrl) ...@@ -40,7 +40,7 @@ void mctrl_gpio_set(struct mctrl_gpios *gpios, unsigned int mctrl)
{ {
enum mctrl_gpio_idx i; enum mctrl_gpio_idx i;
struct gpio_desc *desc_array[UART_GPIO_MAX]; struct gpio_desc *desc_array[UART_GPIO_MAX];
int value_array[UART_GPIO_MAX]; DECLARE_BITMAP(values, UART_GPIO_MAX);
unsigned int count = 0; unsigned int count = 0;
if (gpios == NULL) if (gpios == NULL)
...@@ -49,10 +49,11 @@ void mctrl_gpio_set(struct mctrl_gpios *gpios, unsigned int mctrl) ...@@ -49,10 +49,11 @@ void mctrl_gpio_set(struct mctrl_gpios *gpios, unsigned int mctrl)
for (i = 0; i < UART_GPIO_MAX; i++) for (i = 0; i < UART_GPIO_MAX; i++)
if (gpios->gpio[i] && mctrl_gpios_desc[i].dir_out) { if (gpios->gpio[i] && mctrl_gpios_desc[i].dir_out) {
desc_array[count] = gpios->gpio[i]; desc_array[count] = gpios->gpio[i];
value_array[count] = !!(mctrl & mctrl_gpios_desc[i].mctrl); __assign_bit(count, values,
mctrl & mctrl_gpios_desc[i].mctrl);
count++; count++;
} }
gpiod_set_array_value(count, desc_array, value_array); gpiod_set_array_value(count, desc_array, NULL, values);
} }
EXPORT_SYMBOL_GPL(mctrl_gpio_set); EXPORT_SYMBOL_GPL(mctrl_gpio_set);
......
...@@ -17,11 +17,20 @@ struct device; ...@@ -17,11 +17,20 @@ struct device;
*/ */
struct gpio_desc; struct gpio_desc;
/**
* Opaque descriptor for a structure of GPIO array attributes. This structure
* is attached to struct gpiod_descs obtained from gpiod_get_array() and can be
* passed back to get/set array functions in order to activate fast processing
* path if applicable.
*/
struct gpio_array;
/** /**
* Struct containing an array of descriptors that can be obtained using * Struct containing an array of descriptors that can be obtained using
* gpiod_get_array(). * gpiod_get_array().
*/ */
struct gpio_descs { struct gpio_descs {
struct gpio_array *info;
unsigned int ndescs; unsigned int ndescs;
struct gpio_desc *desc[]; struct gpio_desc *desc[];
}; };
...@@ -105,36 +114,46 @@ int gpiod_direction_output_raw(struct gpio_desc *desc, int value); ...@@ -105,36 +114,46 @@ int gpiod_direction_output_raw(struct gpio_desc *desc, int value);
/* Value get/set from non-sleeping context */ /* Value get/set from non-sleeping context */
int gpiod_get_value(const struct gpio_desc *desc); int gpiod_get_value(const struct gpio_desc *desc);
int gpiod_get_array_value(unsigned int array_size, int gpiod_get_array_value(unsigned int array_size,
struct gpio_desc **desc_array, int *value_array); struct gpio_desc **desc_array,
struct gpio_array *array_info,
unsigned long *value_bitmap);
void gpiod_set_value(struct gpio_desc *desc, int value); void gpiod_set_value(struct gpio_desc *desc, int value);
void gpiod_set_array_value(unsigned int array_size, int gpiod_set_array_value(unsigned int array_size,
struct gpio_desc **desc_array, int *value_array); struct gpio_desc **desc_array,
struct gpio_array *array_info,
unsigned long *value_bitmap);
int gpiod_get_raw_value(const struct gpio_desc *desc); int gpiod_get_raw_value(const struct gpio_desc *desc);
int gpiod_get_raw_array_value(unsigned int array_size, int gpiod_get_raw_array_value(unsigned int array_size,
struct gpio_desc **desc_array, struct gpio_desc **desc_array,
int *value_array); struct gpio_array *array_info,
unsigned long *value_bitmap);
void gpiod_set_raw_value(struct gpio_desc *desc, int value); void gpiod_set_raw_value(struct gpio_desc *desc, int value);
int gpiod_set_raw_array_value(unsigned int array_size, int gpiod_set_raw_array_value(unsigned int array_size,
struct gpio_desc **desc_array, struct gpio_desc **desc_array,
int *value_array); struct gpio_array *array_info,
unsigned long *value_bitmap);
/* Value get/set from sleeping context */ /* Value get/set from sleeping context */
int gpiod_get_value_cansleep(const struct gpio_desc *desc); int gpiod_get_value_cansleep(const struct gpio_desc *desc);
int gpiod_get_array_value_cansleep(unsigned int array_size, int gpiod_get_array_value_cansleep(unsigned int array_size,
struct gpio_desc **desc_array, struct gpio_desc **desc_array,
int *value_array); struct gpio_array *array_info,
unsigned long *value_bitmap);
void gpiod_set_value_cansleep(struct gpio_desc *desc, int value); void gpiod_set_value_cansleep(struct gpio_desc *desc, int value);
void gpiod_set_array_value_cansleep(unsigned int array_size, int gpiod_set_array_value_cansleep(unsigned int array_size,
struct gpio_desc **desc_array, struct gpio_desc **desc_array,
int *value_array); struct gpio_array *array_info,
unsigned long *value_bitmap);
int gpiod_get_raw_value_cansleep(const struct gpio_desc *desc); int gpiod_get_raw_value_cansleep(const struct gpio_desc *desc);
int gpiod_get_raw_array_value_cansleep(unsigned int array_size, int gpiod_get_raw_array_value_cansleep(unsigned int array_size,
struct gpio_desc **desc_array, struct gpio_desc **desc_array,
int *value_array); struct gpio_array *array_info,
unsigned long *value_bitmap);
void gpiod_set_raw_value_cansleep(struct gpio_desc *desc, int value); void gpiod_set_raw_value_cansleep(struct gpio_desc *desc, int value);
int gpiod_set_raw_array_value_cansleep(unsigned int array_size, int gpiod_set_raw_array_value_cansleep(unsigned int array_size,
struct gpio_desc **desc_array, struct gpio_desc **desc_array,
int *value_array); struct gpio_array *array_info,
unsigned long *value_bitmap);
int gpiod_set_debounce(struct gpio_desc *desc, unsigned debounce); int gpiod_set_debounce(struct gpio_desc *desc, unsigned debounce);
int gpiod_set_transitory(struct gpio_desc *desc, bool transitory); int gpiod_set_transitory(struct gpio_desc *desc, bool transitory);
...@@ -331,7 +350,8 @@ static inline int gpiod_get_value(const struct gpio_desc *desc) ...@@ -331,7 +350,8 @@ static inline int gpiod_get_value(const struct gpio_desc *desc)
} }
static inline int gpiod_get_array_value(unsigned int array_size, static inline int gpiod_get_array_value(unsigned int array_size,
struct gpio_desc **desc_array, struct gpio_desc **desc_array,
int *value_array) struct gpio_array *array_info,
unsigned long *value_bitmap)
{ {
/* GPIO can never have been requested */ /* GPIO can never have been requested */
WARN_ON(1); WARN_ON(1);
...@@ -342,12 +362,14 @@ static inline void gpiod_set_value(struct gpio_desc *desc, int value) ...@@ -342,12 +362,14 @@ static inline void gpiod_set_value(struct gpio_desc *desc, int value)
/* GPIO can never have been requested */ /* GPIO can never have been requested */
WARN_ON(1); WARN_ON(1);
} }
static inline void gpiod_set_array_value(unsigned int array_size, static inline int gpiod_set_array_value(unsigned int array_size,
struct gpio_desc **desc_array, struct gpio_desc **desc_array,
int *value_array) struct gpio_array *array_info,
unsigned long *value_bitmap)
{ {
/* GPIO can never have been requested */ /* GPIO can never have been requested */
WARN_ON(1); WARN_ON(1);
return 0;
} }
static inline int gpiod_get_raw_value(const struct gpio_desc *desc) static inline int gpiod_get_raw_value(const struct gpio_desc *desc)
{ {
...@@ -357,7 +379,8 @@ static inline int gpiod_get_raw_value(const struct gpio_desc *desc) ...@@ -357,7 +379,8 @@ static inline int gpiod_get_raw_value(const struct gpio_desc *desc)
} }
static inline int gpiod_get_raw_array_value(unsigned int array_size, static inline int gpiod_get_raw_array_value(unsigned int array_size,
struct gpio_desc **desc_array, struct gpio_desc **desc_array,
int *value_array) struct gpio_array *array_info,
unsigned long *value_bitmap)
{ {
/* GPIO can never have been requested */ /* GPIO can never have been requested */
WARN_ON(1); WARN_ON(1);
...@@ -370,7 +393,8 @@ static inline void gpiod_set_raw_value(struct gpio_desc *desc, int value) ...@@ -370,7 +393,8 @@ static inline void gpiod_set_raw_value(struct gpio_desc *desc, int value)
} }
static inline int gpiod_set_raw_array_value(unsigned int array_size, static inline int gpiod_set_raw_array_value(unsigned int array_size,
struct gpio_desc **desc_array, struct gpio_desc **desc_array,
int *value_array) struct gpio_array *array_info,
unsigned long *value_bitmap)
{ {
/* GPIO can never have been requested */ /* GPIO can never have been requested */
WARN_ON(1); WARN_ON(1);
...@@ -385,7 +409,8 @@ static inline int gpiod_get_value_cansleep(const struct gpio_desc *desc) ...@@ -385,7 +409,8 @@ static inline int gpiod_get_value_cansleep(const struct gpio_desc *desc)
} }
static inline int gpiod_get_array_value_cansleep(unsigned int array_size, static inline int gpiod_get_array_value_cansleep(unsigned int array_size,
struct gpio_desc **desc_array, struct gpio_desc **desc_array,
int *value_array) struct gpio_array *array_info,
unsigned long *value_bitmap)
{ {
/* GPIO can never have been requested */ /* GPIO can never have been requested */
WARN_ON(1); WARN_ON(1);
...@@ -396,12 +421,14 @@ static inline void gpiod_set_value_cansleep(struct gpio_desc *desc, int value) ...@@ -396,12 +421,14 @@ static inline void gpiod_set_value_cansleep(struct gpio_desc *desc, int value)
/* GPIO can never have been requested */ /* GPIO can never have been requested */
WARN_ON(1); WARN_ON(1);
} }
static inline void gpiod_set_array_value_cansleep(unsigned int array_size, static inline int gpiod_set_array_value_cansleep(unsigned int array_size,
struct gpio_desc **desc_array, struct gpio_desc **desc_array,
int *value_array) struct gpio_array *array_info,
unsigned long *value_bitmap)
{ {
/* GPIO can never have been requested */ /* GPIO can never have been requested */
WARN_ON(1); WARN_ON(1);
return 0;
} }
static inline int gpiod_get_raw_value_cansleep(const struct gpio_desc *desc) static inline int gpiod_get_raw_value_cansleep(const struct gpio_desc *desc)
{ {
...@@ -411,7 +438,8 @@ static inline int gpiod_get_raw_value_cansleep(const struct gpio_desc *desc) ...@@ -411,7 +438,8 @@ static inline int gpiod_get_raw_value_cansleep(const struct gpio_desc *desc)
} }
static inline int gpiod_get_raw_array_value_cansleep(unsigned int array_size, static inline int gpiod_get_raw_array_value_cansleep(unsigned int array_size,
struct gpio_desc **desc_array, struct gpio_desc **desc_array,
int *value_array) struct gpio_array *array_info,
unsigned long *value_bitmap)
{ {
/* GPIO can never have been requested */ /* GPIO can never have been requested */
WARN_ON(1); WARN_ON(1);
...@@ -425,7 +453,8 @@ static inline void gpiod_set_raw_value_cansleep(struct gpio_desc *desc, ...@@ -425,7 +453,8 @@ static inline void gpiod_set_raw_value_cansleep(struct gpio_desc *desc,
} }
static inline int gpiod_set_raw_array_value_cansleep(unsigned int array_size, static inline int gpiod_set_raw_array_value_cansleep(unsigned int array_size,
struct gpio_desc **desc_array, struct gpio_desc **desc_array,
int *value_array) struct gpio_array *array_info,
unsigned long *value_bitmap)
{ {
/* GPIO can never have been requested */ /* GPIO can never have been requested */
WARN_ON(1); WARN_ON(1);
......
...@@ -66,9 +66,15 @@ struct gpio_irq_chip { ...@@ -66,9 +66,15 @@ struct gpio_irq_chip {
/** /**
* @lock_key: * @lock_key:
* *
* Per GPIO IRQ chip lockdep classes. * Per GPIO IRQ chip lockdep class for IRQ lock.
*/ */
struct lock_class_key *lock_key; struct lock_class_key *lock_key;
/**
* @request_key:
*
* Per GPIO IRQ chip lockdep class for IRQ request.
*/
struct lock_class_key *request_key; struct lock_class_key *request_key;
/** /**
...@@ -145,6 +151,20 @@ struct gpio_irq_chip { ...@@ -145,6 +151,20 @@ struct gpio_irq_chip {
* will allocate and map all IRQs during initialization. * will allocate and map all IRQs during initialization.
*/ */
unsigned int first; unsigned int first;
/**
* @irq_enable:
*
* Store old irq_chip irq_enable callback
*/
void (*irq_enable)(struct irq_data *data);
/**
* @irq_disable:
*
* Store old irq_chip irq_disable callback
*/
void (*irq_disable)(struct irq_data *data);
}; };
static inline struct gpio_irq_chip *to_gpio_irq_chip(struct irq_chip *chip) static inline struct gpio_irq_chip *to_gpio_irq_chip(struct irq_chip *chip)
...@@ -165,9 +185,13 @@ static inline struct gpio_irq_chip *to_gpio_irq_chip(struct irq_chip *chip) ...@@ -165,9 +185,13 @@ static inline struct gpio_irq_chip *to_gpio_irq_chip(struct irq_chip *chip)
* @free: optional hook for chip-specific deactivation, such as * @free: optional hook for chip-specific deactivation, such as
* disabling module power and clock; may sleep * disabling module power and clock; may sleep
* @get_direction: returns direction for signal "offset", 0=out, 1=in, * @get_direction: returns direction for signal "offset", 0=out, 1=in,
* (same as GPIOF_DIR_XXX), or negative error * (same as GPIOF_DIR_XXX), or negative error.
* It is recommended to always implement this function, even on
* input-only or output-only gpio chips.
* @direction_input: configures signal "offset" as input, or returns error * @direction_input: configures signal "offset" as input, or returns error
* This can be omitted on input-only or output-only gpio chips.
* @direction_output: configures signal "offset" as output, or returns error * @direction_output: configures signal "offset" as output, or returns error
* This can be omitted on input-only or output-only gpio chips.
* @get: returns value for signal "offset", 0=low, 1=high, or negative error * @get: returns value for signal "offset", 0=low, 1=high, or negative error
* @get_multiple: reads values for multiple signals defined by "mask" and * @get_multiple: reads values for multiple signals defined by "mask" and
* stores them in "bits", returns 0 on success or negative error * stores them in "bits", returns 0 on success or negative error
...@@ -263,6 +287,9 @@ struct gpio_chip { ...@@ -263,6 +287,9 @@ struct gpio_chip {
void (*dbg_show)(struct seq_file *s, void (*dbg_show)(struct seq_file *s,
struct gpio_chip *chip); struct gpio_chip *chip);
int (*init_valid_mask)(struct gpio_chip *chip);
int base; int base;
u16 ngpio; u16 ngpio;
const char *const *names; const char *const *names;
...@@ -301,7 +328,9 @@ struct gpio_chip { ...@@ -301,7 +328,9 @@ struct gpio_chip {
/** /**
* @need_valid_mask: * @need_valid_mask:
* *
* If set core allocates @valid_mask with all bits set to one. * If set core allocates @valid_mask with all its values initialized
* with init_valid_mask() or set to one if init_valid_mask() is not
* defined
*/ */
bool need_valid_mask; bool need_valid_mask;
...@@ -402,6 +431,10 @@ extern struct gpio_chip *gpiochip_find(void *data, ...@@ -402,6 +431,10 @@ extern struct gpio_chip *gpiochip_find(void *data,
int gpiochip_lock_as_irq(struct gpio_chip *chip, unsigned int offset); int gpiochip_lock_as_irq(struct gpio_chip *chip, unsigned int offset);
void gpiochip_unlock_as_irq(struct gpio_chip *chip, unsigned int offset); void gpiochip_unlock_as_irq(struct gpio_chip *chip, unsigned int offset);
bool gpiochip_line_is_irq(struct gpio_chip *chip, unsigned int offset); bool gpiochip_line_is_irq(struct gpio_chip *chip, unsigned int offset);
int gpiochip_reqres_irq(struct gpio_chip *chip, unsigned int offset);
void gpiochip_relres_irq(struct gpio_chip *chip, unsigned int offset);
void gpiochip_disable_irq(struct gpio_chip *chip, unsigned int offset);
void gpiochip_enable_irq(struct gpio_chip *chip, unsigned int offset);
/* Line status inquiry for drivers */ /* Line status inquiry for drivers */
bool gpiochip_line_is_open_drain(struct gpio_chip *chip, unsigned int offset); bool gpiochip_line_is_open_drain(struct gpio_chip *chip, unsigned int offset);
......
...@@ -16,46 +16,12 @@ ...@@ -16,46 +16,12 @@
#ifndef __DAVINCI_GPIO_PLATFORM_H #ifndef __DAVINCI_GPIO_PLATFORM_H
#define __DAVINCI_GPIO_PLATFORM_H #define __DAVINCI_GPIO_PLATFORM_H
#include <linux/io.h>
#include <linux/spinlock.h>
#include <asm-generic/gpio.h>
#define MAX_REGS_BANKS 5
#define MAX_INT_PER_BANK 32
struct davinci_gpio_platform_data { struct davinci_gpio_platform_data {
u32 ngpio; u32 ngpio;
u32 gpio_unbanked; u32 gpio_unbanked;
}; };
struct davinci_gpio_irq_data {
void __iomem *regs;
struct davinci_gpio_controller *chip;
int bank_num;
};
struct davinci_gpio_controller {
struct gpio_chip chip;
struct irq_domain *irq_domain;
/* Serialize access to GPIO registers */
spinlock_t lock;
void __iomem *regs[MAX_REGS_BANKS];
int gpio_unbanked;
int irqs[MAX_INT_PER_BANK];
unsigned int base;
};
/*
* basic gpio routines
*/
#define GPIO(X) (X) /* 0 <= X <= (DAVINCI_N_GPIO - 1) */
/* Convert GPIO signal to GPIO pin number */ /* Convert GPIO signal to GPIO pin number */
#define GPIO_TO_PIN(bank, gpio) (16 * (bank) + (gpio)) #define GPIO_TO_PIN(bank, gpio) (16 * (bank) + (gpio))
static inline u32 __gpio_mask(unsigned gpio)
{
return 1 << (gpio % 32);
}
#endif #endif
...@@ -197,23 +197,12 @@ struct omap_gpio_platform_data { ...@@ -197,23 +197,12 @@ struct omap_gpio_platform_data {
bool is_mpuio; /* whether the bank is of type MPUIO */ bool is_mpuio; /* whether the bank is of type MPUIO */
u32 non_wakeup_gpios; u32 non_wakeup_gpios;
u32 quirks; /* Version specific quirks mask */
struct omap_gpio_reg_offs *regs; struct omap_gpio_reg_offs *regs;
/* Return context loss count due to PM states changing */ /* Return context loss count due to PM states changing */
int (*get_context_loss_count)(struct device *dev); int (*get_context_loss_count)(struct device *dev);
}; };
#if IS_BUILTIN(CONFIG_GPIO_OMAP)
extern void omap2_gpio_prepare_for_idle(int off_mode);
extern void omap2_gpio_resume_after_idle(void);
#else
static inline void omap2_gpio_prepare_for_idle(int off_mode)
{
}
static inline void omap2_gpio_resume_after_idle(void)
{
}
#endif
#endif #endif
/*
* GPIO (DIO) header for Technologic Systems TS-5500
*
* Copyright (c) 2012 Savoir-faire Linux Inc.
* Vivien Didelot <vivien.didelot@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#ifndef _PDATA_GPIO_TS5500_H
#define _PDATA_GPIO_TS5500_H
/**
* struct ts5500_dio_platform_data - TS-5500 pin block configuration
* @base: The GPIO base number to use.
* @strap: The only pin connected to an interrupt in a block is input-only.
* If you need a bidirectional line which can trigger an IRQ, you
* may strap it with an in/out pin. This flag indicates this case.
*/
struct ts5500_dio_platform_data {
int base;
bool strap;
};
#endif /* _PDATA_GPIO_TS5500_H */
...@@ -65,7 +65,7 @@ struct gpioline_info { ...@@ -65,7 +65,7 @@ struct gpioline_info {
/** /**
* struct gpiohandle_request - Information about a GPIO handle request * struct gpiohandle_request - Information about a GPIO handle request
* @lineoffsets: an array desired lines, specified by offset index for the * @lineoffsets: an array of desired lines, specified by offset index for the
* associated GPIO device * associated GPIO device
* @flags: desired flags for the desired GPIO lines, such as * @flags: desired flags for the desired GPIO lines, such as
* GPIOHANDLE_REQUEST_OUTPUT, GPIOHANDLE_REQUEST_ACTIVE_LOW etc, OR:ed * GPIOHANDLE_REQUEST_OUTPUT, GPIOHANDLE_REQUEST_ACTIVE_LOW etc, OR:ed
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment