mirror of
https://github.com/linux-msm/laptops-kernel.git
synced 2026-08-13 14:19:53 -07:00
Merge tag 'gpio-updates-for-v6.18-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/brgl/linux
Pull gpio updates from Bartosz Golaszewski:
"There are two new drivers and support for more models in existing
ones.
The generic GPIO API has been reworked and all users converted
which allowed us to move the fields specific to the generic GPIO
implementation out of the high-level struct gpio_chip into its own
structure that wraps the gpio_chip.
Other than that, there's nothing too exciting. Mostly minor tweaks and
fixes all over the place, some refactoring and some small new features
in helper modules.
GPIO core:
- add support for sparse pin ranges to the glue between GPIO and
pinctrl
- use a common prefix across all GPIO descriptor flags for improved
namespacing
New drivers:
- add new GPIO driver for the Nuvoton NCT6694
- add new GPIO driver for MAX7360
Driver improvements:
- add support for Tegra 256 to the gpio-tegra186 driver
- add support for Loongson-2K0300 to the gpio-loongson-64bit driver
- refactor the gpio-aggregator module to expose its GPIO forwarder
API to other in-kernel users (to enable merging of a new pinctrl
driver that uses it)
- convert all remaining drivers to using the modernized generic GPIO
chip API and remove the old interface
- stop displaying global GPIO numbers in debugfs output of controller
drivers
- extend the gpio-regmap helper with a new config option and improve
its support for GPIO interrupts
- remove redundant fast_io parameter from regmap configs in GPIO
drivers that already use MMIO regmaps which imply it
- add support for a new model in gpio-mmio: ixp4xx expansion bus
- order includes alphabetically in a few drivers for better
readability
- use generic device properties where applicable
- use devm_mutex_init() where applicable
- extend build coverage of drivers by enabling more to be compiled
with COMPILE_TEST enabled
- allow building gpio-stmpe as a module
- use dev_err_probe() where it makes sense in drivers
Late driver fixes:
- fix setting GPIO direction to output in gpio-mpfs
Documentation:
- document the usage of software nodes with GPIO chips
Device-tree bindings:
- Add DT bindings documents for new hardware: Tegra256, MAX7360
- Document a new model in Loongson bindings: LS2K0300
- Document a new model using the generic GPIO binding: IXP4xx
- Convert the DT binding for fsl,mxs-pinctrl to YAML
- fix the schema ID in the "trivial" GPIO schema
- describe GPIO hogs in the generic GPIO binding"
* tag 'gpio-updates-for-v6.18-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/brgl/linux: (122 commits)
gpio: mpfs: fix setting gpio direction to output
gpio: generic: move GPIO_GENERIC_ flags to the correct header
gpio: generic: rename BGPIOF_ flags to GPIO_GENERIC_
gpio: nomadik: fix the debugfs helper stub
MAINTAINERS: Add entry on MAX7360 driver
input: misc: Add support for MAX7360 rotary
input: keyboard: Add support for MAX7360 keypad
gpio: max7360: Add MAX7360 gpio support
gpio: regmap: Allow to provide init_valid_mask callback
gpio: regmap: Allow to allocate regmap-irq device
pwm: max7360: Add MAX7360 PWM support
pinctrl: Add MAX7360 pinctrl driver
mfd: Add max7360 support
dt-bindings: mfd: gpio: Add MAX7360
rtc: Add Nuvoton NCT6694 RTC support
hwmon: Add Nuvoton NCT6694 HWMON support
watchdog: Add Nuvoton NCT6694 WDT support
can: Add Nuvoton NCT6694 CANFD support
i2c: Add Nuvoton NCT6694 I2C support
gpio: Add Nuvoton NCT6694 GPIO support
...
This commit is contained in:
@@ -22,6 +22,7 @@ properties:
|
||||
- brcm,bcm6345-gpio
|
||||
- ni,169445-nand-gpio
|
||||
- wd,mbl-gpio # Western Digital MyBook Live memory-mapped GPIO controller
|
||||
- intel,ixp4xx-expansion-bus-mmio-gpio
|
||||
|
||||
big-endian: true
|
||||
|
||||
@@ -89,6 +90,20 @@ properties:
|
||||
description:
|
||||
If this property is present, the controller cannot drive the GPIO lines.
|
||||
|
||||
if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
const: intel,ixp4xx-expansion-bus-mmio-gpio
|
||||
then:
|
||||
$ref: /schemas/memory-controllers/intel,ixp4xx-expansion-peripheral-props.yaml#
|
||||
|
||||
patternProperties:
|
||||
"^.+-hog(-[0-9]+)?$":
|
||||
type: object
|
||||
required:
|
||||
- gpio-hog
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
@@ -96,7 +111,7 @@ required:
|
||||
- '#gpio-cells'
|
||||
- gpio-controller
|
||||
|
||||
additionalProperties: false
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
@@ -126,3 +141,22 @@ examples:
|
||||
gpio-controller;
|
||||
#gpio-cells = <2>;
|
||||
};
|
||||
|
||||
bus@c4000000 {
|
||||
compatible = "intel,ixp42x-expansion-bus-controller", "syscon";
|
||||
reg = <0xc4000000 0x30>;
|
||||
native-endian;
|
||||
#address-cells = <2>;
|
||||
#size-cells = <1>;
|
||||
ranges = <0 0x0 0x50000000 0x01000000>;
|
||||
dma-ranges = <0 0x0 0x50000000 0x01000000>;
|
||||
gpio@1,0 {
|
||||
compatible = "intel,ixp4xx-expansion-bus-mmio-gpio";
|
||||
gpio-controller;
|
||||
#gpio-cells = <2>;
|
||||
big-endian;
|
||||
reg = <1 0x00000000 0x2>;
|
||||
reg-names = "dat";
|
||||
intel,ixp4xx-eb-write-enable = <1>;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -18,9 +18,13 @@ description: |
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- fsl,imx23-pinctrl
|
||||
- fsl,imx28-pinctrl
|
||||
items:
|
||||
- enum:
|
||||
- fsl,imx23-pinctrl
|
||||
- fsl,imx28-pinctrl
|
||||
# Over 10 years old devices, driver use simple-bus to probe child gpio
|
||||
# Devices. Keep it as it to be compatible existed dts files.
|
||||
- const: simple-bus
|
||||
|
||||
'#address-cells':
|
||||
const: 1
|
||||
@@ -31,7 +35,65 @@ properties:
|
||||
maxItems: 1
|
||||
|
||||
patternProperties:
|
||||
"gpio@[0-9]+$":
|
||||
"^(?!gpio@)[^@]+@[0-9]+$":
|
||||
type: object
|
||||
properties:
|
||||
fsl,pinmux-ids:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32-array
|
||||
description: |
|
||||
An integer array. Each integer in the array specify a pin
|
||||
with given mux function, with bank, pin and mux packed as below.
|
||||
|
||||
[15..12] : bank number
|
||||
[11..4] : pin number
|
||||
[3..0] : mux selection
|
||||
|
||||
This integer with mux selection packed is used as an entity by both group
|
||||
and config nodes to identify a pin. The mux selection in the integer takes
|
||||
effects only on group node, and will get ignored by driver with config node,
|
||||
since config node is only meant to set up pin configurations.
|
||||
|
||||
Valid values for these integers are listed below.
|
||||
|
||||
reg:
|
||||
items:
|
||||
- description: |
|
||||
pin group index. NOTE: it is supposed wrong use reg property
|
||||
here. But it is over 10 years devices. Just keep it as it.
|
||||
|
||||
fsl,drive-strength:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
enum: [0, 1, 2, 3]
|
||||
description: |
|
||||
0: MXS_DRIVE_4mA
|
||||
1: MXS_DRIVE_8mA
|
||||
2: MXS_DRIVE_12mA
|
||||
3: MXS_DRIVE_16mA
|
||||
|
||||
fsl,voltage:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
enum: [0, 1]
|
||||
description: |
|
||||
0: MXS_VOLTAGE_LOW - 1.8 V
|
||||
1: MXS_VOLTAGE_HIGH - 3.3 V
|
||||
|
||||
fsl,pull-up:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
enum: [0, 1]
|
||||
description: |
|
||||
0: MXS_PULL_DISABLE - Disable the internal pull-up
|
||||
1: MXS_PULL_ENABLE - Enable the internal pull-up
|
||||
|
||||
Note that when enabling the pull-up, the internal pad keeper gets disabled.
|
||||
Also, some pins doesn't have a pull up, in that case, setting the fsl,pull-up
|
||||
will only disable the internal pad keeper.
|
||||
|
||||
required:
|
||||
- fsl,pinmux-ids
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
"^gpio@[0-9]+$":
|
||||
type: object
|
||||
properties:
|
||||
compatible:
|
||||
@@ -80,7 +142,7 @@ examples:
|
||||
pinctrl@80018000 {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
compatible = "fsl,imx28-pinctrl";
|
||||
compatible = "fsl,imx28-pinctrl", "simple-bus";
|
||||
reg = <0x80018000 0x2000>;
|
||||
|
||||
gpio@0 {
|
||||
@@ -132,4 +194,12 @@ examples:
|
||||
interrupt-controller;
|
||||
#interrupt-cells = <2>;
|
||||
};
|
||||
|
||||
lcdif-apx4@5 {
|
||||
reg = <5>;
|
||||
fsl,pinmux-ids = <0x1181 0x1191>;
|
||||
fsl,drive-strength = <0>;
|
||||
fsl,voltage = <0>;
|
||||
fsl,pull-up = <0>;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -14,6 +14,7 @@ properties:
|
||||
oneOf:
|
||||
- enum:
|
||||
- loongson,ls2k-gpio
|
||||
- loongson,ls2k0300-gpio
|
||||
- loongson,ls2k0500-gpio0
|
||||
- loongson,ls2k0500-gpio1
|
||||
- loongson,ls2k2000-gpio0
|
||||
@@ -36,7 +37,7 @@ properties:
|
||||
|
||||
ngpios:
|
||||
minimum: 1
|
||||
maximum: 64
|
||||
maximum: 128
|
||||
|
||||
"#gpio-cells":
|
||||
const: 2
|
||||
@@ -49,6 +50,14 @@ properties:
|
||||
minItems: 1
|
||||
maxItems: 64
|
||||
|
||||
"#interrupt-cells":
|
||||
const: 2
|
||||
|
||||
interrupt-controller: true
|
||||
|
||||
resets:
|
||||
maxItems: 1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
@@ -58,6 +67,23 @@ required:
|
||||
- gpio-ranges
|
||||
- interrupts
|
||||
|
||||
allOf:
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
const: loongson,ls2k0300-gpio
|
||||
then:
|
||||
required:
|
||||
- "#interrupt-cells"
|
||||
- interrupt-controller
|
||||
- resets
|
||||
else:
|
||||
properties:
|
||||
"#interrupts-cells": false
|
||||
interrupt-controller: false
|
||||
resets: false
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
|
||||
@@ -95,9 +95,9 @@ examples:
|
||||
#gpio-cells = <2>;
|
||||
|
||||
maxim,modesel-gpios = <&gpio2 23>;
|
||||
maxim,fault-gpios = <&gpio2 24 GPIO_ACTIVE_LOW>;
|
||||
maxim,db0-gpios = <&gpio2 25>;
|
||||
maxim,db1-gpios = <&gpio2 26>;
|
||||
maxim,fault-gpios = <&gpio2 24 GPIO_ACTIVE_LOW>;
|
||||
maxim,db0-gpios = <&gpio2 25>;
|
||||
maxim,db1-gpios = <&gpio2 26>;
|
||||
|
||||
spi-max-frequency = <25000000>;
|
||||
};
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/gpio/maxim,max7360-gpio.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Maxim MAX7360 GPIO controller
|
||||
|
||||
maintainers:
|
||||
- Kamel Bouhara <kamel.bouhara@bootlin.com>
|
||||
- Mathieu Dubois-Briand <mathieu.dubois-briand@bootlin.com>
|
||||
|
||||
description: |
|
||||
Maxim MAX7360 GPIO controller, in MAX7360 chipset
|
||||
https://www.analog.com/en/products/max7360.html
|
||||
|
||||
The device provides two series of GPIOs, referred here as GPIOs and GPOs.
|
||||
|
||||
PORT0 to PORT7 pins can be used as GPIOs, with support for interrupts and
|
||||
constant-current mode. These pins will also be used by the rotary encoder and
|
||||
PWM functionalities.
|
||||
|
||||
COL2 to COL7 pins can be used as GPOs, there is no input capability. COL pins
|
||||
will be partitioned, with the first pins being affected to the keypad
|
||||
functionality and the last ones as GPOs.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- maxim,max7360-gpio
|
||||
- maxim,max7360-gpo
|
||||
|
||||
gpio-controller: true
|
||||
|
||||
"#gpio-cells":
|
||||
const: 2
|
||||
|
||||
interrupt-controller: true
|
||||
|
||||
"#interrupt-cells":
|
||||
const: 2
|
||||
|
||||
maxim,constant-current-disable:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
description:
|
||||
Bit field, each bit disables constant-current output of the associated
|
||||
GPIO, starting from the least significant bit for the first GPIO.
|
||||
maximum: 0xff
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- gpio-controller
|
||||
|
||||
allOf:
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- maxim,max7360-gpio
|
||||
ngpios: false
|
||||
then:
|
||||
required:
|
||||
- interrupt-controller
|
||||
else:
|
||||
properties:
|
||||
interrupt-controller: false
|
||||
maxim,constant-current-disable: false
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
gpio {
|
||||
compatible = "maxim,max7360-gpio";
|
||||
|
||||
gpio-controller;
|
||||
#gpio-cells = <2>;
|
||||
maxim,constant-current-disable = <0x06>;
|
||||
|
||||
interrupt-controller;
|
||||
#interrupt-cells = <2>;
|
||||
};
|
||||
@@ -85,6 +85,7 @@ properties:
|
||||
- nvidia,tegra194-gpio-aon
|
||||
- nvidia,tegra234-gpio
|
||||
- nvidia,tegra234-gpio-aon
|
||||
- nvidia,tegra256-gpio
|
||||
|
||||
reg-names:
|
||||
items:
|
||||
@@ -155,6 +156,7 @@ allOf:
|
||||
- nvidia,tegra186-gpio
|
||||
- nvidia,tegra194-gpio
|
||||
- nvidia,tegra234-gpio
|
||||
- nvidia,tegra256-gpio
|
||||
then:
|
||||
properties:
|
||||
interrupts:
|
||||
|
||||
@@ -80,7 +80,7 @@ examples:
|
||||
gpio@d4019000 {
|
||||
compatible = "spacemit,k1-gpio";
|
||||
reg = <0xd4019000 0x800>;
|
||||
clocks =<&ccu 9>, <&ccu 61>;
|
||||
clocks = <&ccu 9>, <&ccu 61>;
|
||||
clock-names = "core", "bus";
|
||||
gpio-controller;
|
||||
#gpio-cells = <3>;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/trivial-gpio.yaml#
|
||||
$id: http://devicetree.org/schemas/gpio/trivial-gpio.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Trivial 2-cell GPIO controllers
|
||||
|
||||
@@ -0,0 +1,191 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/mfd/maxim,max7360.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Maxim MAX7360 Keypad, Rotary encoder, PWM and GPIO controller
|
||||
|
||||
maintainers:
|
||||
- Kamel Bouhara <kamel.bouhara@bootlin.com>
|
||||
- Mathieu Dubois-Briand <mathieu.dubois-briand@bootlin.com>
|
||||
|
||||
description: |
|
||||
Maxim MAX7360 device, with following functions:
|
||||
- keypad controller
|
||||
- rotary controller
|
||||
- GPIO and GPO controller
|
||||
- PWM controller
|
||||
|
||||
https://www.analog.com/en/products/max7360.html
|
||||
|
||||
allOf:
|
||||
- $ref: /schemas/input/matrix-keymap.yaml#
|
||||
- $ref: /schemas/input/input.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- maxim,max7360
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
interrupts:
|
||||
maxItems: 2
|
||||
|
||||
interrupt-names:
|
||||
items:
|
||||
- const: inti
|
||||
- const: intk
|
||||
|
||||
keypad-debounce-delay-ms:
|
||||
description: Keypad debounce delay in ms
|
||||
minimum: 9
|
||||
maximum: 40
|
||||
default: 9
|
||||
|
||||
rotary-debounce-delay-ms:
|
||||
description: Rotary encoder debounce delay in ms
|
||||
minimum: 0
|
||||
maximum: 15
|
||||
default: 0
|
||||
|
||||
linux,axis:
|
||||
$ref: /schemas/input/rotary-encoder.yaml#/properties/linux,axis
|
||||
|
||||
rotary-encoder,relative-axis:
|
||||
$ref: /schemas/types.yaml#/definitions/flag
|
||||
description:
|
||||
Register a relative axis rather than an absolute one.
|
||||
|
||||
rotary-encoder,steps:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
default: 24
|
||||
description:
|
||||
Number of steps in a full turnaround of the
|
||||
encoder. Only relevant for absolute axis. Defaults to 24 which is a
|
||||
typical value for such devices.
|
||||
|
||||
rotary-encoder,rollover:
|
||||
$ref: /schemas/types.yaml#/definitions/flag
|
||||
description:
|
||||
Automatic rollover when the rotary value becomes
|
||||
greater than the specified steps or smaller than 0. For absolute axis only.
|
||||
|
||||
"#pwm-cells":
|
||||
const: 3
|
||||
|
||||
gpio:
|
||||
$ref: /schemas/gpio/maxim,max7360-gpio.yaml#
|
||||
description:
|
||||
PORT0 to PORT7 general purpose input/output pins configuration.
|
||||
|
||||
gpo:
|
||||
$ref: /schemas/gpio/maxim,max7360-gpio.yaml#
|
||||
description: >
|
||||
COL2 to COL7 general purpose output pins configuration. Allows to use
|
||||
unused keypad columns as outputs.
|
||||
|
||||
The MAX7360 has 8 column lines and 6 of them can be used as GPOs. GPIOs
|
||||
numbers used for this gpio-controller node do correspond to the column
|
||||
numbers: values 0 and 1 are never valid, values from 2 to 7 might be valid
|
||||
depending on the value of the keypad,num-column property.
|
||||
|
||||
patternProperties:
|
||||
'-pins$':
|
||||
type: object
|
||||
description:
|
||||
Pinctrl node's client devices use subnodes for desired pin configuration.
|
||||
Client device subnodes use below standard properties.
|
||||
$ref: /schemas/pinctrl/pincfg-node.yaml
|
||||
|
||||
properties:
|
||||
pins:
|
||||
description:
|
||||
List of gpio pins affected by the properties specified in this
|
||||
subnode.
|
||||
items:
|
||||
pattern: '^(PORT[0-7]|ROTARY)$'
|
||||
minItems: 1
|
||||
maxItems: 8
|
||||
|
||||
function:
|
||||
description:
|
||||
Specify the alternative function to be configured for the specified
|
||||
pins.
|
||||
enum: [gpio, pwm, rotary]
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- interrupts
|
||||
- interrupt-names
|
||||
- linux,keymap
|
||||
- linux,axis
|
||||
- "#pwm-cells"
|
||||
- gpio
|
||||
- gpo
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/input/input.h>
|
||||
#include <dt-bindings/interrupt-controller/arm-gic.h>
|
||||
|
||||
i2c {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
io-expander@38 {
|
||||
compatible = "maxim,max7360";
|
||||
reg = <0x38>;
|
||||
|
||||
interrupt-parent = <&gpio1>;
|
||||
interrupts = <23 IRQ_TYPE_LEVEL_LOW>,
|
||||
<24 IRQ_TYPE_LEVEL_LOW>;
|
||||
interrupt-names = "inti", "intk";
|
||||
|
||||
keypad,num-rows = <8>;
|
||||
keypad,num-columns = <4>;
|
||||
linux,keymap = <
|
||||
MATRIX_KEY(0x00, 0x00, KEY_F5)
|
||||
MATRIX_KEY(0x01, 0x00, KEY_F4)
|
||||
MATRIX_KEY(0x02, 0x01, KEY_F6)
|
||||
>;
|
||||
keypad-debounce-delay-ms = <10>;
|
||||
autorepeat;
|
||||
|
||||
rotary-debounce-delay-ms = <2>;
|
||||
linux,axis = <0>; /* REL_X */
|
||||
rotary-encoder,relative-axis;
|
||||
|
||||
#pwm-cells = <3>;
|
||||
|
||||
max7360_gpio: gpio {
|
||||
compatible = "maxim,max7360-gpio";
|
||||
|
||||
gpio-controller;
|
||||
#gpio-cells = <2>;
|
||||
maxim,constant-current-disable = <0x06>;
|
||||
|
||||
interrupt-controller;
|
||||
#interrupt-cells = <0x2>;
|
||||
};
|
||||
|
||||
max7360_gpo: gpo {
|
||||
compatible = "maxim,max7360-gpo";
|
||||
|
||||
gpio-controller;
|
||||
#gpio-cells = <2>;
|
||||
};
|
||||
|
||||
backlight_pins: backlight-pins {
|
||||
pins = "PORT2";
|
||||
function = "pwm";
|
||||
};
|
||||
};
|
||||
};
|
||||
@@ -1,127 +0,0 @@
|
||||
* Freescale MXS Pin Controller
|
||||
|
||||
The pins controlled by mxs pin controller are organized in banks, each bank
|
||||
has 32 pins. Each pin has 4 multiplexing functions, and generally, the 4th
|
||||
function is GPIO. The configuration on the pins includes drive strength,
|
||||
voltage and pull-up.
|
||||
|
||||
Required properties:
|
||||
- compatible: "fsl,imx23-pinctrl" or "fsl,imx28-pinctrl"
|
||||
- reg: Should contain the register physical address and length for the
|
||||
pin controller.
|
||||
|
||||
Please refer to pinctrl-bindings.txt in this directory for details of the
|
||||
common pinctrl bindings used by client devices.
|
||||
|
||||
The node of mxs pin controller acts as a container for an arbitrary number of
|
||||
subnodes. Each of these subnodes represents some desired configuration for
|
||||
a group of pins, and only affects those parameters that are explicitly listed.
|
||||
In other words, a subnode that describes a drive strength parameter implies no
|
||||
information about pull-up. For this reason, even seemingly boolean values are
|
||||
actually tristates in this binding: unspecified, off, or on. Unspecified is
|
||||
represented as an absent property, and off/on are represented as integer
|
||||
values 0 and 1.
|
||||
|
||||
Those subnodes under mxs pin controller node will fall into two categories.
|
||||
One is to set up a group of pins for a function, both mux selection and pin
|
||||
configurations, and it's called group node in the binding document. The other
|
||||
one is to adjust the pin configuration for some particular pins that need a
|
||||
different configuration than what is defined in group node. The binding
|
||||
document calls this type of node config node.
|
||||
|
||||
On mxs, there is no hardware pin group. The pin group in this binding only
|
||||
means a group of pins put together for particular peripheral to work in
|
||||
particular function, like SSP0 functioning as mmc0-8bit. That said, the
|
||||
group node should include all the pins needed for one function rather than
|
||||
having these pins defined in several group nodes. It also means each of
|
||||
"pinctrl-*" phandle in client device node should only have one group node
|
||||
pointed in there, while the phandle can have multiple config node referenced
|
||||
there to adjust configurations for some pins in the group.
|
||||
|
||||
Required subnode-properties:
|
||||
- fsl,pinmux-ids: An integer array. Each integer in the array specify a pin
|
||||
with given mux function, with bank, pin and mux packed as below.
|
||||
|
||||
[15..12] : bank number
|
||||
[11..4] : pin number
|
||||
[3..0] : mux selection
|
||||
|
||||
This integer with mux selection packed is used as an entity by both group
|
||||
and config nodes to identify a pin. The mux selection in the integer takes
|
||||
effects only on group node, and will get ignored by driver with config node,
|
||||
since config node is only meant to set up pin configurations.
|
||||
|
||||
Valid values for these integers are listed below.
|
||||
|
||||
- reg: Should be the index of the group nodes for same function. This property
|
||||
is required only for group nodes, and should not be present in any config
|
||||
nodes.
|
||||
|
||||
Optional subnode-properties:
|
||||
- fsl,drive-strength: Integer.
|
||||
0: MXS_DRIVE_4mA
|
||||
1: MXS_DRIVE_8mA
|
||||
2: MXS_DRIVE_12mA
|
||||
3: MXS_DRIVE_16mA
|
||||
- fsl,voltage: Integer.
|
||||
0: MXS_VOLTAGE_LOW - 1.8 V
|
||||
1: MXS_VOLTAGE_HIGH - 3.3 V
|
||||
- fsl,pull-up: Integer.
|
||||
0: MXS_PULL_DISABLE - Disable the internal pull-up
|
||||
1: MXS_PULL_ENABLE - Enable the internal pull-up
|
||||
|
||||
Note that when enabling the pull-up, the internal pad keeper gets disabled.
|
||||
Also, some pins doesn't have a pull up, in that case, setting the fsl,pull-up
|
||||
will only disable the internal pad keeper.
|
||||
|
||||
Examples:
|
||||
|
||||
pinctrl@80018000 {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
compatible = "fsl,imx28-pinctrl";
|
||||
reg = <0x80018000 2000>;
|
||||
|
||||
mmc0_8bit_pins_a: mmc0-8bit@0 {
|
||||
reg = <0>;
|
||||
fsl,pinmux-ids = <
|
||||
MX28_PAD_SSP0_DATA0__SSP0_D0
|
||||
MX28_PAD_SSP0_DATA1__SSP0_D1
|
||||
MX28_PAD_SSP0_DATA2__SSP0_D2
|
||||
MX28_PAD_SSP0_DATA3__SSP0_D3
|
||||
MX28_PAD_SSP0_DATA4__SSP0_D4
|
||||
MX28_PAD_SSP0_DATA5__SSP0_D5
|
||||
MX28_PAD_SSP0_DATA6__SSP0_D6
|
||||
MX28_PAD_SSP0_DATA7__SSP0_D7
|
||||
MX28_PAD_SSP0_CMD__SSP0_CMD
|
||||
MX28_PAD_SSP0_DETECT__SSP0_CARD_DETECT
|
||||
MX28_PAD_SSP0_SCK__SSP0_SCK
|
||||
>;
|
||||
fsl,drive-strength = <MXS_DRIVE_4mA>;
|
||||
fsl,voltage = <MXS_VOLTAGE_HIGH>;
|
||||
fsl,pull-up = <MXS_PULL_ENABLE>;
|
||||
};
|
||||
|
||||
mmc_cd_cfg: mmc-cd-cfg {
|
||||
fsl,pinmux-ids = <MX28_PAD_SSP0_DETECT__SSP0_CARD_DETECT>;
|
||||
fsl,pull-up = <MXS_PULL_DISABLE>;
|
||||
};
|
||||
|
||||
mmc_sck_cfg: mmc-sck-cfg {
|
||||
fsl,pinmux-ids = <MX28_PAD_SSP0_SCK__SSP0_SCK>;
|
||||
fsl,drive-strength = <MXS_DRIVE_12mA>;
|
||||
fsl,pull-up = <MXS_PULL_DISABLE>;
|
||||
};
|
||||
};
|
||||
|
||||
In this example, group node mmc0-8bit defines a group of pins for mxs SSP0
|
||||
to function as a 8-bit mmc device, with 8mA, 3.3V and pull-up configurations
|
||||
applied on all these pins. And config nodes mmc-cd-cfg and mmc-sck-cfg are
|
||||
adjusting the configuration for pins card-detection and clock from what group
|
||||
node mmc0-8bit defines. Only the configuration properties to be adjusted need
|
||||
to be listed in the config nodes.
|
||||
|
||||
Valid values for i.MX28/i.MX23 pinmux-id are defined in
|
||||
arch/arm/boot/dts/imx28-pinfunc.h and arch/arm/boot/dts/imx23-pinfunc.h.
|
||||
The definitions for the padconfig properties can be found in
|
||||
arch/arm/boot/dts/mxs-pinfunc.h.
|
||||
@@ -94,6 +94,71 @@ with the help of _DSD (Device Specific Data), introduced in ACPI 5.1::
|
||||
For more information about the ACPI GPIO bindings see
|
||||
Documentation/firmware-guide/acpi/gpio-properties.rst.
|
||||
|
||||
Software Nodes
|
||||
--------------
|
||||
|
||||
Software nodes allow board-specific code to construct an in-memory,
|
||||
device-tree-like structure using struct software_node and struct
|
||||
property_entry. This structure can then be associated with a platform device,
|
||||
allowing drivers to use the standard device properties API to query
|
||||
configuration, just as they would on an ACPI or device tree system.
|
||||
|
||||
Software-node-backed GPIOs are described using the ``PROPERTY_ENTRY_GPIO()``
|
||||
macro, which ties a software node representing the GPIO controller with
|
||||
consumer device. It allows consumers to use regular gpiolib APIs, such as
|
||||
gpiod_get(), gpiod_get_optional().
|
||||
|
||||
The software node representing a GPIO controller need not be attached to the
|
||||
GPIO controller device. The only requirement is that the node must be
|
||||
registered and its name must match the GPIO controller's label.
|
||||
|
||||
For example, here is how to describe a single GPIO-connected LED. This is an
|
||||
alternative to using platform_data on legacy systems.
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
#include <linux/property.h>
|
||||
#include <linux/gpio/machine.h>
|
||||
#include <linux/gpio/property.h>
|
||||
|
||||
/*
|
||||
* 1. Define a node for the GPIO controller. Its .name must match the
|
||||
* controller's label.
|
||||
*/
|
||||
static const struct software_node gpio_controller_node = {
|
||||
.name = "gpio-foo",
|
||||
};
|
||||
|
||||
/* 2. Define the properties for the LED device. */
|
||||
static const struct property_entry led_device_props[] = {
|
||||
PROPERTY_ENTRY_STRING("label", "myboard:green:status"),
|
||||
PROPERTY_ENTRY_STRING("linux,default-trigger", "heartbeat"),
|
||||
PROPERTY_ENTRY_GPIO("gpios", &gpio_controller_node, 42, GPIO_ACTIVE_HIGH),
|
||||
{ }
|
||||
};
|
||||
|
||||
/* 3. Define the software node for the LED device. */
|
||||
static const struct software_node led_device_swnode = {
|
||||
.name = "status-led",
|
||||
.properties = led_device_props,
|
||||
};
|
||||
|
||||
/*
|
||||
* 4. Register the software nodes and the platform device.
|
||||
*/
|
||||
const struct software_node *swnodes[] = {
|
||||
&gpio_controller_node,
|
||||
&led_device_swnode,
|
||||
NULL
|
||||
};
|
||||
software_node_register_node_group(swnodes);
|
||||
|
||||
// Then register a platform_device for "leds-gpio" and associate
|
||||
// it with &led_device_swnode via .fwnode.
|
||||
|
||||
For a complete guide on converting board files to use software nodes, see
|
||||
Documentation/driver-api/gpio/legacy-boards.rst.
|
||||
|
||||
Platform Data
|
||||
-------------
|
||||
Finally, GPIOs can be bound to devices and functions using platform data. Board
|
||||
|
||||
@@ -12,6 +12,7 @@ Contents:
|
||||
driver
|
||||
consumer
|
||||
board
|
||||
legacy-boards
|
||||
drivers-on-gpio
|
||||
bt8xxgpio
|
||||
|
||||
|
||||
@@ -0,0 +1,298 @@
|
||||
Supporting Legacy Boards
|
||||
========================
|
||||
|
||||
Many drivers in the kernel, such as ``leds-gpio`` and ``gpio-keys``, are
|
||||
migrating away from using board-specific ``platform_data`` to a unified device
|
||||
properties interface. This interface allows drivers to be simpler and more
|
||||
generic, as they can query properties in a standardized way.
|
||||
|
||||
On modern systems, these properties are provided via device tree. However, some
|
||||
older platforms have not been converted to device tree and instead rely on
|
||||
board files to describe their hardware configuration. To bridge this gap and
|
||||
allow these legacy boards to work with modern, generic drivers, the kernel
|
||||
provides a mechanism called **software nodes**.
|
||||
|
||||
This document provides a guide on how to convert a legacy board file from using
|
||||
``platform_data`` and ``gpiod_lookup_table`` to the modern software node
|
||||
approach for describing GPIO-connected devices.
|
||||
|
||||
The Core Idea: Software Nodes
|
||||
-----------------------------
|
||||
|
||||
Software nodes allow board-specific code to construct an in-memory,
|
||||
device-tree-like structure using struct software_node and struct
|
||||
property_entry. This structure can then be associated with a platform device,
|
||||
allowing drivers to use the standard device properties API (e.g.,
|
||||
device_property_read_u32(), device_property_read_string()) to query
|
||||
configuration, just as they would on an ACPI or device tree system.
|
||||
|
||||
The gpiolib code has support for handling software nodes, so that if GPIO is
|
||||
described properly, as detailed in the section below, then regular gpiolib APIs,
|
||||
such as gpiod_get(), gpiod_get_optional(), and others will work.
|
||||
|
||||
Requirements for GPIO Properties
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
When using software nodes to describe GPIO connections, the following
|
||||
requirements must be met for the GPIO core to correctly resolve the reference:
|
||||
|
||||
1. **The GPIO controller's software node "name" must match the controller's
|
||||
"label".** The gpiolib core uses this name to find the corresponding
|
||||
struct gpio_chip at runtime.
|
||||
This software node has to be registered, but need not be attached to the
|
||||
device representing the GPIO controller that is providing the GPIO in
|
||||
question. It may be left as a "free floating" node.
|
||||
|
||||
2. **The GPIO property must be a reference.** The ``PROPERTY_ENTRY_GPIO()``
|
||||
macro handles this as it is an alias for ``PROPERTY_ENTRY_REF()``.
|
||||
|
||||
3. **The reference must have exactly two arguments:**
|
||||
|
||||
- The first argument is the GPIO offset within the controller.
|
||||
- The second argument is the flags for the GPIO line (e.g.,
|
||||
GPIO_ACTIVE_HIGH, GPIO_ACTIVE_LOW).
|
||||
|
||||
The ``PROPERTY_ENTRY_GPIO()`` macro is the preferred way of defining GPIO
|
||||
properties in software nodes.
|
||||
|
||||
Conversion Example
|
||||
------------------
|
||||
|
||||
Let's walk through an example of converting a board file that defines a GPIO-
|
||||
connected LED and a button.
|
||||
|
||||
Before: Using Platform Data
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
A typical legacy board file might look like this:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/leds.h>
|
||||
#include <linux/gpio_keys.h>
|
||||
#include <linux/gpio/machine.h>
|
||||
|
||||
#define MYBOARD_GPIO_CONTROLLER "gpio-foo"
|
||||
|
||||
/* LED setup */
|
||||
static const struct gpio_led myboard_leds[] = {
|
||||
{
|
||||
.name = "myboard:green:status",
|
||||
.default_trigger = "heartbeat",
|
||||
},
|
||||
};
|
||||
|
||||
static const struct gpio_led_platform_data myboard_leds_pdata = {
|
||||
.num_leds = ARRAY_SIZE(myboard_leds),
|
||||
.leds = myboard_leds,
|
||||
};
|
||||
|
||||
static struct gpiod_lookup_table myboard_leds_gpios = {
|
||||
.dev_id = "leds-gpio",
|
||||
.table = {
|
||||
GPIO_LOOKUP_IDX(MYBOARD_GPIO_CONTROLLER, 42, NULL, 0, GPIO_ACTIVE_HIGH),
|
||||
{ },
|
||||
},
|
||||
};
|
||||
|
||||
/* Button setup */
|
||||
static struct gpio_keys_button myboard_buttons[] = {
|
||||
{
|
||||
.code = KEY_WPS_BUTTON,
|
||||
.desc = "WPS Button",
|
||||
.active_low = 1,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct gpio_keys_platform_data myboard_buttons_pdata = {
|
||||
.buttons = myboard_buttons,
|
||||
.nbuttons = ARRAY_SIZE(myboard_buttons),
|
||||
};
|
||||
|
||||
static struct gpiod_lookup_table myboard_buttons_gpios = {
|
||||
.dev_id = "gpio-keys",
|
||||
.table = {
|
||||
GPIO_LOOKUP_IDX(MYBOARD_GPIO_CONTROLLER, 15, NULL, 0, GPIO_ACTIVE_LOW),
|
||||
{ },
|
||||
},
|
||||
};
|
||||
|
||||
/* Device registration */
|
||||
static int __init myboard_init(void)
|
||||
{
|
||||
gpiod_add_lookup_table(&myboard_leds_gpios);
|
||||
gpiod_add_lookup_table(&myboard_buttons_gpios);
|
||||
|
||||
platform_device_register_data(NULL, "leds-gpio", -1,
|
||||
&myboard_leds_pdata, sizeof(myboard_leds_pdata));
|
||||
platform_device_register_data(NULL, "gpio-keys", -1,
|
||||
&myboard_buttons_pdata, sizeof(myboard_buttons_pdata));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
After: Using Software Nodes
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Here is how the same configuration can be expressed using software nodes.
|
||||
|
||||
Step 1: Define the GPIO Controller Node
|
||||
***************************************
|
||||
|
||||
First, define a software node that represents the GPIO controller that the
|
||||
LEDs and buttons are connected to. The ``name`` of this node must match the
|
||||
name of the driver for the GPIO controller (e.g., "gpio-foo").
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
#include <linux/property.h>
|
||||
#include <linux/gpio/property.h>
|
||||
|
||||
#define MYBOARD_GPIO_CONTROLLER "gpio-foo"
|
||||
|
||||
static const struct software_node myboard_gpio_controller_node = {
|
||||
.name = MYBOARD_GPIO_CONTROLLER,
|
||||
};
|
||||
|
||||
Step 2: Define Consumer Device Nodes and Properties
|
||||
***************************************************
|
||||
|
||||
Next, define the software nodes for the consumer devices (the LEDs and buttons).
|
||||
This involves creating a parent node for each device type and child nodes for
|
||||
each individual LED or button.
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
/* LED setup */
|
||||
static const struct software_node myboard_leds_node = {
|
||||
.name = "myboard-leds",
|
||||
};
|
||||
|
||||
static const struct property_entry myboard_status_led_props[] = {
|
||||
PROPERTY_ENTRY_STRING("label", "myboard:green:status"),
|
||||
PROPERTY_ENTRY_STRING("linux,default-trigger", "heartbeat"),
|
||||
PROPERTY_ENTRY_GPIO("gpios", &myboard_gpio_controller_node, 42, GPIO_ACTIVE_HIGH),
|
||||
{ }
|
||||
};
|
||||
|
||||
static const struct software_node myboard_status_led_swnode = {
|
||||
.name = "status-led",
|
||||
.parent = &myboard_leds_node,
|
||||
.properties = myboard_status_led_props,
|
||||
};
|
||||
|
||||
/* Button setup */
|
||||
static const struct software_node myboard_keys_node = {
|
||||
.name = "myboard-keys",
|
||||
};
|
||||
|
||||
static const struct property_entry myboard_wps_button_props[] = {
|
||||
PROPERTY_ENTRY_STRING("label", "WPS Button"),
|
||||
PROPERTY_ENTRY_U32("linux,code", KEY_WPS_BUTTON),
|
||||
PROPERTY_ENTRY_GPIO("gpios", &myboard_gpio_controller_node, 15, GPIO_ACTIVE_LOW),
|
||||
{ }
|
||||
};
|
||||
|
||||
static const struct software_node myboard_wps_button_swnode = {
|
||||
.name = "wps-button",
|
||||
.parent = &myboard_keys_node,
|
||||
.properties = myboard_wps_button_props,
|
||||
};
|
||||
|
||||
|
||||
|
||||
Step 3: Group and Register the Nodes
|
||||
************************************
|
||||
|
||||
For maintainability, it is often beneficial to group all software nodes into a
|
||||
single array and register them with one call.
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
static const struct software_node * const myboard_swnodes[] = {
|
||||
&myboard_gpio_controller_node,
|
||||
&myboard_leds_node,
|
||||
&myboard_status_led_swnode,
|
||||
&myboard_keys_node,
|
||||
&myboard_wps_button_swnode,
|
||||
NULL
|
||||
};
|
||||
|
||||
static int __init myboard_init(void)
|
||||
{
|
||||
int error;
|
||||
|
||||
error = software_node_register_node_group(myboard_swnodes);
|
||||
if (error) {
|
||||
pr_err("Failed to register software nodes: %d\n", error);
|
||||
return error;
|
||||
}
|
||||
|
||||
// ... platform device registration follows
|
||||
}
|
||||
|
||||
.. note::
|
||||
When splitting registration of nodes by devices that they represent, it is
|
||||
essential that the software node representing the GPIO controller itself
|
||||
is registered first, before any of the nodes that reference it.
|
||||
|
||||
Step 4: Register Platform Devices with Software Nodes
|
||||
*****************************************************
|
||||
|
||||
Finally, register the platform devices and associate them with their respective
|
||||
software nodes using the ``fwnode`` field in struct platform_device_info.
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
static struct platform_device *leds_pdev;
|
||||
static struct platform_device *keys_pdev;
|
||||
|
||||
static int __init myboard_init(void)
|
||||
{
|
||||
struct platform_device_info pdev_info;
|
||||
int error;
|
||||
|
||||
error = software_node_register_node_group(myboard_swnodes);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
memset(&pdev_info, 0, sizeof(pdev_info));
|
||||
pdev_info.name = "leds-gpio";
|
||||
pdev_info.id = PLATFORM_DEVID_NONE;
|
||||
pdev_info.fwnode = software_node_fwnode(&myboard_leds_node);
|
||||
leds_pdev = platform_device_register_full(&pdev_info);
|
||||
if (IS_ERR(leds_pdev)) {
|
||||
error = PTR_ERR(leds_pdev);
|
||||
goto err_unregister_nodes;
|
||||
}
|
||||
|
||||
memset(&pdev_info, 0, sizeof(pdev_info));
|
||||
pdev_info.name = "gpio-keys";
|
||||
pdev_info.id = PLATFORM_DEVID_NONE;
|
||||
pdev_info.fwnode = software_node_fwnode(&myboard_keys_node);
|
||||
keys_pdev = platform_device_register_full(&pdev_info);
|
||||
if (IS_ERR(keys_pdev)) {
|
||||
error = PTR_ERR(keys_pdev);
|
||||
platform_device_unregister(leds_pdev);
|
||||
goto err_unregister_nodes;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_unregister_nodes:
|
||||
software_node_unregister_node_group(myboard_swnodes);
|
||||
return error;
|
||||
}
|
||||
|
||||
static void __exit myboard_exit(void)
|
||||
{
|
||||
platform_device_unregister(keys_pdev);
|
||||
platform_device_unregister(leds_pdev);
|
||||
software_node_unregister_node_group(myboard_swnodes);
|
||||
}
|
||||
|
||||
With these changes, the generic ``leds-gpio`` and ``gpio-keys`` drivers will
|
||||
be able to probe successfully and get their configuration from the properties
|
||||
defined in the software nodes, removing the need for board-specific platform
|
||||
data.
|
||||
+25
@@ -15065,6 +15065,19 @@ L: linux-iio@vger.kernel.org
|
||||
S: Maintained
|
||||
F: drivers/iio/temperature/max30208.c
|
||||
|
||||
MAXIM MAX7360 KEYPAD LED MFD DRIVER
|
||||
M: Mathieu Dubois-Briand <mathieu.dubois-briand@bootlin.com>
|
||||
S: Maintained
|
||||
F: Documentation/devicetree/bindings/gpio/maxim,max7360-gpio.yaml
|
||||
F: Documentation/devicetree/bindings/mfd/maxim,max7360.yaml
|
||||
F: drivers/gpio/gpio-max7360.c
|
||||
F: drivers/input/keyboard/max7360-keypad.c
|
||||
F: drivers/input/misc/max7360-rotary.c
|
||||
F: drivers/mfd/max7360.c
|
||||
F: drivers/pinctrl/pinctrl-max7360.c
|
||||
F: drivers/pwm/pwm-max7360.c
|
||||
F: include/linux/mfd/max7360.h
|
||||
|
||||
MAXIM MAX77650 PMIC MFD DRIVER
|
||||
M: Bartosz Golaszewski <brgl@bgdev.pl>
|
||||
L: linux-kernel@vger.kernel.org
|
||||
@@ -18162,6 +18175,18 @@ F: drivers/nubus/
|
||||
F: include/linux/nubus.h
|
||||
F: include/uapi/linux/nubus.h
|
||||
|
||||
NUVOTON NCT6694 MFD DRIVER
|
||||
M: Ming Yu <tmyu0@nuvoton.com>
|
||||
S: Supported
|
||||
F: drivers/gpio/gpio-nct6694.c
|
||||
F: drivers/hwmon/nct6694-hwmon.c
|
||||
F: drivers/i2c/busses/i2c-nct6694.c
|
||||
F: drivers/mfd/nct6694.c
|
||||
F: drivers/net/can/usb/nct6694_canfd.c
|
||||
F: drivers/rtc/rtc-nct6694.c
|
||||
F: drivers/watchdog/nct6694_wdt.c
|
||||
F: include/linux/mfd/nct6694.h
|
||||
|
||||
NUVOTON NCT7201 IIO DRIVER
|
||||
M: Eason Yang <j2anfernee@gmail.com>
|
||||
L: linux-iio@vger.kernel.org
|
||||
|
||||
+39
-10
@@ -303,7 +303,7 @@ config GPIO_EN7523
|
||||
|
||||
config GPIO_EP93XX
|
||||
def_bool y
|
||||
depends on ARCH_EP93XX
|
||||
depends on ARCH_EP93XX || COMPILE_TEST
|
||||
select GPIO_GENERIC
|
||||
select GPIOLIB_IRQCHIP
|
||||
|
||||
@@ -408,8 +408,7 @@ config GPIO_IMX_SCU
|
||||
|
||||
config GPIO_IXP4XX
|
||||
bool "Intel IXP4xx GPIO"
|
||||
depends on ARCH_IXP4XX
|
||||
depends on OF
|
||||
depends on (ARCH_IXP4XX && OF) || COMPILE_TEST
|
||||
select GPIO_GENERIC
|
||||
select GPIOLIB_IRQCHIP
|
||||
select IRQ_DOMAIN_HIERARCHY
|
||||
@@ -437,6 +436,7 @@ config GPIO_LOONGSON_64BIT
|
||||
depends on LOONGARCH || COMPILE_TEST
|
||||
depends on OF_GPIO
|
||||
select GPIO_GENERIC
|
||||
select GPIOLIB_IRQCHIP
|
||||
help
|
||||
Say yes here to support the GPIO functionality of a number of
|
||||
Loongson series of chips. The Loongson GPIO controller supports
|
||||
@@ -734,7 +734,8 @@ config GPIO_TANGIER
|
||||
If built as a module its name will be gpio-tangier.
|
||||
|
||||
config GPIO_TB10X
|
||||
bool
|
||||
bool "Abilis Systems TB10x GPIO controller"
|
||||
depends on ARC_PLAT_TB10X || COMPILE_TEST
|
||||
select GPIO_GENERIC
|
||||
select GENERIC_IRQ_CHIP
|
||||
select OF_GPIO
|
||||
@@ -883,7 +884,7 @@ config GPIO_ZYNQMP_MODEPIN
|
||||
|
||||
config GPIO_LOONGSON1
|
||||
tristate "Loongson1 GPIO support"
|
||||
depends on MACH_LOONGSON32
|
||||
depends on MACH_LOONGSON32 || COMPILE_TEST
|
||||
select GPIO_GENERIC
|
||||
help
|
||||
Say Y or M here to support GPIO on Loongson1 SoCs.
|
||||
@@ -1193,14 +1194,18 @@ config GPIO_PCA953X
|
||||
4 bits: pca9536, pca9537
|
||||
|
||||
8 bits: max7310, max7315, pca6107, pca9534, pca9538, pca9554,
|
||||
pca9556, pca9557, pca9574, tca6408, tca9554, xra1202
|
||||
pca9556, pca9557, pca9574, tca6408, tca9554, xra1202,
|
||||
pcal6408, pcal9554b, tca9538
|
||||
|
||||
16 bits: max7312, max7313, pca9535, pca9539, pca9555, pca9575,
|
||||
tca6416
|
||||
tca6416, pca6416, pcal6416, pcal9535, pcal9555a, max7318,
|
||||
tca9539
|
||||
|
||||
24 bits: tca6424
|
||||
18 bits: tca6418
|
||||
|
||||
40 bits: pca9505, pca9698
|
||||
24 bits: tca6424, pcal6524
|
||||
|
||||
40 bits: pca9505, pca9698, pca9506
|
||||
|
||||
config GPIO_PCA953X_IRQ
|
||||
bool "Interrupt controller support for PCA953x"
|
||||
@@ -1491,6 +1496,18 @@ config GPIO_MADERA
|
||||
help
|
||||
Support for GPIOs on Cirrus Logic Madera class codecs.
|
||||
|
||||
config GPIO_MAX7360
|
||||
tristate "MAX7360 GPIO support"
|
||||
depends on MFD_MAX7360
|
||||
select GPIO_REGMAP
|
||||
select REGMAP_IRQ
|
||||
help
|
||||
Allows to use MAX7360 I/O Expander PWM lines as GPIO and keypad COL
|
||||
lines as GPO.
|
||||
|
||||
This driver can also be built as a module. If so, the module will be
|
||||
called gpio-max7360.
|
||||
|
||||
config GPIO_MAX77620
|
||||
tristate "GPIO support for PMIC MAX77620 and MAX20024"
|
||||
depends on MFD_MAX77620
|
||||
@@ -1521,6 +1538,18 @@ config GPIO_MAX77759
|
||||
This driver can also be built as a module. If so, the module will be
|
||||
called gpio-max77759.
|
||||
|
||||
config GPIO_NCT6694
|
||||
tristate "Nuvoton NCT6694 GPIO controller support"
|
||||
depends on MFD_NCT6694
|
||||
select GENERIC_IRQ_CHIP
|
||||
select GPIOLIB_IRQCHIP
|
||||
help
|
||||
This driver supports 8 GPIO pins per bank that can all be interrupt
|
||||
sources.
|
||||
|
||||
This driver can also be built as a module. If so, the module will be
|
||||
called gpio-nct6694.
|
||||
|
||||
config GPIO_PALMAS
|
||||
tristate "TI PALMAS series PMICs GPIO"
|
||||
depends on MFD_PALMAS
|
||||
@@ -1558,7 +1587,7 @@ config GPIO_SL28CPLD
|
||||
called gpio-sl28cpld.
|
||||
|
||||
config GPIO_STMPE
|
||||
bool "STMPE GPIOs"
|
||||
tristate "STMPE GPIOs"
|
||||
depends on MFD_STMPE
|
||||
depends on OF_GPIO
|
||||
select GPIOLIB_IRQCHIP
|
||||
|
||||
@@ -106,6 +106,7 @@ obj-$(CONFIG_GPIO_MAX7300) += gpio-max7300.o
|
||||
obj-$(CONFIG_GPIO_MAX7301) += gpio-max7301.o
|
||||
obj-$(CONFIG_GPIO_MAX730X) += gpio-max730x.o
|
||||
obj-$(CONFIG_GPIO_MAX732X) += gpio-max732x.o
|
||||
obj-$(CONFIG_GPIO_MAX7360) += gpio-max7360.o
|
||||
obj-$(CONFIG_GPIO_MAX77620) += gpio-max77620.o
|
||||
obj-$(CONFIG_GPIO_MAX77650) += gpio-max77650.o
|
||||
obj-$(CONFIG_GPIO_MAX77759) += gpio-max77759.o
|
||||
@@ -128,6 +129,7 @@ obj-$(CONFIG_GPIO_MT7621) += gpio-mt7621.o
|
||||
obj-$(CONFIG_GPIO_MVEBU) += gpio-mvebu.o
|
||||
obj-$(CONFIG_GPIO_MXC) += gpio-mxc.o
|
||||
obj-$(CONFIG_GPIO_MXS) += gpio-mxs.o
|
||||
obj-$(CONFIG_GPIO_NCT6694) += gpio-nct6694.o
|
||||
obj-$(CONFIG_GPIO_NOMADIK) += gpio-nomadik.o
|
||||
obj-$(CONFIG_GPIO_NPCM_SGPIO) += gpio-npcm-sgpio.o
|
||||
obj-$(CONFIG_GPIO_OCTEON) += gpio-octeon.o
|
||||
|
||||
@@ -131,11 +131,6 @@ Work items:
|
||||
helpers (x86 inb()/outb()) and convert port-mapped I/O drivers to use
|
||||
this with dry-coding and sending to maintainers to test
|
||||
|
||||
- Move the MMIO GPIO specific fields out of struct gpio_chip into a
|
||||
dedicated structure. Currently every GPIO chip has them if gpio-mmio is
|
||||
enabled in Kconfig even if it itself doesn't register with the helper
|
||||
library.
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
Generic regmap GPIO
|
||||
@@ -176,18 +171,6 @@ cannot be converted yet, but watch this space!
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
Convert all GPIO chips to using the new, value returning line setters
|
||||
|
||||
struct gpio_chip's set() and set_multiple() callbacks are now deprecated. They
|
||||
return void and thus do not allow drivers to indicate failure to set the line
|
||||
value back to the caller.
|
||||
|
||||
We've now added new variants - set_rv() and set_multiple_rv() that return an
|
||||
integer. Let's convert all GPIO drivers treewide to use the new callbacks,
|
||||
remove the old ones and finally rename the new ones back to the old names.
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
Remove legacy sysfs features
|
||||
|
||||
We have two parallel per-chip class devices and per-exported-line attribute
|
||||
|
||||
+353
-57
@@ -12,6 +12,7 @@
|
||||
#include <linux/configfs.h>
|
||||
#include <linux/ctype.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/idr.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/list.h>
|
||||
@@ -28,6 +29,7 @@
|
||||
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/gpio/driver.h>
|
||||
#include <linux/gpio/forwarder.h>
|
||||
#include <linux/gpio/machine.h>
|
||||
|
||||
#include "dev-sync-probe.h"
|
||||
@@ -244,18 +246,34 @@ struct gpiochip_fwd {
|
||||
spinlock_t slock; /* protects tmp[] if !can_sleep */
|
||||
};
|
||||
struct gpiochip_fwd_timing *delay_timings;
|
||||
void *data;
|
||||
unsigned long *valid_mask;
|
||||
unsigned long tmp[]; /* values and descs for multiple ops */
|
||||
};
|
||||
|
||||
#define fwd_tmp_values(fwd) &(fwd)->tmp[0]
|
||||
#define fwd_tmp_descs(fwd) (void *)&(fwd)->tmp[BITS_TO_LONGS((fwd)->chip.ngpio)]
|
||||
#define fwd_tmp_values(fwd) (&(fwd)->tmp[0])
|
||||
#define fwd_tmp_descs(fwd) ((void *)&(fwd)->tmp[BITS_TO_LONGS((fwd)->chip.ngpio)])
|
||||
|
||||
#define fwd_tmp_size(ngpios) (BITS_TO_LONGS((ngpios)) + (ngpios))
|
||||
|
||||
static int gpio_fwd_request(struct gpio_chip *chip, unsigned int offset)
|
||||
{
|
||||
struct gpiochip_fwd *fwd = gpiochip_get_data(chip);
|
||||
|
||||
return test_bit(offset, fwd->valid_mask) ? 0 : -ENODEV;
|
||||
}
|
||||
|
||||
static int gpio_fwd_get_direction(struct gpio_chip *chip, unsigned int offset)
|
||||
{
|
||||
struct gpiochip_fwd *fwd = gpiochip_get_data(chip);
|
||||
|
||||
/*
|
||||
* get_direction() is called during gpiochip registration, return
|
||||
* -ENODEV if there is no GPIO desc for the line.
|
||||
*/
|
||||
if (!test_bit(offset, fwd->valid_mask))
|
||||
return -ENODEV;
|
||||
|
||||
return gpiod_get_direction(fwd->descs[offset]);
|
||||
}
|
||||
|
||||
@@ -453,10 +471,11 @@ static int gpiochip_fwd_delay_of_xlate(struct gpio_chip *chip,
|
||||
return line;
|
||||
}
|
||||
|
||||
static int gpiochip_fwd_setup_delay_line(struct device *dev, struct gpio_chip *chip,
|
||||
struct gpiochip_fwd *fwd)
|
||||
static int gpiochip_fwd_setup_delay_line(struct gpiochip_fwd *fwd)
|
||||
{
|
||||
fwd->delay_timings = devm_kcalloc(dev, chip->ngpio,
|
||||
struct gpio_chip *chip = &fwd->chip;
|
||||
|
||||
fwd->delay_timings = devm_kcalloc(chip->parent, chip->ngpio,
|
||||
sizeof(*fwd->delay_timings),
|
||||
GFP_KERNEL);
|
||||
if (!fwd->delay_timings)
|
||||
@@ -468,20 +487,333 @@ static int gpiochip_fwd_setup_delay_line(struct device *dev, struct gpio_chip *c
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
static int gpiochip_fwd_setup_delay_line(struct device *dev, struct gpio_chip *chip,
|
||||
struct gpiochip_fwd *fwd)
|
||||
static int gpiochip_fwd_setup_delay_line(struct gpiochip_fwd *fwd)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif /* !CONFIG_OF_GPIO */
|
||||
|
||||
/**
|
||||
* gpiochip_fwd_get_gpiochip - Get the GPIO chip for the GPIO forwarder
|
||||
* @fwd: GPIO forwarder
|
||||
*
|
||||
* Returns: The GPIO chip for the GPIO forwarder
|
||||
*/
|
||||
struct gpio_chip *gpiochip_fwd_get_gpiochip(struct gpiochip_fwd *fwd)
|
||||
{
|
||||
return &fwd->chip;
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(gpiochip_fwd_get_gpiochip, "GPIO_FORWARDER");
|
||||
|
||||
/**
|
||||
* gpiochip_fwd_get_data - Get driver-private data for the GPIO forwarder
|
||||
* @fwd: GPIO forwarder
|
||||
*
|
||||
* Returns: The driver-private data for the GPIO forwarder
|
||||
*/
|
||||
void *gpiochip_fwd_get_data(struct gpiochip_fwd *fwd)
|
||||
{
|
||||
return fwd->data;
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(gpiochip_fwd_get_data, "GPIO_FORWARDER");
|
||||
|
||||
/**
|
||||
* gpiochip_fwd_gpio_request - Request a line of the GPIO forwarder
|
||||
* @fwd: GPIO forwarder
|
||||
* @offset: the offset of the line to request
|
||||
*
|
||||
* Returns: 0 on success, or negative errno on failure.
|
||||
*/
|
||||
int gpiochip_fwd_gpio_request(struct gpiochip_fwd *fwd, unsigned int offset)
|
||||
{
|
||||
struct gpio_chip *gc = gpiochip_fwd_get_gpiochip(fwd);
|
||||
|
||||
return gpio_fwd_request(gc, offset);
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(gpiochip_fwd_gpio_request, "GPIO_FORWARDER");
|
||||
|
||||
/**
|
||||
* gpiochip_fwd_gpio_get_direction - Return the current direction of a GPIO forwarder line
|
||||
* @fwd: GPIO forwarder
|
||||
* @offset: the offset of the line
|
||||
*
|
||||
* Returns: 0 for output, 1 for input, or an error code in case of error.
|
||||
*/
|
||||
int gpiochip_fwd_gpio_get_direction(struct gpiochip_fwd *fwd, unsigned int offset)
|
||||
{
|
||||
struct gpio_chip *gc = gpiochip_fwd_get_gpiochip(fwd);
|
||||
|
||||
return gpio_fwd_get_direction(gc, offset);
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(gpiochip_fwd_gpio_get_direction, "GPIO_FORWARDER");
|
||||
|
||||
/**
|
||||
* gpiochip_fwd_gpio_direction_output - Set a GPIO forwarder line direction to
|
||||
* output
|
||||
* @fwd: GPIO forwarder
|
||||
* @offset: the offset of the line
|
||||
* @value: value to set
|
||||
*
|
||||
* Returns: 0 on success, or negative errno on failure.
|
||||
*/
|
||||
int gpiochip_fwd_gpio_direction_output(struct gpiochip_fwd *fwd, unsigned int offset,
|
||||
int value)
|
||||
{
|
||||
struct gpio_chip *gc = gpiochip_fwd_get_gpiochip(fwd);
|
||||
|
||||
return gpio_fwd_direction_output(gc, offset, value);
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(gpiochip_fwd_gpio_direction_output, "GPIO_FORWARDER");
|
||||
|
||||
/**
|
||||
* gpiochip_fwd_gpio_direction_input - Set a GPIO forwarder line direction to input
|
||||
* @fwd: GPIO forwarder
|
||||
* @offset: the offset of the line
|
||||
*
|
||||
* Returns: 0 on success, or negative errno on failure.
|
||||
*/
|
||||
int gpiochip_fwd_gpio_direction_input(struct gpiochip_fwd *fwd, unsigned int offset)
|
||||
{
|
||||
struct gpio_chip *gc = gpiochip_fwd_get_gpiochip(fwd);
|
||||
|
||||
return gpio_fwd_direction_input(gc, offset);
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(gpiochip_fwd_gpio_direction_input, "GPIO_FORWARDER");
|
||||
|
||||
/**
|
||||
* gpiochip_fwd_gpio_get - Return a GPIO forwarder line's value
|
||||
* @fwd: GPIO forwarder
|
||||
* @offset: the offset of the line
|
||||
*
|
||||
* Returns: The GPIO's logical value, i.e. taking the ACTIVE_LOW status into
|
||||
* account, or negative errno on failure.
|
||||
*/
|
||||
int gpiochip_fwd_gpio_get(struct gpiochip_fwd *fwd, unsigned int offset)
|
||||
{
|
||||
struct gpio_chip *gc = gpiochip_fwd_get_gpiochip(fwd);
|
||||
|
||||
return gpio_fwd_get(gc, offset);
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(gpiochip_fwd_gpio_get, "GPIO_FORWARDER");
|
||||
|
||||
/**
|
||||
* gpiochip_fwd_gpio_get_multiple - Get values for multiple GPIO forwarder lines
|
||||
* @fwd: GPIO forwarder
|
||||
* @mask: bit mask array; one bit per line; BITS_PER_LONG bits per word defines
|
||||
* which lines are to be read
|
||||
* @bits: bit value array; one bit per line; BITS_PER_LONG bits per word will
|
||||
* contains the read values for the lines specified by mask
|
||||
*
|
||||
* Returns: 0 on success, or negative errno on failure.
|
||||
*/
|
||||
int gpiochip_fwd_gpio_get_multiple(struct gpiochip_fwd *fwd, unsigned long *mask,
|
||||
unsigned long *bits)
|
||||
{
|
||||
struct gpio_chip *gc = gpiochip_fwd_get_gpiochip(fwd);
|
||||
|
||||
return gpio_fwd_get_multiple_locked(gc, mask, bits);
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(gpiochip_fwd_gpio_get_multiple, "GPIO_FORWARDER");
|
||||
|
||||
/**
|
||||
* gpiochip_fwd_gpio_set - Assign value to a GPIO forwarder line.
|
||||
* @fwd: GPIO forwarder
|
||||
* @offset: the offset of the line
|
||||
* @value: value to set
|
||||
*
|
||||
* Returns: 0 on success, or negative errno on failure.
|
||||
*/
|
||||
int gpiochip_fwd_gpio_set(struct gpiochip_fwd *fwd, unsigned int offset, int value)
|
||||
{
|
||||
struct gpio_chip *gc = gpiochip_fwd_get_gpiochip(fwd);
|
||||
|
||||
return gpio_fwd_set(gc, offset, value);
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(gpiochip_fwd_gpio_set, "GPIO_FORWARDER");
|
||||
|
||||
/**
|
||||
* gpiochip_fwd_gpio_set_multiple - Assign values to multiple GPIO forwarder lines
|
||||
* @fwd: GPIO forwarder
|
||||
* @mask: bit mask array; one bit per output; BITS_PER_LONG bits per word
|
||||
* defines which outputs are to be changed
|
||||
* @bits: bit value array; one bit per output; BITS_PER_LONG bits per word
|
||||
* defines the values the outputs specified by mask are to be set to
|
||||
*
|
||||
* Returns: 0 on success, or negative errno on failure.
|
||||
*/
|
||||
int gpiochip_fwd_gpio_set_multiple(struct gpiochip_fwd *fwd, unsigned long *mask,
|
||||
unsigned long *bits)
|
||||
{
|
||||
struct gpio_chip *gc = gpiochip_fwd_get_gpiochip(fwd);
|
||||
|
||||
return gpio_fwd_set_multiple_locked(gc, mask, bits);
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(gpiochip_fwd_gpio_set_multiple, "GPIO_FORWARDER");
|
||||
|
||||
/**
|
||||
* gpiochip_fwd_gpio_set_config - Set @config for a GPIO forwarder line
|
||||
* @fwd: GPIO forwarder
|
||||
* @offset: the offset of the line
|
||||
* @config: Same packed config format as generic pinconf
|
||||
*
|
||||
* Returns: 0 on success, %-ENOTSUPP if the controller doesn't support setting
|
||||
* the configuration.
|
||||
*/
|
||||
int gpiochip_fwd_gpio_set_config(struct gpiochip_fwd *fwd, unsigned int offset,
|
||||
unsigned long config)
|
||||
{
|
||||
struct gpio_chip *gc = gpiochip_fwd_get_gpiochip(fwd);
|
||||
|
||||
return gpio_fwd_set_config(gc, offset, config);
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(gpiochip_fwd_gpio_set_config, "GPIO_FORWARDER");
|
||||
|
||||
/**
|
||||
* gpiochip_fwd_gpio_to_irq - Return the IRQ corresponding to a GPIO forwarder line
|
||||
* @fwd: GPIO forwarder
|
||||
* @offset: the offset of the line
|
||||
*
|
||||
* Returns: The Linux IRQ corresponding to the passed line, or an error code in
|
||||
* case of error.
|
||||
*/
|
||||
int gpiochip_fwd_gpio_to_irq(struct gpiochip_fwd *fwd, unsigned int offset)
|
||||
{
|
||||
struct gpio_chip *gc = gpiochip_fwd_get_gpiochip(fwd);
|
||||
|
||||
return gpio_fwd_to_irq(gc, offset);
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(gpiochip_fwd_gpio_to_irq, "GPIO_FORWARDER");
|
||||
|
||||
/**
|
||||
* devm_gpiochip_fwd_alloc - Allocate and initialize a new GPIO forwarder
|
||||
* @dev: Parent device pointer
|
||||
* @ngpios: Number of GPIOs in the forwarder
|
||||
*
|
||||
* Returns: An opaque object pointer, or an ERR_PTR()-encoded negative error
|
||||
* code on failure.
|
||||
*/
|
||||
struct gpiochip_fwd *devm_gpiochip_fwd_alloc(struct device *dev,
|
||||
unsigned int ngpios)
|
||||
{
|
||||
struct gpiochip_fwd *fwd;
|
||||
struct gpio_chip *chip;
|
||||
|
||||
fwd = devm_kzalloc(dev, struct_size(fwd, tmp, fwd_tmp_size(ngpios)), GFP_KERNEL);
|
||||
if (!fwd)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
fwd->descs = devm_kcalloc(dev, ngpios, sizeof(*fwd->descs), GFP_KERNEL);
|
||||
if (!fwd->descs)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
fwd->valid_mask = devm_bitmap_zalloc(dev, ngpios, GFP_KERNEL);
|
||||
if (!fwd->valid_mask)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
chip = &fwd->chip;
|
||||
|
||||
chip->label = dev_name(dev);
|
||||
chip->parent = dev;
|
||||
chip->owner = THIS_MODULE;
|
||||
chip->request = gpio_fwd_request;
|
||||
chip->get_direction = gpio_fwd_get_direction;
|
||||
chip->direction_input = gpio_fwd_direction_input;
|
||||
chip->direction_output = gpio_fwd_direction_output;
|
||||
chip->get = gpio_fwd_get;
|
||||
chip->get_multiple = gpio_fwd_get_multiple_locked;
|
||||
chip->set = gpio_fwd_set;
|
||||
chip->set_multiple = gpio_fwd_set_multiple_locked;
|
||||
chip->to_irq = gpio_fwd_to_irq;
|
||||
chip->base = -1;
|
||||
chip->ngpio = ngpios;
|
||||
|
||||
return fwd;
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(devm_gpiochip_fwd_alloc, "GPIO_FORWARDER");
|
||||
|
||||
/**
|
||||
* gpiochip_fwd_desc_add - Add a GPIO desc in the forwarder
|
||||
* @fwd: GPIO forwarder
|
||||
* @desc: GPIO descriptor to register
|
||||
* @offset: offset for the GPIO in the forwarder
|
||||
*
|
||||
* Returns: 0 on success, or negative errno on failure.
|
||||
*/
|
||||
int gpiochip_fwd_desc_add(struct gpiochip_fwd *fwd, struct gpio_desc *desc,
|
||||
unsigned int offset)
|
||||
{
|
||||
struct gpio_chip *chip = &fwd->chip;
|
||||
|
||||
if (offset >= chip->ngpio)
|
||||
return -EINVAL;
|
||||
|
||||
if (test_and_set_bit(offset, fwd->valid_mask))
|
||||
return -EEXIST;
|
||||
|
||||
/*
|
||||
* If any of the GPIO lines are sleeping, then the entire forwarder
|
||||
* will be sleeping.
|
||||
*/
|
||||
if (gpiod_cansleep(desc))
|
||||
chip->can_sleep = true;
|
||||
|
||||
fwd->descs[offset] = desc;
|
||||
|
||||
dev_dbg(chip->parent, "%u => gpio %d irq %d\n", offset,
|
||||
desc_to_gpio(desc), gpiod_to_irq(desc));
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(gpiochip_fwd_desc_add, "GPIO_FORWARDER");
|
||||
|
||||
/**
|
||||
* gpiochip_fwd_desc_free - Remove a GPIO desc from the forwarder
|
||||
* @fwd: GPIO forwarder
|
||||
* @offset: offset of GPIO desc to remove
|
||||
*/
|
||||
void gpiochip_fwd_desc_free(struct gpiochip_fwd *fwd, unsigned int offset)
|
||||
{
|
||||
if (test_and_clear_bit(offset, fwd->valid_mask))
|
||||
gpiod_put(fwd->descs[offset]);
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(gpiochip_fwd_desc_free, "GPIO_FORWARDER");
|
||||
|
||||
/**
|
||||
* gpiochip_fwd_register - Register a GPIO forwarder
|
||||
* @fwd: GPIO forwarder
|
||||
* @data: driver-private data associated with this forwarder
|
||||
*
|
||||
* Returns: 0 on success, or negative errno on failure.
|
||||
*/
|
||||
int gpiochip_fwd_register(struct gpiochip_fwd *fwd, void *data)
|
||||
{
|
||||
struct gpio_chip *chip = &fwd->chip;
|
||||
|
||||
/*
|
||||
* Some gpio_desc were not registered. They will be registered at runtime
|
||||
* but we have to suppose they can sleep.
|
||||
*/
|
||||
if (!bitmap_full(fwd->valid_mask, chip->ngpio))
|
||||
chip->can_sleep = true;
|
||||
|
||||
if (chip->can_sleep)
|
||||
mutex_init(&fwd->mlock);
|
||||
else
|
||||
spin_lock_init(&fwd->slock);
|
||||
|
||||
fwd->data = data;
|
||||
|
||||
return devm_gpiochip_add_data(chip->parent, chip, fwd);
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(gpiochip_fwd_register, "GPIO_FORWARDER");
|
||||
|
||||
/**
|
||||
* gpiochip_fwd_create() - Create a new GPIO forwarder
|
||||
* @dev: Parent device pointer
|
||||
* @ngpios: Number of GPIOs in the forwarder.
|
||||
* @descs: Array containing the GPIO descriptors to forward to.
|
||||
* This array must contain @ngpios entries, and must not be deallocated
|
||||
* before the forwarder has been destroyed again.
|
||||
* This array must contain @ngpios entries, and can be deallocated
|
||||
* as the forwarder has its own array.
|
||||
* @features: Bitwise ORed features as defined with FWD_FEATURE_*.
|
||||
*
|
||||
* This function creates a new gpiochip, which forwards all GPIO operations to
|
||||
@@ -495,64 +827,27 @@ static struct gpiochip_fwd *gpiochip_fwd_create(struct device *dev,
|
||||
struct gpio_desc *descs[],
|
||||
unsigned long features)
|
||||
{
|
||||
const char *label = dev_name(dev);
|
||||
struct gpiochip_fwd *fwd;
|
||||
struct gpio_chip *chip;
|
||||
unsigned int i;
|
||||
int error;
|
||||
|
||||
fwd = devm_kzalloc(dev, struct_size(fwd, tmp, fwd_tmp_size(ngpios)),
|
||||
GFP_KERNEL);
|
||||
if (!fwd)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
fwd = devm_gpiochip_fwd_alloc(dev, ngpios);
|
||||
if (IS_ERR(fwd))
|
||||
return fwd;
|
||||
|
||||
chip = &fwd->chip;
|
||||
|
||||
/*
|
||||
* If any of the GPIO lines are sleeping, then the entire forwarder
|
||||
* will be sleeping.
|
||||
* If any of the chips support .set_config(), then the forwarder will
|
||||
* support setting configs.
|
||||
*/
|
||||
for (i = 0; i < ngpios; i++) {
|
||||
struct gpio_chip *parent = gpiod_to_chip(descs[i]);
|
||||
|
||||
dev_dbg(dev, "%u => gpio %d irq %d\n", i,
|
||||
desc_to_gpio(descs[i]), gpiod_to_irq(descs[i]));
|
||||
|
||||
if (gpiod_cansleep(descs[i]))
|
||||
chip->can_sleep = true;
|
||||
if (parent && parent->set_config)
|
||||
chip->set_config = gpio_fwd_set_config;
|
||||
}
|
||||
|
||||
chip->label = label;
|
||||
chip->parent = dev;
|
||||
chip->owner = THIS_MODULE;
|
||||
chip->get_direction = gpio_fwd_get_direction;
|
||||
chip->direction_input = gpio_fwd_direction_input;
|
||||
chip->direction_output = gpio_fwd_direction_output;
|
||||
chip->get = gpio_fwd_get;
|
||||
chip->get_multiple = gpio_fwd_get_multiple_locked;
|
||||
chip->set = gpio_fwd_set;
|
||||
chip->set_multiple = gpio_fwd_set_multiple_locked;
|
||||
chip->to_irq = gpio_fwd_to_irq;
|
||||
chip->base = -1;
|
||||
chip->ngpio = ngpios;
|
||||
fwd->descs = descs;
|
||||
|
||||
if (chip->can_sleep)
|
||||
mutex_init(&fwd->mlock);
|
||||
else
|
||||
spin_lock_init(&fwd->slock);
|
||||
|
||||
if (features & FWD_FEATURE_DELAY) {
|
||||
error = gpiochip_fwd_setup_delay_line(dev, chip, fwd);
|
||||
error = gpiochip_fwd_desc_add(fwd, descs[i], i);
|
||||
if (error)
|
||||
return ERR_PTR(error);
|
||||
}
|
||||
|
||||
error = devm_gpiochip_add_data(dev, chip, fwd);
|
||||
if (features & FWD_FEATURE_DELAY) {
|
||||
error = gpiochip_fwd_setup_delay_line(fwd);
|
||||
if (error)
|
||||
return ERR_PTR(error);
|
||||
}
|
||||
|
||||
error = gpiochip_fwd_register(fwd, NULL);
|
||||
if (error)
|
||||
return ERR_PTR(error);
|
||||
|
||||
@@ -1334,6 +1629,7 @@ static int gpio_aggregator_probe(struct platform_device *pdev)
|
||||
return PTR_ERR(fwd);
|
||||
|
||||
platform_set_drvdata(pdev, fwd);
|
||||
devm_kfree(dev, descs);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
+23
-21
@@ -9,6 +9,7 @@
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/gpio/driver.h>
|
||||
#include <linux/gpio/generic.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/platform_device.h>
|
||||
@@ -24,54 +25,50 @@
|
||||
#define PT_SYNC_REG 0x28
|
||||
|
||||
struct pt_gpio_chip {
|
||||
struct gpio_chip gc;
|
||||
struct gpio_generic_chip chip;
|
||||
void __iomem *reg_base;
|
||||
};
|
||||
|
||||
static int pt_gpio_request(struct gpio_chip *gc, unsigned offset)
|
||||
{
|
||||
struct gpio_generic_chip *gen_gc = to_gpio_generic_chip(gc);
|
||||
struct pt_gpio_chip *pt_gpio = gpiochip_get_data(gc);
|
||||
unsigned long flags;
|
||||
u32 using_pins;
|
||||
|
||||
dev_dbg(gc->parent, "pt_gpio_request offset=%x\n", offset);
|
||||
|
||||
raw_spin_lock_irqsave(&gc->bgpio_lock, flags);
|
||||
guard(gpio_generic_lock_irqsave)(gen_gc);
|
||||
|
||||
using_pins = readl(pt_gpio->reg_base + PT_SYNC_REG);
|
||||
if (using_pins & BIT(offset)) {
|
||||
dev_warn(gc->parent, "PT GPIO pin %x reconfigured\n",
|
||||
offset);
|
||||
raw_spin_unlock_irqrestore(&gc->bgpio_lock, flags);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
writel(using_pins | BIT(offset), pt_gpio->reg_base + PT_SYNC_REG);
|
||||
|
||||
raw_spin_unlock_irqrestore(&gc->bgpio_lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void pt_gpio_free(struct gpio_chip *gc, unsigned offset)
|
||||
{
|
||||
struct gpio_generic_chip *gen_gc = to_gpio_generic_chip(gc);
|
||||
struct pt_gpio_chip *pt_gpio = gpiochip_get_data(gc);
|
||||
unsigned long flags;
|
||||
u32 using_pins;
|
||||
|
||||
raw_spin_lock_irqsave(&gc->bgpio_lock, flags);
|
||||
guard(gpio_generic_lock_irqsave)(gen_gc);
|
||||
|
||||
using_pins = readl(pt_gpio->reg_base + PT_SYNC_REG);
|
||||
using_pins &= ~BIT(offset);
|
||||
writel(using_pins, pt_gpio->reg_base + PT_SYNC_REG);
|
||||
|
||||
raw_spin_unlock_irqrestore(&gc->bgpio_lock, flags);
|
||||
|
||||
dev_dbg(gc->parent, "pt_gpio_free offset=%x\n", offset);
|
||||
}
|
||||
|
||||
static int pt_gpio_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct gpio_generic_chip_config config;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct pt_gpio_chip *pt_gpio;
|
||||
int ret = 0;
|
||||
@@ -91,22 +88,27 @@ static int pt_gpio_probe(struct platform_device *pdev)
|
||||
return PTR_ERR(pt_gpio->reg_base);
|
||||
}
|
||||
|
||||
ret = bgpio_init(&pt_gpio->gc, dev, 4,
|
||||
pt_gpio->reg_base + PT_INPUTDATA_REG,
|
||||
pt_gpio->reg_base + PT_OUTPUTDATA_REG, NULL,
|
||||
pt_gpio->reg_base + PT_DIRECTION_REG, NULL,
|
||||
BGPIOF_READ_OUTPUT_REG_SET);
|
||||
config = (struct gpio_generic_chip_config) {
|
||||
.dev = dev,
|
||||
.sz = 4,
|
||||
.dat = pt_gpio->reg_base + PT_INPUTDATA_REG,
|
||||
.set = pt_gpio->reg_base + PT_OUTPUTDATA_REG,
|
||||
.dirout = pt_gpio->reg_base + PT_DIRECTION_REG,
|
||||
.flags = GPIO_GENERIC_READ_OUTPUT_REG_SET,
|
||||
};
|
||||
|
||||
ret = gpio_generic_chip_init(&pt_gpio->chip, &config);
|
||||
if (ret) {
|
||||
dev_err(dev, "bgpio_init failed\n");
|
||||
dev_err(dev, "failed to initialize the generic GPIO chip\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
pt_gpio->gc.owner = THIS_MODULE;
|
||||
pt_gpio->gc.request = pt_gpio_request;
|
||||
pt_gpio->gc.free = pt_gpio_free;
|
||||
pt_gpio->gc.ngpio = (uintptr_t)device_get_match_data(dev);
|
||||
pt_gpio->chip.gc.owner = THIS_MODULE;
|
||||
pt_gpio->chip.gc.request = pt_gpio_request;
|
||||
pt_gpio->chip.gc.free = pt_gpio_free;
|
||||
pt_gpio->chip.gc.ngpio = (uintptr_t)device_get_match_data(dev);
|
||||
|
||||
ret = devm_gpiochip_add_data(dev, &pt_gpio->gc, pt_gpio);
|
||||
ret = devm_gpiochip_add_data(dev, &pt_gpio->chip.gc, pt_gpio);
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to register GPIO lib\n");
|
||||
return ret;
|
||||
|
||||
+42
-46
@@ -10,6 +10,7 @@
|
||||
|
||||
#include <linux/device.h>
|
||||
#include <linux/gpio/driver.h>
|
||||
#include <linux/gpio/generic.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
@@ -28,17 +29,17 @@
|
||||
#define AR71XX_GPIO_REG_INT_MASK 0x24
|
||||
|
||||
struct ath79_gpio_ctrl {
|
||||
struct gpio_chip gc;
|
||||
struct gpio_generic_chip chip;
|
||||
void __iomem *base;
|
||||
raw_spinlock_t lock;
|
||||
unsigned long both_edges;
|
||||
};
|
||||
|
||||
static struct ath79_gpio_ctrl *irq_data_to_ath79_gpio(struct irq_data *data)
|
||||
{
|
||||
struct gpio_chip *gc = irq_data_get_irq_chip_data(data);
|
||||
struct gpio_generic_chip *gen_gc = to_gpio_generic_chip(gc);
|
||||
|
||||
return container_of(gc, struct ath79_gpio_ctrl, gc);
|
||||
return container_of(gen_gc, struct ath79_gpio_ctrl, chip);
|
||||
}
|
||||
|
||||
static u32 ath79_gpio_read(struct ath79_gpio_ctrl *ctrl, unsigned reg)
|
||||
@@ -70,48 +71,43 @@ static void ath79_gpio_irq_unmask(struct irq_data *data)
|
||||
{
|
||||
struct ath79_gpio_ctrl *ctrl = irq_data_to_ath79_gpio(data);
|
||||
u32 mask = BIT(irqd_to_hwirq(data));
|
||||
unsigned long flags;
|
||||
|
||||
gpiochip_enable_irq(&ctrl->gc, irqd_to_hwirq(data));
|
||||
raw_spin_lock_irqsave(&ctrl->lock, flags);
|
||||
gpiochip_enable_irq(&ctrl->chip.gc, irqd_to_hwirq(data));
|
||||
|
||||
guard(gpio_generic_lock_irqsave)(&ctrl->chip);
|
||||
|
||||
ath79_gpio_update_bits(ctrl, AR71XX_GPIO_REG_INT_MASK, mask, mask);
|
||||
raw_spin_unlock_irqrestore(&ctrl->lock, flags);
|
||||
}
|
||||
|
||||
static void ath79_gpio_irq_mask(struct irq_data *data)
|
||||
{
|
||||
struct ath79_gpio_ctrl *ctrl = irq_data_to_ath79_gpio(data);
|
||||
u32 mask = BIT(irqd_to_hwirq(data));
|
||||
unsigned long flags;
|
||||
|
||||
raw_spin_lock_irqsave(&ctrl->lock, flags);
|
||||
ath79_gpio_update_bits(ctrl, AR71XX_GPIO_REG_INT_MASK, mask, 0);
|
||||
raw_spin_unlock_irqrestore(&ctrl->lock, flags);
|
||||
gpiochip_disable_irq(&ctrl->gc, irqd_to_hwirq(data));
|
||||
scoped_guard(gpio_generic_lock_irqsave, &ctrl->chip)
|
||||
ath79_gpio_update_bits(ctrl, AR71XX_GPIO_REG_INT_MASK, mask, 0);
|
||||
|
||||
gpiochip_disable_irq(&ctrl->chip.gc, irqd_to_hwirq(data));
|
||||
}
|
||||
|
||||
static void ath79_gpio_irq_enable(struct irq_data *data)
|
||||
{
|
||||
struct ath79_gpio_ctrl *ctrl = irq_data_to_ath79_gpio(data);
|
||||
u32 mask = BIT(irqd_to_hwirq(data));
|
||||
unsigned long flags;
|
||||
|
||||
raw_spin_lock_irqsave(&ctrl->lock, flags);
|
||||
guard(gpio_generic_lock_irqsave)(&ctrl->chip);
|
||||
ath79_gpio_update_bits(ctrl, AR71XX_GPIO_REG_INT_ENABLE, mask, mask);
|
||||
ath79_gpio_update_bits(ctrl, AR71XX_GPIO_REG_INT_MASK, mask, mask);
|
||||
raw_spin_unlock_irqrestore(&ctrl->lock, flags);
|
||||
}
|
||||
|
||||
static void ath79_gpio_irq_disable(struct irq_data *data)
|
||||
{
|
||||
struct ath79_gpio_ctrl *ctrl = irq_data_to_ath79_gpio(data);
|
||||
u32 mask = BIT(irqd_to_hwirq(data));
|
||||
unsigned long flags;
|
||||
|
||||
raw_spin_lock_irqsave(&ctrl->lock, flags);
|
||||
guard(gpio_generic_lock_irqsave)(&ctrl->chip);
|
||||
ath79_gpio_update_bits(ctrl, AR71XX_GPIO_REG_INT_MASK, mask, 0);
|
||||
ath79_gpio_update_bits(ctrl, AR71XX_GPIO_REG_INT_ENABLE, mask, 0);
|
||||
raw_spin_unlock_irqrestore(&ctrl->lock, flags);
|
||||
}
|
||||
|
||||
static int ath79_gpio_irq_set_type(struct irq_data *data,
|
||||
@@ -120,7 +116,6 @@ static int ath79_gpio_irq_set_type(struct irq_data *data,
|
||||
struct ath79_gpio_ctrl *ctrl = irq_data_to_ath79_gpio(data);
|
||||
u32 mask = BIT(irqd_to_hwirq(data));
|
||||
u32 type = 0, polarity = 0;
|
||||
unsigned long flags;
|
||||
bool disabled;
|
||||
|
||||
switch (flow_type) {
|
||||
@@ -142,7 +137,7 @@ static int ath79_gpio_irq_set_type(struct irq_data *data,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
raw_spin_lock_irqsave(&ctrl->lock, flags);
|
||||
guard(gpio_generic_lock_irqsave)(&ctrl->chip);
|
||||
|
||||
if (flow_type == IRQ_TYPE_EDGE_BOTH) {
|
||||
ctrl->both_edges |= mask;
|
||||
@@ -167,8 +162,6 @@ static int ath79_gpio_irq_set_type(struct irq_data *data,
|
||||
ath79_gpio_update_bits(
|
||||
ctrl, AR71XX_GPIO_REG_INT_ENABLE, mask, mask);
|
||||
|
||||
raw_spin_unlock_irqrestore(&ctrl->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -187,28 +180,27 @@ static void ath79_gpio_irq_handler(struct irq_desc *desc)
|
||||
{
|
||||
struct gpio_chip *gc = irq_desc_get_handler_data(desc);
|
||||
struct irq_chip *irqchip = irq_desc_get_chip(desc);
|
||||
struct gpio_generic_chip *gen_gc = to_gpio_generic_chip(gc);
|
||||
struct ath79_gpio_ctrl *ctrl =
|
||||
container_of(gc, struct ath79_gpio_ctrl, gc);
|
||||
unsigned long flags, pending;
|
||||
container_of(gen_gc, struct ath79_gpio_ctrl, chip);
|
||||
unsigned long pending;
|
||||
u32 both_edges, state;
|
||||
int irq;
|
||||
|
||||
chained_irq_enter(irqchip, desc);
|
||||
|
||||
raw_spin_lock_irqsave(&ctrl->lock, flags);
|
||||
scoped_guard(gpio_generic_lock_irqsave, &ctrl->chip) {
|
||||
pending = ath79_gpio_read(ctrl, AR71XX_GPIO_REG_INT_PENDING);
|
||||
|
||||
pending = ath79_gpio_read(ctrl, AR71XX_GPIO_REG_INT_PENDING);
|
||||
|
||||
/* Update the polarity of the both edges irqs */
|
||||
both_edges = ctrl->both_edges & pending;
|
||||
if (both_edges) {
|
||||
state = ath79_gpio_read(ctrl, AR71XX_GPIO_REG_IN);
|
||||
ath79_gpio_update_bits(ctrl, AR71XX_GPIO_REG_INT_POLARITY,
|
||||
both_edges, ~state);
|
||||
/* Update the polarity of the both edges irqs */
|
||||
both_edges = ctrl->both_edges & pending;
|
||||
if (both_edges) {
|
||||
state = ath79_gpio_read(ctrl, AR71XX_GPIO_REG_IN);
|
||||
ath79_gpio_update_bits(ctrl, AR71XX_GPIO_REG_INT_POLARITY,
|
||||
both_edges, ~state);
|
||||
}
|
||||
}
|
||||
|
||||
raw_spin_unlock_irqrestore(&ctrl->lock, flags);
|
||||
|
||||
for_each_set_bit(irq, &pending, gc->ngpio)
|
||||
generic_handle_domain_irq(gc->irq.domain, irq);
|
||||
|
||||
@@ -224,6 +216,7 @@ MODULE_DEVICE_TABLE(of, ath79_gpio_of_match);
|
||||
|
||||
static int ath79_gpio_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct gpio_generic_chip_config config;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct ath79_gpio_ctrl *ctrl;
|
||||
struct gpio_irq_chip *girq;
|
||||
@@ -252,22 +245,25 @@ static int ath79_gpio_probe(struct platform_device *pdev)
|
||||
if (IS_ERR(ctrl->base))
|
||||
return PTR_ERR(ctrl->base);
|
||||
|
||||
raw_spin_lock_init(&ctrl->lock);
|
||||
err = bgpio_init(&ctrl->gc, dev, 4,
|
||||
ctrl->base + AR71XX_GPIO_REG_IN,
|
||||
ctrl->base + AR71XX_GPIO_REG_SET,
|
||||
ctrl->base + AR71XX_GPIO_REG_CLEAR,
|
||||
oe_inverted ? NULL : ctrl->base + AR71XX_GPIO_REG_OE,
|
||||
oe_inverted ? ctrl->base + AR71XX_GPIO_REG_OE : NULL,
|
||||
0);
|
||||
config = (struct gpio_generic_chip_config) {
|
||||
.dev = dev,
|
||||
.sz = 4,
|
||||
.dat = ctrl->base + AR71XX_GPIO_REG_IN,
|
||||
.set = ctrl->base + AR71XX_GPIO_REG_SET,
|
||||
.clr = ctrl->base + AR71XX_GPIO_REG_CLEAR,
|
||||
.dirout = oe_inverted ? NULL : ctrl->base + AR71XX_GPIO_REG_OE,
|
||||
.dirin = oe_inverted ? ctrl->base + AR71XX_GPIO_REG_OE : NULL,
|
||||
};
|
||||
|
||||
err = gpio_generic_chip_init(&ctrl->chip, &config);
|
||||
if (err) {
|
||||
dev_err(dev, "bgpio_init failed\n");
|
||||
dev_err(dev, "failed to initialize generic GPIO chip\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Optional interrupt setup */
|
||||
if (device_property_read_bool(dev, "interrupt-controller")) {
|
||||
girq = &ctrl->gc.irq;
|
||||
girq = &ctrl->chip.gc.irq;
|
||||
gpio_irq_chip_set_chip(girq, &ath79_gpio_irqchip);
|
||||
girq->parent_handler = ath79_gpio_irq_handler;
|
||||
girq->num_parents = 1;
|
||||
@@ -280,7 +276,7 @@ static int ath79_gpio_probe(struct platform_device *pdev)
|
||||
girq->handler = handle_simple_irq;
|
||||
}
|
||||
|
||||
return devm_gpiochip_add_data(dev, &ctrl->gc, ctrl);
|
||||
return devm_gpiochip_add_data(dev, &ctrl->chip.gc, ctrl);
|
||||
}
|
||||
|
||||
static struct platform_driver ath79_gpio_driver = {
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user