gpio updates for v6.3
Core GPIOLIB: - drop several OF interfaces after moving a significant part of the code to using software nodes - remove more interfaces referring to the global GPIO numberspace that we're getting rid of - improvements in the gpio-regmap library - add helper for GPIO device reference counting - remove unused APIs - minor tweaks like sorting headers alphabetically Extended support in existing drivers: - add support for Tegra 234 PMC to gpio-tegra186 Driver improvements: - migrate the 104-dio/idi family of drivers to using the regmap-irq API - migrate gpio-i8255 and gpio-mm to the GPIO regmap API - clean-ups in gpio-pca953x - remove duplicate assignments of of_gpio_n_cells in gpio-davinci, gpio-ge, gpio-xilinx, gpio-zevio and gpio-wcd934x - improvements to gpio-pcf857x: implement get/set_multiple callbacks, use generic device properties instead of OF + minor tweaks - fix OF-related header includes and Kconfig dependencies in gpio-zevio - dynamically allocate the GPIO base in gpio-omap - use a dedicated printf specifier for printing fwnode info in gpio-sim - use dev_name() for the GPIO chip label in gpio-vf610 - other minor tweaks and fixes Documentation: - remove mentions of legacy API from comments in various places - convert the DT binding documents to YAML schema for Fujitsu MB86S7x, Unisoc GPIO and Unisoc EIC - document the Unisoc UMS512 controller in DT bindings -----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEEFp3rbAvDxGAT0sefEacuoBRx13IFAmP13YgACgkQEacuoBRx 13L7Ng/+P1e/j+Z32kPrpiKTChHnQ5ty9VFGwQQX2Gva32bRh/WuzhI2leHUIzOb a6qnwxoVUPml6IEoh8jctENM4/J/BBtEkmXAl3f4sd3j7yz7G85y3XiV5qyRV4lH dNWjvwtfATI0nxp58NiqRiZVx2W62AJtNgHOaG+OMe+KL6GZf6F/nEqtRGFHA3yi pxmajxIRADCgEH9lQ61B6MSd8tM2EEEe2G36mHQRni85L2XSXl6r7zbWFLtdLTf3 KkSM4f8gjIMud6tZr7TsS7l3afZXCrtxrF74/WCYLInRNWuMkC9sHU/EkyfnqoVS MYMfaprhXP6gyVxJJrqPwJOo1mSMAijIga6HzmcMF6MmozwmbpYeUiTEVW48fxLg tHZV2CzxOJqXC36RDIUGDYalHmyknVsK8CeGtHuJNg87TAczRX/tAJtyji3Y1yQd YRAKVp2akkc8uzPKf8UU0Vnp+vgej84RbKsjHs+7NoPepQW6lG8iYDMNMMiokYAH EvXlakqSbQiIdipF7vsk6NuWMlXn1LusL9SdxC7332l88Ix7wFlhtNr1Ggf8kdmB nPrmG3EqG/zXm+3AYvFY6xbAVXOsNwU1K+/4et5sRTG8lWNrB73qMAi0UYOm25J5 A4VTaGQyP4Coqa+1yoVsaequOrkq7WsZVakLMMUGGrWva11Ajl0= =wWXb -----END PGP SIGNATURE----- Merge tag 'gpio-updates-for-v6.3' of git://git.kernel.org/pub/scm/linux/kernel/git/brgl/linux Pull gpio updates from Bartosz Golaszewski: "A rather small update, there are no new drivers, just improvements and refactoring in existing ones. Thanks to migrating of several drivers to using generalized APIs and dropping of OF interfaces in favor of using software nodes we're actually removing more code than we're adding. Core GPIOLIB: - drop several OF interfaces after moving a significant part of the code to using software nodes - remove more interfaces referring to the global GPIO numberspace that we're getting rid of - improvements in the gpio-regmap library - add helper for GPIO device reference counting - remove unused APIs - minor tweaks like sorting headers alphabetically Extended support in existing drivers: - add support for Tegra 234 PMC to gpio-tegra186 Driver improvements: - migrate the 104-dio/idi family of drivers to using the regmap-irq API - migrate gpio-i8255 and gpio-mm to the GPIO regmap API - clean-ups in gpio-pca953x - remove duplicate assignments of of_gpio_n_cells in gpio-davinci, gpio-ge, gpio-xilinx, gpio-zevio and gpio-wcd934x - improvements to gpio-pcf857x: implement get/set_multiple callbacks, use generic device properties instead of OF + minor tweaks - fix OF-related header includes and Kconfig dependencies in gpio-zevio - dynamically allocate the GPIO base in gpio-omap - use a dedicated printf specifier for printing fwnode info in gpio-sim - use dev_name() for the GPIO chip label in gpio-vf610 - other minor tweaks and fixes Documentation: - remove mentions of legacy API from comments in various places - convert the DT binding documents to YAML schema for Fujitsu MB86S7x, Unisoc GPIO and Unisoc EIC - document the Unisoc UMS512 controller in DT bindings" * tag 'gpio-updates-for-v6.3' of git://git.kernel.org/pub/scm/linux/kernel/git/brgl/linux: (54 commits) gpio: sim: Use %pfwP specifier instead of calling fwnode API directly gpio: tegra186: remove unneeded loop in tegra186_gpio_init_route_mapping() gpiolib: of: Move enum of_gpio_flags to its only user gpio: mvebu: Use IS_REACHABLE instead of IS_ENABLED for CONFIG_PWM gpio: zevio: Add missing header gpio: Get rid of gpio_to_chip() gpio: pcf857x: Drop unneeded explicit casting gpio: pcf857x: Make use of device properties gpio: pcf857x: Get rid of legacy platform data gpio: rockchip: Do not mention legacy API in the code gpio: wcd934x: Remove duplicate assignment of of_gpio_n_cells gpio: zevio: Use proper headers and drop OF_GPIO dependency gpio: zevio: Remove duplicate assignment of of_gpio_n_cells gpio: xilinx: Remove duplicate assignment of of_gpio_n_cells dt-bindings: gpio: Add compatible string for Unisoc UMS512 dt-bindings: gpio: Convert Unisoc EIC controller binding to yaml dt-bindings: gpio: Convert Unisoc GPIO controller binding to yaml gpio: ge: Remove duplicate assignment of of_gpio_n_cells gpio: davinci: Remove duplicate assignment of of_gpio_n_cells gpio: omap: use dynamic allocation of base ...
This commit is contained in:
Коммит
17bbc46fc9
|
@ -1,20 +0,0 @@
|
|||
Fujitsu MB86S7x GPIO Controller
|
||||
-------------------------------
|
||||
|
||||
Required properties:
|
||||
- compatible: Should be "fujitsu,mb86s70-gpio"
|
||||
- reg: Base address and length of register space
|
||||
- clocks: Specify the clock
|
||||
- gpio-controller: Marks the device node as a gpio controller.
|
||||
- #gpio-cells: Should be <2>. The first cell is the pin number and the
|
||||
second cell is used to specify optional parameters:
|
||||
- bit 0 specifies polarity (0 for normal, 1 for inverted).
|
||||
|
||||
Examples:
|
||||
gpio0: gpio@31000000 {
|
||||
compatible = "fujitsu,mb86s70-gpio";
|
||||
reg = <0 0x31000000 0x10000>;
|
||||
gpio-controller;
|
||||
#gpio-cells = <2>;
|
||||
clocks = <&clk 0 2 1>;
|
||||
};
|
|
@ -0,0 +1,50 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/gpio/fujitsu,mb86s70-gpio.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Fujitsu MB86S7x GPIO Controller
|
||||
|
||||
maintainers:
|
||||
- Jassi Brar <jaswinder.singh@linaro.org>
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
oneOf:
|
||||
- items:
|
||||
- const: socionext,synquacer-gpio
|
||||
- const: fujitsu,mb86s70-gpio
|
||||
- const: fujitsu,mb86s70-gpio
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
'#gpio-cells':
|
||||
const: 2
|
||||
|
||||
gpio-controller: true
|
||||
gpio-line-names: true
|
||||
|
||||
clocks:
|
||||
maxItems: 1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- '#gpio-cells'
|
||||
- gpio-controller
|
||||
- clocks
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
gpio@31000000 {
|
||||
compatible = "fujitsu,mb86s70-gpio";
|
||||
reg = <0x31000000 0x10000>;
|
||||
gpio-controller;
|
||||
#gpio-cells = <2>;
|
||||
clocks = <&clk 0 2 1>;
|
||||
};
|
||||
...
|
|
@ -1,97 +0,0 @@
|
|||
Spreadtrum EIC controller bindings
|
||||
|
||||
The EIC is the abbreviation of external interrupt controller, which can
|
||||
be used only in input mode. The Spreadtrum platform has 2 EIC controllers,
|
||||
one is in digital chip, and another one is in PMIC. The digital chip EIC
|
||||
controller contains 4 sub-modules: EIC-debounce, EIC-latch, EIC-async and
|
||||
EIC-sync. But the PMIC EIC controller contains only one EIC-debounce sub-
|
||||
module.
|
||||
|
||||
The EIC-debounce sub-module provides up to 8 source input signal
|
||||
connections. A debounce mechanism is used to capture the input signals'
|
||||
stable status (millisecond resolution) and a single-trigger mechanism
|
||||
is introduced into this sub-module to enhance the input event detection
|
||||
reliability. In addition, this sub-module's clock can be shut off
|
||||
automatically to reduce power dissipation. Moreover the debounce range
|
||||
is from 1ms to 4s with a step size of 1ms. The input signal will be
|
||||
ignored if it is asserted for less than 1 ms.
|
||||
|
||||
The EIC-latch sub-module is used to latch some special power down signals
|
||||
and generate interrupts, since the EIC-latch does not depend on the APB
|
||||
clock to capture signals.
|
||||
|
||||
The EIC-async sub-module uses a 32kHz clock to capture the short signals
|
||||
(microsecond resolution) to generate interrupts by level or edge trigger.
|
||||
|
||||
The EIC-sync is similar with GPIO's input function, which is a synchronized
|
||||
signal input register. It can generate interrupts by level or edge trigger
|
||||
when detecting input signals.
|
||||
|
||||
Required properties:
|
||||
- compatible: Should be one of the following:
|
||||
"sprd,sc9860-eic-debounce",
|
||||
"sprd,sc9860-eic-latch",
|
||||
"sprd,sc9860-eic-async",
|
||||
"sprd,sc9860-eic-sync",
|
||||
"sprd,sc2731-eic".
|
||||
- reg: Define the base and range of the I/O address space containing
|
||||
the GPIO controller registers.
|
||||
- gpio-controller: Marks the device node as a GPIO controller.
|
||||
- #gpio-cells: Should be <2>. The first cell is the gpio number and
|
||||
the second cell is used to specify optional parameters.
|
||||
- interrupt-controller: Marks the device node as an interrupt controller.
|
||||
- #interrupt-cells: Should be <2>. Specifies the number of cells needed
|
||||
to encode interrupt source.
|
||||
- interrupts: Should be the port interrupt shared by all the gpios.
|
||||
|
||||
Example:
|
||||
eic_debounce: gpio@40210000 {
|
||||
compatible = "sprd,sc9860-eic-debounce";
|
||||
reg = <0 0x40210000 0 0x80>;
|
||||
gpio-controller;
|
||||
#gpio-cells = <2>;
|
||||
interrupt-controller;
|
||||
#interrupt-cells = <2>;
|
||||
interrupts = <GIC_SPI 52 IRQ_TYPE_LEVEL_HIGH>;
|
||||
};
|
||||
|
||||
eic_latch: gpio@40210080 {
|
||||
compatible = "sprd,sc9860-eic-latch";
|
||||
reg = <0 0x40210080 0 0x20>;
|
||||
gpio-controller;
|
||||
#gpio-cells = <2>;
|
||||
interrupt-controller;
|
||||
#interrupt-cells = <2>;
|
||||
interrupts = <GIC_SPI 52 IRQ_TYPE_LEVEL_HIGH>;
|
||||
};
|
||||
|
||||
eic_async: gpio@402100a0 {
|
||||
compatible = "sprd,sc9860-eic-async";
|
||||
reg = <0 0x402100a0 0 0x20>;
|
||||
gpio-controller;
|
||||
#gpio-cells = <2>;
|
||||
interrupt-controller;
|
||||
#interrupt-cells = <2>;
|
||||
interrupts = <GIC_SPI 52 IRQ_TYPE_LEVEL_HIGH>;
|
||||
};
|
||||
|
||||
eic_sync: gpio@402100c0 {
|
||||
compatible = "sprd,sc9860-eic-sync";
|
||||
reg = <0 0x402100c0 0 0x20>;
|
||||
gpio-controller;
|
||||
#gpio-cells = <2>;
|
||||
interrupt-controller;
|
||||
#interrupt-cells = <2>;
|
||||
interrupts = <GIC_SPI 52 IRQ_TYPE_LEVEL_HIGH>;
|
||||
};
|
||||
|
||||
pmic_eic: gpio@300 {
|
||||
compatible = "sprd,sc2731-eic";
|
||||
reg = <0x300>;
|
||||
interrupt-parent = <&sc2731_pmic>;
|
||||
interrupts = <5 IRQ_TYPE_LEVEL_HIGH>;
|
||||
gpio-controller;
|
||||
#gpio-cells = <2>;
|
||||
interrupt-controller;
|
||||
#interrupt-cells = <2>;
|
||||
};
|
|
@ -1,28 +0,0 @@
|
|||
Spreadtrum GPIO controller bindings
|
||||
|
||||
The controller's registers are organized as sets of sixteen 16-bit
|
||||
registers with each set controlling a bank of up to 16 pins. A single
|
||||
interrupt is shared for all of the banks handled by the controller.
|
||||
|
||||
Required properties:
|
||||
- compatible: Should be "sprd,sc9860-gpio".
|
||||
- reg: Define the base and range of the I/O address space containing
|
||||
the GPIO controller registers.
|
||||
- gpio-controller: Marks the device node as a GPIO controller.
|
||||
- #gpio-cells: Should be <2>. The first cell is the gpio number and
|
||||
the second cell is used to specify optional parameters.
|
||||
- interrupt-controller: Marks the device node as an interrupt controller.
|
||||
- #interrupt-cells: Should be <2>. Specifies the number of cells needed
|
||||
to encode interrupt source.
|
||||
- interrupts: Should be the port interrupt shared by all the gpios.
|
||||
|
||||
Example:
|
||||
ap_gpio: gpio@40280000 {
|
||||
compatible = "sprd,sc9860-gpio";
|
||||
reg = <0 0x40280000 0 0x1000>;
|
||||
gpio-controller;
|
||||
#gpio-cells = <2>;
|
||||
interrupt-controller;
|
||||
#interrupt-cells = <2>;
|
||||
interrupts = <GIC_SPI 50 IRQ_TYPE_LEVEL_HIGH>;
|
||||
};
|
|
@ -0,0 +1,124 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
# Copyright 2022 Unisoc Inc.
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/gpio/sprd,gpio-eic.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Unisoc EIC controller
|
||||
|
||||
maintainers:
|
||||
- Orson Zhai <orsonzhai@gmail.com>
|
||||
- Baolin Wang <baolin.wang7@gmail.com>
|
||||
- Chunyan Zhang <zhang.lyra@gmail.com>
|
||||
|
||||
description: |
|
||||
The EIC is the abbreviation of external interrupt controller, which can
|
||||
be used only in input mode. The Spreadtrum platform has 2 EIC controllers,
|
||||
one is in digital chip, and another one is in PMIC. The digital chip EIC
|
||||
controller contains 4 sub-modules, i.e. EIC-debounce, EIC-latch, EIC-async and
|
||||
EIC-sync. But the PMIC EIC controller contains only one EIC-debounce sub-
|
||||
module.
|
||||
|
||||
The EIC-debounce sub-module provides up to 8 source input signal
|
||||
connections. A debounce mechanism is used to capture the input signals'
|
||||
stable status (millisecond resolution) and a single-trigger mechanism
|
||||
is introduced into this sub-module to enhance the input event detection
|
||||
reliability. In addition, this sub-module's clock can be shut off
|
||||
automatically to reduce power dissipation. Moreover the debounce range
|
||||
is from 1ms to 4s with a step size of 1ms. The input signal will be
|
||||
ignored if it is asserted for less than 1 ms.
|
||||
|
||||
The EIC-latch sub-module is used to latch some special power down signals
|
||||
and generate interrupts, since the EIC-latch does not depend on the APB
|
||||
clock to capture signals.
|
||||
|
||||
The EIC-async sub-module uses a 32kHz clock to capture the short signals
|
||||
(microsecond resolution) to generate interrupts by level or edge trigger.
|
||||
|
||||
The EIC-sync is similar with GPIO's input function, which is a synchronized
|
||||
signal input register. It can generate interrupts by level or edge trigger
|
||||
when detecting input signals.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
oneOf:
|
||||
- enum:
|
||||
- sprd,sc9860-eic-debounce
|
||||
- sprd,sc9860-eic-latch
|
||||
- sprd,sc9860-eic-async
|
||||
- sprd,sc9860-eic-sync
|
||||
- sprd,sc2731-eic
|
||||
- items:
|
||||
- enum:
|
||||
- sprd,ums512-eic-debounce
|
||||
- const: sprd,sc9860-eic-debounce
|
||||
- items:
|
||||
- enum:
|
||||
- sprd,ums512-eic-latch
|
||||
- const: sprd,sc9860-eic-latch
|
||||
- items:
|
||||
- enum:
|
||||
- sprd,ums512-eic-async
|
||||
- const: sprd,sc9860-eic-async
|
||||
- items:
|
||||
- enum:
|
||||
- sprd,ums512-eic-sync
|
||||
- const: sprd,sc9860-eic-sync
|
||||
- items:
|
||||
- enum:
|
||||
- sprd,sc2730-eic
|
||||
- const: sprd,sc2731-eic
|
||||
|
||||
reg:
|
||||
minItems: 1
|
||||
maxItems: 3
|
||||
description:
|
||||
EIC controller can support maximum 3 banks which has its own
|
||||
address base.
|
||||
|
||||
gpio-controller: true
|
||||
|
||||
"#gpio-cells":
|
||||
const: 2
|
||||
|
||||
interrupt-controller: true
|
||||
|
||||
"#interrupt-cells":
|
||||
const: 2
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
description:
|
||||
The interrupt shared by all GPIO lines for this controller.
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- gpio-controller
|
||||
- "#gpio-cells"
|
||||
- interrupt-controller
|
||||
- "#interrupt-cells"
|
||||
- interrupts
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/interrupt-controller/arm-gic.h>
|
||||
|
||||
soc {
|
||||
#address-cells = <2>;
|
||||
#size-cells = <2>;
|
||||
|
||||
eic_debounce: gpio@40210000 {
|
||||
compatible = "sprd,sc9860-eic-debounce";
|
||||
reg = <0 0x40210000 0 0x80>;
|
||||
gpio-controller;
|
||||
#gpio-cells = <2>;
|
||||
interrupt-controller;
|
||||
#interrupt-cells = <2>;
|
||||
interrupts = <GIC_SPI 52 IRQ_TYPE_LEVEL_HIGH>;
|
||||
};
|
||||
};
|
||||
...
|
|
@ -0,0 +1,75 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
# Copyright 2022 Unisoc Inc.
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/gpio/sprd,gpio.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Unisoc GPIO controller
|
||||
|
||||
maintainers:
|
||||
- Orson Zhai <orsonzhai@gmail.com>
|
||||
- Baolin Wang <baolin.wang7@gmail.com>
|
||||
- Chunyan Zhang <zhang.lyra@gmail.com>
|
||||
|
||||
description: |
|
||||
The controller's registers are organized as sets of sixteen 16-bit
|
||||
registers with each set controlling a bank of up to 16 pins. A single
|
||||
interrupt is shared for all of the banks handled by the controller.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
oneOf:
|
||||
- const: sprd,sc9860-gpio
|
||||
- items:
|
||||
- enum:
|
||||
- sprd,ums512-gpio
|
||||
- const: sprd,sc9860-gpio
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
gpio-controller: true
|
||||
|
||||
"#gpio-cells":
|
||||
const: 2
|
||||
|
||||
interrupt-controller: true
|
||||
|
||||
"#interrupt-cells":
|
||||
const: 2
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
description: The interrupt shared by all GPIO lines for this controller.
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- gpio-controller
|
||||
- "#gpio-cells"
|
||||
- interrupt-controller
|
||||
- "#interrupt-cells"
|
||||
- interrupts
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/interrupt-controller/arm-gic.h>
|
||||
|
||||
soc {
|
||||
#address-cells = <2>;
|
||||
#size-cells = <2>;
|
||||
|
||||
ap_gpio: gpio@40280000 {
|
||||
compatible = "sprd,sc9860-gpio";
|
||||
reg = <0 0x40280000 0 0x1000>;
|
||||
gpio-controller;
|
||||
#gpio-cells = <2>;
|
||||
interrupt-controller;
|
||||
#interrupt-cells = <2>;
|
||||
interrupts = <GIC_SPI 50 IRQ_TYPE_LEVEL_HIGH>;
|
||||
};
|
||||
};
|
||||
...
|
|
@ -387,9 +387,6 @@ map between them using calls like::
|
|||
/* map GPIO numbers to IRQ numbers */
|
||||
int gpio_to_irq(unsigned gpio);
|
||||
|
||||
/* map IRQ numbers to GPIO numbers (avoid using this) */
|
||||
int irq_to_gpio(unsigned irq);
|
||||
|
||||
Those return either the corresponding number in the other namespace, or
|
||||
else a negative errno code if the mapping can't be done. (For example,
|
||||
some GPIOs can't be used as IRQs.) It is an unchecked error to use a GPIO
|
||||
|
@ -405,11 +402,6 @@ devices, by the board-specific initialization code. Note that IRQ trigger
|
|||
options are part of the IRQ interface, e.g. IRQF_TRIGGER_FALLING, as are
|
||||
system wakeup capabilities.
|
||||
|
||||
Non-error values returned from irq_to_gpio() would most commonly be used
|
||||
with gpio_get_value(), for example to initialize or update driver state
|
||||
when the IRQ is edge-triggered. Note that some platforms don't support
|
||||
this reverse mapping, so you should avoid using it.
|
||||
|
||||
|
||||
Emulating Open Drain Signals
|
||||
----------------------------
|
||||
|
@ -735,10 +727,6 @@ requested using gpio_request()::
|
|||
/* reverse gpio_export() */
|
||||
void gpio_unexport();
|
||||
|
||||
/* create a sysfs link to an exported GPIO node */
|
||||
int gpio_export_link(struct device *dev, const char *name,
|
||||
unsigned gpio)
|
||||
|
||||
After a kernel driver requests a GPIO, it may only be made available in
|
||||
the sysfs interface by gpio_export(). The driver can control whether the
|
||||
signal direction may change. This helps drivers prevent userspace code
|
||||
|
@ -748,11 +736,6 @@ This explicit exporting can help with debugging (by making some kinds
|
|||
of experiments easier), or can provide an always-there interface that's
|
||||
suitable for documenting as part of a board support package.
|
||||
|
||||
After the GPIO has been exported, gpio_export_link() allows creating
|
||||
symlinks from elsewhere in sysfs to the GPIO sysfs node. Drivers can
|
||||
use this to provide the interface under their own device in sysfs with
|
||||
a descriptive name.
|
||||
|
||||
|
||||
API Reference
|
||||
=============
|
||||
|
|
|
@ -358,9 +358,6 @@ GPIO 编号是无符号整数;IRQ 编号也是。这些构成了两个逻辑上
|
|||
/* 映射 GPIO 编号到 IRQ 编号 */
|
||||
int gpio_to_irq(unsigned gpio);
|
||||
|
||||
/* 映射 IRQ 编号到 GPIO 编号 (尽量避免使用) */
|
||||
int irq_to_gpio(unsigned irq);
|
||||
|
||||
它们的返回值为对应命名空间的相关编号,或是负的错误代码(如果无法映射)。
|
||||
(例如,某些 GPIO 无法做为 IRQ 使用。)以下的编号错误是未经检测的:使用一个
|
||||
未通过 gpio_direction_input()配置为输入的 GPIO 编号,或者使用一个
|
||||
|
@ -373,10 +370,6 @@ gpio_to_irq()返回的非错误值可以传递给 request_irq()或者 free_irq()
|
|||
触发选项是 IRQ 接口的一部分,如 IRQF_TRIGGER_FALLING,系统唤醒能力
|
||||
也是如此。
|
||||
|
||||
irq_to_gpio()返回的非错误值大多数通常可以被 gpio_get_value()所使用,
|
||||
比如在 IRQ 是沿触发时初始化或更新驱动状态。注意某些平台不支持反映射,所以
|
||||
你应该尽量避免使用它。
|
||||
|
||||
|
||||
模拟开漏信号
|
||||
------------
|
||||
|
@ -672,10 +665,6 @@ GPIO 控制器的路径类似 /sys/class/gpio/gpiochip42/ (对于从#42 GPIO
|
|||
/* gpio_export()的逆操作 */
|
||||
void gpio_unexport();
|
||||
|
||||
/* 创建一个 sysfs 连接到已导出的 GPIO 节点 */
|
||||
int gpio_export_link(struct device *dev, const char *name,
|
||||
unsigned gpio)
|
||||
|
||||
在一个内核驱动申请一个 GPIO 之后,它可以通过 gpio_export()使其在 sysfs
|
||||
接口中可见。该驱动可以控制信号方向是否可修改。这有助于防止用户空间代码无意间
|
||||
破坏重要的系统状态。
|
||||
|
@ -683,10 +672,6 @@ GPIO 控制器的路径类似 /sys/class/gpio/gpiochip42/ (对于从#42 GPIO
|
|||
这个明确的导出有助于(通过使某些实验更容易来)调试,也可以提供一个始终存在的接口,
|
||||
与文档配合作为板级支持包的一部分。
|
||||
|
||||
在 GPIO 被导出之后,gpio_export_link()允许在 sysfs 文件系统的任何地方
|
||||
创建一个到这个 GPIO sysfs 节点的符号链接。这样驱动就可以通过一个描述性的
|
||||
名字,在 sysfs 中他们所拥有的设备下提供一个(到这个 GPIO sysfs 节点的)接口。
|
||||
|
||||
|
||||
API参考
|
||||
=======
|
||||
|
|
|
@ -363,9 +363,6 @@ GPIO 編號是無符號整數;IRQ 編號也是。這些構成了兩個邏輯上
|
|||
/* 映射 GPIO 編號到 IRQ 編號 */
|
||||
int gpio_to_irq(unsigned gpio);
|
||||
|
||||
/* 映射 IRQ 編號到 GPIO 編號 (儘量避免使用) */
|
||||
int irq_to_gpio(unsigned irq);
|
||||
|
||||
它們的返回值爲對應命名空間的相關編號,或是負的錯誤代碼(如果無法映射)。
|
||||
(例如,某些 GPIO 無法做爲 IRQ 使用。)以下的編號錯誤是未經檢測的:使用一個
|
||||
未通過 gpio_direction_input()配置爲輸入的 GPIO 編號,或者使用一個
|
||||
|
@ -378,10 +375,6 @@ gpio_to_irq()返回的非錯誤值可以傳遞給 request_irq()或者 free_irq()
|
|||
觸發選項是 IRQ 接口的一部分,如 IRQF_TRIGGER_FALLING,系統喚醒能力
|
||||
也是如此。
|
||||
|
||||
irq_to_gpio()返回的非錯誤值大多數通常可以被 gpio_get_value()所使用,
|
||||
比如在 IRQ 是沿觸發時初始化或更新驅動狀態。注意某些平台不支持反映射,所以
|
||||
你應該儘量避免使用它。
|
||||
|
||||
|
||||
模擬開漏信號
|
||||
----------------------------
|
||||
|
@ -634,18 +627,9 @@ GPIO 控制器的路徑類似 /sys/class/gpio/gpiochip42/ (對於從#42 GPIO
|
|||
/* gpio_export()的逆操作 */
|
||||
void gpio_unexport();
|
||||
|
||||
/* 創建一個 sysfs 連接到已導出的 GPIO 節點 */
|
||||
int gpio_export_link(struct device *dev, const char *name,
|
||||
unsigned gpio)
|
||||
|
||||
在一個內核驅動申請一個 GPIO 之後,它可以通過 gpio_export()使其在 sysfs
|
||||
接口中可見。該驅動可以控制信號方向是否可修改。這有助於防止用戶空間代碼無意間
|
||||
破壞重要的系統狀態。
|
||||
|
||||
這個明確的導出有助於(通過使某些實驗更容易來)調試,也可以提供一個始終存在的接口,
|
||||
與文檔配合作爲板級支持包的一部分。
|
||||
|
||||
在 GPIO 被導出之後,gpio_export_link()允許在 sysfs 文件系統的任何地方
|
||||
創建一個到這個 GPIO sysfs 節點的符號連結。這樣驅動就可以通過一個描述性的
|
||||
名字,在 sysfs 中他們所擁有的設備下提供一個(到這個 GPIO sysfs 節點的)接口。
|
||||
|
||||
|
|
|
@ -66,13 +66,6 @@ static inline int gpio_to_irq(unsigned gpio)
|
|||
return __gpio_to_irq(gpio);
|
||||
}
|
||||
|
||||
static inline int irq_to_gpio(unsigned irq)
|
||||
{
|
||||
return (irq >= MCFGPIO_IRQ_VECBASE &&
|
||||
irq < (MCFGPIO_IRQ_VECBASE + MCFGPIO_IRQ_MAX)) ?
|
||||
irq - MCFGPIO_IRQ_VECBASE : -ENXIO;
|
||||
}
|
||||
|
||||
static inline int gpio_cansleep(unsigned gpio)
|
||||
{
|
||||
return gpio < MCFGPIO_PIN_MAX ? 0 : __gpio_cansleep(gpio);
|
||||
|
|
|
@ -40,11 +40,6 @@ static inline int gpio_to_irq(unsigned gpio)
|
|||
return __gpio_to_irq(gpio);
|
||||
}
|
||||
|
||||
static inline int irq_to_gpio(unsigned int irq)
|
||||
{
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_GPIOLIB */
|
||||
|
||||
#endif /* __ASM_SH_GPIO_H */
|
||||
|
|
|
@ -752,7 +752,7 @@ config GPIO_XTENSA
|
|||
|
||||
config GPIO_ZEVIO
|
||||
bool "LSI ZEVIO SoC memory mapped GPIOs"
|
||||
depends on ARM && OF_GPIO
|
||||
depends on ARM
|
||||
help
|
||||
Say yes here to support the GPIO controller in LSI ZEVIO SoCs.
|
||||
|
||||
|
@ -821,6 +821,7 @@ menu "Port-mapped I/O GPIO drivers"
|
|||
|
||||
config GPIO_I8255
|
||||
tristate
|
||||
select GPIO_REGMAP
|
||||
help
|
||||
Enables support for the i8255 interface library functions. The i8255
|
||||
interface library provides functions to facilitate communication with
|
||||
|
@ -835,6 +836,8 @@ config GPIO_104_DIO_48E
|
|||
tristate "ACCES 104-DIO-48E GPIO support"
|
||||
depends on PC104
|
||||
select ISA_BUS_API
|
||||
select REGMAP_MMIO
|
||||
select REGMAP_IRQ
|
||||
select GPIOLIB_IRQCHIP
|
||||
select GPIO_I8255
|
||||
help
|
||||
|
@ -860,8 +863,10 @@ config GPIO_104_IDI_48
|
|||
tristate "ACCES 104-IDI-48 GPIO support"
|
||||
depends on PC104
|
||||
select ISA_BUS_API
|
||||
select REGMAP_MMIO
|
||||
select REGMAP_IRQ
|
||||
select GPIOLIB_IRQCHIP
|
||||
select GPIO_I8255
|
||||
select GPIO_REGMAP
|
||||
help
|
||||
Enables GPIO support for the ACCES 104-IDI-48 family (104-IDI-48A,
|
||||
104-IDI-48AC, 104-IDI-48B, 104-IDI-48BC). The base port addresses for
|
||||
|
@ -883,6 +888,7 @@ config GPIO_GPIO_MM
|
|||
tristate "Diamond Systems GPIO-MM GPIO support"
|
||||
depends on PC104
|
||||
select ISA_BUS_API
|
||||
select REGMAP_MMIO
|
||||
select GPIO_I8255
|
||||
help
|
||||
Enables GPIO support for the Diamond Systems GPIO-MM and GPIO-MM-12.
|
||||
|
|
|
@ -61,8 +61,8 @@ Work items:
|
|||
|
||||
- Get rid of struct of_mm_gpio_chip altogether: use the generic MMIO
|
||||
GPIO for all current users (see below). Delete struct of_mm_gpio_chip,
|
||||
to_of_mm_gpio_chip(), of_mm_gpiochip_add_data(), of_mm_gpiochip_add()
|
||||
of_mm_gpiochip_remove() from the kernel.
|
||||
to_of_mm_gpio_chip(), of_mm_gpiochip_add_data(), of_mm_gpiochip_remove()
|
||||
from the kernel.
|
||||
|
||||
- Change all consumer drivers that #include <linux/of_gpio.h> to
|
||||
#include <linux/gpio/consumer.h> and stop doing custom parsing of the
|
||||
|
|
|
@ -8,17 +8,14 @@
|
|||
*/
|
||||
#include <linux/bits.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/gpio/driver.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/irqdesc.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/isa.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#include "gpio-i8255.h"
|
||||
|
@ -38,212 +35,101 @@ 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_ENABLE_INTERRUPT 0xB
|
||||
#define DIO48E_DISABLE_INTERRUPT DIO48E_ENABLE_INTERRUPT
|
||||
#define DIO48E_CLEAR_INTERRUPT 0xF
|
||||
|
||||
#define DIO48E_NUM_PPI 2
|
||||
|
||||
/**
|
||||
* struct dio48e_reg - device register structure
|
||||
* @ppi: Programmable Peripheral Interface groups
|
||||
* @enable_buffer: Enable/Disable Buffer groups
|
||||
* @unused1: Unused
|
||||
* @enable_interrupt: Write: Enable Interrupt
|
||||
* Read: Disable Interrupt
|
||||
* @unused2: Unused
|
||||
* @enable_counter: Write: Enable Counter/Timer Addressing
|
||||
* Read: Disable Counter/Timer Addressing
|
||||
* @unused3: Unused
|
||||
* @clear_interrupt: Clear Interrupt
|
||||
*/
|
||||
struct dio48e_reg {
|
||||
struct i8255 ppi[DIO48E_NUM_PPI];
|
||||
u8 enable_buffer[DIO48E_NUM_PPI];
|
||||
u8 unused1;
|
||||
u8 enable_interrupt;
|
||||
u8 unused2;
|
||||
u8 enable_counter;
|
||||
u8 unused3;
|
||||
u8 clear_interrupt;
|
||||
static const struct regmap_range dio48e_wr_ranges[] = {
|
||||
regmap_reg_range(0x0, 0x9), regmap_reg_range(0xB, 0xB),
|
||||
regmap_reg_range(0xD, 0xD), regmap_reg_range(0xF, 0xF),
|
||||
};
|
||||
static const struct regmap_range dio48e_rd_ranges[] = {
|
||||
regmap_reg_range(0x0, 0x2), regmap_reg_range(0x4, 0x6),
|
||||
regmap_reg_range(0xB, 0xB), regmap_reg_range(0xD, 0xD),
|
||||
regmap_reg_range(0xF, 0xF),
|
||||
};
|
||||
static const struct regmap_range dio48e_volatile_ranges[] = {
|
||||
i8255_volatile_regmap_range(0x0), i8255_volatile_regmap_range(0x4),
|
||||
regmap_reg_range(0xB, 0xB), regmap_reg_range(0xD, 0xD),
|
||||
regmap_reg_range(0xF, 0xF),
|
||||
};
|
||||
static const struct regmap_range dio48e_precious_ranges[] = {
|
||||
regmap_reg_range(0xB, 0xB), regmap_reg_range(0xD, 0xD),
|
||||
regmap_reg_range(0xF, 0xF),
|
||||
};
|
||||
static const struct regmap_access_table dio48e_wr_table = {
|
||||
.yes_ranges = dio48e_wr_ranges,
|
||||
.n_yes_ranges = ARRAY_SIZE(dio48e_wr_ranges),
|
||||
};
|
||||
static const struct regmap_access_table dio48e_rd_table = {
|
||||
.yes_ranges = dio48e_rd_ranges,
|
||||
.n_yes_ranges = ARRAY_SIZE(dio48e_rd_ranges),
|
||||
};
|
||||
static const struct regmap_access_table dio48e_volatile_table = {
|
||||
.yes_ranges = dio48e_volatile_ranges,
|
||||
.n_yes_ranges = ARRAY_SIZE(dio48e_volatile_ranges),
|
||||
};
|
||||
static const struct regmap_access_table dio48e_precious_table = {
|
||||
.yes_ranges = dio48e_precious_ranges,
|
||||
.n_yes_ranges = ARRAY_SIZE(dio48e_precious_ranges),
|
||||
};
|
||||
static const struct regmap_config dio48e_regmap_config = {
|
||||
.reg_bits = 8,
|
||||
.reg_stride = 1,
|
||||
.val_bits = 8,
|
||||
.io_port = true,
|
||||
.max_register = 0xF,
|
||||
.wr_table = &dio48e_wr_table,
|
||||
.rd_table = &dio48e_rd_table,
|
||||
.volatile_table = &dio48e_volatile_table,
|
||||
.precious_table = &dio48e_precious_table,
|
||||
.cache_type = REGCACHE_FLAT,
|
||||
};
|
||||
|
||||
/**
|
||||
* struct dio48e_gpio - GPIO device private data structure
|
||||
* @chip: instance of the gpio_chip
|
||||
* @ppi_state: PPI device states
|
||||
* @lock: synchronization lock to prevent I/O race conditions
|
||||
* @reg: I/O address offset for the device registers
|
||||
* @irq_mask: I/O bits affected by interrupts
|
||||
*/
|
||||
struct dio48e_gpio {
|
||||
struct gpio_chip chip;
|
||||
struct i8255_state ppi_state[DIO48E_NUM_PPI];
|
||||
raw_spinlock_t lock;
|
||||
struct dio48e_reg __iomem *reg;
|
||||
unsigned char irq_mask;
|
||||
};
|
||||
|
||||
static int dio48e_gpio_get_direction(struct gpio_chip *chip, unsigned int offset)
|
||||
{
|
||||
struct dio48e_gpio *const dio48egpio = gpiochip_get_data(chip);
|
||||
|
||||
if (i8255_get_direction(dio48egpio->ppi_state, offset))
|
||||
return GPIO_LINE_DIRECTION_IN;
|
||||
|
||||
return GPIO_LINE_DIRECTION_OUT;
|
||||
}
|
||||
|
||||
static int dio48e_gpio_direction_input(struct gpio_chip *chip, unsigned int offset)
|
||||
{
|
||||
struct dio48e_gpio *const dio48egpio = gpiochip_get_data(chip);
|
||||
|
||||
i8255_direction_input(dio48egpio->reg->ppi, dio48egpio->ppi_state,
|
||||
offset);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dio48e_gpio_direction_output(struct gpio_chip *chip, unsigned int offset,
|
||||
int value)
|
||||
{
|
||||
struct dio48e_gpio *const dio48egpio = gpiochip_get_data(chip);
|
||||
|
||||
i8255_direction_output(dio48egpio->reg->ppi, dio48egpio->ppi_state,
|
||||
offset, value);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dio48e_gpio_get(struct gpio_chip *chip, unsigned int offset)
|
||||
{
|
||||
struct dio48e_gpio *const dio48egpio = gpiochip_get_data(chip);
|
||||
|
||||
return i8255_get(dio48egpio->reg->ppi, offset);
|
||||
}
|
||||
|
||||
static int dio48e_gpio_get_multiple(struct gpio_chip *chip, unsigned long *mask,
|
||||
unsigned long *bits)
|
||||
{
|
||||
struct dio48e_gpio *const dio48egpio = gpiochip_get_data(chip);
|
||||
|
||||
i8255_get_multiple(dio48egpio->reg->ppi, mask, bits, chip->ngpio);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dio48e_gpio_set(struct gpio_chip *chip, unsigned int offset, int value)
|
||||
{
|
||||
struct dio48e_gpio *const dio48egpio = gpiochip_get_data(chip);
|
||||
|
||||
i8255_set(dio48egpio->reg->ppi, dio48egpio->ppi_state, offset, value);
|
||||
}
|
||||
|
||||
static void dio48e_gpio_set_multiple(struct gpio_chip *chip,
|
||||
unsigned long *mask, unsigned long *bits)
|
||||
{
|
||||
struct dio48e_gpio *const dio48egpio = gpiochip_get_data(chip);
|
||||
|
||||
i8255_set_multiple(dio48egpio->reg->ppi, dio48egpio->ppi_state, mask,
|
||||
bits, chip->ngpio);
|
||||
}
|
||||
|
||||
static void dio48e_irq_ack(struct irq_data *data)
|
||||
{
|
||||
}
|
||||
|
||||
static void dio48e_irq_mask(struct irq_data *data)
|
||||
{
|
||||
struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
|
||||
struct dio48e_gpio *const dio48egpio = gpiochip_get_data(chip);
|
||||
const unsigned long offset = irqd_to_hwirq(data);
|
||||
unsigned long flags;
|
||||
|
||||
/* only bit 3 on each respective Port C supports interrupts */
|
||||
if (offset != 19 && offset != 43)
|
||||
return;
|
||||
|
||||
raw_spin_lock_irqsave(&dio48egpio->lock, flags);
|
||||
|
||||
if (offset == 19)
|
||||
dio48egpio->irq_mask &= ~BIT(0);
|
||||
else
|
||||
dio48egpio->irq_mask &= ~BIT(1);
|
||||
gpiochip_disable_irq(chip, offset);
|
||||
|
||||
if (!dio48egpio->irq_mask)
|
||||
/* disable interrupts */
|
||||
ioread8(&dio48egpio->reg->enable_interrupt);
|
||||
|
||||
raw_spin_unlock_irqrestore(&dio48egpio->lock, flags);
|
||||
}
|
||||
|
||||
static void dio48e_irq_unmask(struct irq_data *data)
|
||||
{
|
||||
struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
|
||||
struct dio48e_gpio *const dio48egpio = gpiochip_get_data(chip);
|
||||
const unsigned long offset = irqd_to_hwirq(data);
|
||||
unsigned long flags;
|
||||
|
||||
/* only bit 3 on each respective Port C supports interrupts */
|
||||
if (offset != 19 && offset != 43)
|
||||
return;
|
||||
|
||||
raw_spin_lock_irqsave(&dio48egpio->lock, flags);
|
||||
|
||||
if (!dio48egpio->irq_mask) {
|
||||
/* enable interrupts */
|
||||
iowrite8(0x00, &dio48egpio->reg->clear_interrupt);
|
||||
iowrite8(0x00, &dio48egpio->reg->enable_interrupt);
|
||||
/* only bit 3 on each respective Port C supports interrupts */
|
||||
#define DIO48E_REGMAP_IRQ(_ppi) \
|
||||
[19 + (_ppi) * 24] = { \
|
||||
.mask = BIT(_ppi), \
|
||||
.type = { .types_supported = IRQ_TYPE_EDGE_RISING }, \
|
||||
}
|
||||
|
||||
gpiochip_enable_irq(chip, offset);
|
||||
if (offset == 19)
|
||||
dio48egpio->irq_mask |= BIT(0);
|
||||
else
|
||||
dio48egpio->irq_mask |= BIT(1);
|
||||
|
||||
raw_spin_unlock_irqrestore(&dio48egpio->lock, flags);
|
||||
}
|
||||
|
||||
static int dio48e_irq_set_type(struct irq_data *data, unsigned int flow_type)
|
||||
{
|
||||
const unsigned long offset = irqd_to_hwirq(data);
|
||||
|
||||
/* only bit 3 on each respective Port C supports interrupts */
|
||||
if (offset != 19 && offset != 43)
|
||||
return -EINVAL;
|
||||
|
||||
if (flow_type != IRQ_TYPE_NONE && flow_type != IRQ_TYPE_EDGE_RISING)
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct irq_chip dio48e_irqchip = {
|
||||
.name = "104-dio-48e",
|
||||
.irq_ack = dio48e_irq_ack,
|
||||
.irq_mask = dio48e_irq_mask,
|
||||
.irq_unmask = dio48e_irq_unmask,
|
||||
.irq_set_type = dio48e_irq_set_type,
|
||||
.flags = IRQCHIP_IMMUTABLE,
|
||||
GPIOCHIP_IRQ_RESOURCE_HELPERS,
|
||||
static const struct regmap_irq dio48e_regmap_irqs[] = {
|
||||
DIO48E_REGMAP_IRQ(0), DIO48E_REGMAP_IRQ(1),
|
||||
};
|
||||
|
||||
static irqreturn_t dio48e_irq_handler(int irq, void *dev_id)
|
||||
static int dio48e_handle_mask_sync(struct regmap *const map, const int index,
|
||||
const unsigned int mask_buf_def,
|
||||
const unsigned int mask_buf,
|
||||
void *const irq_drv_data)
|
||||
{
|
||||
struct dio48e_gpio *const dio48egpio = dev_id;
|
||||
struct gpio_chip *const chip = &dio48egpio->chip;
|
||||
const unsigned long irq_mask = dio48egpio->irq_mask;
|
||||
unsigned long gpio;
|
||||
unsigned int *const irq_mask = irq_drv_data;
|
||||
const unsigned int prev_mask = *irq_mask;
|
||||
const unsigned int all_masked = GENMASK(1, 0);
|
||||
int err;
|
||||
unsigned int val;
|
||||
|
||||
for_each_set_bit(gpio, &irq_mask, 2)
|
||||
generic_handle_domain_irq(chip->irq.domain,
|
||||
19 + gpio*24);
|
||||
/* exit early if no change since the previous mask */
|
||||
if (mask_buf == prev_mask)
|
||||
return 0;
|
||||
|
||||
raw_spin_lock(&dio48egpio->lock);
|
||||
/* remember the current mask for the next mask sync */
|
||||
*irq_mask = mask_buf;
|
||||
|
||||
iowrite8(0x00, &dio48egpio->reg->clear_interrupt);
|
||||
/* if all previously masked, enable interrupts when unmasking */
|
||||
if (prev_mask == all_masked) {
|
||||
err = regmap_write(map, DIO48E_CLEAR_INTERRUPT, 0x00);
|
||||
if (err)
|
||||
return err;
|
||||
return regmap_write(map, DIO48E_ENABLE_INTERRUPT, 0x00);
|
||||
}
|
||||
|
||||
raw_spin_unlock(&dio48egpio->lock);
|
||||
/* if all are currently masked, disable interrupts */
|
||||
if (mask_buf == all_masked)
|
||||
return regmap_read(map, DIO48E_DISABLE_INTERRUPT, &val);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define DIO48E_NGPIO 48
|
||||
|
@ -266,41 +152,24 @@ static const char *dio48e_names[DIO48E_NGPIO] = {
|
|||
"PPI Group 1 Port C 5", "PPI Group 1 Port C 6", "PPI Group 1 Port C 7"
|
||||
};
|
||||
|
||||
static int dio48e_irq_init_hw(struct gpio_chip *gc)
|
||||
static int dio48e_irq_init_hw(struct regmap *const map)
|
||||
{
|
||||
struct dio48e_gpio *const dio48egpio = gpiochip_get_data(gc);
|
||||
unsigned int val;
|
||||
|
||||
/* Disable IRQ by default */
|
||||
ioread8(&dio48egpio->reg->enable_interrupt);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dio48e_init_ppi(struct i8255 __iomem *const ppi,
|
||||
struct i8255_state *const ppi_state)
|
||||
{
|
||||
const unsigned long ngpio = 24;
|
||||
const unsigned long mask = GENMASK(ngpio - 1, 0);
|
||||
const unsigned long bits = 0;
|
||||
unsigned long i;
|
||||
|
||||
/* Initialize all GPIO to output 0 */
|
||||
for (i = 0; i < DIO48E_NUM_PPI; i++) {
|
||||
i8255_mode0_output(&ppi[i]);
|
||||
i8255_set_multiple(&ppi[i], &ppi_state[i], &mask, &bits, ngpio);
|
||||
}
|
||||
return regmap_read(map, DIO48E_DISABLE_INTERRUPT, &val);
|
||||
}
|
||||
|
||||
static int dio48e_probe(struct device *dev, unsigned int id)
|
||||
{
|
||||
struct dio48e_gpio *dio48egpio;
|
||||
const char *const name = dev_name(dev);
|
||||
struct gpio_irq_chip *girq;
|
||||
struct i8255_regmap_config config = {};
|
||||
void __iomem *regs;
|
||||
struct regmap *map;
|
||||
int err;
|
||||
|
||||
dio48egpio = devm_kzalloc(dev, sizeof(*dio48egpio), GFP_KERNEL);
|
||||
if (!dio48egpio)
|
||||
return -ENOMEM;
|
||||
struct regmap_irq_chip *chip;
|
||||
unsigned int irq_mask;
|
||||
struct regmap_irq_chip_data *chip_data;
|
||||
|
||||
if (!devm_request_region(dev, base[id], DIO48E_EXTENT, name)) {
|
||||
dev_err(dev, "Unable to lock port addresses (0x%X-0x%X)\n",
|
||||
|
@ -308,53 +177,52 @@ static int dio48e_probe(struct device *dev, unsigned int id)
|
|||
return -EBUSY;
|
||||
}
|
||||
|
||||
dio48egpio->reg = devm_ioport_map(dev, base[id], DIO48E_EXTENT);
|
||||
if (!dio48egpio->reg)
|
||||
regs = devm_ioport_map(dev, base[id], DIO48E_EXTENT);
|
||||
if (!regs)
|
||||
return -ENOMEM;
|
||||
|
||||
dio48egpio->chip.label = name;
|
||||
dio48egpio->chip.parent = dev;
|
||||
dio48egpio->chip.owner = THIS_MODULE;
|
||||
dio48egpio->chip.base = -1;
|
||||
dio48egpio->chip.ngpio = DIO48E_NGPIO;
|
||||
dio48egpio->chip.names = dio48e_names;
|
||||
dio48egpio->chip.get_direction = dio48e_gpio_get_direction;
|
||||
dio48egpio->chip.direction_input = dio48e_gpio_direction_input;
|
||||
dio48egpio->chip.direction_output = dio48e_gpio_direction_output;
|
||||
dio48egpio->chip.get = dio48e_gpio_get;
|
||||
dio48egpio->chip.get_multiple = dio48e_gpio_get_multiple;
|
||||
dio48egpio->chip.set = dio48e_gpio_set;
|
||||
dio48egpio->chip.set_multiple = dio48e_gpio_set_multiple;
|
||||
map = devm_regmap_init_mmio(dev, regs, &dio48e_regmap_config);
|
||||
if (IS_ERR(map))
|
||||
return dev_err_probe(dev, PTR_ERR(map),
|
||||
"Unable to initialize register map\n");
|
||||
|
||||
girq = &dio48egpio->chip.irq;
|
||||
gpio_irq_chip_set_chip(girq, &dio48e_irqchip);
|
||||
/* This will let us handle the parent IRQ in the driver */
|
||||
girq->parent_handler = NULL;
|
||||
girq->num_parents = 0;
|
||||
girq->parents = NULL;
|
||||
girq->default_type = IRQ_TYPE_NONE;
|
||||
girq->handler = handle_edge_irq;
|
||||
girq->init_hw = dio48e_irq_init_hw;
|
||||
chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL);
|
||||
if (!chip)
|
||||
return -ENOMEM;
|
||||
|
||||
raw_spin_lock_init(&dio48egpio->lock);
|
||||
chip->irq_drv_data = devm_kzalloc(dev, sizeof(irq_mask), GFP_KERNEL);
|
||||
if (!chip->irq_drv_data)
|
||||
return -ENOMEM;
|
||||
|
||||
i8255_state_init(dio48egpio->ppi_state, DIO48E_NUM_PPI);
|
||||
dio48e_init_ppi(dio48egpio->reg->ppi, dio48egpio->ppi_state);
|
||||
chip->name = name;
|
||||
/* No IRQ status register so use CLEAR_INTERRUPT register instead */
|
||||
chip->status_base = DIO48E_CLEAR_INTERRUPT;
|
||||
chip->mask_base = DIO48E_ENABLE_INTERRUPT;
|
||||
chip->ack_base = DIO48E_CLEAR_INTERRUPT;
|
||||
/* CLEAR_INTERRUPT doubles as status register so we need it cleared */
|
||||
chip->clear_ack = true;
|
||||
chip->status_invert = true;
|
||||
chip->num_regs = 1;
|
||||
chip->irqs = dio48e_regmap_irqs;
|
||||
chip->num_irqs = ARRAY_SIZE(dio48e_regmap_irqs);
|
||||
chip->handle_mask_sync = dio48e_handle_mask_sync;
|
||||
|
||||
err = devm_gpiochip_add_data(dev, &dio48egpio->chip, dio48egpio);
|
||||
if (err) {
|
||||
dev_err(dev, "GPIO registering failed (%d)\n", err);
|
||||
/* Initialize to prevent spurious interrupts before we're ready */
|
||||
err = dio48e_irq_init_hw(map);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
err = devm_request_irq(dev, irq[id], dio48e_irq_handler, 0, name,
|
||||
dio48egpio);
|
||||
if (err) {
|
||||
dev_err(dev, "IRQ handler registering failed (%d)\n", err);
|
||||
return err;
|
||||
}
|
||||
err = devm_regmap_add_irq_chip(dev, map, irq[id], 0, 0, chip, &chip_data);
|
||||
if (err)
|
||||
return dev_err_probe(dev, err, "IRQ registration failed\n");
|
||||
|
||||
return 0;
|
||||
config.parent = dev;
|
||||
config.map = map;
|
||||
config.num_ppi = DIO48E_NUM_PPI;
|
||||
config.names = dio48e_names;
|
||||
config.domain = regmap_irq_get_domain(chip_data);
|
||||
|
||||
return devm_i8255_regmap_register(dev, &config);
|
||||
}
|
||||
|
||||
static struct isa_driver dio48e_driver = {
|
||||
|
|
|
@ -8,23 +8,18 @@
|
|||
*/
|
||||
#include <linux/bits.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/gpio/driver.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/gpio/regmap.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/irqdesc.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/isa.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#include "gpio-i8255.h"
|
||||
|
||||
MODULE_IMPORT_NS(I8255);
|
||||
|
||||
#define IDI_48_EXTENT 8
|
||||
#define MAX_NUM_IDI_48 max_num_isa_dev(IDI_48_EXTENT)
|
||||
|
||||
|
@ -38,185 +33,83 @@ 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");
|
||||
|
||||
/**
|
||||
* struct idi_48_reg - device register structure
|
||||
* @port0: Port 0 Inputs
|
||||
* @unused: Unused
|
||||
* @port1: Port 1 Inputs
|
||||
* @irq: Read: IRQ Status Register/IRQ Clear
|
||||
* Write: IRQ Enable/Disable
|
||||
*/
|
||||
struct idi_48_reg {
|
||||
u8 port0[3];
|
||||
u8 unused;
|
||||
u8 port1[3];
|
||||
u8 irq;
|
||||
};
|
||||
#define IDI48_IRQ_STATUS 0x7
|
||||
#define IDI48_IRQ_ENABLE IDI48_IRQ_STATUS
|
||||
|
||||
/**
|
||||
* struct idi_48_gpio - GPIO device private data structure
|
||||
* @chip: instance of the gpio_chip
|
||||
* @lock: synchronization lock to prevent I/O race conditions
|
||||
* @irq_mask: input bits affected by interrupts
|
||||
* @reg: I/O address offset for the device registers
|
||||
* @cos_enb: Change-Of-State IRQ enable boundaries mask
|
||||
*/
|
||||
struct idi_48_gpio {
|
||||
struct gpio_chip chip;
|
||||
spinlock_t lock;
|
||||
unsigned char irq_mask[6];
|
||||
struct idi_48_reg __iomem *reg;
|
||||
unsigned char cos_enb;
|
||||
};
|
||||
|
||||
static int idi_48_gpio_get_direction(struct gpio_chip *chip, unsigned int offset)
|
||||
static int idi_48_reg_mask_xlate(struct gpio_regmap *gpio, unsigned int base,
|
||||
unsigned int offset, unsigned int *reg,
|
||||
unsigned int *mask)
|
||||
{
|
||||
return GPIO_LINE_DIRECTION_IN;
|
||||
}
|
||||
const unsigned int line = offset % 8;
|
||||
const unsigned int stride = offset / 8;
|
||||
const unsigned int port = (stride / 3) * 4;
|
||||
const unsigned int port_stride = stride % 3;
|
||||
|
||||
static int idi_48_gpio_direction_input(struct gpio_chip *chip, unsigned int offset)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int idi_48_gpio_get(struct gpio_chip *chip, unsigned int offset)
|
||||
{
|
||||
struct idi_48_gpio *const idi48gpio = gpiochip_get_data(chip);
|
||||
void __iomem *const ppi = idi48gpio->reg;
|
||||
|
||||
return i8255_get(ppi, offset);
|
||||
}
|
||||
|
||||
static int idi_48_gpio_get_multiple(struct gpio_chip *chip, unsigned long *mask,
|
||||
unsigned long *bits)
|
||||
{
|
||||
struct idi_48_gpio *const idi48gpio = gpiochip_get_data(chip);
|
||||
void __iomem *const ppi = idi48gpio->reg;
|
||||
|
||||
i8255_get_multiple(ppi, mask, bits, chip->ngpio);
|
||||
*reg = base + port + port_stride;
|
||||
*mask = BIT(line);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void idi_48_irq_ack(struct irq_data *data)
|
||||
{
|
||||
}
|
||||
|
||||
static void idi_48_irq_mask(struct irq_data *data)
|
||||
{
|
||||
struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
|
||||
struct idi_48_gpio *const idi48gpio = gpiochip_get_data(chip);
|
||||
const unsigned int offset = irqd_to_hwirq(data);
|
||||
const unsigned long boundary = offset / 8;
|
||||
const unsigned long mask = BIT(offset % 8);
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&idi48gpio->lock, flags);
|
||||
|
||||
idi48gpio->irq_mask[boundary] &= ~mask;
|
||||
gpiochip_disable_irq(chip, offset);
|
||||
|
||||
/* Exit early if there are still input lines with IRQ unmasked */
|
||||
if (idi48gpio->irq_mask[boundary])
|
||||
goto exit;
|
||||
|
||||
idi48gpio->cos_enb &= ~BIT(boundary);
|
||||
|
||||
iowrite8(idi48gpio->cos_enb, &idi48gpio->reg->irq);
|
||||
|
||||
exit:
|
||||
spin_unlock_irqrestore(&idi48gpio->lock, flags);
|
||||
}
|
||||
|
||||
static void idi_48_irq_unmask(struct irq_data *data)
|
||||
{
|
||||
struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
|
||||
struct idi_48_gpio *const idi48gpio = gpiochip_get_data(chip);
|
||||
const unsigned int offset = irqd_to_hwirq(data);
|
||||
const unsigned long boundary = offset / 8;
|
||||
const unsigned long mask = BIT(offset % 8);
|
||||
unsigned int prev_irq_mask;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&idi48gpio->lock, flags);
|
||||
|
||||
prev_irq_mask = idi48gpio->irq_mask[boundary];
|
||||
|
||||
gpiochip_enable_irq(chip, offset);
|
||||
idi48gpio->irq_mask[boundary] |= mask;
|
||||
|
||||
/* Exit early if IRQ was already unmasked for this boundary */
|
||||
if (prev_irq_mask)
|
||||
goto exit;
|
||||
|
||||
idi48gpio->cos_enb |= BIT(boundary);
|
||||
|
||||
iowrite8(idi48gpio->cos_enb, &idi48gpio->reg->irq);
|
||||
|
||||
exit:
|
||||
spin_unlock_irqrestore(&idi48gpio->lock, flags);
|
||||
}
|
||||
|
||||
static int idi_48_irq_set_type(struct irq_data *data, unsigned int flow_type)
|
||||
{
|
||||
/* The only valid irq types are none and both-edges */
|
||||
if (flow_type != IRQ_TYPE_NONE &&
|
||||
(flow_type & IRQ_TYPE_EDGE_BOTH) != IRQ_TYPE_EDGE_BOTH)
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct irq_chip idi_48_irqchip = {
|
||||
.name = "104-idi-48",
|
||||
.irq_ack = idi_48_irq_ack,
|
||||
.irq_mask = idi_48_irq_mask,
|
||||
.irq_unmask = idi_48_irq_unmask,
|
||||
.irq_set_type = idi_48_irq_set_type,
|
||||
.flags = IRQCHIP_IMMUTABLE,
|
||||
GPIOCHIP_IRQ_RESOURCE_HELPERS,
|
||||
static const struct regmap_range idi_48_wr_ranges[] = {
|
||||
regmap_reg_range(0x0, 0x6),
|
||||
};
|
||||
static const struct regmap_range idi_48_rd_ranges[] = {
|
||||
regmap_reg_range(0x0, 0x2), regmap_reg_range(0x4, 0x7),
|
||||
};
|
||||
static const struct regmap_range idi_48_precious_ranges[] = {
|
||||
regmap_reg_range(0x7, 0x7),
|
||||
};
|
||||
static const struct regmap_access_table idi_48_wr_table = {
|
||||
.no_ranges = idi_48_wr_ranges,
|
||||
.n_no_ranges = ARRAY_SIZE(idi_48_wr_ranges),
|
||||
};
|
||||
static const struct regmap_access_table idi_48_rd_table = {
|
||||
.yes_ranges = idi_48_rd_ranges,
|
||||
.n_yes_ranges = ARRAY_SIZE(idi_48_rd_ranges),
|
||||
};
|
||||
static const struct regmap_access_table idi_48_precious_table = {
|
||||
.yes_ranges = idi_48_precious_ranges,
|
||||
.n_yes_ranges = ARRAY_SIZE(idi_48_precious_ranges),
|
||||
};
|
||||
static const struct regmap_config idi48_regmap_config = {
|
||||
.reg_bits = 8,
|
||||
.reg_stride = 1,
|
||||
.val_bits = 8,
|
||||
.io_port = true,
|
||||
.max_register = 0x6,
|
||||
.wr_table = &idi_48_wr_table,
|
||||
.rd_table = &idi_48_rd_table,
|
||||
.precious_table = &idi_48_precious_table,
|
||||
};
|
||||
|
||||
static irqreturn_t idi_48_irq_handler(int irq, void *dev_id)
|
||||
{
|
||||
struct idi_48_gpio *const idi48gpio = dev_id;
|
||||
unsigned long cos_status;
|
||||
unsigned long boundary;
|
||||
unsigned long irq_mask;
|
||||
unsigned long bit_num;
|
||||
unsigned long gpio;
|
||||
struct gpio_chip *const chip = &idi48gpio->chip;
|
||||
|
||||
spin_lock(&idi48gpio->lock);
|
||||
|
||||
cos_status = ioread8(&idi48gpio->reg->irq);
|
||||
|
||||
/* IRQ Status (bit 6) is active low (0 = IRQ generated by device) */
|
||||
if (cos_status & BIT(6)) {
|
||||
spin_unlock(&idi48gpio->lock);
|
||||
return IRQ_NONE;
|
||||
}
|
||||
|
||||
/* Bit 0-5 indicate which Change-Of-State boundary triggered the IRQ */
|
||||
cos_status &= 0x3F;
|
||||
|
||||
for_each_set_bit(boundary, &cos_status, 6) {
|
||||
irq_mask = idi48gpio->irq_mask[boundary];
|
||||
|
||||
for_each_set_bit(bit_num, &irq_mask, 8) {
|
||||
gpio = bit_num + boundary * 8;
|
||||
|
||||
generic_handle_domain_irq(chip->irq.domain,
|
||||
gpio);
|
||||
}
|
||||
}
|
||||
|
||||
spin_unlock(&idi48gpio->lock);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
#define IDI48_NGPIO 48
|
||||
|
||||
#define IDI48_REGMAP_IRQ(_id) \
|
||||
[_id] = { \
|
||||
.mask = BIT((_id) / 8), \
|
||||
.type = { .types_supported = IRQ_TYPE_EDGE_BOTH }, \
|
||||
}
|
||||
|
||||
static const struct regmap_irq idi48_regmap_irqs[IDI48_NGPIO] = {
|
||||
IDI48_REGMAP_IRQ(0), IDI48_REGMAP_IRQ(1), IDI48_REGMAP_IRQ(2), /* 0-2 */
|
||||
IDI48_REGMAP_IRQ(3), IDI48_REGMAP_IRQ(4), IDI48_REGMAP_IRQ(5), /* 3-5 */
|
||||
IDI48_REGMAP_IRQ(6), IDI48_REGMAP_IRQ(7), IDI48_REGMAP_IRQ(8), /* 6-8 */
|
||||
IDI48_REGMAP_IRQ(9), IDI48_REGMAP_IRQ(10), IDI48_REGMAP_IRQ(11), /* 9-11 */
|
||||
IDI48_REGMAP_IRQ(12), IDI48_REGMAP_IRQ(13), IDI48_REGMAP_IRQ(14), /* 12-14 */
|
||||
IDI48_REGMAP_IRQ(15), IDI48_REGMAP_IRQ(16), IDI48_REGMAP_IRQ(17), /* 15-17 */
|
||||
IDI48_REGMAP_IRQ(18), IDI48_REGMAP_IRQ(19), IDI48_REGMAP_IRQ(20), /* 18-20 */
|
||||
IDI48_REGMAP_IRQ(21), IDI48_REGMAP_IRQ(22), IDI48_REGMAP_IRQ(23), /* 21-23 */
|
||||
IDI48_REGMAP_IRQ(24), IDI48_REGMAP_IRQ(25), IDI48_REGMAP_IRQ(26), /* 24-26 */
|
||||
IDI48_REGMAP_IRQ(27), IDI48_REGMAP_IRQ(28), IDI48_REGMAP_IRQ(29), /* 27-29 */
|
||||
IDI48_REGMAP_IRQ(30), IDI48_REGMAP_IRQ(31), IDI48_REGMAP_IRQ(32), /* 30-32 */
|
||||
IDI48_REGMAP_IRQ(33), IDI48_REGMAP_IRQ(34), IDI48_REGMAP_IRQ(35), /* 33-35 */
|
||||
IDI48_REGMAP_IRQ(36), IDI48_REGMAP_IRQ(37), IDI48_REGMAP_IRQ(38), /* 36-38 */
|
||||
IDI48_REGMAP_IRQ(39), IDI48_REGMAP_IRQ(40), IDI48_REGMAP_IRQ(41), /* 39-41 */
|
||||
IDI48_REGMAP_IRQ(42), IDI48_REGMAP_IRQ(43), IDI48_REGMAP_IRQ(44), /* 42-44 */
|
||||
IDI48_REGMAP_IRQ(45), IDI48_REGMAP_IRQ(46), IDI48_REGMAP_IRQ(47), /* 45-47 */
|
||||
};
|
||||
|
||||
static const char *idi48_names[IDI48_NGPIO] = {
|
||||
"Bit 0 A", "Bit 1 A", "Bit 2 A", "Bit 3 A", "Bit 4 A", "Bit 5 A",
|
||||
"Bit 6 A", "Bit 7 A", "Bit 8 A", "Bit 9 A", "Bit 10 A", "Bit 11 A",
|
||||
|
@ -228,75 +121,58 @@ static const char *idi48_names[IDI48_NGPIO] = {
|
|||
"Bit 18 B", "Bit 19 B", "Bit 20 B", "Bit 21 B", "Bit 22 B", "Bit 23 B"
|
||||
};
|
||||
|
||||
static int idi_48_irq_init_hw(struct gpio_chip *gc)
|
||||
{
|
||||
struct idi_48_gpio *const idi48gpio = gpiochip_get_data(gc);
|
||||
|
||||
/* Disable IRQ by default */
|
||||
iowrite8(0, &idi48gpio->reg->irq);
|
||||
ioread8(&idi48gpio->reg->irq);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int idi_48_probe(struct device *dev, unsigned int id)
|
||||
{
|
||||
struct idi_48_gpio *idi48gpio;
|
||||
const char *const name = dev_name(dev);
|
||||
struct gpio_irq_chip *girq;
|
||||
struct gpio_regmap_config config = {};
|
||||
void __iomem *regs;
|
||||
struct regmap *map;
|
||||
struct regmap_irq_chip *chip;
|
||||
struct regmap_irq_chip_data *chip_data;
|
||||
int err;
|
||||
|
||||
idi48gpio = devm_kzalloc(dev, sizeof(*idi48gpio), GFP_KERNEL);
|
||||
if (!idi48gpio)
|
||||
return -ENOMEM;
|
||||
|
||||
if (!devm_request_region(dev, base[id], IDI_48_EXTENT, name)) {
|
||||
dev_err(dev, "Unable to lock port addresses (0x%X-0x%X)\n",
|
||||
base[id], base[id] + IDI_48_EXTENT);
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
idi48gpio->reg = devm_ioport_map(dev, base[id], IDI_48_EXTENT);
|
||||
if (!idi48gpio->reg)
|
||||
regs = devm_ioport_map(dev, base[id], IDI_48_EXTENT);
|
||||
if (!regs)
|
||||
return -ENOMEM;
|
||||
|
||||
idi48gpio->chip.label = name;
|
||||
idi48gpio->chip.parent = dev;
|
||||
idi48gpio->chip.owner = THIS_MODULE;
|
||||
idi48gpio->chip.base = -1;
|
||||
idi48gpio->chip.ngpio = IDI48_NGPIO;
|
||||
idi48gpio->chip.names = idi48_names;
|
||||
idi48gpio->chip.get_direction = idi_48_gpio_get_direction;
|
||||
idi48gpio->chip.direction_input = idi_48_gpio_direction_input;
|
||||
idi48gpio->chip.get = idi_48_gpio_get;
|
||||
idi48gpio->chip.get_multiple = idi_48_gpio_get_multiple;
|
||||
map = devm_regmap_init_mmio(dev, regs, &idi48_regmap_config);
|
||||
if (IS_ERR(map))
|
||||
return dev_err_probe(dev, PTR_ERR(map),
|
||||
"Unable to initialize register map\n");
|
||||
|
||||
girq = &idi48gpio->chip.irq;
|
||||
gpio_irq_chip_set_chip(girq, &idi_48_irqchip);
|
||||
/* This will let us handle the parent IRQ in the driver */
|
||||
girq->parent_handler = NULL;
|
||||
girq->num_parents = 0;
|
||||
girq->parents = NULL;
|
||||
girq->default_type = IRQ_TYPE_NONE;
|
||||
girq->handler = handle_edge_irq;
|
||||
girq->init_hw = idi_48_irq_init_hw;
|
||||
chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL);
|
||||
if (!chip)
|
||||
return -ENOMEM;
|
||||
|
||||
spin_lock_init(&idi48gpio->lock);
|
||||
chip->name = name;
|
||||
chip->status_base = IDI48_IRQ_STATUS;
|
||||
chip->unmask_base = IDI48_IRQ_ENABLE;
|
||||
chip->clear_on_unmask = true;
|
||||
chip->num_regs = 1;
|
||||
chip->irqs = idi48_regmap_irqs;
|
||||
chip->num_irqs = ARRAY_SIZE(idi48_regmap_irqs);
|
||||
|
||||
err = devm_gpiochip_add_data(dev, &idi48gpio->chip, idi48gpio);
|
||||
if (err) {
|
||||
dev_err(dev, "GPIO registering failed (%d)\n", err);
|
||||
return err;
|
||||
}
|
||||
err = devm_regmap_add_irq_chip(dev, map, irq[id], IRQF_SHARED, 0, chip,
|
||||
&chip_data);
|
||||
if (err)
|
||||
return dev_err_probe(dev, err, "IRQ registration failed\n");
|
||||
|
||||
err = devm_request_irq(dev, irq[id], idi_48_irq_handler, IRQF_SHARED,
|
||||
name, idi48gpio);
|
||||
if (err) {
|
||||
dev_err(dev, "IRQ handler registering failed (%d)\n", err);
|
||||
return err;
|
||||
}
|
||||
config.parent = dev;
|
||||
config.regmap = map;
|
||||
config.ngpio = IDI48_NGPIO;
|
||||
config.names = idi48_names;
|
||||
config.reg_dat_base = GPIO_REGMAP_ADDR(0x0);
|
||||
config.ngpio_per_reg = 8;
|
||||
config.reg_mask_xlate = idi_48_reg_mask_xlate;
|
||||
config.irq_domain = regmap_irq_get_domain(chip_data);
|
||||
|
||||
return 0;
|
||||
return PTR_ERR_OR_ZERO(devm_gpio_regmap_register(dev, &config));
|
||||
}
|
||||
|
||||
static struct isa_driver idi_48_driver = {
|
||||
|
|
|
@ -252,7 +252,6 @@ static int davinci_gpio_probe(struct platform_device *pdev)
|
|||
chips->chip.base = pdata->no_auto_base ? pdata->base : -1;
|
||||
|
||||
#ifdef CONFIG_OF_GPIO
|
||||
chips->chip.of_gpio_n_cells = 2;
|
||||
chips->chip.parent = dev;
|
||||
chips->chip.request = gpiochip_generic_request;
|
||||
chips->chip.free = gpiochip_generic_free;
|
||||
|
@ -534,7 +533,7 @@ static int davinci_gpio_irq_setup(struct platform_device *pdev)
|
|||
}
|
||||
|
||||
/*
|
||||
* Arrange gpio_to_irq() support, handling either direct IRQs or
|
||||
* Arrange gpiod_to_irq() support, handling either direct IRQs or
|
||||
* banked IRQs. Having GPIOs in the first GPIO bank use direct
|
||||
* IRQs, while the others use banked IRQs, would need some setup
|
||||
* tweaks to recognize hardware which can do that.
|
||||
|
|
|
@ -81,7 +81,6 @@ static int __init gef_gpio_probe(struct platform_device *pdev)
|
|||
|
||||
gc->base = -1;
|
||||
gc->ngpio = (u16)(uintptr_t)of_device_get_match_data(&pdev->dev);
|
||||
gc->of_gpio_n_cells = 2;
|
||||
|
||||
/* This function adds a memory mapped GPIO chip */
|
||||
ret = devm_gpiochip_add_data(&pdev->dev, gc, NULL);
|
||||
|
|
|
@ -8,13 +8,13 @@
|
|||
*/
|
||||
#include <linux/device.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/gpio/driver.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/isa.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#include "gpio-i8255.h"
|
||||
|
||||
|
@ -30,83 +30,22 @@ MODULE_PARM_DESC(base, "Diamond Systems GPIO-MM base addresses");
|
|||
|
||||
#define GPIOMM_NUM_PPI 2
|
||||
|
||||
/**
|
||||
* struct gpiomm_gpio - GPIO device private data structure
|
||||
* @chip: instance of the gpio_chip
|
||||
* @ppi_state: Programmable Peripheral Interface group states
|
||||
* @ppi: Programmable Peripheral Interface groups
|
||||
*/
|
||||
struct gpiomm_gpio {
|
||||
struct gpio_chip chip;
|
||||
struct i8255_state ppi_state[GPIOMM_NUM_PPI];
|
||||
struct i8255 __iomem *ppi;
|
||||
static const struct regmap_range gpiomm_volatile_ranges[] = {
|
||||
i8255_volatile_regmap_range(0x0), i8255_volatile_regmap_range(0x4),
|
||||
};
|
||||
static const struct regmap_access_table gpiomm_volatile_table = {
|
||||
.yes_ranges = gpiomm_volatile_ranges,
|
||||
.n_yes_ranges = ARRAY_SIZE(gpiomm_volatile_ranges),
|
||||
};
|
||||
static const struct regmap_config gpiomm_regmap_config = {
|
||||
.reg_bits = 8,
|
||||
.reg_stride = 1,
|
||||
.val_bits = 8,
|
||||
.io_port = true,
|
||||
.max_register = 0x7,
|
||||
.volatile_table = &gpiomm_volatile_table,
|
||||
.cache_type = REGCACHE_FLAT,
|
||||
};
|
||||
|
||||
static int gpiomm_gpio_get_direction(struct gpio_chip *chip,
|
||||
unsigned int offset)
|
||||
{
|
||||
struct gpiomm_gpio *const gpiommgpio = gpiochip_get_data(chip);
|
||||
|
||||
if (i8255_get_direction(gpiommgpio->ppi_state, offset))
|
||||
return GPIO_LINE_DIRECTION_IN;
|
||||
|
||||
return GPIO_LINE_DIRECTION_OUT;
|
||||
}
|
||||
|
||||
static int gpiomm_gpio_direction_input(struct gpio_chip *chip,
|
||||
unsigned int offset)
|
||||
{
|
||||
struct gpiomm_gpio *const gpiommgpio = gpiochip_get_data(chip);
|
||||
|
||||
i8255_direction_input(gpiommgpio->ppi, gpiommgpio->ppi_state, offset);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gpiomm_gpio_direction_output(struct gpio_chip *chip,
|
||||
unsigned int offset, int value)
|
||||
{
|
||||
struct gpiomm_gpio *const gpiommgpio = gpiochip_get_data(chip);
|
||||
|
||||
i8255_direction_output(gpiommgpio->ppi, gpiommgpio->ppi_state, offset,
|
||||
value);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gpiomm_gpio_get(struct gpio_chip *chip, unsigned int offset)
|
||||
{
|
||||
struct gpiomm_gpio *const gpiommgpio = gpiochip_get_data(chip);
|
||||
|
||||
return i8255_get(gpiommgpio->ppi, offset);
|
||||
}
|
||||
|
||||
static int gpiomm_gpio_get_multiple(struct gpio_chip *chip, unsigned long *mask,
|
||||
unsigned long *bits)
|
||||
{
|
||||
struct gpiomm_gpio *const gpiommgpio = gpiochip_get_data(chip);
|
||||
|
||||
i8255_get_multiple(gpiommgpio->ppi, mask, bits, chip->ngpio);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void gpiomm_gpio_set(struct gpio_chip *chip, unsigned int offset,
|
||||
int value)
|
||||
{
|
||||
struct gpiomm_gpio *const gpiommgpio = gpiochip_get_data(chip);
|
||||
|
||||
i8255_set(gpiommgpio->ppi, gpiommgpio->ppi_state, offset, value);
|
||||
}
|
||||
|
||||
static void gpiomm_gpio_set_multiple(struct gpio_chip *chip,
|
||||
unsigned long *mask, unsigned long *bits)
|
||||
{
|
||||
struct gpiomm_gpio *const gpiommgpio = gpiochip_get_data(chip);
|
||||
|
||||
i8255_set_multiple(gpiommgpio->ppi, gpiommgpio->ppi_state, mask, bits,
|
||||
chip->ngpio);
|
||||
}
|
||||
|
||||
#define GPIOMM_NGPIO 48
|
||||
static const char *gpiomm_names[GPIOMM_NGPIO] = {
|
||||
|
@ -120,30 +59,11 @@ static const char *gpiomm_names[GPIOMM_NGPIO] = {
|
|||
"Port 2C2", "Port 2C3", "Port 2C4", "Port 2C5", "Port 2C6", "Port 2C7",
|
||||
};
|
||||
|
||||
static void gpiomm_init_dio(struct i8255 __iomem *const ppi,
|
||||
struct i8255_state *const ppi_state)
|
||||
{
|
||||
const unsigned long ngpio = 24;
|
||||
const unsigned long mask = GENMASK(ngpio - 1, 0);
|
||||
const unsigned long bits = 0;
|
||||
unsigned long i;
|
||||
|
||||
/* Initialize all GPIO to output 0 */
|
||||
for (i = 0; i < GPIOMM_NUM_PPI; i++) {
|
||||
i8255_mode0_output(&ppi[i]);
|
||||
i8255_set_multiple(&ppi[i], &ppi_state[i], &mask, &bits, ngpio);
|
||||
}
|
||||
}
|
||||
|
||||
static int gpiomm_probe(struct device *dev, unsigned int id)
|
||||
{
|
||||
struct gpiomm_gpio *gpiommgpio;
|
||||
const char *const name = dev_name(dev);
|
||||
int err;
|
||||
|
||||
gpiommgpio = devm_kzalloc(dev, sizeof(*gpiommgpio), GFP_KERNEL);
|
||||
if (!gpiommgpio)
|
||||
return -ENOMEM;
|
||||
struct i8255_regmap_config config = {};
|
||||
void __iomem *regs;
|
||||
|
||||
if (!devm_request_region(dev, base[id], GPIOMM_EXTENT, name)) {
|
||||
dev_err(dev, "Unable to lock port addresses (0x%X-0x%X)\n",
|
||||
|
@ -151,34 +71,20 @@ static int gpiomm_probe(struct device *dev, unsigned int id)
|
|||
return -EBUSY;
|
||||
}
|
||||
|
||||
gpiommgpio->ppi = devm_ioport_map(dev, base[id], GPIOMM_EXTENT);
|
||||
if (!gpiommgpio->ppi)
|
||||
regs = devm_ioport_map(dev, base[id], GPIOMM_EXTENT);
|
||||
if (!regs)
|
||||
return -ENOMEM;
|
||||
|
||||
gpiommgpio->chip.label = name;
|
||||
gpiommgpio->chip.parent = dev;
|
||||
gpiommgpio->chip.owner = THIS_MODULE;
|
||||
gpiommgpio->chip.base = -1;
|
||||
gpiommgpio->chip.ngpio = GPIOMM_NGPIO;
|
||||
gpiommgpio->chip.names = gpiomm_names;
|
||||
gpiommgpio->chip.get_direction = gpiomm_gpio_get_direction;
|
||||
gpiommgpio->chip.direction_input = gpiomm_gpio_direction_input;
|
||||
gpiommgpio->chip.direction_output = gpiomm_gpio_direction_output;
|
||||
gpiommgpio->chip.get = gpiomm_gpio_get;
|
||||
gpiommgpio->chip.get_multiple = gpiomm_gpio_get_multiple;
|
||||
gpiommgpio->chip.set = gpiomm_gpio_set;
|
||||
gpiommgpio->chip.set_multiple = gpiomm_gpio_set_multiple;
|
||||
config.map = devm_regmap_init_mmio(dev, regs, &gpiomm_regmap_config);
|
||||
if (IS_ERR(config.map))
|
||||
return dev_err_probe(dev, PTR_ERR(config.map),
|
||||
"Unable to initialize register map\n");
|
||||
|
||||
i8255_state_init(gpiommgpio->ppi_state, GPIOMM_NUM_PPI);
|
||||
gpiomm_init_dio(gpiommgpio->ppi, gpiommgpio->ppi_state);
|
||||
config.parent = dev;
|
||||
config.num_ppi = GPIOMM_NUM_PPI;
|
||||
config.names = gpiomm_names;
|
||||
|
||||
err = devm_gpiochip_add_data(dev, &gpiommgpio->chip, gpiommgpio);
|
||||
if (err) {
|
||||
dev_err(dev, "GPIO registering failed (%d)\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return devm_i8255_regmap_register(dev, &config);
|
||||
}
|
||||
|
||||
static struct isa_driver gpiomm_driver = {
|
||||
|
|
|
@ -3,48 +3,43 @@
|
|||
* Intel 8255 Programmable Peripheral Interface
|
||||
* Copyright (C) 2022 William Breathitt Gray
|
||||
*/
|
||||
#include <linux/bitmap.h>
|
||||
#include <linux/bits.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/gpio/regmap.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/regmap.h>
|
||||
|
||||
#include "gpio-i8255.h"
|
||||
|
||||
#define I8255_NGPIO 24
|
||||
#define I8255_NGPIO_PER_REG 8
|
||||
#define I8255_CONTROL_PORTC_LOWER_DIRECTION BIT(0)
|
||||
#define I8255_CONTROL_PORTB_DIRECTION BIT(1)
|
||||
#define I8255_CONTROL_PORTC_UPPER_DIRECTION BIT(3)
|
||||
#define I8255_CONTROL_PORTA_DIRECTION BIT(4)
|
||||
#define I8255_CONTROL_MODE_SET BIT(7)
|
||||
#define I8255_PORTA 0
|
||||
#define I8255_PORTB 1
|
||||
#define I8255_PORTC 2
|
||||
#define I8255_PORTA 0x0
|
||||
#define I8255_PORTB 0x1
|
||||
#define I8255_PORTC 0x2
|
||||
#define I8255_CONTROL 0x3
|
||||
#define I8255_REG_DAT_BASE I8255_PORTA
|
||||
#define I8255_REG_DIR_IN_BASE I8255_CONTROL
|
||||
|
||||
static int i8255_get_port(struct i8255 __iomem *const ppi,
|
||||
const unsigned long io_port, const unsigned long mask)
|
||||
static int i8255_direction_mask(const unsigned int offset)
|
||||
{
|
||||
const unsigned long bank = io_port / 3;
|
||||
const unsigned long ppi_port = io_port % 3;
|
||||
const unsigned int stride = offset / I8255_NGPIO_PER_REG;
|
||||
const unsigned int line = offset % I8255_NGPIO_PER_REG;
|
||||
|
||||
return ioread8(&ppi[bank].port[ppi_port]) & mask;
|
||||
}
|
||||
|
||||
static u8 i8255_direction_mask(const unsigned long offset)
|
||||
{
|
||||
const unsigned long port_offset = offset % 8;
|
||||
const unsigned long io_port = offset / 8;
|
||||
const unsigned long ppi_port = io_port % 3;
|
||||
|
||||
switch (ppi_port) {
|
||||
switch (stride) {
|
||||
case I8255_PORTA:
|
||||
return I8255_CONTROL_PORTA_DIRECTION;
|
||||
case I8255_PORTB:
|
||||
return I8255_CONTROL_PORTB_DIRECTION;
|
||||
case I8255_PORTC:
|
||||
/* Port C can be configured by nibble */
|
||||
if (port_offset >= 4)
|
||||
if (line >= 4)
|
||||
return I8255_CONTROL_PORTC_UPPER_DIRECTION;
|
||||
return I8255_CONTROL_PORTC_LOWER_DIRECTION;
|
||||
default:
|
||||
|
@ -53,234 +48,93 @@ static u8 i8255_direction_mask(const unsigned long offset)
|
|||
}
|
||||
}
|
||||
|
||||
static void i8255_set_port(struct i8255 __iomem *const ppi,
|
||||
struct i8255_state *const state,
|
||||
const unsigned long io_port,
|
||||
const unsigned long mask, const unsigned long bits)
|
||||
static int i8255_ppi_init(struct regmap *const map, const unsigned int base)
|
||||
{
|
||||
const unsigned long bank = io_port / 3;
|
||||
const unsigned long ppi_port = io_port % 3;
|
||||
unsigned long flags;
|
||||
unsigned long out_state;
|
||||
int err;
|
||||
|
||||
spin_lock_irqsave(&state[bank].lock, flags);
|
||||
/* Configure all ports to MODE 0 output mode */
|
||||
err = regmap_write(map, base + I8255_CONTROL, I8255_CONTROL_MODE_SET);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
out_state = ioread8(&ppi[bank].port[ppi_port]);
|
||||
out_state = (out_state & ~mask) | (bits & mask);
|
||||
iowrite8(out_state, &ppi[bank].port[ppi_port]);
|
||||
|
||||
spin_unlock_irqrestore(&state[bank].lock, flags);
|
||||
/* Initialize all GPIO to output 0 */
|
||||
err = regmap_write(map, base + I8255_PORTA, 0x00);
|
||||
if (err)
|
||||
return err;
|
||||
err = regmap_write(map, base + I8255_PORTB, 0x00);
|
||||
if (err)
|
||||
return err;
|
||||
return regmap_write(map, base + I8255_PORTC, 0x00);
|
||||
}
|
||||
|
||||
/**
|
||||
* i8255_direction_input - configure signal offset as input
|
||||
* @ppi: Intel 8255 Programmable Peripheral Interface banks
|
||||
* @state: devices states of the respective PPI banks
|
||||
* @offset: signal offset to configure as input
|
||||
*
|
||||
* Configures a signal @offset as input for the respective Intel 8255
|
||||
* Programmable Peripheral Interface (@ppi) banks. The @state control_state
|
||||
* values are updated to reflect the new configuration.
|
||||
*/
|
||||
void i8255_direction_input(struct i8255 __iomem *const ppi,
|
||||
struct i8255_state *const state,
|
||||
const unsigned long offset)
|
||||
static int i8255_reg_mask_xlate(struct gpio_regmap *gpio, unsigned int base,
|
||||
unsigned int offset, unsigned int *reg,
|
||||
unsigned int *mask)
|
||||
{
|
||||
const unsigned long io_port = offset / 8;
|
||||
const unsigned long bank = io_port / 3;
|
||||
unsigned long flags;
|
||||
const unsigned int ppi = offset / I8255_NGPIO;
|
||||
const unsigned int ppi_offset = offset % I8255_NGPIO;
|
||||
const unsigned int stride = ppi_offset / I8255_NGPIO_PER_REG;
|
||||
const unsigned int line = ppi_offset % I8255_NGPIO_PER_REG;
|
||||
|
||||
spin_lock_irqsave(&state[bank].lock, flags);
|
||||
|
||||
state[bank].control_state |= I8255_CONTROL_MODE_SET;
|
||||
state[bank].control_state |= i8255_direction_mask(offset);
|
||||
|
||||
iowrite8(state[bank].control_state, &ppi[bank].control);
|
||||
|
||||
spin_unlock_irqrestore(&state[bank].lock, flags);
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(i8255_direction_input, I8255);
|
||||
|
||||
/**
|
||||
* i8255_direction_output - configure signal offset as output
|
||||
* @ppi: Intel 8255 Programmable Peripheral Interface banks
|
||||
* @state: devices states of the respective PPI banks
|
||||
* @offset: signal offset to configure as output
|
||||
* @value: signal value to output
|
||||
*
|
||||
* Configures a signal @offset as output for the respective Intel 8255
|
||||
* Programmable Peripheral Interface (@ppi) banks and sets the respective signal
|
||||
* output to the desired @value. The @state control_state values are updated to
|
||||
* reflect the new configuration.
|
||||
*/
|
||||
void i8255_direction_output(struct i8255 __iomem *const ppi,
|
||||
struct i8255_state *const state,
|
||||
const unsigned long offset,
|
||||
const unsigned long value)
|
||||
{
|
||||
const unsigned long io_port = offset / 8;
|
||||
const unsigned long bank = io_port / 3;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&state[bank].lock, flags);
|
||||
|
||||
state[bank].control_state |= I8255_CONTROL_MODE_SET;
|
||||
state[bank].control_state &= ~i8255_direction_mask(offset);
|
||||
|
||||
iowrite8(state[bank].control_state, &ppi[bank].control);
|
||||
|
||||
spin_unlock_irqrestore(&state[bank].lock, flags);
|
||||
|
||||
i8255_set(ppi, state, offset, value);
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(i8255_direction_output, I8255);
|
||||
|
||||
/**
|
||||
* i8255_get - get signal value at signal offset
|
||||
* @ppi: Intel 8255 Programmable Peripheral Interface banks
|
||||
* @offset: offset of signal to get
|
||||
*
|
||||
* Returns the signal value (0=low, 1=high) for the signal at @offset for the
|
||||
* respective Intel 8255 Programmable Peripheral Interface (@ppi) banks.
|
||||
*/
|
||||
int i8255_get(struct i8255 __iomem *const ppi, const unsigned long offset)
|
||||
{
|
||||
const unsigned long io_port = offset / 8;
|
||||
const unsigned long offset_mask = BIT(offset % 8);
|
||||
|
||||
return !!i8255_get_port(ppi, io_port, offset_mask);
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(i8255_get, I8255);
|
||||
|
||||
/**
|
||||
* i8255_get_direction - get the I/O direction for a signal offset
|
||||
* @state: devices states of the respective PPI banks
|
||||
* @offset: offset of signal to get direction
|
||||
*
|
||||
* Returns the signal direction (0=output, 1=input) for the signal at @offset.
|
||||
*/
|
||||
int i8255_get_direction(const struct i8255_state *const state,
|
||||
const unsigned long offset)
|
||||
{
|
||||
const unsigned long io_port = offset / 8;
|
||||
const unsigned long bank = io_port / 3;
|
||||
|
||||
return !!(state[bank].control_state & i8255_direction_mask(offset));
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(i8255_get_direction, I8255);
|
||||
|
||||
/**
|
||||
* i8255_get_multiple - get multiple signal values at multiple signal offsets
|
||||
* @ppi: Intel 8255 Programmable Peripheral Interface banks
|
||||
* @mask: mask of signals to get
|
||||
* @bits: bitmap to store signal values
|
||||
* @ngpio: number of GPIO signals of the respective PPI banks
|
||||
*
|
||||
* Stores in @bits the values (0=low, 1=high) for the signals defined by @mask
|
||||
* for the respective Intel 8255 Programmable Peripheral Interface (@ppi) banks.
|
||||
*/
|
||||
void i8255_get_multiple(struct i8255 __iomem *const ppi,
|
||||
const unsigned long *const mask,
|
||||
unsigned long *const bits, const unsigned long ngpio)
|
||||
{
|
||||
unsigned long offset;
|
||||
unsigned long port_mask;
|
||||
unsigned long io_port;
|
||||
unsigned long port_state;
|
||||
|
||||
bitmap_zero(bits, ngpio);
|
||||
|
||||
for_each_set_clump8(offset, port_mask, mask, ngpio) {
|
||||
io_port = offset / 8;
|
||||
port_state = i8255_get_port(ppi, io_port, port_mask);
|
||||
|
||||
bitmap_set_value8(bits, port_state, offset);
|
||||
switch (base) {
|
||||
case I8255_REG_DAT_BASE:
|
||||
*reg = base + stride + ppi * 4;
|
||||
*mask = BIT(line);
|
||||
return 0;
|
||||
case I8255_REG_DIR_IN_BASE:
|
||||
*reg = base + ppi * 4;
|
||||
*mask = i8255_direction_mask(ppi_offset);
|
||||
return 0;
|
||||
default:
|
||||
/* Should never reach this path */
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(i8255_get_multiple, I8255);
|
||||
|
||||
/**
|
||||
* i8255_mode0_output - configure all PPI ports to MODE 0 output mode
|
||||
* @ppi: Intel 8255 Programmable Peripheral Interface bank
|
||||
* devm_i8255_regmap_register - Register an i8255 GPIO controller
|
||||
* @dev: device that is registering this i8255 GPIO device
|
||||
* @config: configuration for i8255_regmap_config
|
||||
*
|
||||
* Configures all Intel 8255 Programmable Peripheral Interface (@ppi) ports to
|
||||
* MODE 0 (Basic Input/Output) output mode.
|
||||
* Registers an Intel 8255 Programmable Peripheral Interface GPIO controller.
|
||||
* Returns 0 on success and negative error number on failure.
|
||||
*/
|
||||
void i8255_mode0_output(struct i8255 __iomem *const ppi)
|
||||
int devm_i8255_regmap_register(struct device *const dev,
|
||||
const struct i8255_regmap_config *const config)
|
||||
{
|
||||
iowrite8(I8255_CONTROL_MODE_SET, &ppi->control);
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(i8255_mode0_output, I8255);
|
||||
struct gpio_regmap_config gpio_config = {0};
|
||||
unsigned long i;
|
||||
int err;
|
||||
|
||||
/**
|
||||
* i8255_set - set signal value at signal offset
|
||||
* @ppi: Intel 8255 Programmable Peripheral Interface banks
|
||||
* @state: devices states of the respective PPI banks
|
||||
* @offset: offset of signal to set
|
||||
* @value: value of signal to set
|
||||
*
|
||||
* Assigns output @value for the signal at @offset for the respective Intel 8255
|
||||
* Programmable Peripheral Interface (@ppi) banks.
|
||||
*/
|
||||
void i8255_set(struct i8255 __iomem *const ppi, struct i8255_state *const state,
|
||||
const unsigned long offset, const unsigned long value)
|
||||
{
|
||||
const unsigned long io_port = offset / 8;
|
||||
const unsigned long port_offset = offset % 8;
|
||||
const unsigned long mask = BIT(port_offset);
|
||||
const unsigned long bits = value << port_offset;
|
||||
if (!config->parent)
|
||||
return -EINVAL;
|
||||
|
||||
i8255_set_port(ppi, state, io_port, mask, bits);
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(i8255_set, I8255);
|
||||
if (!config->map)
|
||||
return -EINVAL;
|
||||
|
||||
/**
|
||||
* i8255_set_multiple - set signal values at multiple signal offsets
|
||||
* @ppi: Intel 8255 Programmable Peripheral Interface banks
|
||||
* @state: devices states of the respective PPI banks
|
||||
* @mask: mask of signals to set
|
||||
* @bits: bitmap of signal output values
|
||||
* @ngpio: number of GPIO signals of the respective PPI banks
|
||||
*
|
||||
* Assigns output values defined by @bits for the signals defined by @mask for
|
||||
* the respective Intel 8255 Programmable Peripheral Interface (@ppi) banks.
|
||||
*/
|
||||
void i8255_set_multiple(struct i8255 __iomem *const ppi,
|
||||
struct i8255_state *const state,
|
||||
const unsigned long *const mask,
|
||||
const unsigned long *const bits,
|
||||
const unsigned long ngpio)
|
||||
{
|
||||
unsigned long offset;
|
||||
unsigned long port_mask;
|
||||
unsigned long io_port;
|
||||
unsigned long value;
|
||||
if (!config->num_ppi)
|
||||
return -EINVAL;
|
||||
|
||||
for_each_set_clump8(offset, port_mask, mask, ngpio) {
|
||||
io_port = offset / 8;
|
||||
value = bitmap_get_value8(bits, offset);
|
||||
i8255_set_port(ppi, state, io_port, port_mask, value);
|
||||
for (i = 0; i < config->num_ppi; i++) {
|
||||
err = i8255_ppi_init(config->map, i * 4);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(i8255_set_multiple, I8255);
|
||||
|
||||
/**
|
||||
* i8255_state_init - initialize i8255_state structure
|
||||
* @state: devices states of the respective PPI banks
|
||||
* @nbanks: number of Intel 8255 Programmable Peripheral Interface banks
|
||||
*
|
||||
* Initializes the @state of each Intel 8255 Programmable Peripheral Interface
|
||||
* bank for use in i8255 library functions.
|
||||
*/
|
||||
void i8255_state_init(struct i8255_state *const state,
|
||||
const unsigned long nbanks)
|
||||
{
|
||||
unsigned long bank;
|
||||
gpio_config.parent = config->parent;
|
||||
gpio_config.regmap = config->map;
|
||||
gpio_config.ngpio = I8255_NGPIO * config->num_ppi;
|
||||
gpio_config.names = config->names;
|
||||
gpio_config.reg_dat_base = GPIO_REGMAP_ADDR(I8255_REG_DAT_BASE);
|
||||
gpio_config.reg_set_base = GPIO_REGMAP_ADDR(I8255_REG_DAT_BASE);
|
||||
gpio_config.reg_dir_in_base = GPIO_REGMAP_ADDR(I8255_REG_DIR_IN_BASE);
|
||||
gpio_config.ngpio_per_reg = I8255_NGPIO_PER_REG;
|
||||
gpio_config.irq_domain = config->domain;
|
||||
gpio_config.reg_mask_xlate = i8255_reg_mask_xlate;
|
||||
|
||||
for (bank = 0; bank < nbanks; bank++)
|
||||
spin_lock_init(&state[bank].lock);
|
||||
return PTR_ERR_OR_ZERO(devm_gpio_regmap_register(dev, &gpio_config));
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(i8255_state_init, I8255);
|
||||
EXPORT_SYMBOL_NS_GPL(devm_i8255_regmap_register, I8255);
|
||||
|
||||
MODULE_AUTHOR("William Breathitt Gray");
|
||||
MODULE_DESCRIPTION("Intel 8255 Programmable Peripheral Interface");
|
||||
|
|
|
@ -3,44 +3,32 @@
|
|||
#ifndef _I8255_H_
|
||||
#define _I8255_H_
|
||||
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/types.h>
|
||||
struct device;
|
||||
struct irq_domain;
|
||||
struct regmap;
|
||||
|
||||
#define i8255_volatile_regmap_range(_base) regmap_reg_range(_base, _base + 0x2)
|
||||
|
||||
/**
|
||||
* struct i8255 - Intel 8255 register structure
|
||||
* @port: Port A, B, and C
|
||||
* @control: Control register
|
||||
* struct i8255_regmap_config - Configuration for the register map of an i8255
|
||||
* @parent: parent device
|
||||
* @map: regmap for the i8255
|
||||
* @num_ppi: number of i8255 Programmable Peripheral Interface
|
||||
* @names: (optional) array of names for gpios
|
||||
* @domain: (optional) IRQ domain if the controller is interrupt-capable
|
||||
*
|
||||
* Note: The regmap is expected to have cache enabled and i8255 control
|
||||
* registers not marked as volatile.
|
||||
*/
|
||||
struct i8255 {
|
||||
u8 port[3];
|
||||
u8 control;
|
||||
struct i8255_regmap_config {
|
||||
struct device *parent;
|
||||
struct regmap *map;
|
||||
int num_ppi;
|
||||
const char *const *names;
|
||||
struct irq_domain *domain;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct i8255_state - Intel 8255 state structure
|
||||
* @lock: synchronization lock for accessing device state
|
||||
* @control_state: Control register state
|
||||
*/
|
||||
struct i8255_state {
|
||||
spinlock_t lock;
|
||||
u8 control_state;
|
||||
};
|
||||
|
||||
void i8255_direction_input(struct i8255 __iomem *ppi, struct i8255_state *state,
|
||||
unsigned long offset);
|
||||
void i8255_direction_output(struct i8255 __iomem *ppi,
|
||||
struct i8255_state *state, unsigned long offset,
|
||||
unsigned long value);
|
||||
int i8255_get(struct i8255 __iomem *ppi, unsigned long offset);
|
||||
int i8255_get_direction(const struct i8255_state *state, unsigned long offset);
|
||||
void i8255_get_multiple(struct i8255 __iomem *ppi, const unsigned long *mask,
|
||||
unsigned long *bits, unsigned long ngpio);
|
||||
void i8255_mode0_output(struct i8255 __iomem *const ppi);
|
||||
void i8255_set(struct i8255 __iomem *ppi, struct i8255_state *state,
|
||||
unsigned long offset, unsigned long value);
|
||||
void i8255_set_multiple(struct i8255 __iomem *ppi, struct i8255_state *state,
|
||||
const unsigned long *mask, const unsigned long *bits,
|
||||
unsigned long ngpio);
|
||||
void i8255_state_init(struct i8255_state *const state, unsigned long nbanks);
|
||||
int devm_i8255_regmap_register(struct device *dev,
|
||||
const struct i8255_regmap_config *config);
|
||||
|
||||
#endif /* _I8255_H_ */
|
||||
|
|
|
@ -655,11 +655,6 @@ static int msc313_gpio_probe(struct platform_device *pdev)
|
|||
return devm_gpiochip_add_data(dev, gpiochip, gpio);
|
||||
}
|
||||
|
||||
static int msc313_gpio_remove(struct platform_device *pdev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id msc313_gpio_of_match[] = {
|
||||
#ifdef CONFIG_MACH_INFINITY
|
||||
{
|
||||
|
@ -710,6 +705,5 @@ static struct platform_driver msc313_gpio_driver = {
|
|||
.pm = &msc313_gpio_ops,
|
||||
},
|
||||
.probe = msc313_gpio_probe,
|
||||
.remove = msc313_gpio_remove,
|
||||
};
|
||||
builtin_platform_driver(msc313_gpio_driver);
|
||||
|
|
|
@ -1002,7 +1002,7 @@ static int mvebu_gpio_suspend(struct platform_device *pdev, pm_message_t state)
|
|||
BUG();
|
||||
}
|
||||
|
||||
if (IS_ENABLED(CONFIG_PWM))
|
||||
if (IS_REACHABLE(CONFIG_PWM))
|
||||
mvebu_pwm_suspend(mvchip);
|
||||
|
||||
return 0;
|
||||
|
@ -1054,7 +1054,7 @@ static int mvebu_gpio_resume(struct platform_device *pdev)
|
|||
BUG();
|
||||
}
|
||||
|
||||
if (IS_ENABLED(CONFIG_PWM))
|
||||
if (IS_REACHABLE(CONFIG_PWM))
|
||||
mvebu_pwm_resume(mvchip);
|
||||
|
||||
return 0;
|
||||
|
@ -1228,7 +1228,7 @@ static int mvebu_gpio_probe(struct platform_device *pdev)
|
|||
devm_gpiochip_add_data(&pdev->dev, &mvchip->chip, mvchip);
|
||||
|
||||
/* Some MVEBU SoCs have simple PWM support for GPIO lines */
|
||||
if (IS_ENABLED(CONFIG_PWM)) {
|
||||
if (IS_REACHABLE(CONFIG_PWM)) {
|
||||
err = mvebu_pwm_probe(pdev, mvchip, id);
|
||||
if (err)
|
||||
return err;
|
||||
|
|
|
@ -1020,7 +1020,7 @@ static int omap_gpio_chip_init(struct gpio_bank *bank, struct irq_chip *irqc,
|
|||
if (!label)
|
||||
return -ENOMEM;
|
||||
bank->chip.label = label;
|
||||
bank->chip.base = gpio;
|
||||
bank->chip.base = -1;
|
||||
}
|
||||
bank->chip.ngpio = bank->width;
|
||||
|
||||
|
|
|
@ -306,34 +306,31 @@ static bool pca953x_check_register(struct pca953x_chip *chip, unsigned int reg,
|
|||
static bool pcal6534_check_register(struct pca953x_chip *chip, unsigned int reg,
|
||||
u32 checkbank)
|
||||
{
|
||||
int bank_shift;
|
||||
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) {
|
||||
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;
|
||||
reg -= 0x54;
|
||||
bank_shift = 16;
|
||||
} else if (reg >= 0x30) {
|
||||
/*
|
||||
* Reserved block between 14h and 2Fh does not align on
|
||||
* expected bank boundaries like other devices.
|
||||
*/
|
||||
reg -= 0x30;
|
||||
bank_shift = 8;
|
||||
} else {
|
||||
bank = reg / NBANK(chip);
|
||||
offset = reg - (bank * NBANK(chip));
|
||||
bank_shift = 0;
|
||||
}
|
||||
|
||||
bank = bank_shift + reg / NBANK(chip);
|
||||
offset = reg % NBANK(chip);
|
||||
|
||||
/* Register is not in the matching bank. */
|
||||
if (!(BIT(bank) & checkbank))
|
||||
return false;
|
||||
|
@ -464,7 +461,6 @@ static u8 pcal6534_recalc_addr(struct pca953x_chip *chip, int reg, int off)
|
|||
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:
|
||||
|
|
|
@ -18,11 +18,11 @@
|
|||
#define SLG7XL45106_GPO_REG 0xDB
|
||||
|
||||
/**
|
||||
* struct pca9570_platform_data - GPIO platformdata
|
||||
* struct pca9570_chip_data - GPIO platformdata
|
||||
* @ngpio: no of gpios
|
||||
* @command: Command to be sent
|
||||
*/
|
||||
struct pca9570_platform_data {
|
||||
struct pca9570_chip_data {
|
||||
u16 ngpio;
|
||||
u32 command;
|
||||
};
|
||||
|
@ -36,7 +36,7 @@ struct pca9570_platform_data {
|
|||
*/
|
||||
struct pca9570 {
|
||||
struct gpio_chip chip;
|
||||
const struct pca9570_platform_data *p_data;
|
||||
const struct pca9570_chip_data *chip_data;
|
||||
struct mutex lock;
|
||||
u8 out;
|
||||
};
|
||||
|
@ -46,8 +46,8 @@ static int pca9570_read(struct pca9570 *gpio, u8 *value)
|
|||
struct i2c_client *client = to_i2c_client(gpio->chip.parent);
|
||||
int ret;
|
||||
|
||||
if (gpio->p_data->command != 0)
|
||||
ret = i2c_smbus_read_byte_data(client, gpio->p_data->command);
|
||||
if (gpio->chip_data->command != 0)
|
||||
ret = i2c_smbus_read_byte_data(client, gpio->chip_data->command);
|
||||
else
|
||||
ret = i2c_smbus_read_byte(client);
|
||||
|
||||
|
@ -62,8 +62,8 @@ static int pca9570_write(struct pca9570 *gpio, u8 value)
|
|||
{
|
||||
struct i2c_client *client = to_i2c_client(gpio->chip.parent);
|
||||
|
||||
if (gpio->p_data->command != 0)
|
||||
return i2c_smbus_write_byte_data(client, gpio->p_data->command, value);
|
||||
if (gpio->chip_data->command != 0)
|
||||
return i2c_smbus_write_byte_data(client, gpio->chip_data->command, value);
|
||||
|
||||
return i2c_smbus_write_byte(client, value);
|
||||
}
|
||||
|
@ -127,8 +127,8 @@ static int pca9570_probe(struct i2c_client *client)
|
|||
gpio->chip.get = pca9570_get;
|
||||
gpio->chip.set = pca9570_set;
|
||||
gpio->chip.base = -1;
|
||||
gpio->p_data = device_get_match_data(&client->dev);
|
||||
gpio->chip.ngpio = gpio->p_data->ngpio;
|
||||
gpio->chip_data = device_get_match_data(&client->dev);
|
||||
gpio->chip.ngpio = gpio->chip_data->ngpio;
|
||||
gpio->chip.can_sleep = true;
|
||||
|
||||
mutex_init(&gpio->lock);
|
||||
|
@ -141,15 +141,15 @@ static int pca9570_probe(struct i2c_client *client)
|
|||
return devm_gpiochip_add_data(&client->dev, &gpio->chip, gpio);
|
||||
}
|
||||
|
||||
static const struct pca9570_platform_data pca9570_gpio = {
|
||||
static const struct pca9570_chip_data pca9570_gpio = {
|
||||
.ngpio = 4,
|
||||
};
|
||||
|
||||
static const struct pca9570_platform_data pca9571_gpio = {
|
||||
static const struct pca9570_chip_data pca9571_gpio = {
|
||||
.ngpio = 8,
|
||||
};
|
||||
|
||||
static const struct pca9570_platform_data slg7xl45106_gpio = {
|
||||
static const struct pca9570_chip_data slg7xl45106_gpio = {
|
||||
.ngpio = 8,
|
||||
.command = SLG7XL45106_GPO_REG,
|
||||
};
|
||||
|
|
|
@ -7,18 +7,16 @@
|
|||
|
||||
#include <linux/gpio/driver.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/platform_data/pcf857x.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/irqdomain.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/property.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/spinlock.h>
|
||||
|
||||
|
||||
static const struct i2c_device_id pcf857x_id[] = {
|
||||
{ "pcf8574", 8 },
|
||||
{ "pcf8574a", 8 },
|
||||
|
@ -37,7 +35,6 @@ static const struct i2c_device_id pcf857x_id[] = {
|
|||
};
|
||||
MODULE_DEVICE_TABLE(i2c, pcf857x_id);
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static const struct of_device_id pcf857x_of_table[] = {
|
||||
{ .compatible = "nxp,pcf8574" },
|
||||
{ .compatible = "nxp,pcf8574a" },
|
||||
|
@ -55,7 +52,6 @@ static const struct of_device_id pcf857x_of_table[] = {
|
|||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, pcf857x_of_table);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* The pcf857x, pca857x, and pca967x chips only expose one read and one
|
||||
|
@ -73,11 +69,11 @@ struct pcf857x {
|
|||
struct gpio_chip chip;
|
||||
struct i2c_client *client;
|
||||
struct mutex lock; /* protect 'out' */
|
||||
unsigned out; /* software latch */
|
||||
unsigned status; /* current status */
|
||||
unsigned irq_enabled; /* enabled irqs */
|
||||
unsigned int out; /* software latch */
|
||||
unsigned int status; /* current status */
|
||||
unsigned int irq_enabled; /* enabled irqs */
|
||||
|
||||
int (*write)(struct i2c_client *client, unsigned data);
|
||||
int (*write)(struct i2c_client *client, unsigned int data);
|
||||
int (*read)(struct i2c_client *client);
|
||||
};
|
||||
|
||||
|
@ -85,19 +81,19 @@ struct pcf857x {
|
|||
|
||||
/* Talk to 8-bit I/O expander */
|
||||
|
||||
static int i2c_write_le8(struct i2c_client *client, unsigned data)
|
||||
static int i2c_write_le8(struct i2c_client *client, unsigned int data)
|
||||
{
|
||||
return i2c_smbus_write_byte(client, data);
|
||||
}
|
||||
|
||||
static int i2c_read_le8(struct i2c_client *client)
|
||||
{
|
||||
return (int)i2c_smbus_read_byte(client);
|
||||
return i2c_smbus_read_byte(client);
|
||||
}
|
||||
|
||||
/* Talk to 16-bit I/O expander */
|
||||
|
||||
static int i2c_write_le16(struct i2c_client *client, unsigned word)
|
||||
static int i2c_write_le16(struct i2c_client *client, unsigned int word)
|
||||
{
|
||||
u8 buf[2] = { word & 0xff, word >> 8, };
|
||||
int status;
|
||||
|
@ -119,10 +115,10 @@ static int i2c_read_le16(struct i2c_client *client)
|
|||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
static int pcf857x_input(struct gpio_chip *chip, unsigned offset)
|
||||
static int pcf857x_input(struct gpio_chip *chip, unsigned int offset)
|
||||
{
|
||||
struct pcf857x *gpio = gpiochip_get_data(chip);
|
||||
int status;
|
||||
struct pcf857x *gpio = gpiochip_get_data(chip);
|
||||
int status;
|
||||
|
||||
mutex_lock(&gpio->lock);
|
||||
gpio->out |= (1 << offset);
|
||||
|
@ -132,20 +128,35 @@ static int pcf857x_input(struct gpio_chip *chip, unsigned offset)
|
|||
return status;
|
||||
}
|
||||
|
||||
static int pcf857x_get(struct gpio_chip *chip, unsigned offset)
|
||||
static int pcf857x_get(struct gpio_chip *chip, unsigned int offset)
|
||||
{
|
||||
struct pcf857x *gpio = gpiochip_get_data(chip);
|
||||
int value;
|
||||
struct pcf857x *gpio = gpiochip_get_data(chip);
|
||||
int value;
|
||||
|
||||
value = gpio->read(gpio->client);
|
||||
return (value < 0) ? value : !!(value & (1 << offset));
|
||||
}
|
||||
|
||||
static int pcf857x_output(struct gpio_chip *chip, unsigned offset, int value)
|
||||
static int pcf857x_get_multiple(struct gpio_chip *chip, unsigned long *mask,
|
||||
unsigned long *bits)
|
||||
{
|
||||
struct pcf857x *gpio = gpiochip_get_data(chip);
|
||||
unsigned bit = 1 << offset;
|
||||
int status;
|
||||
struct pcf857x *gpio = gpiochip_get_data(chip);
|
||||
int value = gpio->read(gpio->client);
|
||||
|
||||
if (value < 0)
|
||||
return value;
|
||||
|
||||
*bits &= ~*mask;
|
||||
*bits |= value & *mask;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pcf857x_output(struct gpio_chip *chip, unsigned int offset, int value)
|
||||
{
|
||||
struct pcf857x *gpio = gpiochip_get_data(chip);
|
||||
unsigned int bit = 1 << offset;
|
||||
int status;
|
||||
|
||||
mutex_lock(&gpio->lock);
|
||||
if (value)
|
||||
|
@ -158,16 +169,28 @@ static int pcf857x_output(struct gpio_chip *chip, unsigned offset, int value)
|
|||
return status;
|
||||
}
|
||||
|
||||
static void pcf857x_set(struct gpio_chip *chip, unsigned offset, int value)
|
||||
static void pcf857x_set(struct gpio_chip *chip, unsigned int offset, int value)
|
||||
{
|
||||
pcf857x_output(chip, offset, value);
|
||||
}
|
||||
|
||||
static void pcf857x_set_multiple(struct gpio_chip *chip, unsigned long *mask,
|
||||
unsigned long *bits)
|
||||
{
|
||||
struct pcf857x *gpio = gpiochip_get_data(chip);
|
||||
|
||||
mutex_lock(&gpio->lock);
|
||||
gpio->out &= ~*mask;
|
||||
gpio->out |= *bits & *mask;
|
||||
gpio->write(gpio->client, gpio->out);
|
||||
mutex_unlock(&gpio->lock);
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
static irqreturn_t pcf857x_irq(int irq, void *data)
|
||||
{
|
||||
struct pcf857x *gpio = data;
|
||||
struct pcf857x *gpio = data;
|
||||
unsigned long change, i, status;
|
||||
|
||||
status = gpio->read(gpio->client);
|
||||
|
@ -250,18 +273,11 @@ static const struct irq_chip pcf857x_irq_chip = {
|
|||
static int pcf857x_probe(struct i2c_client *client)
|
||||
{
|
||||
const struct i2c_device_id *id = i2c_client_get_device_id(client);
|
||||
struct pcf857x_platform_data *pdata = dev_get_platdata(&client->dev);
|
||||
struct device_node *np = client->dev.of_node;
|
||||
struct pcf857x *gpio;
|
||||
unsigned int n_latch = 0;
|
||||
int status;
|
||||
struct pcf857x *gpio;
|
||||
unsigned int n_latch = 0;
|
||||
int status;
|
||||
|
||||
if (IS_ENABLED(CONFIG_OF) && np)
|
||||
of_property_read_u32(np, "lines-initial-states", &n_latch);
|
||||
else if (pdata)
|
||||
n_latch = pdata->n_latch;
|
||||
else
|
||||
dev_dbg(&client->dev, "no platform data\n");
|
||||
device_property_read_u32(&client->dev, "lines-initial-states", &n_latch);
|
||||
|
||||
/* Allocate, initialize, and register this gpio_chip. */
|
||||
gpio = devm_kzalloc(&client->dev, sizeof(*gpio), GFP_KERNEL);
|
||||
|
@ -270,12 +286,14 @@ static int pcf857x_probe(struct i2c_client *client)
|
|||
|
||||
mutex_init(&gpio->lock);
|
||||
|
||||
gpio->chip.base = pdata ? pdata->gpio_base : -1;
|
||||
gpio->chip.base = -1;
|
||||
gpio->chip.can_sleep = true;
|
||||
gpio->chip.parent = &client->dev;
|
||||
gpio->chip.owner = THIS_MODULE;
|
||||
gpio->chip.get = pcf857x_get;
|
||||
gpio->chip.get_multiple = pcf857x_get_multiple;
|
||||
gpio->chip.set = pcf857x_set;
|
||||
gpio->chip.set_multiple = pcf857x_set_multiple;
|
||||
gpio->chip.direction_input = pcf857x_input;
|
||||
gpio->chip.direction_output = pcf857x_output;
|
||||
gpio->chip.ngpio = id->driver_data;
|
||||
|
@ -377,17 +395,6 @@ static int pcf857x_probe(struct i2c_client *client)
|
|||
if (status < 0)
|
||||
goto fail;
|
||||
|
||||
/* Let platform code set up the GPIOs and their users.
|
||||
* Now is the first time anyone could use them.
|
||||
*/
|
||||
if (pdata && pdata->setup) {
|
||||
status = pdata->setup(client,
|
||||
gpio->chip.base, gpio->chip.ngpio,
|
||||
pdata->context);
|
||||
if (status < 0)
|
||||
dev_warn(&client->dev, "setup --> %d\n", status);
|
||||
}
|
||||
|
||||
dev_info(&client->dev, "probed\n");
|
||||
|
||||
return 0;
|
||||
|
@ -399,16 +406,6 @@ fail:
|
|||
return status;
|
||||
}
|
||||
|
||||
static void pcf857x_remove(struct i2c_client *client)
|
||||
{
|
||||
struct pcf857x_platform_data *pdata = dev_get_platdata(&client->dev);
|
||||
struct pcf857x *gpio = i2c_get_clientdata(client);
|
||||
|
||||
if (pdata && pdata->teardown)
|
||||
pdata->teardown(client, gpio->chip.base, gpio->chip.ngpio,
|
||||
pdata->context);
|
||||
}
|
||||
|
||||
static void pcf857x_shutdown(struct i2c_client *client)
|
||||
{
|
||||
struct pcf857x *gpio = i2c_get_clientdata(client);
|
||||
|
@ -420,10 +417,9 @@ static void pcf857x_shutdown(struct i2c_client *client)
|
|||
static struct i2c_driver pcf857x_driver = {
|
||||
.driver = {
|
||||
.name = "pcf857x",
|
||||
.of_match_table = of_match_ptr(pcf857x_of_table),
|
||||
.of_match_table = pcf857x_of_table,
|
||||
},
|
||||
.probe_new = pcf857x_probe,
|
||||
.remove = pcf857x_remove,
|
||||
.shutdown = pcf857x_shutdown,
|
||||
.id_table = pcf857x_id,
|
||||
};
|
||||
|
|
|
@ -111,6 +111,11 @@ static int gpio_regmap_get_direction(struct gpio_chip *chip,
|
|||
unsigned int base, val, reg, mask;
|
||||
int invert, ret;
|
||||
|
||||
if (gpio->reg_dat_base && !gpio->reg_set_base)
|
||||
return GPIO_LINE_DIRECTION_IN;
|
||||
if (gpio->reg_set_base && !gpio->reg_dat_base)
|
||||
return GPIO_LINE_DIRECTION_OUT;
|
||||
|
||||
if (gpio->reg_dir_out_base) {
|
||||
base = gpio_regmap_addr(gpio->reg_dir_out_base);
|
||||
invert = 0;
|
||||
|
@ -249,15 +254,7 @@ struct gpio_regmap *gpio_regmap_register(const struct gpio_regmap_config *config
|
|||
chip->ngpio = config->ngpio;
|
||||
chip->names = config->names;
|
||||
chip->label = config->label ?: dev_name(config->parent);
|
||||
|
||||
/*
|
||||
* If our regmap is fast_io we should probably set can_sleep to false.
|
||||
* Right now, the regmap doesn't save this property, nor is there any
|
||||
* access function for it.
|
||||
* The only regmap type which uses fast_io is regmap-mmio. For now,
|
||||
* assume a safe default of true here.
|
||||
*/
|
||||
chip->can_sleep = true;
|
||||
chip->can_sleep = regmap_might_sleep(config->regmap);
|
||||
|
||||
chip->get = gpio_regmap_get;
|
||||
if (gpio->reg_set_base && gpio->reg_clr_base)
|
||||
|
@ -265,8 +262,8 @@ struct gpio_regmap *gpio_regmap_register(const struct gpio_regmap_config *config
|
|||
else if (gpio->reg_set_base)
|
||||
chip->set = gpio_regmap_set;
|
||||
|
||||
chip->get_direction = gpio_regmap_get_direction;
|
||||
if (gpio->reg_dir_in_base || gpio->reg_dir_out_base) {
|
||||
chip->get_direction = gpio_regmap_get_direction;
|
||||
chip->direction_input = gpio_regmap_direction_input;
|
||||
chip->direction_output = gpio_regmap_direction_output;
|
||||
}
|
||||
|
|
|
@ -299,7 +299,7 @@ static int rockchip_gpio_set_config(struct gpio_chip *gc, unsigned int offset,
|
|||
}
|
||||
|
||||
/*
|
||||
* gpiolib gpio_to_irq callback function. Creates a mapping between a GPIO pin
|
||||
* gpiod_to_irq() callback function. Creates a mapping between a GPIO pin
|
||||
* and a virtual IRQ, if not already present.
|
||||
*/
|
||||
static int rockchip_gpio_to_irq(struct gpio_chip *gc, unsigned int offset)
|
||||
|
|
|
@ -377,8 +377,8 @@ static int gpio_sim_add_bank(struct fwnode_handle *swnode, struct device *dev)
|
|||
|
||||
ret = fwnode_property_read_string(swnode, "gpio-sim,label", &label);
|
||||
if (ret) {
|
||||
label = devm_kasprintf(dev, GFP_KERNEL, "%s-%s",
|
||||
dev_name(dev), fwnode_get_name(swnode));
|
||||
label = devm_kasprintf(dev, GFP_KERNEL, "%s-%pfwP",
|
||||
dev_name(dev), swnode);
|
||||
if (!label)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
@ -784,10 +784,9 @@ static int gpio_sim_add_hogs(struct gpio_sim_device *dev)
|
|||
GFP_KERNEL);
|
||||
else
|
||||
hog->chip_label = kasprintf(GFP_KERNEL,
|
||||
"gpio-sim.%u-%s",
|
||||
"gpio-sim.%u-%pfwP",
|
||||
dev->id,
|
||||
fwnode_get_name(
|
||||
bank->swnode));
|
||||
bank->swnode);
|
||||
if (!hog->chip_label) {
|
||||
gpio_sim_remove_hogs(dev);
|
||||
return -ENOMEM;
|
||||
|
|
|
@ -670,13 +670,14 @@ static unsigned int tegra186_gpio_child_offset_to_irq(struct gpio_chip *chip,
|
|||
static const struct of_device_id tegra186_pmc_of_match[] = {
|
||||
{ .compatible = "nvidia,tegra186-pmc" },
|
||||
{ .compatible = "nvidia,tegra194-pmc" },
|
||||
{ .compatible = "nvidia,tegra234-pmc" },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
|
||||
static void tegra186_gpio_init_route_mapping(struct tegra_gpio *gpio)
|
||||
{
|
||||
struct device *dev = gpio->gpio.parent;
|
||||
unsigned int i, j;
|
||||
unsigned int i;
|
||||
u32 value;
|
||||
|
||||
for (i = 0; i < gpio->soc->num_ports; i++) {
|
||||
|
@ -698,27 +699,23 @@ static void tegra186_gpio_init_route_mapping(struct tegra_gpio *gpio)
|
|||
* On Tegra194 and later, each pin can be routed to one or more
|
||||
* interrupts.
|
||||
*/
|
||||
for (j = 0; j < gpio->num_irqs_per_bank; j++) {
|
||||
dev_dbg(dev, "programming default interrupt routing for port %s\n",
|
||||
port->name);
|
||||
dev_dbg(dev, "programming default interrupt routing for port %s\n",
|
||||
port->name);
|
||||
|
||||
offset = TEGRA186_GPIO_INT_ROUTE_MAPPING(p, j);
|
||||
offset = TEGRA186_GPIO_INT_ROUTE_MAPPING(p, 0);
|
||||
|
||||
/*
|
||||
* By default we only want to route GPIO pins to IRQ 0. This works
|
||||
* only under the assumption that we're running as the host kernel
|
||||
* and hence all GPIO pins are owned by Linux.
|
||||
*
|
||||
* For cases where Linux is the guest OS, the hypervisor will have
|
||||
* to configure the interrupt routing and pass only the valid
|
||||
* interrupts via device tree.
|
||||
*/
|
||||
if (j == 0) {
|
||||
value = readl(base + offset);
|
||||
value = BIT(port->pins) - 1;
|
||||
writel(value, base + offset);
|
||||
}
|
||||
}
|
||||
/*
|
||||
* By default we only want to route GPIO pins to IRQ 0. This works
|
||||
* only under the assumption that we're running as the host kernel
|
||||
* and hence all GPIO pins are owned by Linux.
|
||||
*
|
||||
* For cases where Linux is the guest OS, the hypervisor will have
|
||||
* to configure the interrupt routing and pass only the valid
|
||||
* interrupts via device tree.
|
||||
*/
|
||||
value = readl(base + offset);
|
||||
value = BIT(port->pins) - 1;
|
||||
writel(value, base + offset);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -317,7 +317,7 @@ static int vf610_gpio_probe(struct platform_device *pdev)
|
|||
|
||||
gc = &port->gc;
|
||||
gc->parent = dev;
|
||||
gc->label = "vf610-gpio";
|
||||
gc->label = dev_name(dev);
|
||||
gc->ngpio = VF610_GPIO_PER_PORT;
|
||||
gc->base = of_alias_get_id(np, "gpio") * VF610_GPIO_PER_PORT;
|
||||
|
||||
|
|
|
@ -98,7 +98,6 @@ static int wcd_gpio_probe(struct platform_device *pdev)
|
|||
chip->base = -1;
|
||||
chip->ngpio = WCD934X_NPINS;
|
||||
chip->label = dev_name(dev);
|
||||
chip->of_gpio_n_cells = 2;
|
||||
chip->can_sleep = false;
|
||||
|
||||
return devm_gpiochip_add_data(dev, chip, data);
|
||||
|
|
|
@ -558,7 +558,6 @@ static int xgpio_probe(struct platform_device *pdev)
|
|||
int status = 0;
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
u32 is_dual = 0;
|
||||
u32 cells = 2;
|
||||
u32 width[2];
|
||||
u32 state[2];
|
||||
u32 dir[2];
|
||||
|
@ -591,15 +590,6 @@ static int xgpio_probe(struct platform_device *pdev)
|
|||
|
||||
bitmap_from_arr32(chip->dir, dir, 64);
|
||||
|
||||
/* Update cells with gpio-cells value */
|
||||
if (of_property_read_u32(np, "#gpio-cells", &cells))
|
||||
dev_dbg(&pdev->dev, "Missing gpio-cells property\n");
|
||||
|
||||
if (cells != 2) {
|
||||
dev_err(&pdev->dev, "#gpio-cells mismatch\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check device node and parent device node for device width
|
||||
* and assume default width of 32
|
||||
|
@ -630,7 +620,6 @@ static int xgpio_probe(struct platform_device *pdev)
|
|||
chip->gc.parent = &pdev->dev;
|
||||
chip->gc.direction_input = xgpio_dir_in;
|
||||
chip->gc.direction_output = xgpio_dir_out;
|
||||
chip->gc.of_gpio_n_cells = cells;
|
||||
chip->gc.get = xgpio_get;
|
||||
chip->gc.set = xgpio_set;
|
||||
chip->gc.request = xgpio_request;
|
||||
|
|
|
@ -5,13 +5,15 @@
|
|||
* Author: Fabian Vogt <fabian@ritter-vogt.de>
|
||||
*/
|
||||
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/spinlock.h>
|
||||
|
||||
#include <linux/gpio/driver.h>
|
||||
|
||||
/*
|
||||
|
@ -162,7 +164,6 @@ static const struct gpio_chip zevio_gpio_chip = {
|
|||
.base = 0,
|
||||
.owner = THIS_MODULE,
|
||||
.ngpio = 32,
|
||||
.of_gpio_n_cells = 2,
|
||||
};
|
||||
|
||||
/* Initialization */
|
||||
|
|
|
@ -1388,16 +1388,6 @@ void acpi_gpiochip_remove(struct gpio_chip *chip)
|
|||
kfree(acpi_gpio);
|
||||
}
|
||||
|
||||
void acpi_gpio_dev_init(struct gpio_chip *gc, struct gpio_device *gdev)
|
||||
{
|
||||
/* Set default fwnode to parent's one if present */
|
||||
if (gc->parent)
|
||||
ACPI_COMPANION_SET(&gdev->dev, ACPI_COMPANION(gc->parent));
|
||||
|
||||
if (gc->fwnode)
|
||||
device_set_node(&gdev->dev, gc->fwnode);
|
||||
}
|
||||
|
||||
static int acpi_gpio_package_count(const union acpi_object *obj)
|
||||
{
|
||||
const union acpi_object *element = obj->package.elements;
|
||||
|
|
|
@ -25,8 +25,6 @@ struct gpio_device;
|
|||
void acpi_gpiochip_add(struct gpio_chip *chip);
|
||||
void acpi_gpiochip_remove(struct gpio_chip *chip);
|
||||
|
||||
void acpi_gpio_dev_init(struct gpio_chip *gc, struct gpio_device *gdev);
|
||||
|
||||
void acpi_gpiochip_request_interrupts(struct gpio_chip *chip);
|
||||
void acpi_gpiochip_free_interrupts(struct gpio_chip *chip);
|
||||
|
||||
|
@ -41,8 +39,6 @@ int acpi_gpio_count(struct device *dev, const char *con_id);
|
|||
static inline void acpi_gpiochip_add(struct gpio_chip *chip) { }
|
||||
static inline void acpi_gpiochip_remove(struct gpio_chip *chip) { }
|
||||
|
||||
static inline void acpi_gpio_dev_init(struct gpio_chip *gc, struct gpio_device *gdev) { }
|
||||
|
||||
static inline void
|
||||
acpi_gpiochip_request_interrupts(struct gpio_chip *chip) { }
|
||||
|
||||
|
|
|
@ -321,7 +321,7 @@ static void linehandle_free(struct linehandle_state *lh)
|
|||
if (lh->descs[i])
|
||||
gpiod_free(lh->descs[i]);
|
||||
kfree(lh->label);
|
||||
put_device(&lh->gdev->dev);
|
||||
gpio_device_put(lh->gdev);
|
||||
kfree(lh);
|
||||
}
|
||||
|
||||
|
@ -363,8 +363,7 @@ static int linehandle_create(struct gpio_device *gdev, void __user *ip)
|
|||
lh = kzalloc(sizeof(*lh), GFP_KERNEL);
|
||||
if (!lh)
|
||||
return -ENOMEM;
|
||||
lh->gdev = gdev;
|
||||
get_device(&gdev->dev);
|
||||
lh->gdev = gpio_device_get(gdev);
|
||||
|
||||
if (handlereq.consumer_label[0] != '\0') {
|
||||
/* label is only initialized if consumer_label is set */
|
||||
|
@ -1576,7 +1575,7 @@ static void linereq_free(struct linereq *lr)
|
|||
}
|
||||
kfifo_free(&lr->events);
|
||||
kfree(lr->label);
|
||||
put_device(&lr->gdev->dev);
|
||||
gpio_device_put(lr->gdev);
|
||||
kfree(lr);
|
||||
}
|
||||
|
||||
|
@ -1646,8 +1645,7 @@ static int linereq_create(struct gpio_device *gdev, void __user *ip)
|
|||
if (!lr)
|
||||
return -ENOMEM;
|
||||
|
||||
lr->gdev = gdev;
|
||||
get_device(&gdev->dev);
|
||||
lr->gdev = gpio_device_get(gdev);
|
||||
|
||||
for (i = 0; i < ulr.num_lines; i++) {
|
||||
lr->lines[i].req = lr;
|
||||
|
@ -1916,7 +1914,7 @@ static void lineevent_free(struct lineevent_state *le)
|
|||
if (le->desc)
|
||||
gpiod_free(le->desc);
|
||||
kfree(le->label);
|
||||
put_device(&le->gdev->dev);
|
||||
gpio_device_put(le->gdev);
|
||||
kfree(le);
|
||||
}
|
||||
|
||||
|
@ -2094,8 +2092,7 @@ static int lineevent_create(struct gpio_device *gdev, void __user *ip)
|
|||
le = kzalloc(sizeof(*le), GFP_KERNEL);
|
||||
if (!le)
|
||||
return -ENOMEM;
|
||||
le->gdev = gdev;
|
||||
get_device(&gdev->dev);
|
||||
le->gdev = gpio_device_get(gdev);
|
||||
|
||||
if (eventreq.consumer_label[0] != '\0') {
|
||||
/* label is only initialized if consumer_label is set */
|
||||
|
@ -2671,7 +2668,7 @@ static int gpio_chrdev_open(struct inode *inode, struct file *file)
|
|||
|
||||
init_waitqueue_head(&cdev->wait);
|
||||
INIT_KFIFO(cdev->events);
|
||||
cdev->gdev = gdev;
|
||||
cdev->gdev = gpio_device_get(gdev);
|
||||
|
||||
cdev->lineinfo_changed_nb.notifier_call = lineinfo_changed_notify;
|
||||
ret = blocking_notifier_chain_register(&gdev->notifier,
|
||||
|
@ -2679,7 +2676,6 @@ static int gpio_chrdev_open(struct inode *inode, struct file *file)
|
|||
if (ret)
|
||||
goto out_free_bitmap;
|
||||
|
||||
get_device(&gdev->dev);
|
||||
file->private_data = cdev;
|
||||
|
||||
ret = nonseekable_open(inode, file);
|
||||
|
@ -2694,6 +2690,7 @@ out_unregister_notifier:
|
|||
blocking_notifier_chain_unregister(&gdev->notifier,
|
||||
&cdev->lineinfo_changed_nb);
|
||||
out_free_bitmap:
|
||||
gpio_device_put(gdev);
|
||||
bitmap_free(cdev->watched_lines);
|
||||
out_free_cdev:
|
||||
kfree(cdev);
|
||||
|
@ -2716,7 +2713,7 @@ static int gpio_chrdev_release(struct inode *inode, struct file *file)
|
|||
bitmap_free(cdev->watched_lines);
|
||||
blocking_notifier_chain_unregister(&gdev->notifier,
|
||||
&cdev->lineinfo_changed_nb);
|
||||
put_device(&gdev->dev);
|
||||
gpio_device_put(gdev);
|
||||
kfree(cdev);
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -129,61 +129,6 @@ struct gpio_desc *__must_check devm_gpiod_get_index(struct device *dev,
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(devm_gpiod_get_index);
|
||||
|
||||
/**
|
||||
* devm_gpiod_get_from_of_node() - obtain a GPIO from an OF node
|
||||
* @dev: device for lifecycle management
|
||||
* @node: handle of the OF node
|
||||
* @propname: name of the DT 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
|
||||
*
|
||||
* 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 *devm_gpiod_get_from_of_node(struct device *dev,
|
||||
const struct device_node *node,
|
||||
const char *propname, int index,
|
||||
enum gpiod_flags dflags,
|
||||
const char *label)
|
||||
{
|
||||
struct gpio_desc **dr;
|
||||
struct gpio_desc *desc;
|
||||
|
||||
desc = gpiod_get_from_of_node(node, propname, index, dflags, label);
|
||||
if (IS_ERR(desc))
|
||||
return desc;
|
||||
|
||||
/*
|
||||
* For non-exclusive GPIO descriptors, check if this descriptor is
|
||||
* already under resource management by this device.
|
||||
*/
|
||||
if (dflags & GPIOD_FLAGS_BIT_NONEXCLUSIVE) {
|
||||
struct devres *dres;
|
||||
|
||||
dres = devres_find(dev, devm_gpiod_release,
|
||||
devm_gpiod_match, &desc);
|
||||
if (dres)
|
||||
return desc;
|
||||
}
|
||||
|
||||
dr = devres_alloc(devm_gpiod_release, sizeof(struct gpio_desc *),
|
||||
GFP_KERNEL);
|
||||
if (!dr) {
|
||||
gpiod_put(desc);
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
|
||||
*dr = desc;
|
||||
devres_add(dev, dr);
|
||||
|
||||
return desc;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(devm_gpiod_get_from_of_node);
|
||||
|
||||
/**
|
||||
* devm_fwnode_gpiod_get_index - get a GPIO descriptor from a given node
|
||||
* @dev: GPIO consumer
|
||||
|
|
|
@ -23,6 +23,47 @@
|
|||
#include "gpiolib.h"
|
||||
#include "gpiolib-of.h"
|
||||
|
||||
/*
|
||||
* This is Linux-specific flags. By default controllers' and Linux' mapping
|
||||
* match, but GPIO controllers are free to translate their own flags to
|
||||
* Linux-specific in their .xlate callback. Though, 1:1 mapping is recommended.
|
||||
*/
|
||||
enum of_gpio_flags {
|
||||
OF_GPIO_ACTIVE_LOW = 0x1,
|
||||
OF_GPIO_SINGLE_ENDED = 0x2,
|
||||
OF_GPIO_OPEN_DRAIN = 0x4,
|
||||
OF_GPIO_TRANSITORY = 0x8,
|
||||
OF_GPIO_PULL_UP = 0x10,
|
||||
OF_GPIO_PULL_DOWN = 0x20,
|
||||
OF_GPIO_PULL_DISABLE = 0x40,
|
||||
};
|
||||
|
||||
/**
|
||||
* of_gpio_named_count() - Count GPIOs for a device
|
||||
* @np: device node to count GPIOs for
|
||||
* @propname: property name containing gpio specifier(s)
|
||||
*
|
||||
* The function returns the count of GPIOs specified for a node.
|
||||
* Note that the empty GPIO specifiers count too. Returns either
|
||||
* Number of gpios defined in property,
|
||||
* -EINVAL for an incorrectly formed gpios property, or
|
||||
* -ENOENT for a missing gpios property
|
||||
*
|
||||
* Example:
|
||||
* gpios = <0
|
||||
* &gpio1 1 2
|
||||
* 0
|
||||
* &gpio2 3 4>;
|
||||
*
|
||||
* The above example defines four GPIOs, two of which are not specified.
|
||||
* This function will return '4'
|
||||
*/
|
||||
static int of_gpio_named_count(const struct device_node *np,
|
||||
const char *propname)
|
||||
{
|
||||
return of_count_phandle_with_args(np, propname, "#gpio-cells");
|
||||
}
|
||||
|
||||
/**
|
||||
* of_gpio_spi_cs_get_count() - special GPIO counting for SPI
|
||||
* @dev: Consuming device
|
||||
|
@ -50,12 +91,6 @@ static int of_gpio_spi_cs_get_count(struct device *dev, const char *con_id)
|
|||
return of_gpio_named_count(np, "gpios");
|
||||
}
|
||||
|
||||
/*
|
||||
* This is used by external users of of_gpio_count() from <linux/of_gpio.h>
|
||||
*
|
||||
* FIXME: get rid of those external users by converting them to GPIO
|
||||
* descriptors and let them all use gpiod_count()
|
||||
*/
|
||||
int of_gpio_get_count(struct device *dev, const char *con_id)
|
||||
{
|
||||
int ret;
|
||||
|
@ -345,19 +380,28 @@ out:
|
|||
return desc;
|
||||
}
|
||||
|
||||
int of_get_named_gpio_flags(const struct device_node *np, const char *list_name,
|
||||
int index, enum of_gpio_flags *flags)
|
||||
/**
|
||||
* of_get_named_gpio() - Get a GPIO number to use with GPIO API
|
||||
* @np: device node to get GPIO from
|
||||
* @propname: Name of property containing gpio specifier(s)
|
||||
* @index: index of the GPIO
|
||||
*
|
||||
* Returns GPIO number to use with Linux generic GPIO API, or one of the errno
|
||||
* value on the error condition.
|
||||
*/
|
||||
int of_get_named_gpio(const struct device_node *np, const char *propname,
|
||||
int index)
|
||||
{
|
||||
struct gpio_desc *desc;
|
||||
|
||||
desc = of_get_named_gpiod_flags(np, list_name, index, flags);
|
||||
desc = of_get_named_gpiod_flags(np, propname, index, NULL);
|
||||
|
||||
if (IS_ERR(desc))
|
||||
return PTR_ERR(desc);
|
||||
else
|
||||
return desc_to_gpio(desc);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(of_get_named_gpio_flags);
|
||||
EXPORT_SYMBOL_GPL(of_get_named_gpio);
|
||||
|
||||
/* Converts gpio_lookup_flags into bitmask of GPIO_* values */
|
||||
static unsigned long of_convert_gpio_flags(enum of_gpio_flags flags)
|
||||
|
@ -389,52 +433,6 @@ static unsigned long of_convert_gpio_flags(enum of_gpio_flags flags)
|
|||
return lflags;
|
||||
}
|
||||
|
||||
/**
|
||||
* gpiod_get_from_of_node() - obtain a GPIO from an OF node
|
||||
* @node: handle of the OF node
|
||||
* @propname: name of the DT 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
|
||||
*
|
||||
* 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 *gpiod_get_from_of_node(const struct device_node *node,
|
||||
const char *propname, int index,
|
||||
enum gpiod_flags dflags,
|
||||
const char *label)
|
||||
{
|
||||
unsigned long lflags;
|
||||
struct gpio_desc *desc;
|
||||
enum of_gpio_flags of_flags;
|
||||
int ret;
|
||||
|
||||
desc = of_get_named_gpiod_flags(node, propname, index, &of_flags);
|
||||
if (!desc || IS_ERR(desc))
|
||||
return desc;
|
||||
|
||||
ret = gpiod_request(desc, label);
|
||||
if (ret == -EBUSY && (dflags & GPIOD_FLAGS_BIT_NONEXCLUSIVE))
|
||||
return desc;
|
||||
if (ret)
|
||||
return ERR_PTR(ret);
|
||||
|
||||
lflags = of_convert_gpio_flags(of_flags);
|
||||
|
||||
ret = gpiod_configure_flags(desc, propname, lflags, dflags);
|
||||
if (ret < 0) {
|
||||
gpiod_put(desc);
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
return desc;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(gpiod_get_from_of_node);
|
||||
|
||||
static struct gpio_desc *of_find_gpio_rename(struct device_node *np,
|
||||
const char *con_id,
|
||||
unsigned int idx,
|
||||
|
@ -668,7 +666,7 @@ static struct gpio_desc *of_parse_own_gpio(struct device_node *np,
|
|||
u32 tmp;
|
||||
int ret;
|
||||
|
||||
chip_np = chip->of_node;
|
||||
chip_np = dev_of_node(&chip->gpiodev->dev);
|
||||
if (!chip_np)
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
|
@ -760,7 +758,7 @@ static int of_gpiochip_scan_gpios(struct gpio_chip *chip)
|
|||
struct device_node *np;
|
||||
int ret;
|
||||
|
||||
for_each_available_child_of_node(chip->of_node, np) {
|
||||
for_each_available_child_of_node(dev_of_node(&chip->gpiodev->dev), np) {
|
||||
if (!of_property_read_bool(np, "gpio-hog"))
|
||||
continue;
|
||||
|
||||
|
@ -970,14 +968,15 @@ EXPORT_SYMBOL_GPL(of_mm_gpiochip_remove);
|
|||
#ifdef CONFIG_PINCTRL
|
||||
static int of_gpiochip_add_pin_range(struct gpio_chip *chip)
|
||||
{
|
||||
struct device_node *np = chip->of_node;
|
||||
struct of_phandle_args pinspec;
|
||||
struct pinctrl_dev *pctldev;
|
||||
struct device_node *np;
|
||||
int index = 0, ret;
|
||||
const char *name;
|
||||
static const char group_names_propname[] = "gpio-ranges-group-names";
|
||||
struct property *group_names;
|
||||
|
||||
np = dev_of_node(&chip->gpiodev->dev);
|
||||
if (!np)
|
||||
return 0;
|
||||
|
||||
|
@ -1063,7 +1062,7 @@ int of_gpiochip_add(struct gpio_chip *chip)
|
|||
struct device_node *np;
|
||||
int ret;
|
||||
|
||||
np = to_of_node(dev_fwnode(&chip->gpiodev->dev));
|
||||
np = dev_of_node(&chip->gpiodev->dev);
|
||||
if (!np)
|
||||
return 0;
|
||||
|
||||
|
@ -1092,19 +1091,3 @@ void of_gpiochip_remove(struct gpio_chip *chip)
|
|||
{
|
||||
fwnode_handle_put(chip->fwnode);
|
||||
}
|
||||
|
||||
void of_gpio_dev_init(struct gpio_chip *gc, struct gpio_device *gdev)
|
||||
{
|
||||
/* Set default OF node to parent's one if present */
|
||||
if (gc->parent)
|
||||
gdev->dev.of_node = gc->parent->of_node;
|
||||
|
||||
if (gc->fwnode)
|
||||
gc->of_node = to_of_node(gc->fwnode);
|
||||
|
||||
/* If the gpiochip has an assigned OF node this takes precedence */
|
||||
if (gc->of_node)
|
||||
gdev->dev.of_node = gc->of_node;
|
||||
else
|
||||
gc->of_node = gdev->dev.of_node;
|
||||
}
|
||||
|
|
|
@ -23,7 +23,6 @@ struct gpio_desc *of_find_gpio(struct device_node *np,
|
|||
int of_gpiochip_add(struct gpio_chip *gc);
|
||||
void of_gpiochip_remove(struct gpio_chip *gc);
|
||||
int of_gpio_get_count(struct device *dev, const char *con_id);
|
||||
void of_gpio_dev_init(struct gpio_chip *gc, struct gpio_device *gdev);
|
||||
#else
|
||||
static inline struct gpio_desc *of_find_gpio(struct device_node *np,
|
||||
const char *con_id,
|
||||
|
@ -38,10 +37,6 @@ static inline int of_gpio_get_count(struct device *dev, const char *con_id)
|
|||
{
|
||||
return 0;
|
||||
}
|
||||
static inline void of_gpio_dev_init(struct gpio_chip *gc,
|
||||
struct gpio_device *gdev)
|
||||
{
|
||||
}
|
||||
#endif /* CONFIG_OF_GPIO */
|
||||
|
||||
extern struct notifier_block gpio_of_notifier;
|
||||
|
|
|
@ -1,34 +1,35 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/bitmap.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/compat.h>
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/file.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/idr.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/gpio/driver.h>
|
||||
#include <linux/gpio/machine.h>
|
||||
#include <linux/idr.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/pinctrl/consumer.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/compat.h>
|
||||
#include <linux/file.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/spinlock.h>
|
||||
|
||||
#include <uapi/linux/gpio.h>
|
||||
|
||||
#include "gpiolib.h"
|
||||
#include "gpiolib-of.h"
|
||||
#include "gpiolib-acpi.h"
|
||||
#include "gpiolib-swnode.h"
|
||||
#include "gpiolib-cdev.h"
|
||||
#include "gpiolib-of.h"
|
||||
#include "gpiolib-swnode.h"
|
||||
#include "gpiolib-sysfs.h"
|
||||
#include "gpiolib.h"
|
||||
|
||||
#define CREATE_TRACE_POINTS
|
||||
#include <trace/events/gpio.h>
|
||||
|
@ -659,10 +660,12 @@ int gpiochip_add_data_with_key(struct gpio_chip *gc, void *data,
|
|||
int base = 0;
|
||||
int ret = 0;
|
||||
|
||||
/* If the calling driver did not initialize firmware node, do it here */
|
||||
if (gc->fwnode)
|
||||
fwnode = gc->fwnode;
|
||||
else if (gc->parent)
|
||||
fwnode = dev_fwnode(gc->parent);
|
||||
gc->fwnode = fwnode;
|
||||
|
||||
/*
|
||||
* First: allocate and populate the internal stat container, and
|
||||
|
@ -676,14 +679,7 @@ int gpiochip_add_data_with_key(struct gpio_chip *gc, void *data,
|
|||
gdev->chip = gc;
|
||||
gc->gpiodev = gdev;
|
||||
|
||||
of_gpio_dev_init(gc, gdev);
|
||||
acpi_gpio_dev_init(gc, gdev);
|
||||
|
||||
/*
|
||||
* Assign fwnode depending on the result of the previous calls,
|
||||
* if none of them succeed, assign it to the parent's one.
|
||||
*/
|
||||
gc->fwnode = gdev->dev.fwnode = dev_fwnode(&gdev->dev) ?: fwnode;
|
||||
device_set_node(&gdev->dev, gc->fwnode);
|
||||
|
||||
gdev->id = ida_alloc(&gpio_ida, GFP_KERNEL);
|
||||
if (gdev->id < 0) {
|
||||
|
@ -882,7 +878,7 @@ err_free_gpiochip_mask:
|
|||
gpiochip_free_valid_mask(gc);
|
||||
if (gdev->dev.release) {
|
||||
/* release() has been registered by gpiochip_setup_dev() */
|
||||
put_device(&gdev->dev);
|
||||
gpio_device_put(gdev);
|
||||
goto err_print_message;
|
||||
}
|
||||
err_remove_from_list:
|
||||
|
@ -972,7 +968,7 @@ void gpiochip_remove(struct gpio_chip *gc)
|
|||
*/
|
||||
gcdev_unregister(gdev);
|
||||
up_write(&gdev->sem);
|
||||
put_device(&gdev->dev);
|
||||
gpio_device_put(gdev);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(gpiochip_remove);
|
||||
|
||||
|
@ -1126,14 +1122,8 @@ static void gpiochip_set_hierarchical_irqchip(struct gpio_chip *gc,
|
|||
/* Just pick something */
|
||||
fwspec.param[1] = IRQ_TYPE_EDGE_RISING;
|
||||
fwspec.param_count = 2;
|
||||
ret = __irq_domain_alloc_irqs(gc->irq.domain,
|
||||
/* just pick something */
|
||||
-1,
|
||||
1,
|
||||
NUMA_NO_NODE,
|
||||
&fwspec,
|
||||
false,
|
||||
NULL);
|
||||
ret = irq_domain_alloc_irqs(gc->irq.domain, 1,
|
||||
NUMA_NO_NODE, &fwspec);
|
||||
if (ret < 0) {
|
||||
chip_err(gc,
|
||||
"can not allocate irq for GPIO line %d parent hwirq %d in hierarchy domain: %d\n",
|
||||
|
@ -2063,17 +2053,15 @@ static int validate_desc(const struct gpio_desc *desc, const char *func)
|
|||
int gpiod_request(struct gpio_desc *desc, const char *label)
|
||||
{
|
||||
int ret = -EPROBE_DEFER;
|
||||
struct gpio_device *gdev;
|
||||
|
||||
VALIDATE_DESC(desc);
|
||||
gdev = desc->gdev;
|
||||
|
||||
if (try_module_get(gdev->owner)) {
|
||||
if (try_module_get(desc->gdev->owner)) {
|
||||
ret = gpiod_request_commit(desc, label);
|
||||
if (ret)
|
||||
module_put(gdev->owner);
|
||||
module_put(desc->gdev->owner);
|
||||
else
|
||||
get_device(&gdev->dev);
|
||||
gpio_device_get(desc->gdev);
|
||||
}
|
||||
|
||||
if (ret)
|
||||
|
@ -2134,7 +2122,7 @@ void gpiod_free(struct gpio_desc *desc)
|
|||
{
|
||||
if (desc && desc->gdev && gpiod_free_commit(desc)) {
|
||||
module_put(desc->gdev->owner);
|
||||
put_device(&desc->gdev->dev);
|
||||
gpio_device_put(desc->gdev);
|
||||
} else {
|
||||
WARN_ON(extra_checks);
|
||||
}
|
||||
|
|
|
@ -82,6 +82,16 @@ static inline struct gpio_device *to_gpio_device(struct device *dev)
|
|||
return container_of(dev, struct gpio_device, dev);
|
||||
}
|
||||
|
||||
static inline struct gpio_device *gpio_device_get(struct gpio_device *gdev)
|
||||
{
|
||||
return to_gpio_device(get_device(&gdev->dev));
|
||||
}
|
||||
|
||||
static inline void gpio_device_put(struct gpio_device *gdev)
|
||||
{
|
||||
put_device(&gdev->dev);
|
||||
}
|
||||
|
||||
/* gpio suffixes used for ACPI and device tree lookup */
|
||||
static __maybe_unused const char * const gpio_suffixes[] = { "gpios", "gpio" };
|
||||
|
||||
|
|
|
@ -325,7 +325,12 @@ static bool pinctrl_ready_for_gpio_range(unsigned gpio)
|
|||
{
|
||||
struct pinctrl_dev *pctldev;
|
||||
struct pinctrl_gpio_range *range = NULL;
|
||||
struct gpio_chip *chip = gpio_to_chip(gpio);
|
||||
/*
|
||||
* FIXME: "gpio" here is a number in the global GPIO numberspace.
|
||||
* get rid of this from the ranges eventually and get the GPIO
|
||||
* descriptor from the gpio_chip.
|
||||
*/
|
||||
struct gpio_chip *chip = gpiod_to_chip(gpio_to_desc(gpio));
|
||||
|
||||
if (WARN(!chip, "no gpio_chip for gpio%i?", gpio))
|
||||
return false;
|
||||
|
@ -1657,7 +1662,12 @@ static int pinctrl_pins_show(struct seq_file *s, void *what)
|
|||
}
|
||||
}
|
||||
if (gpio_num >= 0)
|
||||
chip = gpio_to_chip(gpio_num);
|
||||
/*
|
||||
* FIXME: gpio_num comes from the global GPIO numberspace.
|
||||
* we need to get rid of the range->base eventually and
|
||||
* get the descriptor directly from the gpio_chip.
|
||||
*/
|
||||
chip = gpiod_to_chip(gpio_to_desc(gpio_num));
|
||||
else
|
||||
chip = NULL;
|
||||
if (chip)
|
||||
|
|
|
@ -31,12 +31,6 @@ struct module;
|
|||
struct device_node;
|
||||
struct gpio_desc;
|
||||
|
||||
/* caller holds gpio_lock *OR* gpio is marked as requested */
|
||||
static inline struct gpio_chip *gpio_to_chip(unsigned gpio)
|
||||
{
|
||||
return gpiod_to_chip(gpio_to_desc(gpio));
|
||||
}
|
||||
|
||||
/* Always use the library code for GPIO management calls,
|
||||
* or when sleeping may be involved.
|
||||
*/
|
||||
|
@ -103,12 +97,6 @@ static inline int gpio_export(unsigned gpio, bool direction_may_change)
|
|||
return gpiod_export(gpio_to_desc(gpio), direction_may_change);
|
||||
}
|
||||
|
||||
static inline int gpio_export_link(struct device *dev, const char *name,
|
||||
unsigned gpio)
|
||||
{
|
||||
return gpiod_export_link(dev, name, gpio_to_desc(gpio));
|
||||
}
|
||||
|
||||
static inline void gpio_unexport(unsigned gpio)
|
||||
{
|
||||
gpiod_unexport(gpio_to_desc(gpio));
|
||||
|
|
|
@ -81,11 +81,6 @@ static inline int gpio_to_irq(unsigned int gpio)
|
|||
return __gpio_to_irq(gpio);
|
||||
}
|
||||
|
||||
static inline int irq_to_gpio(unsigned int irq)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
#endif /* ! CONFIG_ARCH_HAVE_CUSTOM_GPIO_H */
|
||||
|
||||
/* CONFIG_GPIOLIB: bindings for managed devices that want to request gpios */
|
||||
|
@ -197,14 +192,6 @@ static inline int gpio_export(unsigned gpio, bool direction_may_change)
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
static inline int gpio_export_link(struct device *dev, const char *name,
|
||||
unsigned gpio)
|
||||
{
|
||||
/* GPIO can never have been exported */
|
||||
WARN_ON(1);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static inline void gpio_unexport(unsigned gpio)
|
||||
{
|
||||
/* GPIO can never have been exported */
|
||||
|
@ -218,13 +205,6 @@ static inline int gpio_to_irq(unsigned gpio)
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
static inline int irq_to_gpio(unsigned irq)
|
||||
{
|
||||
/* irq can never have been returned from gpio_to_irq() */
|
||||
WARN_ON(1);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static inline int devm_gpio_request(struct device *dev, unsigned gpio,
|
||||
const char *label)
|
||||
{
|
||||
|
|
|
@ -581,54 +581,6 @@ struct gpio_desc *devm_fwnode_gpiod_get(struct device *dev,
|
|||
flags, label);
|
||||
}
|
||||
|
||||
#if IS_ENABLED(CONFIG_GPIOLIB) && IS_ENABLED(CONFIG_OF_GPIO)
|
||||
struct device_node;
|
||||
|
||||
struct gpio_desc *gpiod_get_from_of_node(const struct device_node *node,
|
||||
const char *propname, int index,
|
||||
enum gpiod_flags dflags,
|
||||
const char *label);
|
||||
|
||||
#else /* CONFIG_GPIOLIB && CONFIG_OF_GPIO */
|
||||
|
||||
struct device_node;
|
||||
|
||||
static inline
|
||||
struct gpio_desc *gpiod_get_from_of_node(const struct device_node *node,
|
||||
const char *propname, int index,
|
||||
enum gpiod_flags dflags,
|
||||
const char *label)
|
||||
{
|
||||
return ERR_PTR(-ENOSYS);
|
||||
}
|
||||
|
||||
#endif /* CONFIG_GPIOLIB && CONFIG_OF_GPIO */
|
||||
|
||||
#ifdef CONFIG_GPIOLIB
|
||||
struct device_node;
|
||||
|
||||
struct gpio_desc *devm_gpiod_get_from_of_node(struct device *dev,
|
||||
const struct device_node *node,
|
||||
const char *propname, int index,
|
||||
enum gpiod_flags dflags,
|
||||
const char *label);
|
||||
|
||||
#else /* CONFIG_GPIOLIB */
|
||||
|
||||
struct device_node;
|
||||
|
||||
static inline
|
||||
struct gpio_desc *devm_gpiod_get_from_of_node(struct device *dev,
|
||||
const struct device_node *node,
|
||||
const char *propname, int index,
|
||||
enum gpiod_flags dflags,
|
||||
const char *label)
|
||||
{
|
||||
return ERR_PTR(-ENOSYS);
|
||||
}
|
||||
|
||||
#endif /* CONFIG_GPIOLIB */
|
||||
|
||||
struct acpi_gpio_params {
|
||||
unsigned int crs_entry_index;
|
||||
unsigned int line_index;
|
||||
|
|
|
@ -336,7 +336,7 @@ struct gpio_irq_chip {
|
|||
* @set_multiple: assigns output values for multiple signals defined by "mask"
|
||||
* @set_config: optional hook for all kinds of settings. Uses the same
|
||||
* packed config format as generic pinconf.
|
||||
* @to_irq: optional hook supporting non-static gpio_to_irq() mappings;
|
||||
* @to_irq: optional hook supporting non-static gpiod_to_irq() mappings;
|
||||
* implementation may not sleep
|
||||
* @dbg_show: optional routine to show contents in debugfs; default code
|
||||
* will be used when this is omitted, but custom code can show extra
|
||||
|
@ -503,13 +503,6 @@ struct gpio_chip {
|
|||
* the device tree automatically may have an OF translation
|
||||
*/
|
||||
|
||||
/**
|
||||
* @of_node:
|
||||
*
|
||||
* Pointer to a device tree node representing this GPIO controller.
|
||||
*/
|
||||
struct device_node *of_node;
|
||||
|
||||
/**
|
||||
* @of_gpio_n_cells:
|
||||
*
|
||||
|
|
|
@ -17,21 +17,6 @@
|
|||
|
||||
struct device_node;
|
||||
|
||||
/*
|
||||
* This is Linux-specific flags. By default controllers' and Linux' mapping
|
||||
* match, but GPIO controllers are free to translate their own flags to
|
||||
* Linux-specific in their .xlate callback. Though, 1:1 mapping is recommended.
|
||||
*/
|
||||
enum of_gpio_flags {
|
||||
OF_GPIO_ACTIVE_LOW = 0x1,
|
||||
OF_GPIO_SINGLE_ENDED = 0x2,
|
||||
OF_GPIO_OPEN_DRAIN = 0x4,
|
||||
OF_GPIO_TRANSITORY = 0x8,
|
||||
OF_GPIO_PULL_UP = 0x10,
|
||||
OF_GPIO_PULL_DOWN = 0x20,
|
||||
OF_GPIO_PULL_DISABLE = 0x40,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_OF_GPIO
|
||||
|
||||
#include <linux/container_of.h>
|
||||
|
@ -50,17 +35,12 @@ static inline struct of_mm_gpio_chip *to_of_mm_gpio_chip(struct gpio_chip *gc)
|
|||
return container_of(gc, struct of_mm_gpio_chip, gc);
|
||||
}
|
||||
|
||||
extern int of_get_named_gpio_flags(const struct device_node *np,
|
||||
const char *list_name, int index, enum of_gpio_flags *flags);
|
||||
extern int of_get_named_gpio(const struct device_node *np,
|
||||
const char *list_name, int index);
|
||||
|
||||
extern int of_mm_gpiochip_add_data(struct device_node *np,
|
||||
struct of_mm_gpio_chip *mm_gc,
|
||||
void *data);
|
||||
static inline int of_mm_gpiochip_add(struct device_node *np,
|
||||
struct of_mm_gpio_chip *mm_gc)
|
||||
{
|
||||
return of_mm_gpiochip_add_data(np, mm_gc, NULL);
|
||||
}
|
||||
extern void of_mm_gpiochip_remove(struct of_mm_gpio_chip *mm_gc);
|
||||
|
||||
#else /* CONFIG_OF_GPIO */
|
||||
|
@ -68,86 +48,12 @@ extern void of_mm_gpiochip_remove(struct of_mm_gpio_chip *mm_gc);
|
|||
#include <linux/errno.h>
|
||||
|
||||
/* Drivers may not strictly depend on the GPIO support, so let them link. */
|
||||
static inline int of_get_named_gpio_flags(const struct device_node *np,
|
||||
const char *list_name, int index, enum of_gpio_flags *flags)
|
||||
static inline int of_get_named_gpio(const struct device_node *np,
|
||||
const char *propname, int index)
|
||||
{
|
||||
if (flags)
|
||||
*flags = 0;
|
||||
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_OF_GPIO */
|
||||
|
||||
/**
|
||||
* of_gpio_named_count() - Count GPIOs for a device
|
||||
* @np: device node to count GPIOs for
|
||||
* @propname: property name containing gpio specifier(s)
|
||||
*
|
||||
* The function returns the count of GPIOs specified for a node.
|
||||
* Note that the empty GPIO specifiers count too. Returns either
|
||||
* Number of gpios defined in property,
|
||||
* -EINVAL for an incorrectly formed gpios property, or
|
||||
* -ENOENT for a missing gpios property
|
||||
*
|
||||
* Example:
|
||||
* gpios = <0
|
||||
* &gpio1 1 2
|
||||
* 0
|
||||
* &gpio2 3 4>;
|
||||
*
|
||||
* The above example defines four GPIOs, two of which are not specified.
|
||||
* This function will return '4'
|
||||
*/
|
||||
static inline int of_gpio_named_count(const struct device_node *np,
|
||||
const char *propname)
|
||||
{
|
||||
return of_count_phandle_with_args(np, propname, "#gpio-cells");
|
||||
}
|
||||
|
||||
/**
|
||||
* of_gpio_count() - Count GPIOs for a device
|
||||
* @np: device node to count GPIOs for
|
||||
*
|
||||
* Same as of_gpio_named_count, but hard coded to use the 'gpios' property
|
||||
*/
|
||||
static inline int of_gpio_count(const struct device_node *np)
|
||||
{
|
||||
return of_gpio_named_count(np, "gpios");
|
||||
}
|
||||
|
||||
static inline int of_get_gpio_flags(const struct device_node *np, int index,
|
||||
enum of_gpio_flags *flags)
|
||||
{
|
||||
return of_get_named_gpio_flags(np, "gpios", index, flags);
|
||||
}
|
||||
|
||||
/**
|
||||
* of_get_named_gpio() - Get a GPIO number to use with GPIO API
|
||||
* @np: device node to get GPIO from
|
||||
* @propname: Name of property containing gpio specifier(s)
|
||||
* @index: index of the GPIO
|
||||
*
|
||||
* Returns GPIO number to use with Linux generic GPIO API, or one of the errno
|
||||
* value on the error condition.
|
||||
*/
|
||||
static inline int of_get_named_gpio(const struct device_node *np,
|
||||
const char *propname, int index)
|
||||
{
|
||||
return of_get_named_gpio_flags(np, propname, index, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* of_get_gpio() - Get a GPIO number to use with GPIO API
|
||||
* @np: device node to get GPIO from
|
||||
* @index: index of the GPIO
|
||||
*
|
||||
* Returns GPIO number to use with Linux generic GPIO API, or one of the errno
|
||||
* value on the error condition.
|
||||
*/
|
||||
static inline int of_get_gpio(const struct device_node *np, int index)
|
||||
{
|
||||
return of_get_gpio_flags(np, index, NULL);
|
||||
}
|
||||
|
||||
#endif /* __LINUX_OF_GPIO_H */
|
||||
|
|
|
@ -1,45 +0,0 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#ifndef __LINUX_PCF857X_H
|
||||
#define __LINUX_PCF857X_H
|
||||
|
||||
/**
|
||||
* struct pcf857x_platform_data - data to set up pcf857x driver
|
||||
* @gpio_base: number of the chip's first GPIO
|
||||
* @n_latch: optional bit-inverse of initial register value; if
|
||||
* you leave this initialized to zero the driver will act
|
||||
* like the chip was just reset
|
||||
* @setup: optional callback issued once the GPIOs are valid
|
||||
* @teardown: optional callback issued before the GPIOs are invalidated
|
||||
* @context: optional parameter passed to setup() and teardown()
|
||||
*
|
||||
* In addition to the I2C_BOARD_INFO() state appropriate to each chip,
|
||||
* the i2c_board_info used with the pcf875x driver must provide its
|
||||
* platform_data (pointer to one of these structures) with at least
|
||||
* the gpio_base value initialized.
|
||||
*
|
||||
* The @setup callback may be used with the kind of board-specific glue
|
||||
* which hands the (now-valid) GPIOs to other drivers, or which puts
|
||||
* devices in their initial states using these GPIOs.
|
||||
*
|
||||
* These GPIO chips are only "quasi-bidirectional"; read the chip specs
|
||||
* to understand the behavior. They don't have separate registers to
|
||||
* record which pins are used for input or output, record which output
|
||||
* values are driven, or provide access to input values. That must be
|
||||
* inferred by reading the chip's value and knowing the last value written
|
||||
* to it. If you leave n_latch initialized to zero, that last written
|
||||
* value is presumed to be all ones (as if the chip were just reset).
|
||||
*/
|
||||
struct pcf857x_platform_data {
|
||||
unsigned gpio_base;
|
||||
unsigned n_latch;
|
||||
|
||||
int (*setup)(struct i2c_client *client,
|
||||
int gpio, unsigned ngpio,
|
||||
void *context);
|
||||
void (*teardown)(struct i2c_client *client,
|
||||
int gpio, unsigned ngpio,
|
||||
void *context);
|
||||
void *context;
|
||||
};
|
||||
|
||||
#endif /* __LINUX_PCF857X_H */
|
Загрузка…
Ссылка в новой задаче