mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-12-28 16:56:26 +00:00
gpio updates for v6.1-rc1
New drivers: - add a new driver for the IMX System Controller Unit GPIOs GPIO core: - add fdinfo output for the GPIO character device file descriptors (allows user-space to determine which processes own which GPIO lines) - improvements to OF GPIO code - new quirk for Asus UM325UAZ in gpiolib-acpi - new quirk for Freescale SPI in gpiolib-of Driver improvements: - add a new macro that reduces the amount of boilerplate code in ISA drivers and use it in relevant drivers - support two new models in gpio-pca953x - support new model in gpio-f7188x - convert more drivers to use immutable irq chips - other minor tweaks Device-tree bindings: - add DT bindings for gpio-imx-scu - convert Xilinx GPIO bindings to YAML - reference the properties from the SPI peripheral device-tree bindings instead of providing custom ones in the GPIO controller document - add parsing of GPIO hog nodes to the DT bindings for gpio-mpfs-gpio - relax the node name requirements in gpio-stmpe - add new models for gpio-rcar and gpio-pxa95xx - add a new vendor prefix: Diodes (for Diodes, Inc.) Misc: - pulled in the immutable branch from the x86 platform drivers tree including support for a new simatic board that depends on GPIO changes -----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEEFp3rbAvDxGAT0sefEacuoBRx13IFAmNAhB8ACgkQEacuoBRx 13KY5xAAjBvBPNxtKqwqs82M6A3rmIPGsfuBBsuWGwQw9MFrVeHx1c58uCistq1s ECnvNuPkpXB/9npXWvWipr9kV5UA5hneDzT9ploUzCsSi+Bvb8W2ZUmW1tsELo04 deJmQ5VAImcUVnDIuIwWXt+sx0Clc8fMVNGy9yiSs1JOAT1WO7N9VNy/is3cRIk2 VsVH7iN/G7MJPWx+CoBj7eVkdXs7W93yUSW6QLzVCvoYFWcf8A4xQe2SDFnaRXvH 5BERflEjbl+0iSHG14jvd7YMmMdnxCZdCkFpjVIEUpKvVT/X6+wbO7q1aCz0/Vig LgbElUT8fRCq7RxrZjrZA7mXI8rpSkTugDqweIbqlw8larA5zjSj+S+0mpEQPwZT tA+mEjHRBWiDBr//tHgnF9TU4HezVwqFaZ72bhctuIgZ5ivbF8PA+Cd7HAkUKnn8 K8dZdOde4d9WmWj7w3olIgFOwJwvPCztKr5uYgxJOG8ECr7MM5pepaMXK6stSC19 21Iwwb9dOUi3LwIWAQW2upG0S9BNHGy/hqNd5YN+lF2S9neQ3n4vrWQj7AJivtXi vldCqXdbukyrKiUlf9svXdmudYFPgf6zwPlXNWk1CtZ1uB8OR8rbDn9bEeQSwzGf op6ADdPTuoD49NO0r49cb8dmr1tFwGbGIX54JJB3FTKuGo7SxcY= =Ax6X -----END PGP SIGNATURE----- Merge tag 'gpio-updates-for-v6.1-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/brgl/linux Pull gpio updates from Bartosz Golaszewski: "We have a single new driver, support for a bunch of new models, improvements in drivers and core gpiolib code as well device-tree bindings changes. Summary: New driver: - IMX System Controller Unit GPIOs GPIO core: - add fdinfo output for the GPIO character device file descriptors (allows user-space to determine which processes own which GPIO lines) - improvements to OF GPIO code - new quirk for Asus UM325UAZ in gpiolib-acpi - new quirk for Freescale SPI in gpiolib-of Driver improvements: - add a new macro that reduces the amount of boilerplate code in ISA drivers and use it in relevant drivers - support two new models in gpio-pca953x - support new model in gpio-f7188x - convert more drivers to use immutable irq chips - other minor tweaks Device-tree bindings: - add DT bindings for gpio-imx-scu - convert Xilinx GPIO bindings to YAML - reference the properties from the SPI peripheral device-tree bindings instead of providing custom ones in the GPIO controller document - add parsing of GPIO hog nodes to the DT bindings for gpio-mpfs-gpio - relax the node name requirements in gpio-stmpe - add new models for gpio-rcar and gpio-pxa95xx - add a new vendor prefix: Diodes (for Diodes, Inc.) Misc: - pulled in the immutable branch from the x86 platform drivers tree including support for a new simatic board that depends on GPIO changes" * tag 'gpio-updates-for-v6.1-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/brgl/linux: (36 commits) gpio: tc3589x: Make irqchip immutable gpiolib: cdev: add fdinfo output for line request file descriptors gpio: twl4030: Reorder functions which allows to drop a forward declaraion gpiolib: fix OOB access in quirk callbacks gpiolib: of: factor out conversion from OF flags gpiolib: rework quirk handling in of_find_gpio() gpiolib: of: make Freescale SPI quirk similar to all others gpiolib: of: do not ignore requested index when applying quirks gpio: ws16c48: Ensure number of irq matches number of base gpio: 104-idio-16: Ensure number of irq matches number of base gpio: 104-idi-48: Ensure number of irq matches number of base gpio: 104-dio-48e: Ensure number of irq matches number of base counter: 104-quad-8: Ensure number of irq matches number of base isa: Introduce the module_isa_driver_with_irq helper macro gpio: pca953x: Add support for PCAL6534 gpio: pca953x: Swap if statements to save later complexity gpio: pca953x: Fix pca953x_gpio_set_pull_up_down() dt-bindings: gpio: pca95xx: add entry for pcal6534 and PI4IOE5V6534Q dt-bindings: vendor-prefixes: add Diodes gpio: mt7621: Switch to use platform_get_irq() function ...
This commit is contained in:
commit
f01603979a
@ -30,6 +30,11 @@ properties:
|
||||
Clock controller node that provides the clocks controlled by the SCU
|
||||
$ref: /schemas/clock/fsl,scu-clk.yaml
|
||||
|
||||
gpio:
|
||||
description:
|
||||
Control the GPIO PINs on SCU domain over the firmware APIs
|
||||
$ref: /schemas/gpio/fsl,imx8qxp-sc-gpio.yaml
|
||||
|
||||
ocotp:
|
||||
description:
|
||||
OCOTP controller node provided by the SCU
|
||||
|
@ -33,8 +33,6 @@ properties:
|
||||
description: GPIO connected to the OE (Output Enable) pin.
|
||||
maxItems: 1
|
||||
|
||||
spi-max-frequency: true
|
||||
|
||||
patternProperties:
|
||||
"^(hog-[0-9]+|.+-hog(-[0-9]+)?)$":
|
||||
type: object
|
||||
@ -59,7 +57,10 @@ required:
|
||||
- '#gpio-cells'
|
||||
- registers-number
|
||||
|
||||
additionalProperties: false
|
||||
allOf:
|
||||
- $ref: /schemas/spi/spi-peripheral-props.yaml#
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
|
@ -0,0 +1,39 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/gpio/fsl,imx8qxp-sc-gpio.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: GPIO driver over IMX SCU firmware API
|
||||
|
||||
maintainers:
|
||||
- Shenwei Wang <shenwei.wang@nxp.com>
|
||||
|
||||
description: |
|
||||
This module provides the standard interface to control the
|
||||
resource pins in SCU domain on i.MX8 platforms.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- fsl,imx8qxp-sc-gpio
|
||||
|
||||
"#gpio-cells":
|
||||
const: 2
|
||||
|
||||
gpio-controller: true
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- "#gpio-cells"
|
||||
- gpio-controller
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
gpio0: gpio {
|
||||
compatible = "fsl,imx8qxp-sc-gpio";
|
||||
gpio-controller;
|
||||
#gpio-cells = <2>;
|
||||
};
|
@ -15,52 +15,59 @@ description: |+
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- exar,xra1202
|
||||
- maxim,max7310
|
||||
- maxim,max7312
|
||||
- maxim,max7313
|
||||
- maxim,max7315
|
||||
- maxim,max7319
|
||||
- maxim,max7320
|
||||
- maxim,max7321
|
||||
- maxim,max7322
|
||||
- maxim,max7323
|
||||
- maxim,max7324
|
||||
- maxim,max7325
|
||||
- maxim,max7326
|
||||
- maxim,max7327
|
||||
- nxp,pca6408
|
||||
- nxp,pca6416
|
||||
- nxp,pca9505
|
||||
- nxp,pca9506
|
||||
- nxp,pca9534
|
||||
- nxp,pca9535
|
||||
- nxp,pca9536
|
||||
- nxp,pca9537
|
||||
- nxp,pca9538
|
||||
- nxp,pca9539
|
||||
- nxp,pca9554
|
||||
- nxp,pca9555
|
||||
- nxp,pca9556
|
||||
- nxp,pca9557
|
||||
- nxp,pca9574
|
||||
- nxp,pca9575
|
||||
- nxp,pca9698
|
||||
- nxp,pcal6416
|
||||
- nxp,pcal6524
|
||||
- nxp,pcal9535
|
||||
- nxp,pcal9554b
|
||||
- nxp,pcal9555a
|
||||
- onnn,cat9554
|
||||
- onnn,pca9654
|
||||
- ti,pca6107
|
||||
- ti,pca9536
|
||||
- ti,tca6408
|
||||
- ti,tca6416
|
||||
- ti,tca6424
|
||||
- ti,tca9539
|
||||
- ti,tca9554
|
||||
oneOf:
|
||||
- items:
|
||||
- const: diodes,pi4ioe5v6534q
|
||||
- const: nxp,pcal6534
|
||||
- items:
|
||||
- enum:
|
||||
- exar,xra1202
|
||||
- maxim,max7310
|
||||
- maxim,max7312
|
||||
- maxim,max7313
|
||||
- maxim,max7315
|
||||
- maxim,max7319
|
||||
- maxim,max7320
|
||||
- maxim,max7321
|
||||
- maxim,max7322
|
||||
- maxim,max7323
|
||||
- maxim,max7324
|
||||
- maxim,max7325
|
||||
- maxim,max7326
|
||||
- maxim,max7327
|
||||
- nxp,pca6408
|
||||
- nxp,pca6416
|
||||
- nxp,pca9505
|
||||
- nxp,pca9506
|
||||
- nxp,pca9534
|
||||
- nxp,pca9535
|
||||
- nxp,pca9536
|
||||
- nxp,pca9537
|
||||
- nxp,pca9538
|
||||
- nxp,pca9539
|
||||
- nxp,pca9554
|
||||
- nxp,pca9555
|
||||
- nxp,pca9556
|
||||
- nxp,pca9557
|
||||
- nxp,pca9574
|
||||
- nxp,pca9575
|
||||
- nxp,pca9698
|
||||
- nxp,pcal6408
|
||||
- nxp,pcal6416
|
||||
- nxp,pcal6524
|
||||
- nxp,pcal6534
|
||||
- nxp,pcal9535
|
||||
- nxp,pcal9554b
|
||||
- nxp,pcal9555a
|
||||
- onnn,cat9554
|
||||
- onnn,pca9654
|
||||
- ti,pca6107
|
||||
- ti,pca9536
|
||||
- ti,tca6408
|
||||
- ti,tca6416
|
||||
- ti,tca6424
|
||||
- ti,tca9539
|
||||
- ti,tca9554
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
@ -8,8 +8,7 @@ Optional properties:
|
||||
- st,norequest-mask: bitmask specifying which GPIOs should _not_ be requestable
|
||||
due to different usage (e.g. touch, keypad)
|
||||
|
||||
Node name must be stmpe_gpio and should be child node of stmpe node to which it
|
||||
belongs.
|
||||
Node should be child node of stmpe node to which it belongs.
|
||||
|
||||
Example:
|
||||
stmpe_gpio {
|
||||
|
@ -1,48 +0,0 @@
|
||||
Xilinx plb/axi GPIO controller
|
||||
|
||||
Dual channel GPIO controller with configurable number of pins
|
||||
(from 1 to 32 per channel). Every pin can be configured as
|
||||
input/output/tristate. Both channels share the same global IRQ but
|
||||
local interrupts can be enabled on channel basis.
|
||||
|
||||
Required properties:
|
||||
- compatible : Should be "xlnx,xps-gpio-1.00.a"
|
||||
- reg : Address and length of the register set for the device
|
||||
- #gpio-cells : Should be two. The first cell is the pin number and the
|
||||
second cell is used to specify optional parameters (currently unused).
|
||||
- gpio-controller : Marks the device node as a GPIO controller.
|
||||
|
||||
Optional properties:
|
||||
- clocks : Input clock specifier. Refer to common clock bindings.
|
||||
- interrupts : Interrupt mapping for GPIO IRQ.
|
||||
- xlnx,all-inputs : if n-th bit is setup, GPIO-n is input
|
||||
- xlnx,dout-default : if n-th bit is 1, GPIO-n default value is 1
|
||||
- xlnx,gpio-width : gpio width
|
||||
- xlnx,tri-default : if n-th bit is 1, GPIO-n is in tristate mode
|
||||
- xlnx,is-dual : if 1, controller also uses the second channel
|
||||
- xlnx,all-inputs-2 : as above but for the second channel
|
||||
- xlnx,dout-default-2 : as above but the second channel
|
||||
- xlnx,gpio2-width : as above but for the second channel
|
||||
- xlnx,tri-default-2 : as above but for the second channel
|
||||
|
||||
|
||||
Example:
|
||||
gpio: gpio@40000000 {
|
||||
#gpio-cells = <2>;
|
||||
compatible = "xlnx,xps-gpio-1.00.a";
|
||||
clocks = <&clkc25>;
|
||||
gpio-controller ;
|
||||
interrupt-parent = <µblaze_0_intc>;
|
||||
interrupts = < 6 2 >;
|
||||
reg = < 0x40000000 0x10000 >;
|
||||
xlnx,all-inputs = <0x0>;
|
||||
xlnx,all-inputs-2 = <0x0>;
|
||||
xlnx,dout-default = <0x0>;
|
||||
xlnx,dout-default-2 = <0x0>;
|
||||
xlnx,gpio-width = <0x2>;
|
||||
xlnx,gpio2-width = <0x2>;
|
||||
xlnx,interrupt-present = <0x1>;
|
||||
xlnx,is-dual = <0x1>;
|
||||
xlnx,tri-default = <0xffffffff>;
|
||||
xlnx,tri-default-2 = <0xffffffff>;
|
||||
} ;
|
@ -44,6 +44,24 @@ properties:
|
||||
|
||||
gpio-controller: true
|
||||
|
||||
patternProperties:
|
||||
"^.+-hog(-[0-9]+)?$":
|
||||
type: object
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
properties:
|
||||
gpio-hog: true
|
||||
gpios: true
|
||||
input: true
|
||||
output-high: true
|
||||
output-low: true
|
||||
line-name: true
|
||||
|
||||
required:
|
||||
- gpio-hog
|
||||
- gpios
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
|
@ -52,6 +52,7 @@ properties:
|
||||
- enum:
|
||||
- renesas,gpio-r8a779a0 # R-Car V3U
|
||||
- renesas,gpio-r8a779f0 # R-Car S4-8
|
||||
- renesas,gpio-r8a779g0 # R-Car V4H
|
||||
- const: renesas,rcar-gen4-gpio # R-Car Gen4
|
||||
|
||||
reg:
|
||||
|
154
Documentation/devicetree/bindings/gpio/xlnx,gpio-xilinx.yaml
Normal file
154
Documentation/devicetree/bindings/gpio/xlnx,gpio-xilinx.yaml
Normal file
@ -0,0 +1,154 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/gpio/xlnx,gpio-xilinx.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Xilinx AXI GPIO controller
|
||||
|
||||
maintainers:
|
||||
- Neeli Srinivas <srinivas.neeli@xilinx.com>
|
||||
|
||||
description:
|
||||
The AXI GPIO design provides a general purpose input/output interface
|
||||
to an AXI4-Lite interface. The AXI GPIO can be configured as either
|
||||
a single or a dual-channel device. The width of each channel is
|
||||
independently configurable. The channels can be configured to
|
||||
generate an interrupt when a transition on any of their inputs occurs.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- xlnx,xps-gpio-1.00.a
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
"#gpio-cells":
|
||||
const: 2
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
gpio-controller: true
|
||||
|
||||
gpio-line-names:
|
||||
description: strings describing the names of each gpio line
|
||||
minItems: 1
|
||||
maxItems: 64
|
||||
|
||||
interrupt-controller: true
|
||||
|
||||
"#interrupt-cells":
|
||||
const: 2
|
||||
|
||||
clocks:
|
||||
maxItems: 1
|
||||
|
||||
interrupt-names: true
|
||||
|
||||
xlnx,all-inputs:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
description: This option sets this GPIO channel1 bits in input mode.
|
||||
|
||||
xlnx,all-inputs-2:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
description: This option sets this GPIO channel2 bits in input mode.
|
||||
|
||||
xlnx,all-outputs:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
description: This option sets this GPIO channel1 bits in output mode.
|
||||
|
||||
xlnx,all-outputs-2:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
description: This option sets this GPIO channel2 bits in output mode.
|
||||
|
||||
xlnx,dout-default:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
description: Sets the default value of all the enabled bits of
|
||||
channel1.
|
||||
default: 0
|
||||
|
||||
xlnx,dout-default-2:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
description: Sets the default value of all the enabled bits of
|
||||
channel2.
|
||||
default: 0
|
||||
|
||||
xlnx,gpio-width:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
description: The value defines the bit width of the GPIO channel1.
|
||||
minimum: 1
|
||||
maximum: 32
|
||||
default: 32
|
||||
|
||||
xlnx,gpio2-width:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
description: The value defines the bit width of the GPIO channel2.
|
||||
minimum: 1
|
||||
maximum: 32
|
||||
default: 32
|
||||
|
||||
xlnx,interrupt-present:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
description: This parameter enables interrupt control logic
|
||||
and interrupt registers in GPIO module.
|
||||
minimum: 0
|
||||
maximum: 1
|
||||
default: 0
|
||||
|
||||
xlnx,is-dual:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
description: This parameter enables a second GPIO channel (GPIO2).
|
||||
minimum: 0
|
||||
maximum: 1
|
||||
default: 0
|
||||
|
||||
xlnx,tri-default:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
description: This value configures the input or output mode
|
||||
of each bit of GPIO channel1.
|
||||
|
||||
xlnx,tri-default-2:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
description: This value configures the input or output mode
|
||||
of each bit of GPIO channel2.
|
||||
|
||||
required:
|
||||
- reg
|
||||
- compatible
|
||||
- gpio-controller
|
||||
- "#gpio-cells"
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/interrupt-controller/arm-gic.h>
|
||||
|
||||
gpio@e000a000 {
|
||||
compatible = "xlnx,xps-gpio-1.00.a";
|
||||
reg = <0xa0020000 0x10000>;
|
||||
#gpio-cells = <2>;
|
||||
#interrupt-cells = <0x2>;
|
||||
clocks = <&zynqmp_clk 71>;
|
||||
gpio-controller;
|
||||
interrupt-controller;
|
||||
interrupt-names = "ip2intc_irpt";
|
||||
interrupt-parent = <&gic>;
|
||||
interrupts = <0 89 4>;
|
||||
xlnx,all-inputs = <0x0>;
|
||||
xlnx,all-inputs-2 = <0x0>;
|
||||
xlnx,all-outputs = <0x0>;
|
||||
xlnx,all-outputs-2 = <0x0>;
|
||||
xlnx,dout-default = <0x0>;
|
||||
xlnx,dout-default-2 = <0x0>;
|
||||
xlnx,gpio-width = <0x20>;
|
||||
xlnx,gpio2-width = <0x20>;
|
||||
xlnx,interrupt-present = <0x1>;
|
||||
xlnx,is-dual = <0x1>;
|
||||
xlnx,tri-default = <0xFFFFFFFF>;
|
||||
xlnx,tri-default-2 = <0xFFFFFFFF>;
|
||||
};
|
||||
|
||||
...
|
@ -330,6 +330,8 @@ patternProperties:
|
||||
description: Digi International Inc.
|
||||
"^digilent,.*":
|
||||
description: Diglent, Inc.
|
||||
"^diodes,.*":
|
||||
description: Diodes, Inc.
|
||||
"^dioo,.*":
|
||||
description: Dioo Microcircuit Co., Ltd
|
||||
"^dlc,.*":
|
||||
|
@ -28,7 +28,8 @@ module_param_hw_array(base, uint, ioport, &num_quad8, 0);
|
||||
MODULE_PARM_DESC(base, "ACCES 104-QUAD-8 base addresses");
|
||||
|
||||
static unsigned int irq[max_num_isa_dev(QUAD8_EXTENT)];
|
||||
module_param_hw_array(irq, uint, irq, NULL, 0);
|
||||
static unsigned int num_irq;
|
||||
module_param_hw_array(irq, uint, irq, &num_irq, 0);
|
||||
MODULE_PARM_DESC(irq, "ACCES 104-QUAD-8 interrupt line numbers");
|
||||
|
||||
#define QUAD8_NUM_COUNTERS 8
|
||||
@ -1271,7 +1272,7 @@ static struct isa_driver quad8_driver = {
|
||||
}
|
||||
};
|
||||
|
||||
module_isa_driver(quad8_driver, num_quad8);
|
||||
module_isa_driver_with_irq(quad8_driver, num_quad8, num_irq);
|
||||
|
||||
MODULE_AUTHOR("William Breathitt Gray <vilhelm.gray@gmail.com>");
|
||||
MODULE_DESCRIPTION("ACCES 104-QUAD-8 driver");
|
||||
|
@ -341,6 +341,10 @@ config GPIO_ICH
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
config GPIO_IMX_SCU
|
||||
def_bool y
|
||||
depends on IMX_SCU
|
||||
|
||||
config GPIO_IOP
|
||||
tristate "Intel IOP GPIO"
|
||||
depends on ARCH_IOP32X || COMPILE_TEST
|
||||
|
@ -70,6 +70,7 @@ obj-$(CONFIG_HTC_EGPIO) += gpio-htc-egpio.o
|
||||
obj-$(CONFIG_GPIO_I8255) += gpio-i8255.o
|
||||
obj-$(CONFIG_GPIO_ICH) += gpio-ich.o
|
||||
obj-$(CONFIG_GPIO_IDT3243X) += gpio-idt3243x.o
|
||||
obj-$(CONFIG_GPIO_IMX_SCU) += gpio-imx-scu.o
|
||||
obj-$(CONFIG_GPIO_IOP) += gpio-iop.o
|
||||
obj-$(CONFIG_GPIO_IT87) += gpio-it87.o
|
||||
obj-$(CONFIG_GPIO_IXP4XX) += gpio-ixp4xx.o
|
||||
|
@ -34,7 +34,8 @@ module_param_hw_array(base, uint, ioport, &num_dio48e, 0);
|
||||
MODULE_PARM_DESC(base, "ACCES 104-DIO-48E base addresses");
|
||||
|
||||
static unsigned int irq[MAX_NUM_DIO48E];
|
||||
module_param_hw_array(irq, uint, irq, NULL, 0);
|
||||
static unsigned int num_irq;
|
||||
module_param_hw_array(irq, uint, irq, &num_irq, 0);
|
||||
MODULE_PARM_DESC(irq, "ACCES 104-DIO-48E interrupt line numbers");
|
||||
|
||||
#define DIO48E_NUM_PPI 2
|
||||
@ -362,7 +363,7 @@ static struct isa_driver dio48e_driver = {
|
||||
.name = "104-dio-48e"
|
||||
},
|
||||
};
|
||||
module_isa_driver(dio48e_driver, num_dio48e);
|
||||
module_isa_driver_with_irq(dio48e_driver, num_dio48e, num_irq);
|
||||
|
||||
MODULE_AUTHOR("William Breathitt Gray <vilhelm.gray@gmail.com>");
|
||||
MODULE_DESCRIPTION("ACCES 104-DIO-48E GPIO driver");
|
||||
|
@ -34,7 +34,8 @@ module_param_hw_array(base, uint, ioport, &num_idi_48, 0);
|
||||
MODULE_PARM_DESC(base, "ACCES 104-IDI-48 base addresses");
|
||||
|
||||
static unsigned int irq[MAX_NUM_IDI_48];
|
||||
module_param_hw_array(irq, uint, irq, NULL, 0);
|
||||
static unsigned int num_irq;
|
||||
module_param_hw_array(irq, uint, irq, &num_irq, 0);
|
||||
MODULE_PARM_DESC(irq, "ACCES 104-IDI-48 interrupt line numbers");
|
||||
|
||||
/**
|
||||
@ -304,7 +305,7 @@ static struct isa_driver idi_48_driver = {
|
||||
.name = "104-idi-48"
|
||||
},
|
||||
};
|
||||
module_isa_driver(idi_48_driver, num_idi_48);
|
||||
module_isa_driver_with_irq(idi_48_driver, num_idi_48, num_irq);
|
||||
|
||||
MODULE_AUTHOR("William Breathitt Gray <vilhelm.gray@gmail.com>");
|
||||
MODULE_DESCRIPTION("ACCES 104-IDI-48 GPIO driver");
|
||||
|
@ -30,7 +30,8 @@ module_param_hw_array(base, uint, ioport, &num_idio_16, 0);
|
||||
MODULE_PARM_DESC(base, "ACCES 104-IDIO-16 base addresses");
|
||||
|
||||
static unsigned int irq[MAX_NUM_IDIO_16];
|
||||
module_param_hw_array(irq, uint, irq, NULL, 0);
|
||||
static unsigned int num_irq;
|
||||
module_param_hw_array(irq, uint, irq, &num_irq, 0);
|
||||
MODULE_PARM_DESC(irq, "ACCES 104-IDIO-16 interrupt line numbers");
|
||||
|
||||
/**
|
||||
@ -337,7 +338,7 @@ static struct isa_driver idio_16_driver = {
|
||||
},
|
||||
};
|
||||
|
||||
module_isa_driver(idio_16_driver, num_idio_16);
|
||||
module_isa_driver_with_irq(idio_16_driver, num_idio_16, num_irq);
|
||||
|
||||
MODULE_AUTHOR("William Breathitt Gray <vilhelm.gray@gmail.com>");
|
||||
MODULE_DESCRIPTION("ACCES 104-IDIO-16 GPIO driver");
|
||||
|
@ -21,6 +21,12 @@
|
||||
#define EXAR_OFFSET_MPIOLVL_HI 0x96
|
||||
#define EXAR_OFFSET_MPIOSEL_HI 0x99
|
||||
|
||||
/*
|
||||
* The Device Configuration and UART Configuration Registers
|
||||
* for each UART channel take 1KB of memory address space.
|
||||
*/
|
||||
#define EXAR_UART_CHANNEL_SIZE 0x400
|
||||
|
||||
#define DRIVER_NAME "gpio_exar"
|
||||
|
||||
static DEFINE_IDA(ida_index);
|
||||
@ -31,26 +37,39 @@ struct exar_gpio_chip {
|
||||
int index;
|
||||
char name[20];
|
||||
unsigned int first_pin;
|
||||
/*
|
||||
* The offset to the cascaded device's (if existing)
|
||||
* Device Configuration Registers.
|
||||
*/
|
||||
unsigned int cascaded_offset;
|
||||
};
|
||||
|
||||
static unsigned int
|
||||
exar_offset_to_sel_addr(struct exar_gpio_chip *exar_gpio, unsigned int offset)
|
||||
{
|
||||
return (offset + exar_gpio->first_pin) / 8 ? EXAR_OFFSET_MPIOSEL_HI
|
||||
: EXAR_OFFSET_MPIOSEL_LO;
|
||||
unsigned int pin = exar_gpio->first_pin + (offset % 16);
|
||||
unsigned int cascaded = offset / 16;
|
||||
unsigned int addr = pin / 8 ? EXAR_OFFSET_MPIOSEL_HI : EXAR_OFFSET_MPIOSEL_LO;
|
||||
|
||||
return addr + (cascaded ? exar_gpio->cascaded_offset : 0);
|
||||
}
|
||||
|
||||
static unsigned int
|
||||
exar_offset_to_lvl_addr(struct exar_gpio_chip *exar_gpio, unsigned int offset)
|
||||
{
|
||||
return (offset + exar_gpio->first_pin) / 8 ? EXAR_OFFSET_MPIOLVL_HI
|
||||
: EXAR_OFFSET_MPIOLVL_LO;
|
||||
unsigned int pin = exar_gpio->first_pin + (offset % 16);
|
||||
unsigned int cascaded = offset / 16;
|
||||
unsigned int addr = pin / 8 ? EXAR_OFFSET_MPIOLVL_HI : EXAR_OFFSET_MPIOLVL_LO;
|
||||
|
||||
return addr + (cascaded ? exar_gpio->cascaded_offset : 0);
|
||||
}
|
||||
|
||||
static unsigned int
|
||||
exar_offset_to_bit(struct exar_gpio_chip *exar_gpio, unsigned int offset)
|
||||
{
|
||||
return (offset + exar_gpio->first_pin) % 8;
|
||||
unsigned int pin = exar_gpio->first_pin + (offset % 16);
|
||||
|
||||
return pin % 8;
|
||||
}
|
||||
|
||||
static int exar_get_direction(struct gpio_chip *chip, unsigned int offset)
|
||||
@ -153,6 +172,17 @@ static int gpio_exar_probe(struct platform_device *pdev)
|
||||
if (!exar_gpio)
|
||||
return -ENOMEM;
|
||||
|
||||
/*
|
||||
* If cascaded, secondary xr17v354 or xr17v358 have the same amount
|
||||
* of MPIOs as their primaries and the last 4 bits of the primary's
|
||||
* PCI Device ID is the number of its UART channels.
|
||||
*/
|
||||
if (pcidev->device & GENMASK(15, 12)) {
|
||||
ngpios += ngpios;
|
||||
exar_gpio->cascaded_offset = (pcidev->device & GENMASK(3, 0)) *
|
||||
EXAR_UART_CHANNEL_SIZE;
|
||||
}
|
||||
|
||||
/*
|
||||
* We don't need to check the return values of mmio regmap operations (unless
|
||||
* the regmap has a clock attached which is not the case here).
|
||||
|
139
drivers/gpio/gpio-imx-scu.c
Normal file
139
drivers/gpio/gpio-imx-scu.c
Normal file
@ -0,0 +1,139 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright 2021~2022 NXP
|
||||
*
|
||||
* The driver exports a standard gpiochip interface
|
||||
* to control the PIN resources on SCU domain.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/gpio/driver.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/firmware/imx/svc/rm.h>
|
||||
#include <dt-bindings/firmware/imx/rsrc.h>
|
||||
|
||||
struct scu_gpio_priv {
|
||||
struct gpio_chip chip;
|
||||
struct mutex lock;
|
||||
struct device *dev;
|
||||
struct imx_sc_ipc *handle;
|
||||
};
|
||||
|
||||
static unsigned int scu_rsrc_arr[] = {
|
||||
IMX_SC_R_BOARD_R0,
|
||||
IMX_SC_R_BOARD_R1,
|
||||
IMX_SC_R_BOARD_R2,
|
||||
IMX_SC_R_BOARD_R3,
|
||||
IMX_SC_R_BOARD_R4,
|
||||
IMX_SC_R_BOARD_R5,
|
||||
IMX_SC_R_BOARD_R6,
|
||||
IMX_SC_R_BOARD_R7,
|
||||
};
|
||||
|
||||
static int imx_scu_gpio_get(struct gpio_chip *chip, unsigned int offset)
|
||||
{
|
||||
struct scu_gpio_priv *priv = gpiochip_get_data(chip);
|
||||
int level;
|
||||
int err;
|
||||
|
||||
if (offset >= chip->ngpio)
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&priv->lock);
|
||||
|
||||
/* to read PIN state via scu api */
|
||||
err = imx_sc_misc_get_control(priv->handle,
|
||||
scu_rsrc_arr[offset], 0, &level);
|
||||
mutex_unlock(&priv->lock);
|
||||
|
||||
if (err) {
|
||||
dev_err(priv->dev, "SCU get failed: %d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
return level;
|
||||
}
|
||||
|
||||
static void imx_scu_gpio_set(struct gpio_chip *chip, unsigned int offset, int value)
|
||||
{
|
||||
struct scu_gpio_priv *priv = gpiochip_get_data(chip);
|
||||
int err;
|
||||
|
||||
if (offset >= chip->ngpio)
|
||||
return;
|
||||
|
||||
mutex_lock(&priv->lock);
|
||||
|
||||
/* to set PIN output level via scu api */
|
||||
err = imx_sc_misc_set_control(priv->handle,
|
||||
scu_rsrc_arr[offset], 0, value);
|
||||
mutex_unlock(&priv->lock);
|
||||
|
||||
if (err)
|
||||
dev_err(priv->dev, "SCU set (%d) failed: %d\n",
|
||||
scu_rsrc_arr[offset], err);
|
||||
}
|
||||
|
||||
static int imx_scu_gpio_get_direction(struct gpio_chip *chip, unsigned int offset)
|
||||
{
|
||||
if (offset >= chip->ngpio)
|
||||
return -EINVAL;
|
||||
|
||||
return GPIO_LINE_DIRECTION_OUT;
|
||||
}
|
||||
|
||||
static int imx_scu_gpio_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct scu_gpio_priv *priv;
|
||||
struct gpio_chip *gc;
|
||||
int ret;
|
||||
|
||||
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = imx_scu_get_handle(&priv->handle);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
priv->dev = dev;
|
||||
mutex_init(&priv->lock);
|
||||
|
||||
gc = &priv->chip;
|
||||
gc->base = -1;
|
||||
gc->parent = dev;
|
||||
gc->ngpio = sizeof(scu_rsrc_arr)/sizeof(unsigned int);
|
||||
gc->label = dev_name(dev);
|
||||
gc->get = imx_scu_gpio_get;
|
||||
gc->set = imx_scu_gpio_set;
|
||||
gc->get_direction = imx_scu_gpio_get_direction;
|
||||
|
||||
platform_set_drvdata(pdev, priv);
|
||||
|
||||
return devm_gpiochip_add_data(dev, gc, priv);
|
||||
}
|
||||
|
||||
static const struct of_device_id imx_scu_gpio_dt_ids[] = {
|
||||
{ .compatible = "fsl,imx8qxp-sc-gpio" },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
|
||||
static struct platform_driver imx_scu_gpio_driver = {
|
||||
.driver = {
|
||||
.name = "gpio-imx-scu",
|
||||
.of_match_table = imx_scu_gpio_dt_ids,
|
||||
},
|
||||
.probe = imx_scu_gpio_probe,
|
||||
};
|
||||
|
||||
static int __init _imx_scu_gpio_init(void)
|
||||
{
|
||||
return platform_driver_register(&imx_scu_gpio_driver);
|
||||
}
|
||||
|
||||
subsys_initcall_sync(_imx_scu_gpio_init);
|
||||
|
||||
MODULE_AUTHOR("Shenwei Wang <shenwei.wang@nxp.com>");
|
||||
MODULE_DESCRIPTION("NXP GPIO over IMX SCU API");
|
||||
MODULE_LICENSE("GPL");
|
@ -9,7 +9,6 @@
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/spinlock.h>
|
||||
|
||||
@ -299,7 +298,6 @@ static int
|
||||
mediatek_gpio_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct device_node *np = dev->of_node;
|
||||
struct mtk *mtk;
|
||||
int i;
|
||||
int ret;
|
||||
@ -312,7 +310,10 @@ mediatek_gpio_probe(struct platform_device *pdev)
|
||||
if (IS_ERR(mtk->base))
|
||||
return PTR_ERR(mtk->base);
|
||||
|
||||
mtk->gpio_irq = irq_of_parse_and_map(np, 0);
|
||||
mtk->gpio_irq = platform_get_irq(pdev, 0);
|
||||
if (mtk->gpio_irq < 0)
|
||||
return mtk->gpio_irq;
|
||||
|
||||
mtk->dev = dev;
|
||||
platform_set_drvdata(pdev, mtk);
|
||||
|
||||
|
@ -66,6 +66,7 @@
|
||||
#define PCA_LATCH_INT (PCA_PCAL | PCA_INT)
|
||||
#define PCA953X_TYPE BIT(12)
|
||||
#define PCA957X_TYPE BIT(13)
|
||||
#define PCAL653X_TYPE BIT(14)
|
||||
#define PCA_TYPE_MASK GENMASK(15, 12)
|
||||
|
||||
#define PCA_CHIP_TYPE(x) ((x) & PCA_TYPE_MASK)
|
||||
@ -89,8 +90,10 @@ static const struct i2c_device_id pca953x_id[] = {
|
||||
{ "pca9575", 16 | PCA957X_TYPE | PCA_INT, },
|
||||
{ "pca9698", 40 | PCA953X_TYPE, },
|
||||
|
||||
{ "pcal6408", 8 | PCA953X_TYPE | PCA_LATCH_INT, },
|
||||
{ "pcal6416", 16 | PCA953X_TYPE | PCA_LATCH_INT, },
|
||||
{ "pcal6524", 24 | PCA953X_TYPE | PCA_LATCH_INT, },
|
||||
{ "pcal6534", 34 | PCAL653X_TYPE | PCA_LATCH_INT, },
|
||||
{ "pcal9535", 16 | PCA953X_TYPE | PCA_LATCH_INT, },
|
||||
{ "pcal9554b", 8 | PCA953X_TYPE | PCA_LATCH_INT, },
|
||||
{ "pcal9555a", 16 | PCA953X_TYPE | PCA_LATCH_INT, },
|
||||
@ -211,6 +214,10 @@ struct pca953x_chip {
|
||||
struct regulator *regulator;
|
||||
|
||||
const struct pca953x_reg_config *regs;
|
||||
|
||||
u8 (*recalc_addr)(struct pca953x_chip *chip, int reg, int off);
|
||||
bool (*check_reg)(struct pca953x_chip *chip, unsigned int reg,
|
||||
u32 checkbank);
|
||||
};
|
||||
|
||||
static int pca953x_bank_shift(struct pca953x_chip *chip)
|
||||
@ -288,18 +295,67 @@ static bool pca953x_check_register(struct pca953x_chip *chip, unsigned int reg,
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Unfortunately, whilst the PCAL6534 chip (and compatibles) broadly follow the
|
||||
* same register layout as the PCAL6524, the spacing of the registers has been
|
||||
* fundamentally altered by compacting them and thus does not obey the same
|
||||
* rules, including being able to use bit shifting to determine bank. These
|
||||
* chips hence need special handling here.
|
||||
*/
|
||||
static bool pcal6534_check_register(struct pca953x_chip *chip, unsigned int reg,
|
||||
u32 checkbank)
|
||||
{
|
||||
int bank;
|
||||
int offset;
|
||||
|
||||
if (reg >= 0x30) {
|
||||
/*
|
||||
* Reserved block between 14h and 2Fh does not align on
|
||||
* expected bank boundaries like other devices.
|
||||
*/
|
||||
int temp = reg - 0x30;
|
||||
|
||||
bank = temp / NBANK(chip);
|
||||
offset = temp - (bank * NBANK(chip));
|
||||
bank += 8;
|
||||
} else if (reg >= 0x54) {
|
||||
/*
|
||||
* Handle lack of reserved registers after output port
|
||||
* configuration register to form a bank.
|
||||
*/
|
||||
int temp = reg - 0x54;
|
||||
|
||||
bank = temp / NBANK(chip);
|
||||
offset = temp - (bank * NBANK(chip));
|
||||
bank += 16;
|
||||
} else {
|
||||
bank = reg / NBANK(chip);
|
||||
offset = reg - (bank * NBANK(chip));
|
||||
}
|
||||
|
||||
/* Register is not in the matching bank. */
|
||||
if (!(BIT(bank) & checkbank))
|
||||
return false;
|
||||
|
||||
/* Register is not within allowed range of bank. */
|
||||
if (offset >= NBANK(chip))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool pca953x_readable_register(struct device *dev, unsigned int reg)
|
||||
{
|
||||
struct pca953x_chip *chip = dev_get_drvdata(dev);
|
||||
u32 bank;
|
||||
|
||||
if (PCA_CHIP_TYPE(chip->driver_data) == PCA953X_TYPE) {
|
||||
bank = PCA953x_BANK_INPUT | PCA953x_BANK_OUTPUT |
|
||||
PCA953x_BANK_POLARITY | PCA953x_BANK_CONFIG;
|
||||
} else {
|
||||
if (PCA_CHIP_TYPE(chip->driver_data) == PCA957X_TYPE) {
|
||||
bank = PCA957x_BANK_INPUT | PCA957x_BANK_OUTPUT |
|
||||
PCA957x_BANK_POLARITY | PCA957x_BANK_CONFIG |
|
||||
PCA957x_BANK_BUSHOLD;
|
||||
} else {
|
||||
bank = PCA953x_BANK_INPUT | PCA953x_BANK_OUTPUT |
|
||||
PCA953x_BANK_POLARITY | PCA953x_BANK_CONFIG;
|
||||
}
|
||||
|
||||
if (chip->driver_data & PCA_PCAL) {
|
||||
@ -308,7 +364,7 @@ static bool pca953x_readable_register(struct device *dev, unsigned int reg)
|
||||
PCAL9xxx_BANK_IRQ_STAT;
|
||||
}
|
||||
|
||||
return pca953x_check_register(chip, reg, bank);
|
||||
return chip->check_reg(chip, reg, bank);
|
||||
}
|
||||
|
||||
static bool pca953x_writeable_register(struct device *dev, unsigned int reg)
|
||||
@ -316,19 +372,19 @@ static bool pca953x_writeable_register(struct device *dev, unsigned int reg)
|
||||
struct pca953x_chip *chip = dev_get_drvdata(dev);
|
||||
u32 bank;
|
||||
|
||||
if (PCA_CHIP_TYPE(chip->driver_data) == PCA953X_TYPE) {
|
||||
bank = PCA953x_BANK_OUTPUT | PCA953x_BANK_POLARITY |
|
||||
PCA953x_BANK_CONFIG;
|
||||
} else {
|
||||
if (PCA_CHIP_TYPE(chip->driver_data) == PCA957X_TYPE) {
|
||||
bank = PCA957x_BANK_OUTPUT | PCA957x_BANK_POLARITY |
|
||||
PCA957x_BANK_CONFIG | PCA957x_BANK_BUSHOLD;
|
||||
} else {
|
||||
bank = PCA953x_BANK_OUTPUT | PCA953x_BANK_POLARITY |
|
||||
PCA953x_BANK_CONFIG;
|
||||
}
|
||||
|
||||
if (chip->driver_data & PCA_PCAL)
|
||||
bank |= PCAL9xxx_BANK_IN_LATCH | PCAL9xxx_BANK_PULL_EN |
|
||||
PCAL9xxx_BANK_PULL_SEL | PCAL9xxx_BANK_IRQ_MASK;
|
||||
|
||||
return pca953x_check_register(chip, reg, bank);
|
||||
return chip->check_reg(chip, reg, bank);
|
||||
}
|
||||
|
||||
static bool pca953x_volatile_register(struct device *dev, unsigned int reg)
|
||||
@ -336,15 +392,15 @@ static bool pca953x_volatile_register(struct device *dev, unsigned int reg)
|
||||
struct pca953x_chip *chip = dev_get_drvdata(dev);
|
||||
u32 bank;
|
||||
|
||||
if (PCA_CHIP_TYPE(chip->driver_data) == PCA953X_TYPE)
|
||||
bank = PCA953x_BANK_INPUT;
|
||||
else
|
||||
if (PCA_CHIP_TYPE(chip->driver_data) == PCA957X_TYPE)
|
||||
bank = PCA957x_BANK_INPUT;
|
||||
else
|
||||
bank = PCA953x_BANK_INPUT;
|
||||
|
||||
if (chip->driver_data & PCA_PCAL)
|
||||
bank |= PCAL9xxx_BANK_IRQ_STAT;
|
||||
|
||||
return pca953x_check_register(chip, reg, bank);
|
||||
return chip->check_reg(chip, reg, bank);
|
||||
}
|
||||
|
||||
static const struct regmap_config pca953x_i2c_regmap = {
|
||||
@ -389,9 +445,42 @@ static u8 pca953x_recalc_addr(struct pca953x_chip *chip, int reg, int off)
|
||||
return regaddr;
|
||||
}
|
||||
|
||||
/*
|
||||
* The PCAL6534 and compatible chips have altered bank alignment that doesn't
|
||||
* fit within the bit shifting scheme used for other devices.
|
||||
*/
|
||||
static u8 pcal6534_recalc_addr(struct pca953x_chip *chip, int reg, int off)
|
||||
{
|
||||
int addr;
|
||||
int pinctrl;
|
||||
|
||||
addr = (reg & PCAL_GPIO_MASK) * NBANK(chip);
|
||||
|
||||
switch (reg) {
|
||||
case PCAL953X_OUT_STRENGTH:
|
||||
case PCAL953X_IN_LATCH:
|
||||
case PCAL953X_PULL_EN:
|
||||
case PCAL953X_PULL_SEL:
|
||||
case PCAL953X_INT_MASK:
|
||||
case PCAL953X_INT_STAT:
|
||||
case PCAL953X_OUT_CONF:
|
||||
pinctrl = ((reg & PCAL_PINCTRL_MASK) >> 1) + 0x20;
|
||||
break;
|
||||
case PCAL6524_INT_EDGE:
|
||||
case PCAL6524_INT_CLR:
|
||||
case PCAL6524_IN_STATUS:
|
||||
case PCAL6524_OUT_INDCONF:
|
||||
case PCAL6524_DEBOUNCE:
|
||||
pinctrl = ((reg & PCAL_PINCTRL_MASK) >> 1) + 0x1c;
|
||||
break;
|
||||
}
|
||||
|
||||
return pinctrl + addr + (off / BANK_SZ);
|
||||
}
|
||||
|
||||
static int pca953x_write_regs(struct pca953x_chip *chip, int reg, unsigned long *val)
|
||||
{
|
||||
u8 regaddr = pca953x_recalc_addr(chip, reg, 0);
|
||||
u8 regaddr = chip->recalc_addr(chip, reg, 0);
|
||||
u8 value[MAX_BANK];
|
||||
int i, ret;
|
||||
|
||||
@ -409,7 +498,7 @@ static int pca953x_write_regs(struct pca953x_chip *chip, int reg, unsigned long
|
||||
|
||||
static int pca953x_read_regs(struct pca953x_chip *chip, int reg, unsigned long *val)
|
||||
{
|
||||
u8 regaddr = pca953x_recalc_addr(chip, reg, 0);
|
||||
u8 regaddr = chip->recalc_addr(chip, reg, 0);
|
||||
u8 value[MAX_BANK];
|
||||
int i, ret;
|
||||
|
||||
@ -428,7 +517,7 @@ static int pca953x_read_regs(struct pca953x_chip *chip, int reg, unsigned long *
|
||||
static int pca953x_gpio_direction_input(struct gpio_chip *gc, unsigned off)
|
||||
{
|
||||
struct pca953x_chip *chip = gpiochip_get_data(gc);
|
||||
u8 dirreg = pca953x_recalc_addr(chip, chip->regs->direction, off);
|
||||
u8 dirreg = chip->recalc_addr(chip, chip->regs->direction, off);
|
||||
u8 bit = BIT(off % BANK_SZ);
|
||||
int ret;
|
||||
|
||||
@ -442,8 +531,8 @@ static int pca953x_gpio_direction_output(struct gpio_chip *gc,
|
||||
unsigned off, int val)
|
||||
{
|
||||
struct pca953x_chip *chip = gpiochip_get_data(gc);
|
||||
u8 dirreg = pca953x_recalc_addr(chip, chip->regs->direction, off);
|
||||
u8 outreg = pca953x_recalc_addr(chip, chip->regs->output, off);
|
||||
u8 dirreg = chip->recalc_addr(chip, chip->regs->direction, off);
|
||||
u8 outreg = chip->recalc_addr(chip, chip->regs->output, off);
|
||||
u8 bit = BIT(off % BANK_SZ);
|
||||
int ret;
|
||||
|
||||
@ -463,7 +552,7 @@ static int pca953x_gpio_direction_output(struct gpio_chip *gc,
|
||||
static int pca953x_gpio_get_value(struct gpio_chip *gc, unsigned off)
|
||||
{
|
||||
struct pca953x_chip *chip = gpiochip_get_data(gc);
|
||||
u8 inreg = pca953x_recalc_addr(chip, chip->regs->input, off);
|
||||
u8 inreg = chip->recalc_addr(chip, chip->regs->input, off);
|
||||
u8 bit = BIT(off % BANK_SZ);
|
||||
u32 reg_val;
|
||||
int ret;
|
||||
@ -480,7 +569,7 @@ static int pca953x_gpio_get_value(struct gpio_chip *gc, unsigned off)
|
||||
static void pca953x_gpio_set_value(struct gpio_chip *gc, unsigned off, int val)
|
||||
{
|
||||
struct pca953x_chip *chip = gpiochip_get_data(gc);
|
||||
u8 outreg = pca953x_recalc_addr(chip, chip->regs->output, off);
|
||||
u8 outreg = chip->recalc_addr(chip, chip->regs->output, off);
|
||||
u8 bit = BIT(off % BANK_SZ);
|
||||
|
||||
mutex_lock(&chip->i2c_lock);
|
||||
@ -491,7 +580,7 @@ static void pca953x_gpio_set_value(struct gpio_chip *gc, unsigned off, int val)
|
||||
static int pca953x_gpio_get_direction(struct gpio_chip *gc, unsigned off)
|
||||
{
|
||||
struct pca953x_chip *chip = gpiochip_get_data(gc);
|
||||
u8 dirreg = pca953x_recalc_addr(chip, chip->regs->direction, off);
|
||||
u8 dirreg = chip->recalc_addr(chip, chip->regs->direction, off);
|
||||
u8 bit = BIT(off % BANK_SZ);
|
||||
u32 reg_val;
|
||||
int ret;
|
||||
@ -548,8 +637,10 @@ static int pca953x_gpio_set_pull_up_down(struct pca953x_chip *chip,
|
||||
unsigned int offset,
|
||||
unsigned long config)
|
||||
{
|
||||
u8 pull_en_reg = pca953x_recalc_addr(chip, PCAL953X_PULL_EN, offset);
|
||||
u8 pull_sel_reg = pca953x_recalc_addr(chip, PCAL953X_PULL_SEL, offset);
|
||||
enum pin_config_param param = pinconf_to_config_param(config);
|
||||
|
||||
u8 pull_en_reg = chip->recalc_addr(chip, PCAL953X_PULL_EN, offset);
|
||||
u8 pull_sel_reg = chip->recalc_addr(chip, PCAL953X_PULL_SEL, offset);
|
||||
u8 bit = BIT(offset % BANK_SZ);
|
||||
int ret;
|
||||
|
||||
@ -563,9 +654,9 @@ static int pca953x_gpio_set_pull_up_down(struct pca953x_chip *chip,
|
||||
mutex_lock(&chip->i2c_lock);
|
||||
|
||||
/* Configure pull-up/pull-down */
|
||||
if (config == PIN_CONFIG_BIAS_PULL_UP)
|
||||
if (param == PIN_CONFIG_BIAS_PULL_UP)
|
||||
ret = regmap_write_bits(chip->regmap, pull_sel_reg, bit, bit);
|
||||
else if (config == PIN_CONFIG_BIAS_PULL_DOWN)
|
||||
else if (param == PIN_CONFIG_BIAS_PULL_DOWN)
|
||||
ret = regmap_write_bits(chip->regmap, pull_sel_reg, bit, 0);
|
||||
else
|
||||
ret = 0;
|
||||
@ -573,7 +664,7 @@ static int pca953x_gpio_set_pull_up_down(struct pca953x_chip *chip,
|
||||
goto exit;
|
||||
|
||||
/* Disable/Enable pull-up/pull-down */
|
||||
if (config == PIN_CONFIG_BIAS_DISABLE)
|
||||
if (param == PIN_CONFIG_BIAS_DISABLE)
|
||||
ret = regmap_write_bits(chip->regmap, pull_en_reg, bit, 0);
|
||||
else
|
||||
ret = regmap_write_bits(chip->regmap, pull_en_reg, bit, bit);
|
||||
@ -912,13 +1003,13 @@ static int device_pca95xx_init(struct pca953x_chip *chip, u32 invert)
|
||||
u8 regaddr;
|
||||
int ret;
|
||||
|
||||
regaddr = pca953x_recalc_addr(chip, chip->regs->output, 0);
|
||||
regaddr = chip->recalc_addr(chip, chip->regs->output, 0);
|
||||
ret = regcache_sync_region(chip->regmap, regaddr,
|
||||
regaddr + NBANK(chip) - 1);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
regaddr = pca953x_recalc_addr(chip, chip->regs->direction, 0);
|
||||
regaddr = chip->recalc_addr(chip, chip->regs->direction, 0);
|
||||
ret = regcache_sync_region(chip->regmap, regaddr,
|
||||
regaddr + NBANK(chip) - 1);
|
||||
if (ret)
|
||||
@ -1037,6 +1128,14 @@ static int pca953x_probe(struct i2c_client *client,
|
||||
regmap_config = &pca953x_i2c_regmap;
|
||||
}
|
||||
|
||||
if (PCA_CHIP_TYPE(chip->driver_data) == PCAL653X_TYPE) {
|
||||
chip->recalc_addr = pcal6534_recalc_addr;
|
||||
chip->check_reg = pcal6534_check_register;
|
||||
} else {
|
||||
chip->recalc_addr = pca953x_recalc_addr;
|
||||
chip->check_reg = pca953x_check_register;
|
||||
}
|
||||
|
||||
chip->regmap = devm_regmap_init_i2c(client, regmap_config);
|
||||
if (IS_ERR(chip->regmap)) {
|
||||
ret = PTR_ERR(chip->regmap);
|
||||
@ -1068,13 +1167,12 @@ static int pca953x_probe(struct i2c_client *client,
|
||||
/* initialize cached registers from their original values.
|
||||
* we can't share this chip with another i2c master.
|
||||
*/
|
||||
|
||||
if (PCA_CHIP_TYPE(chip->driver_data) == PCA953X_TYPE) {
|
||||
chip->regs = &pca953x_regs;
|
||||
ret = device_pca95xx_init(chip, invert);
|
||||
} else {
|
||||
if (PCA_CHIP_TYPE(chip->driver_data) == PCA957X_TYPE) {
|
||||
chip->regs = &pca957x_regs;
|
||||
ret = device_pca957x_init(chip, invert);
|
||||
} else {
|
||||
chip->regs = &pca953x_regs;
|
||||
ret = device_pca95xx_init(chip, invert);
|
||||
}
|
||||
if (ret)
|
||||
goto err_exit;
|
||||
@ -1125,14 +1223,14 @@ static int pca953x_regcache_sync(struct device *dev)
|
||||
* The ordering between direction and output is important,
|
||||
* sync these registers first and only then sync the rest.
|
||||
*/
|
||||
regaddr = pca953x_recalc_addr(chip, chip->regs->direction, 0);
|
||||
regaddr = chip->recalc_addr(chip, chip->regs->direction, 0);
|
||||
ret = regcache_sync_region(chip->regmap, regaddr, regaddr + NBANK(chip) - 1);
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to sync GPIO dir registers: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
regaddr = pca953x_recalc_addr(chip, chip->regs->output, 0);
|
||||
regaddr = chip->recalc_addr(chip, chip->regs->output, 0);
|
||||
ret = regcache_sync_region(chip->regmap, regaddr, regaddr + NBANK(chip) - 1);
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to sync GPIO out registers: %d\n", ret);
|
||||
@ -1141,7 +1239,7 @@ static int pca953x_regcache_sync(struct device *dev)
|
||||
|
||||
#ifdef CONFIG_GPIO_PCA953X_IRQ
|
||||
if (chip->driver_data & PCA_PCAL) {
|
||||
regaddr = pca953x_recalc_addr(chip, PCAL953X_IN_LATCH, 0);
|
||||
regaddr = chip->recalc_addr(chip, PCAL953X_IN_LATCH, 0);
|
||||
ret = regcache_sync_region(chip->regmap, regaddr,
|
||||
regaddr + NBANK(chip) - 1);
|
||||
if (ret) {
|
||||
@ -1150,7 +1248,7 @@ static int pca953x_regcache_sync(struct device *dev)
|
||||
return ret;
|
||||
}
|
||||
|
||||
regaddr = pca953x_recalc_addr(chip, PCAL953X_INT_MASK, 0);
|
||||
regaddr = chip->recalc_addr(chip, PCAL953X_INT_MASK, 0);
|
||||
ret = regcache_sync_region(chip->regmap, regaddr,
|
||||
regaddr + NBANK(chip) - 1);
|
||||
if (ret) {
|
||||
@ -1214,6 +1312,7 @@ static int pca953x_resume(struct device *dev)
|
||||
#endif
|
||||
|
||||
/* convenience to stop overlong match-table lines */
|
||||
#define OF_653X(__nrgpio, __int) ((void *)(__nrgpio | PCAL653X_TYPE | __int))
|
||||
#define OF_953X(__nrgpio, __int) (void *)(__nrgpio | PCA953X_TYPE | __int)
|
||||
#define OF_957X(__nrgpio, __int) (void *)(__nrgpio | PCA957X_TYPE | __int)
|
||||
|
||||
@ -1236,8 +1335,10 @@ static const struct of_device_id pca953x_dt_ids[] = {
|
||||
{ .compatible = "nxp,pca9575", .data = OF_957X(16, PCA_INT), },
|
||||
{ .compatible = "nxp,pca9698", .data = OF_953X(40, 0), },
|
||||
|
||||
{ .compatible = "nxp,pcal6408", .data = OF_953X(8, PCA_LATCH_INT), },
|
||||
{ .compatible = "nxp,pcal6416", .data = OF_953X(16, PCA_LATCH_INT), },
|
||||
{ .compatible = "nxp,pcal6524", .data = OF_953X(24, PCA_LATCH_INT), },
|
||||
{ .compatible = "nxp,pcal6534", .data = OF_653X(34, PCA_LATCH_INT), },
|
||||
{ .compatible = "nxp,pcal9535", .data = OF_953X(16, PCA_LATCH_INT), },
|
||||
{ .compatible = "nxp,pcal9554b", .data = OF_953X( 8, PCA_LATCH_INT), },
|
||||
{ .compatible = "nxp,pcal9555a", .data = OF_953X(16, PCA_LATCH_INT), },
|
||||
|
@ -325,26 +325,15 @@ static void rockchip_irq_demux(struct irq_desc *desc)
|
||||
{
|
||||
struct irq_chip *chip = irq_desc_get_chip(desc);
|
||||
struct rockchip_pin_bank *bank = irq_desc_get_handler_data(desc);
|
||||
u32 pend;
|
||||
unsigned long pending;
|
||||
unsigned int irq;
|
||||
|
||||
dev_dbg(bank->dev, "got irq for bank %s\n", bank->name);
|
||||
|
||||
chained_irq_enter(chip, desc);
|
||||
|
||||
pend = readl_relaxed(bank->reg_base + bank->gpio_regs->int_status);
|
||||
|
||||
while (pend) {
|
||||
unsigned int irq, virq;
|
||||
|
||||
irq = __ffs(pend);
|
||||
pend &= ~BIT(irq);
|
||||
virq = irq_find_mapping(bank->domain, irq);
|
||||
|
||||
if (!virq) {
|
||||
dev_err(bank->dev, "unmapped irq %d\n", irq);
|
||||
continue;
|
||||
}
|
||||
|
||||
pending = readl_relaxed(bank->reg_base + bank->gpio_regs->int_status);
|
||||
for_each_set_bit(irq, &pending, 32) {
|
||||
dev_dbg(bank->dev, "handling irq %d\n", irq);
|
||||
|
||||
/*
|
||||
@ -378,7 +367,7 @@ static void rockchip_irq_demux(struct irq_desc *desc)
|
||||
} while ((data & BIT(irq)) != (data_old & BIT(irq)));
|
||||
}
|
||||
|
||||
generic_handle_irq(virq);
|
||||
generic_handle_domain_irq(bank->domain, irq);
|
||||
}
|
||||
|
||||
chained_irq_exit(chip, desc);
|
||||
|
@ -230,6 +230,7 @@ static void tc3589x_gpio_irq_mask(struct irq_data *d)
|
||||
|
||||
tc3589x_gpio->regs[REG_IE][regoffset] &= ~mask;
|
||||
tc3589x_gpio->regs[REG_DIRECT][regoffset] |= mask;
|
||||
gpiochip_disable_irq(gc, offset);
|
||||
}
|
||||
|
||||
static void tc3589x_gpio_irq_unmask(struct irq_data *d)
|
||||
@ -240,17 +241,20 @@ static void tc3589x_gpio_irq_unmask(struct irq_data *d)
|
||||
int regoffset = offset / 8;
|
||||
int mask = BIT(offset % 8);
|
||||
|
||||
gpiochip_enable_irq(gc, offset);
|
||||
tc3589x_gpio->regs[REG_IE][regoffset] |= mask;
|
||||
tc3589x_gpio->regs[REG_DIRECT][regoffset] &= ~mask;
|
||||
}
|
||||
|
||||
static struct irq_chip tc3589x_gpio_irq_chip = {
|
||||
static const struct irq_chip tc3589x_gpio_irq_chip = {
|
||||
.name = "tc3589x-gpio",
|
||||
.irq_bus_lock = tc3589x_gpio_irq_lock,
|
||||
.irq_bus_sync_unlock = tc3589x_gpio_irq_sync_unlock,
|
||||
.irq_mask = tc3589x_gpio_irq_mask,
|
||||
.irq_unmask = tc3589x_gpio_irq_unmask,
|
||||
.irq_set_type = tc3589x_gpio_irq_set_type,
|
||||
.flags = IRQCHIP_IMMUTABLE,
|
||||
GPIOCHIP_IRQ_RESOURCE_HELPERS,
|
||||
};
|
||||
|
||||
static irqreturn_t tc3589x_gpio_irq(int irq, void *dev)
|
||||
@ -321,7 +325,7 @@ static int tc3589x_gpio_probe(struct platform_device *pdev)
|
||||
tc3589x_gpio->chip.base = -1;
|
||||
|
||||
girq = &tc3589x_gpio->chip.irq;
|
||||
girq->chip = &tc3589x_gpio_irq_chip;
|
||||
gpio_irq_chip_set_chip(girq, &tc3589x_gpio_irq_chip);
|
||||
/* This will let us handle the parent IRQ in the driver */
|
||||
girq->parent_handler = NULL;
|
||||
girq->num_parents = 0;
|
||||
|
@ -465,8 +465,6 @@ static int gpio_twl4030_debounce(u32 debounce, u8 mmc_cd)
|
||||
REG_GPIO_DEBEN1, 3);
|
||||
}
|
||||
|
||||
static int gpio_twl4030_remove(struct platform_device *pdev);
|
||||
|
||||
static struct twl4030_gpio_platform_data *of_gpio_twl4030(struct device *dev,
|
||||
struct twl4030_gpio_platform_data *pdata)
|
||||
{
|
||||
@ -494,6 +492,18 @@ static struct twl4030_gpio_platform_data *of_gpio_twl4030(struct device *dev,
|
||||
return omap_twl_info;
|
||||
}
|
||||
|
||||
/* Cannot use as gpio_twl4030_probe() calls us */
|
||||
static int gpio_twl4030_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct gpio_twl4030_priv *priv = platform_get_drvdata(pdev);
|
||||
|
||||
gpiochip_remove(&priv->gpio_chip);
|
||||
|
||||
/* REVISIT no support yet for deregistering all the IRQs */
|
||||
WARN_ON(!is_module());
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gpio_twl4030_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct twl4030_gpio_platform_data *pdata = dev_get_platdata(&pdev->dev);
|
||||
@ -590,18 +600,6 @@ static int gpio_twl4030_probe(struct platform_device *pdev)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Cannot use as gpio_twl4030_probe() calls us */
|
||||
static int gpio_twl4030_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct gpio_twl4030_priv *priv = platform_get_drvdata(pdev);
|
||||
|
||||
gpiochip_remove(&priv->gpio_chip);
|
||||
|
||||
/* REVISIT no support yet for deregistering all the IRQs */
|
||||
WARN_ON(!is_module());
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id twl_gpio_match[] = {
|
||||
{ .compatible = "ti,twl4030-gpio", },
|
||||
{ },
|
||||
|
@ -7,6 +7,7 @@
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/ucb1400.h>
|
||||
#include <linux/gpio/driver.h>
|
||||
|
||||
static int ucb1400_gpio_dir_in(struct gpio_chip *gc, unsigned off)
|
||||
{
|
||||
|
@ -27,7 +27,8 @@ module_param_hw_array(base, uint, ioport, &num_ws16c48, 0);
|
||||
MODULE_PARM_DESC(base, "WinSystems WS16C48 base addresses");
|
||||
|
||||
static unsigned int irq[MAX_NUM_WS16C48];
|
||||
module_param_hw_array(irq, uint, irq, NULL, 0);
|
||||
static unsigned int num_irq;
|
||||
module_param_hw_array(irq, uint, irq, &num_irq, 0);
|
||||
MODULE_PARM_DESC(irq, "WinSystems WS16C48 interrupt line numbers");
|
||||
|
||||
/**
|
||||
@ -501,7 +502,7 @@ static struct isa_driver ws16c48_driver = {
|
||||
},
|
||||
};
|
||||
|
||||
module_isa_driver(ws16c48_driver, num_ws16c48);
|
||||
module_isa_driver_with_irq(ws16c48_driver, num_ws16c48, num_irq);
|
||||
|
||||
MODULE_AUTHOR("William Breathitt Gray <vilhelm.gray@gmail.com>");
|
||||
MODULE_DESCRIPTION("WinSystems WS16C48 GPIO driver");
|
||||
|
@ -32,9 +32,16 @@ MODULE_PARM_DESC(ignore_wake,
|
||||
"controller@pin combos on which to ignore the ACPI wake flag "
|
||||
"ignore_wake=controller@pin[,controller@pin[,...]]");
|
||||
|
||||
static char *ignore_interrupt;
|
||||
module_param(ignore_interrupt, charp, 0444);
|
||||
MODULE_PARM_DESC(ignore_interrupt,
|
||||
"controller@pin combos on which to ignore interrupt "
|
||||
"ignore_interrupt=controller@pin[,controller@pin[,...]]");
|
||||
|
||||
struct acpi_gpiolib_dmi_quirk {
|
||||
bool no_edge_events_on_boot;
|
||||
char *ignore_wake;
|
||||
char *ignore_interrupt;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -317,14 +324,15 @@ static struct gpio_desc *acpi_request_own_gpiod(struct gpio_chip *chip,
|
||||
return desc;
|
||||
}
|
||||
|
||||
static bool acpi_gpio_in_ignore_list(const char *controller_in, unsigned int pin_in)
|
||||
static bool acpi_gpio_in_ignore_list(const char *ignore_list, const char *controller_in,
|
||||
unsigned int pin_in)
|
||||
{
|
||||
const char *controller, *pin_str;
|
||||
unsigned int pin;
|
||||
char *endp;
|
||||
int len;
|
||||
|
||||
controller = ignore_wake;
|
||||
controller = ignore_list;
|
||||
while (controller) {
|
||||
pin_str = strchr(controller, '@');
|
||||
if (!pin_str)
|
||||
@ -348,7 +356,7 @@ static bool acpi_gpio_in_ignore_list(const char *controller_in, unsigned int pin
|
||||
|
||||
return false;
|
||||
err:
|
||||
pr_err_once("Error: Invalid value for gpiolib_acpi.ignore_wake: %s\n", ignore_wake);
|
||||
pr_err_once("Error: Invalid value for gpiolib_acpi.ignore_...: %s\n", ignore_list);
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -360,7 +368,7 @@ static bool acpi_gpio_irq_is_wake(struct device *parent,
|
||||
if (agpio->wake_capable != ACPI_WAKE_CAPABLE)
|
||||
return false;
|
||||
|
||||
if (acpi_gpio_in_ignore_list(dev_name(parent), pin)) {
|
||||
if (acpi_gpio_in_ignore_list(ignore_wake, dev_name(parent), pin)) {
|
||||
dev_info(parent, "Ignoring wakeup on pin %u\n", pin);
|
||||
return false;
|
||||
}
|
||||
@ -427,6 +435,11 @@ static acpi_status acpi_gpiochip_alloc_event(struct acpi_resource *ares,
|
||||
goto fail_unlock_irq;
|
||||
}
|
||||
|
||||
if (acpi_gpio_in_ignore_list(ignore_interrupt, dev_name(chip->parent), pin)) {
|
||||
dev_info(chip->parent, "Ignoring interrupt on pin %u\n", pin);
|
||||
return AE_OK;
|
||||
}
|
||||
|
||||
event = kzalloc(sizeof(*event), GFP_KERNEL);
|
||||
if (!event)
|
||||
goto fail_unlock_irq;
|
||||
@ -1563,6 +1576,20 @@ static const struct dmi_system_id gpiolib_acpi_quirks[] __initconst = {
|
||||
.ignore_wake = "INT33FF:01@0",
|
||||
},
|
||||
},
|
||||
{
|
||||
/*
|
||||
* Interrupt storm caused from edge triggered floating pin
|
||||
* Found in BIOS UX325UAZ.300
|
||||
* https://bugzilla.kernel.org/show_bug.cgi?id=216208
|
||||
*/
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "ZenBook UX325UAZ_UM325UAZ"),
|
||||
},
|
||||
.driver_data = &(struct acpi_gpiolib_dmi_quirk) {
|
||||
.ignore_interrupt = "AMDI0030:00@18",
|
||||
},
|
||||
},
|
||||
{} /* Terminating entry */
|
||||
};
|
||||
|
||||
@ -1585,6 +1612,9 @@ static int __init acpi_gpio_setup_params(void)
|
||||
if (ignore_wake == NULL && quirk && quirk->ignore_wake)
|
||||
ignore_wake = quirk->ignore_wake;
|
||||
|
||||
if (ignore_interrupt == NULL && quirk && quirk->ignore_interrupt)
|
||||
ignore_interrupt = quirk->ignore_interrupt;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1497,6 +1497,21 @@ static int linereq_release(struct inode *inode, struct file *file)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PROC_FS
|
||||
static void linereq_show_fdinfo(struct seq_file *out, struct file *file)
|
||||
{
|
||||
struct linereq *lr = file->private_data;
|
||||
struct device *dev = &lr->gdev->dev;
|
||||
u16 i;
|
||||
|
||||
seq_printf(out, "gpio-chip:\t%s\n", dev_name(dev));
|
||||
|
||||
for (i = 0; i < lr->num_lines; i++)
|
||||
seq_printf(out, "gpio-line:\t%d\n",
|
||||
gpio_chip_hwgpio(lr->lines[i].desc));
|
||||
}
|
||||
#endif
|
||||
|
||||
static const struct file_operations line_fileops = {
|
||||
.release = linereq_release,
|
||||
.read = linereq_read,
|
||||
@ -1507,6 +1522,9 @@ static const struct file_operations line_fileops = {
|
||||
#ifdef CONFIG_COMPAT
|
||||
.compat_ioctl = linereq_ioctl_compat,
|
||||
#endif
|
||||
#ifdef CONFIG_PROC_FS
|
||||
.show_fdinfo = linereq_show_fdinfo,
|
||||
#endif
|
||||
};
|
||||
|
||||
static int linereq_create(struct gpio_device *gdev, void __user *ip)
|
||||
|
@ -289,6 +289,36 @@ int of_get_named_gpio_flags(const struct device_node *np, const char *list_name,
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(of_get_named_gpio_flags);
|
||||
|
||||
/* Converts gpio_lookup_flags into bitmask of GPIO_* values */
|
||||
static unsigned long of_convert_gpio_flags(enum of_gpio_flags flags)
|
||||
{
|
||||
unsigned long lflags = GPIO_LOOKUP_FLAGS_DEFAULT;
|
||||
|
||||
if (flags & OF_GPIO_ACTIVE_LOW)
|
||||
lflags |= GPIO_ACTIVE_LOW;
|
||||
|
||||
if (flags & OF_GPIO_SINGLE_ENDED) {
|
||||
if (flags & OF_GPIO_OPEN_DRAIN)
|
||||
lflags |= GPIO_OPEN_DRAIN;
|
||||
else
|
||||
lflags |= GPIO_OPEN_SOURCE;
|
||||
}
|
||||
|
||||
if (flags & OF_GPIO_TRANSITORY)
|
||||
lflags |= GPIO_TRANSITORY;
|
||||
|
||||
if (flags & OF_GPIO_PULL_UP)
|
||||
lflags |= GPIO_PULL_UP;
|
||||
|
||||
if (flags & OF_GPIO_PULL_DOWN)
|
||||
lflags |= GPIO_PULL_DOWN;
|
||||
|
||||
if (flags & OF_GPIO_PULL_DISABLE)
|
||||
lflags |= GPIO_PULL_DISABLE;
|
||||
|
||||
return lflags;
|
||||
}
|
||||
|
||||
/**
|
||||
* gpiod_get_from_of_node() - obtain a GPIO from an OF node
|
||||
* @node: handle of the OF node
|
||||
@ -308,26 +338,14 @@ struct gpio_desc *gpiod_get_from_of_node(const struct device_node *node,
|
||||
enum gpiod_flags dflags,
|
||||
const char *label)
|
||||
{
|
||||
unsigned long lflags = GPIO_LOOKUP_FLAGS_DEFAULT;
|
||||
unsigned long lflags;
|
||||
struct gpio_desc *desc;
|
||||
enum of_gpio_flags flags;
|
||||
bool active_low = false;
|
||||
bool single_ended = false;
|
||||
bool open_drain = false;
|
||||
bool transitory = false;
|
||||
enum of_gpio_flags of_flags;
|
||||
int ret;
|
||||
|
||||
desc = of_get_named_gpiod_flags(node, propname,
|
||||
index, &flags);
|
||||
|
||||
if (!desc || IS_ERR(desc)) {
|
||||
desc = of_get_named_gpiod_flags(node, propname, index, &of_flags);
|
||||
if (!desc || IS_ERR(desc))
|
||||
return desc;
|
||||
}
|
||||
|
||||
active_low = flags & OF_GPIO_ACTIVE_LOW;
|
||||
single_ended = flags & OF_GPIO_SINGLE_ENDED;
|
||||
open_drain = flags & OF_GPIO_OPEN_DRAIN;
|
||||
transitory = flags & OF_GPIO_TRANSITORY;
|
||||
|
||||
ret = gpiod_request(desc, label);
|
||||
if (ret == -EBUSY && (dflags & GPIOD_FLAGS_BIT_NONEXCLUSIVE))
|
||||
@ -335,27 +353,7 @@ struct gpio_desc *gpiod_get_from_of_node(const struct device_node *node,
|
||||
if (ret)
|
||||
return ERR_PTR(ret);
|
||||
|
||||
if (active_low)
|
||||
lflags |= GPIO_ACTIVE_LOW;
|
||||
|
||||
if (single_ended) {
|
||||
if (open_drain)
|
||||
lflags |= GPIO_OPEN_DRAIN;
|
||||
else
|
||||
lflags |= GPIO_OPEN_SOURCE;
|
||||
}
|
||||
|
||||
if (transitory)
|
||||
lflags |= GPIO_TRANSITORY;
|
||||
|
||||
if (flags & OF_GPIO_PULL_UP)
|
||||
lflags |= GPIO_PULL_UP;
|
||||
|
||||
if (flags & OF_GPIO_PULL_DOWN)
|
||||
lflags |= GPIO_PULL_DOWN;
|
||||
|
||||
if (flags & OF_GPIO_PULL_DISABLE)
|
||||
lflags |= GPIO_PULL_DISABLE;
|
||||
lflags = of_convert_gpio_flags(of_flags);
|
||||
|
||||
ret = gpiod_configure_flags(desc, propname, lflags, dflags);
|
||||
if (ret < 0) {
|
||||
@ -372,12 +370,12 @@ EXPORT_SYMBOL_GPL(gpiod_get_from_of_node);
|
||||
* properties should be named "foo-gpios" so we have this special kludge for
|
||||
* them.
|
||||
*/
|
||||
static struct gpio_desc *of_find_spi_gpio(struct device *dev, const char *con_id,
|
||||
static struct gpio_desc *of_find_spi_gpio(struct device_node *np,
|
||||
const char *con_id,
|
||||
unsigned int idx,
|
||||
enum of_gpio_flags *of_flags)
|
||||
{
|
||||
char prop_name[32]; /* 32 is max size of property name */
|
||||
const struct device_node *np = dev->of_node;
|
||||
struct gpio_desc *desc;
|
||||
|
||||
/*
|
||||
* Hopefully the compiler stubs the rest of the function if this
|
||||
@ -393,8 +391,7 @@ static struct gpio_desc *of_find_spi_gpio(struct device *dev, const char *con_id
|
||||
/* Will be "gpio-sck", "gpio-mosi" or "gpio-miso" */
|
||||
snprintf(prop_name, sizeof(prop_name), "%s-%s", "gpio", con_id);
|
||||
|
||||
desc = of_get_named_gpiod_flags(np, prop_name, 0, of_flags);
|
||||
return desc;
|
||||
return of_get_named_gpiod_flags(np, prop_name, idx, of_flags);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -402,13 +399,11 @@ static struct gpio_desc *of_find_spi_gpio(struct device *dev, const char *con_id
|
||||
* lines rather than "cs-gpios" like all other SPI hardware. Account for this
|
||||
* with a special quirk.
|
||||
*/
|
||||
static struct gpio_desc *of_find_spi_cs_gpio(struct device *dev,
|
||||
static struct gpio_desc *of_find_spi_cs_gpio(struct device_node *np,
|
||||
const char *con_id,
|
||||
unsigned int idx,
|
||||
unsigned long *flags)
|
||||
enum of_gpio_flags *of_flags)
|
||||
{
|
||||
const struct device_node *np = dev->of_node;
|
||||
|
||||
if (!IS_ENABLED(CONFIG_SPI_MASTER))
|
||||
return ERR_PTR(-ENOENT);
|
||||
|
||||
@ -426,7 +421,7 @@ static struct gpio_desc *of_find_spi_cs_gpio(struct device *dev,
|
||||
* uses just "gpios" so translate to that when "cs-gpios" is
|
||||
* requested.
|
||||
*/
|
||||
return of_find_gpio(dev, NULL, idx, flags);
|
||||
return of_get_named_gpiod_flags(np, "gpios", idx, of_flags);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -434,7 +429,9 @@ static struct gpio_desc *of_find_spi_cs_gpio(struct device *dev,
|
||||
* properties should be named "foo-gpios" so we have this special kludge for
|
||||
* them.
|
||||
*/
|
||||
static struct gpio_desc *of_find_regulator_gpio(struct device *dev, const char *con_id,
|
||||
static struct gpio_desc *of_find_regulator_gpio(struct device_node *np,
|
||||
const char *con_id,
|
||||
unsigned int idx,
|
||||
enum of_gpio_flags *of_flags)
|
||||
{
|
||||
/* These are the connection IDs we accept as legacy GPIO phandles */
|
||||
@ -443,8 +440,6 @@ static struct gpio_desc *of_find_regulator_gpio(struct device *dev, const char *
|
||||
"wlf,ldo1ena", /* WM8994 */
|
||||
"wlf,ldo2ena", /* WM8994 */
|
||||
};
|
||||
const struct device_node *np = dev->of_node;
|
||||
struct gpio_desc *desc;
|
||||
int i;
|
||||
|
||||
if (!IS_ENABLED(CONFIG_REGULATOR))
|
||||
@ -457,12 +452,12 @@ static struct gpio_desc *of_find_regulator_gpio(struct device *dev, const char *
|
||||
if (i < 0)
|
||||
return ERR_PTR(-ENOENT);
|
||||
|
||||
desc = of_get_named_gpiod_flags(np, con_id, 0, of_flags);
|
||||
return desc;
|
||||
return of_get_named_gpiod_flags(np, con_id, idx, of_flags);
|
||||
}
|
||||
|
||||
static struct gpio_desc *of_find_arizona_gpio(struct device *dev,
|
||||
static struct gpio_desc *of_find_arizona_gpio(struct device_node *np,
|
||||
const char *con_id,
|
||||
unsigned int idx,
|
||||
enum of_gpio_flags *of_flags)
|
||||
{
|
||||
if (!IS_ENABLED(CONFIG_MFD_ARIZONA))
|
||||
@ -471,17 +466,18 @@ static struct gpio_desc *of_find_arizona_gpio(struct device *dev,
|
||||
if (!con_id || strcmp(con_id, "wlf,reset"))
|
||||
return ERR_PTR(-ENOENT);
|
||||
|
||||
return of_get_named_gpiod_flags(dev->of_node, con_id, 0, of_flags);
|
||||
return of_get_named_gpiod_flags(np, con_id, idx, of_flags);
|
||||
}
|
||||
|
||||
static struct gpio_desc *of_find_usb_gpio(struct device *dev,
|
||||
static struct gpio_desc *of_find_usb_gpio(struct device_node *np,
|
||||
const char *con_id,
|
||||
unsigned int idx,
|
||||
enum of_gpio_flags *of_flags)
|
||||
{
|
||||
/*
|
||||
* Currently this USB quirk is only for the Fairchild FUSB302 host which is using
|
||||
* an undocumented DT GPIO line named "fcs,int_n" without the compulsory "-gpios"
|
||||
* suffix.
|
||||
* Currently this USB quirk is only for the Fairchild FUSB302 host
|
||||
* which is using an undocumented DT GPIO line named "fcs,int_n"
|
||||
* without the compulsory "-gpios" suffix.
|
||||
*/
|
||||
if (!IS_ENABLED(CONFIG_TYPEC_FUSB302))
|
||||
return ERR_PTR(-ENOENT);
|
||||
@ -489,14 +485,28 @@ static struct gpio_desc *of_find_usb_gpio(struct device *dev,
|
||||
if (!con_id || strcmp(con_id, "fcs,int_n"))
|
||||
return ERR_PTR(-ENOENT);
|
||||
|
||||
return of_get_named_gpiod_flags(dev->of_node, con_id, 0, of_flags);
|
||||
return of_get_named_gpiod_flags(np, con_id, idx, of_flags);
|
||||
}
|
||||
|
||||
typedef struct gpio_desc *(*of_find_gpio_quirk)(struct device_node *np,
|
||||
const char *con_id,
|
||||
unsigned int idx,
|
||||
enum of_gpio_flags *of_flags);
|
||||
static const of_find_gpio_quirk of_find_gpio_quirks[] = {
|
||||
of_find_spi_gpio,
|
||||
of_find_spi_cs_gpio,
|
||||
of_find_regulator_gpio,
|
||||
of_find_arizona_gpio,
|
||||
of_find_usb_gpio,
|
||||
NULL
|
||||
};
|
||||
|
||||
struct gpio_desc *of_find_gpio(struct device *dev, const char *con_id,
|
||||
unsigned int idx, unsigned long *flags)
|
||||
{
|
||||
char prop_name[32]; /* 32 is max size of property name */
|
||||
enum of_gpio_flags of_flags;
|
||||
const of_find_gpio_quirk *q;
|
||||
struct gpio_desc *desc;
|
||||
unsigned int i;
|
||||
|
||||
@ -516,51 +526,14 @@ struct gpio_desc *of_find_gpio(struct device *dev, const char *con_id,
|
||||
break;
|
||||
}
|
||||
|
||||
if (gpiod_not_found(desc)) {
|
||||
/* Special handling for SPI GPIOs if used */
|
||||
desc = of_find_spi_gpio(dev, con_id, &of_flags);
|
||||
}
|
||||
|
||||
if (gpiod_not_found(desc)) {
|
||||
/* This quirk looks up flags and all */
|
||||
desc = of_find_spi_cs_gpio(dev, con_id, idx, flags);
|
||||
if (!IS_ERR(desc))
|
||||
return desc;
|
||||
}
|
||||
|
||||
if (gpiod_not_found(desc)) {
|
||||
/* Special handling for regulator GPIOs if used */
|
||||
desc = of_find_regulator_gpio(dev, con_id, &of_flags);
|
||||
}
|
||||
|
||||
if (gpiod_not_found(desc))
|
||||
desc = of_find_arizona_gpio(dev, con_id, &of_flags);
|
||||
|
||||
if (gpiod_not_found(desc))
|
||||
desc = of_find_usb_gpio(dev, con_id, &of_flags);
|
||||
/* Properly named GPIO was not found, try workarounds */
|
||||
for (q = of_find_gpio_quirks; gpiod_not_found(desc) && *q; q++)
|
||||
desc = (*q)(dev->of_node, con_id, idx, &of_flags);
|
||||
|
||||
if (IS_ERR(desc))
|
||||
return desc;
|
||||
|
||||
if (of_flags & OF_GPIO_ACTIVE_LOW)
|
||||
*flags |= GPIO_ACTIVE_LOW;
|
||||
|
||||
if (of_flags & OF_GPIO_SINGLE_ENDED) {
|
||||
if (of_flags & OF_GPIO_OPEN_DRAIN)
|
||||
*flags |= GPIO_OPEN_DRAIN;
|
||||
else
|
||||
*flags |= GPIO_OPEN_SOURCE;
|
||||
}
|
||||
|
||||
if (of_flags & OF_GPIO_TRANSITORY)
|
||||
*flags |= GPIO_TRANSITORY;
|
||||
|
||||
if (of_flags & OF_GPIO_PULL_UP)
|
||||
*flags |= GPIO_PULL_UP;
|
||||
if (of_flags & OF_GPIO_PULL_DOWN)
|
||||
*flags |= GPIO_PULL_DOWN;
|
||||
if (of_flags & OF_GPIO_PULL_DISABLE)
|
||||
*flags |= GPIO_PULL_DISABLE;
|
||||
*flags = of_convert_gpio_flags(of_flags);
|
||||
|
||||
return desc;
|
||||
}
|
||||
@ -618,16 +591,7 @@ static struct gpio_desc *of_parse_own_gpio(struct device_node *np,
|
||||
if (IS_ERR(desc))
|
||||
return desc;
|
||||
|
||||
if (xlate_flags & OF_GPIO_ACTIVE_LOW)
|
||||
*lflags |= GPIO_ACTIVE_LOW;
|
||||
if (xlate_flags & OF_GPIO_TRANSITORY)
|
||||
*lflags |= GPIO_TRANSITORY;
|
||||
if (xlate_flags & OF_GPIO_PULL_UP)
|
||||
*lflags |= GPIO_PULL_UP;
|
||||
if (xlate_flags & OF_GPIO_PULL_DOWN)
|
||||
*lflags |= GPIO_PULL_DOWN;
|
||||
if (xlate_flags & OF_GPIO_PULL_DISABLE)
|
||||
*lflags |= GPIO_PULL_DISABLE;
|
||||
*lflags = of_convert_gpio_flags(xlate_flags);
|
||||
|
||||
if (of_property_read_bool(np, "input"))
|
||||
*dflags |= GPIOD_IN;
|
||||
|
@ -3798,6 +3798,72 @@ static int platform_gpio_count(struct device *dev, const char *con_id)
|
||||
return count;
|
||||
}
|
||||
|
||||
/**
|
||||
* fwnode_get_named_gpiod - obtain a GPIO from firmware node
|
||||
* @fwnode: handle of the firmware node
|
||||
* @propname: name of the firmware property representing the GPIO
|
||||
* @index: index of the GPIO to obtain for the consumer
|
||||
* @dflags: GPIO initialization flags
|
||||
* @label: label to attach to the requested GPIO
|
||||
*
|
||||
* This function can be used for drivers that get their configuration
|
||||
* from opaque firmware.
|
||||
*
|
||||
* The function properly finds the corresponding GPIO using whatever is the
|
||||
* underlying firmware interface and then makes sure that the GPIO
|
||||
* descriptor is requested before it is returned to the caller.
|
||||
*
|
||||
* Returns:
|
||||
* On successful request the GPIO pin is configured in accordance with
|
||||
* provided @dflags.
|
||||
*
|
||||
* In case of error an ERR_PTR() is returned.
|
||||
*/
|
||||
static struct gpio_desc *fwnode_get_named_gpiod(struct fwnode_handle *fwnode,
|
||||
const char *propname, int index,
|
||||
enum gpiod_flags dflags,
|
||||
const char *label)
|
||||
{
|
||||
unsigned long lflags = GPIO_LOOKUP_FLAGS_DEFAULT;
|
||||
struct gpio_desc *desc = ERR_PTR(-ENODEV);
|
||||
int ret;
|
||||
|
||||
if (is_of_node(fwnode)) {
|
||||
desc = gpiod_get_from_of_node(to_of_node(fwnode),
|
||||
propname, index,
|
||||
dflags,
|
||||
label);
|
||||
return desc;
|
||||
} else if (is_acpi_node(fwnode)) {
|
||||
struct acpi_gpio_info info;
|
||||
|
||||
desc = acpi_node_get_gpiod(fwnode, propname, index, &info);
|
||||
if (IS_ERR(desc))
|
||||
return desc;
|
||||
|
||||
acpi_gpio_update_gpiod_flags(&dflags, &info);
|
||||
acpi_gpio_update_gpiod_lookup_flags(&lflags, &info);
|
||||
} else {
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
/* Currently only ACPI takes this path */
|
||||
ret = gpiod_request(desc, label);
|
||||
if (ret)
|
||||
return ERR_PTR(ret);
|
||||
|
||||
ret = gpiod_configure_flags(desc, propname, lflags, dflags);
|
||||
if (ret < 0) {
|
||||
gpiod_put(desc);
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
blocking_notifier_call_chain(&desc->gdev->notifier,
|
||||
GPIOLINE_CHANGED_REQUESTED, desc);
|
||||
|
||||
return desc;
|
||||
}
|
||||
|
||||
/**
|
||||
* fwnode_gpiod_get_index - obtain a GPIO from firmware node
|
||||
* @fwnode: handle of the firmware node
|
||||
@ -4063,72 +4129,6 @@ struct gpio_desc *__must_check gpiod_get_index(struct device *dev,
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(gpiod_get_index);
|
||||
|
||||
/**
|
||||
* fwnode_get_named_gpiod - obtain a GPIO from firmware node
|
||||
* @fwnode: handle of the firmware node
|
||||
* @propname: name of the firmware property representing the GPIO
|
||||
* @index: index of the GPIO to obtain for the consumer
|
||||
* @dflags: GPIO initialization flags
|
||||
* @label: label to attach to the requested GPIO
|
||||
*
|
||||
* This function can be used for drivers that get their configuration
|
||||
* from opaque firmware.
|
||||
*
|
||||
* The function properly finds the corresponding GPIO using whatever is the
|
||||
* underlying firmware interface and then makes sure that the GPIO
|
||||
* descriptor is requested before it is returned to the caller.
|
||||
*
|
||||
* Returns:
|
||||
* On successful request the GPIO pin is configured in accordance with
|
||||
* provided @dflags.
|
||||
*
|
||||
* In case of error an ERR_PTR() is returned.
|
||||
*/
|
||||
struct gpio_desc *fwnode_get_named_gpiod(struct fwnode_handle *fwnode,
|
||||
const char *propname, int index,
|
||||
enum gpiod_flags dflags,
|
||||
const char *label)
|
||||
{
|
||||
unsigned long lflags = GPIO_LOOKUP_FLAGS_DEFAULT;
|
||||
struct gpio_desc *desc = ERR_PTR(-ENODEV);
|
||||
int ret;
|
||||
|
||||
if (is_of_node(fwnode)) {
|
||||
desc = gpiod_get_from_of_node(to_of_node(fwnode),
|
||||
propname, index,
|
||||
dflags,
|
||||
label);
|
||||
return desc;
|
||||
} else if (is_acpi_node(fwnode)) {
|
||||
struct acpi_gpio_info info;
|
||||
|
||||
desc = acpi_node_get_gpiod(fwnode, propname, index, &info);
|
||||
if (IS_ERR(desc))
|
||||
return desc;
|
||||
|
||||
acpi_gpio_update_gpiod_flags(&dflags, &info);
|
||||
acpi_gpio_update_gpiod_lookup_flags(&lflags, &info);
|
||||
} else
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
/* Currently only ACPI takes this path */
|
||||
ret = gpiod_request(desc, label);
|
||||
if (ret)
|
||||
return ERR_PTR(ret);
|
||||
|
||||
ret = gpiod_configure_flags(desc, propname, lflags, dflags);
|
||||
if (ret < 0) {
|
||||
gpiod_put(desc);
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
blocking_notifier_call_chain(&desc->gdev->notifier,
|
||||
GPIOLINE_CHANGED_REQUESTED, desc);
|
||||
|
||||
return desc;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(fwnode_get_named_gpiod);
|
||||
|
||||
/**
|
||||
* gpiod_get_index_optional - obtain an optional GPIO from a multi-index GPIO
|
||||
* function
|
||||
|
@ -174,10 +174,6 @@ int desc_to_gpio(const struct gpio_desc *desc);
|
||||
/* Child properties interface */
|
||||
struct fwnode_handle;
|
||||
|
||||
struct gpio_desc *fwnode_get_named_gpiod(struct fwnode_handle *fwnode,
|
||||
const char *propname, int index,
|
||||
enum gpiod_flags dflags,
|
||||
const char *label);
|
||||
struct gpio_desc *fwnode_gpiod_get_index(struct fwnode_handle *fwnode,
|
||||
const char *con_id, int index,
|
||||
enum gpiod_flags flags,
|
||||
@ -553,15 +549,6 @@ static inline int desc_to_gpio(const struct gpio_desc *desc)
|
||||
/* Child properties interface */
|
||||
struct fwnode_handle;
|
||||
|
||||
static inline
|
||||
struct gpio_desc *fwnode_get_named_gpiod(struct fwnode_handle *fwnode,
|
||||
const char *propname, int index,
|
||||
enum gpiod_flags dflags,
|
||||
const char *label)
|
||||
{
|
||||
return ERR_PTR(-ENOSYS);
|
||||
}
|
||||
|
||||
static inline
|
||||
struct gpio_desc *fwnode_gpiod_get_index(struct fwnode_handle *fwnode,
|
||||
const char *con_id, int index,
|
||||
|
@ -38,6 +38,32 @@ static inline void isa_unregister_driver(struct isa_driver *d)
|
||||
}
|
||||
#endif
|
||||
|
||||
#define module_isa_driver_init(__isa_driver, __num_isa_dev) \
|
||||
static int __init __isa_driver##_init(void) \
|
||||
{ \
|
||||
return isa_register_driver(&(__isa_driver), __num_isa_dev); \
|
||||
} \
|
||||
module_init(__isa_driver##_init)
|
||||
|
||||
#define module_isa_driver_with_irq_init(__isa_driver, __num_isa_dev, __num_irq) \
|
||||
static int __init __isa_driver##_init(void) \
|
||||
{ \
|
||||
if (__num_irq != __num_isa_dev) { \
|
||||
pr_err("%s: Number of irq (%u) does not match number of base (%u)\n", \
|
||||
__isa_driver.driver.name, __num_irq, __num_isa_dev); \
|
||||
return -EINVAL; \
|
||||
} \
|
||||
return isa_register_driver(&(__isa_driver), __num_isa_dev); \
|
||||
} \
|
||||
module_init(__isa_driver##_init)
|
||||
|
||||
#define module_isa_driver_exit(__isa_driver) \
|
||||
static void __exit __isa_driver##_exit(void) \
|
||||
{ \
|
||||
isa_unregister_driver(&(__isa_driver)); \
|
||||
} \
|
||||
module_exit(__isa_driver##_exit)
|
||||
|
||||
/**
|
||||
* module_isa_driver() - Helper macro for registering a ISA driver
|
||||
* @__isa_driver: isa_driver struct
|
||||
@ -48,16 +74,22 @@ static inline void isa_unregister_driver(struct isa_driver *d)
|
||||
* use this macro once, and calling it replaces module_init and module_exit.
|
||||
*/
|
||||
#define module_isa_driver(__isa_driver, __num_isa_dev) \
|
||||
static int __init __isa_driver##_init(void) \
|
||||
{ \
|
||||
return isa_register_driver(&(__isa_driver), __num_isa_dev); \
|
||||
} \
|
||||
module_init(__isa_driver##_init); \
|
||||
static void __exit __isa_driver##_exit(void) \
|
||||
{ \
|
||||
isa_unregister_driver(&(__isa_driver)); \
|
||||
} \
|
||||
module_exit(__isa_driver##_exit);
|
||||
module_isa_driver_init(__isa_driver, __num_isa_dev); \
|
||||
module_isa_driver_exit(__isa_driver)
|
||||
|
||||
/**
|
||||
* module_isa_driver_with_irq() - Helper macro for registering an ISA driver with irq
|
||||
* @__isa_driver: isa_driver struct
|
||||
* @__num_isa_dev: number of devices to register
|
||||
* @__num_irq: number of IRQ to register
|
||||
*
|
||||
* Helper macro for ISA drivers with irq that do not do anything special in
|
||||
* module init/exit. Each module may only use this macro once, and calling it
|
||||
* replaces module_init and module_exit.
|
||||
*/
|
||||
#define module_isa_driver_with_irq(__isa_driver, __num_isa_dev, __num_irq) \
|
||||
module_isa_driver_with_irq_init(__isa_driver, __num_isa_dev, __num_irq); \
|
||||
module_isa_driver_exit(__isa_driver)
|
||||
|
||||
/**
|
||||
* max_num_isa_dev() - Maximum possible number registered of an ISA device
|
||||
|
@ -23,7 +23,7 @@
|
||||
#include <sound/ac97_codec.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/gpio/driver.h>
|
||||
|
||||
/*
|
||||
* UCB1400 AC-link registers
|
||||
|
Loading…
Reference in New Issue
Block a user