gpio updates for v6.4-rc1
New drivers: - add a driver for the Loongson GPIO controller - add a driver for the fxl6408 I2C GPIO expander - add a GPIO module containing code common for Intel Elkhart Lake and Merrifield platforms - add a driver for the Intel Elkhart Lake platform reusing the code from the intel tangier library GPIOLIB core: - GPIO ACPI improvements - simplify gpiochip_add_data_with_keys() fwnode handling - cleanup header inclusions (remove unneeded ones, order the rest alphabetically) - remove duplicate code (reuse krealloc() instead of open-coding it, drop a duplicated check in gpiod_find_and_request()) - reshuffle the code to remove unnecessary forward declarations - coding style cleanups and improvements - add a helper for accessing device fwnodes - small updates in docs Driver improvements: - convert all remaining GPIO irqchip drivers to using immutable irqchips - drop unnecessary of_match_ptr() macro expansions - shrink the code in gpio-merrifield significantly by reusing the code from gpio-tangier + minor tweaks to the driver code - remove MODULE_LICENSE() from drivers that can only be built-in - add device-tree support to gpio-loongson1 - use new regmap features in gpio-104-dio-48e and gpio-pcie-idio-24 - minor tweaks and fixes to gpio-xra1403, gpio-sim, gpio-tegra194, gpio-omap, gpio-aspeed, gpio-raspberrypi-exp - shrink code in gpio-ich and gpio-pxa - Kconfig tweak for gpio-pmic-eic-sprd -----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEEFp3rbAvDxGAT0sefEacuoBRx13IFAmRGjBIACgkQEacuoBRx 13IBMA/+PTEowr87BTJW+Z0Y3EoXPGZSKFzUpnzpbGo7CT5mEO3KBbyikZi3asZ4 5mVPbHOC7OU8t76KSGYWXwPh0bvskt+jR2wz19f6F65g1W2SnTym52wAPUJDrKvm YQofEGcz9ykTIo5KQjAyqADYrrfIOKCOZbN59k8GscXBHkYmGFO3ZhEa5HhzcF+S qJBxnJ13Tbg9bszyl062pLqsNYGDeqqSuELrhALQCzSCM3WlJQOaHUEG//mS1Syu OHX2pwjw8u3HxBo6pKMK5fa4/aFM+EUAvSdDX59WmVrPnpLCHezyh4K3WQFUSnwG OJsW+b/eUDjICQBRvsHIJLuiAr19UouWWY6IZE9dTOjoPO1KWHtbaYX8rHWRZWCM +/QVfLavmXbOHW/pS2+NNxCARwu8o8ozcopY3PT6TjC5aN8/IkVT4eSaT3mJYXmh 8uS/5aY1Th0eyK5GHv7IcNME5Jb+sAHEnqG0Ebns7a9kOGQdEMJwZrnc5IjKWSMd PAKNjWYZ49XALtl8vVSar2DYt6d6z+UvGDX67s686FVpCDk15cyUE6VjdtKdGdsd mH+OnCaWDt+l89DEqZ4298ZA6kNk2CkHHjIO/TBDkU3jP7/wp/NtU0RTuCXydwjW aNjnfHd2JMJ//wQ4l2fQgpzWfVEN34mKZ2pysDotY47bwjpPD7o= =X+sP -----END PGP SIGNATURE----- Merge tag 'gpio-updates-for-v6.4' of git://git.kernel.org/pub/scm/linux/kernel/git/brgl/linux Pull gpio updates from Bartosz Golaszewski: "We have some new drivers, significant refactoring of existing intel platforms, lots of improvements all around, mass conversion to using immutable irqchips by drivers that had not been converted individually yet and some changes in the core library code. Summary: New drivers: - add a driver for the Loongson GPIO controller - add a driver for the fxl6408 I2C GPIO expander - add a GPIO module containing code common for Intel Elkhart Lake and Merrifield platforms - add a driver for the Intel Elkhart Lake platform reusing the code from the intel tangier library GPIOLIB core: - GPIO ACPI improvements - simplify gpiochip_add_data_with_keys() fwnode handling - cleanup header inclusions (remove unneeded ones, order the rest alphabetically) - remove duplicate code (reuse krealloc() instead of open-coding it, drop a duplicated check in gpiod_find_and_request()) - reshuffle the code to remove unnecessary forward declarations - coding style cleanups and improvements - add a helper for accessing device fwnodes - small updates in docs Driver improvements: - convert all remaining GPIO irqchip drivers to using immutable irqchips - drop unnecessary of_match_ptr() macro expansions - shrink the code in gpio-merrifield significantly by reusing the code from gpio-tangier + minor tweaks to the driver code - remove MODULE_LICENSE() from drivers that can only be built-in - add device-tree support to gpio-loongson1 - use new regmap features in gpio-104-dio-48e and gpio-pcie-idio-24 - minor tweaks and fixes to gpio-xra1403, gpio-sim, gpio-tegra194, gpio-omap, gpio-aspeed, gpio-raspberrypi-exp - shrink code in gpio-ich and gpio-pxa - Kconfig tweak for gpio-pmic-eic-sprd" * tag 'gpio-updates-for-v6.4' of git://git.kernel.org/pub/scm/linux/kernel/git/brgl/linux: (99 commits) gpio: gpiolib: Simplify gpiochip_add_data_with_key() fwnode gpiolib: Add gpiochip_set_data() helper gpiolib: Move gpiochip_get_data() higher in the code gpiolib: Check array_info for NULL only once in gpiod_get_array() gpiolib: Replace open coded krealloc() gpiolib: acpi: Add a ignore wakeup quirk for Clevo NL5xNU gpiolib: acpi: Move ACPI device NULL check to acpi_get_driver_gpio_data() gpiolib: acpi: use the fwnode in acpi_gpiochip_find() gpio: mm-lantiq: Fix typo in the newly added header filename sh: mach-x3proto: Add missing #include <linux/gpio/driver.h> powerpc/40x: Add missing select OF_GPIO_MM_GPIOCHIP gpio: xlp: Convert to immutable irq_chip gpio: xilinx: Convert to immutable irq_chip gpio: xgs-iproc: Convert to immutable irq_chip gpio: visconti: Convert to immutable irq_chip gpio: tqmx86: Convert to immutable irq_chip gpio: thunderx: Convert to immutable irq_chip gpio: stmpe: Convert to immutable irq_chip gpio: siox: Convert to immutable irq_chip gpio: rda: Convert to immutable irq_chip ...
This commit is contained in:
Коммит
2c96606a0f
|
@ -145,7 +145,7 @@ requested using gpio_request()::
|
|||
/* export the GPIO to userspace */
|
||||
int gpiod_export(struct gpio_desc *desc, bool direction_may_change);
|
||||
|
||||
/* reverse gpio_export() */
|
||||
/* reverse gpiod_export() */
|
||||
void gpiod_unexport(struct gpio_desc *desc);
|
||||
|
||||
/* create a sysfs link to an exported GPIO node */
|
||||
|
|
|
@ -0,0 +1,58 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/gpio/fcs,fxl6408.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Fairchild FXL6408 I2C GPIO Expander
|
||||
|
||||
maintainers:
|
||||
- Emanuele Ghidoli <emanuele.ghidoli@toradex.com>
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- fcs,fxl6408
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
"#gpio-cells":
|
||||
const: 2
|
||||
|
||||
gpio-controller: true
|
||||
|
||||
gpio-line-names:
|
||||
minItems: 1
|
||||
maxItems: 8
|
||||
|
||||
patternProperties:
|
||||
"^(hog-[0-9]+|.+-hog(-[0-9]+)?)$":
|
||||
required:
|
||||
- gpio-hog
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- gpio-controller
|
||||
- "#gpio-cells"
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
i2c {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
gpio_expander_43: gpio-expander@43 {
|
||||
compatible = "fcs,fxl6408";
|
||||
reg = <0x43>;
|
||||
gpio-controller;
|
||||
#gpio-cells = <2>;
|
||||
gpio-line-names = "Wi-Fi_W_DISABLE", "Wi-Fi_WKUP_WLAN",
|
||||
"PWR_EN_+V3.3_WiFi_N", "PCIe_REF_CLK_EN",
|
||||
"USB_RESET_N", "USB_BYPASS_N", "Wi-Fi_PDn",
|
||||
"Wi-Fi_WKUP_BT";
|
||||
};
|
||||
};
|
|
@ -154,18 +154,35 @@ of the GPIOs that can't be used.
|
|||
|
||||
Optionally, a GPIO controller may have a "gpio-line-names" property. This is
|
||||
an array of strings defining the names of the GPIO lines going out of the
|
||||
GPIO controller. This name should be the most meaningful producer name
|
||||
for the system, such as a rail name indicating the usage. Package names
|
||||
such as pin name are discouraged: such lines have opaque names (since they
|
||||
are by definition generic purpose) and such names are usually not very
|
||||
helpful. For example "MMC-CD", "Red LED Vdd" and "ethernet reset" are
|
||||
reasonable line names as they describe what the line is used for. "GPIO0"
|
||||
is not a good name to give to a GPIO line. Placeholders are discouraged:
|
||||
rather use the "" (blank string) if the use of the GPIO line is undefined
|
||||
in your design. The names are assigned starting from line offset 0 from
|
||||
left to right from the passed array. An incomplete array (where the number
|
||||
of passed named are less than ngpios) will still be used up until the last
|
||||
provided valid line index.
|
||||
GPIO controller.
|
||||
|
||||
For lines which are routed to on-board devices, this name should be
|
||||
the most meaningful producer name for the system, such as a rail name
|
||||
indicating the usage. Package names, such as a pin name, are discouraged:
|
||||
such lines have opaque names (since they are by definition general-purpose)
|
||||
and such names are usually not very helpful. For example "MMC-CD", "Red LED
|
||||
Vdd" and "ethernet reset" are reasonable line names as they describe what
|
||||
the line is used for. "GPIO0" is not a good name to give to a GPIO line
|
||||
that is hard-wired to a specific device.
|
||||
|
||||
However, in the case of lines that are routed to a general purpose header
|
||||
(e.g. the Raspberry Pi 40-pin header), and therefore are not hard-wired to
|
||||
specific devices, using a pin number or the names on the header is fine
|
||||
provided these are real (preferably unique) names. Using an SoC's pad name
|
||||
or package name, or names made up from kernel-internal software constructs,
|
||||
are strongly discouraged. For example "pin8 [gpio14/uart0_txd]" is fine
|
||||
if the board's documentation labels pin 8 as such. However "PortB_24" (an
|
||||
example of a name from an SoC's reference manual) would not be desirable.
|
||||
|
||||
In either case placeholders are discouraged: rather use the "" (blank
|
||||
string) if the use of the GPIO line is undefined in your design. Ideally,
|
||||
try to add comments to the dts file describing the naming the convention
|
||||
you have chosen, and specifying from where the names are derived.
|
||||
|
||||
The names are assigned starting from line offset 0, from left to right,
|
||||
from the passed array. An incomplete array (where the number of passed
|
||||
names is less than ngpios) will be used up until the last provided valid
|
||||
line index.
|
||||
|
||||
Example:
|
||||
|
||||
|
|
|
@ -0,0 +1,126 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/gpio/loongson,ls-gpio.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Loongson GPIO controller.
|
||||
|
||||
maintainers:
|
||||
- Yinbo Zhu <zhuyinbo@loongson.cn>
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- loongson,ls2k-gpio
|
||||
- loongson,ls7a-gpio
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
ngpios:
|
||||
minimum: 1
|
||||
maximum: 64
|
||||
|
||||
"#gpio-cells":
|
||||
const: 2
|
||||
|
||||
gpio-controller: true
|
||||
|
||||
gpio-ranges: true
|
||||
|
||||
interrupts:
|
||||
minItems: 1
|
||||
maxItems: 64
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- ngpios
|
||||
- "#gpio-cells"
|
||||
- gpio-controller
|
||||
- gpio-ranges
|
||||
- interrupts
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/interrupt-controller/irq.h>
|
||||
|
||||
gpio0: gpio@1fe00500 {
|
||||
compatible = "loongson,ls2k-gpio";
|
||||
reg = <0x1fe00500 0x38>;
|
||||
ngpios = <64>;
|
||||
#gpio-cells = <2>;
|
||||
gpio-controller;
|
||||
gpio-ranges = <&pctrl 0 0 15>,
|
||||
<&pctrl 16 16 15>,
|
||||
<&pctrl 32 32 10>,
|
||||
<&pctrl 44 44 20>;
|
||||
interrupt-parent = <&liointc1>;
|
||||
interrupts = <28 IRQ_TYPE_LEVEL_LOW>,
|
||||
<29 IRQ_TYPE_LEVEL_LOW>,
|
||||
<30 IRQ_TYPE_LEVEL_LOW>,
|
||||
<30 IRQ_TYPE_LEVEL_LOW>,
|
||||
<26 IRQ_TYPE_LEVEL_LOW>,
|
||||
<26 IRQ_TYPE_LEVEL_LOW>,
|
||||
<26 IRQ_TYPE_LEVEL_LOW>,
|
||||
<26 IRQ_TYPE_LEVEL_LOW>,
|
||||
<26 IRQ_TYPE_LEVEL_LOW>,
|
||||
<26 IRQ_TYPE_LEVEL_LOW>,
|
||||
<26 IRQ_TYPE_LEVEL_LOW>,
|
||||
<26 IRQ_TYPE_LEVEL_LOW>,
|
||||
<26 IRQ_TYPE_LEVEL_LOW>,
|
||||
<26 IRQ_TYPE_LEVEL_LOW>,
|
||||
<26 IRQ_TYPE_LEVEL_LOW>,
|
||||
<>,
|
||||
<26 IRQ_TYPE_LEVEL_LOW>,
|
||||
<26 IRQ_TYPE_LEVEL_LOW>,
|
||||
<26 IRQ_TYPE_LEVEL_LOW>,
|
||||
<26 IRQ_TYPE_LEVEL_LOW>,
|
||||
<26 IRQ_TYPE_LEVEL_LOW>,
|
||||
<26 IRQ_TYPE_LEVEL_LOW>,
|
||||
<26 IRQ_TYPE_LEVEL_LOW>,
|
||||
<26 IRQ_TYPE_LEVEL_LOW>,
|
||||
<26 IRQ_TYPE_LEVEL_LOW>,
|
||||
<26 IRQ_TYPE_LEVEL_LOW>,
|
||||
<26 IRQ_TYPE_LEVEL_LOW>,
|
||||
<26 IRQ_TYPE_LEVEL_LOW>,
|
||||
<26 IRQ_TYPE_LEVEL_LOW>,
|
||||
<26 IRQ_TYPE_LEVEL_LOW>,
|
||||
<26 IRQ_TYPE_LEVEL_LOW>,
|
||||
<26 IRQ_TYPE_LEVEL_LOW>,
|
||||
<27 IRQ_TYPE_LEVEL_LOW>,
|
||||
<27 IRQ_TYPE_LEVEL_LOW>,
|
||||
<27 IRQ_TYPE_LEVEL_LOW>,
|
||||
<27 IRQ_TYPE_LEVEL_LOW>,
|
||||
<27 IRQ_TYPE_LEVEL_LOW>,
|
||||
<>,
|
||||
<27 IRQ_TYPE_LEVEL_LOW>,
|
||||
<27 IRQ_TYPE_LEVEL_LOW>,
|
||||
<27 IRQ_TYPE_LEVEL_LOW>,
|
||||
<27 IRQ_TYPE_LEVEL_LOW>,
|
||||
<>,
|
||||
<>,
|
||||
<27 IRQ_TYPE_LEVEL_LOW>,
|
||||
<27 IRQ_TYPE_LEVEL_LOW>,
|
||||
<27 IRQ_TYPE_LEVEL_LOW>,
|
||||
<27 IRQ_TYPE_LEVEL_LOW>,
|
||||
<27 IRQ_TYPE_LEVEL_LOW>,
|
||||
<27 IRQ_TYPE_LEVEL_LOW>,
|
||||
<27 IRQ_TYPE_LEVEL_LOW>,
|
||||
<27 IRQ_TYPE_LEVEL_LOW>,
|
||||
<27 IRQ_TYPE_LEVEL_LOW>,
|
||||
<27 IRQ_TYPE_LEVEL_LOW>,
|
||||
<27 IRQ_TYPE_LEVEL_LOW>,
|
||||
<27 IRQ_TYPE_LEVEL_LOW>,
|
||||
<27 IRQ_TYPE_LEVEL_LOW>,
|
||||
<27 IRQ_TYPE_LEVEL_LOW>,
|
||||
<27 IRQ_TYPE_LEVEL_LOW>,
|
||||
<27 IRQ_TYPE_LEVEL_LOW>,
|
||||
<27 IRQ_TYPE_LEVEL_LOW>,
|
||||
<27 IRQ_TYPE_LEVEL_LOW>,
|
||||
<27 IRQ_TYPE_LEVEL_LOW>,
|
||||
<27 IRQ_TYPE_LEVEL_LOW>;
|
||||
};
|
|
@ -0,0 +1,49 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/gpio/loongson,ls1x-gpio.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Loongson-1 GPIO controller
|
||||
|
||||
maintainers:
|
||||
- Keguang Zhang <keguang.zhang@gmail.com>
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: loongson,ls1x-gpio
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
gpio-controller: true
|
||||
|
||||
"#gpio-cells":
|
||||
const: 2
|
||||
|
||||
ngpios:
|
||||
minimum: 1
|
||||
maximum: 32
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- gpio-controller
|
||||
- "#gpio-cells"
|
||||
- ngpios
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
gpio0: gpio@1fd010c0 {
|
||||
compatible = "loongson,ls1x-gpio";
|
||||
reg = <0x1fd010c0 0x4>;
|
||||
|
||||
gpio-controller;
|
||||
#gpio-cells = <2>;
|
||||
|
||||
ngpios = <32>;
|
||||
};
|
||||
|
||||
...
|
|
@ -218,10 +218,10 @@ not support open drain/open source in hardware, the GPIO library will instead
|
|||
use a trick: when a line is set as output, if the line is flagged as open
|
||||
drain, and the IN output value is low, it will be driven low as usual. But
|
||||
if the IN output value is set to high, it will instead *NOT* be driven high,
|
||||
instead it will be switched to input, as input mode is high impedance, thus
|
||||
achieving an "open drain emulation" of sorts: electrically the behaviour will
|
||||
be identical, with the exception of possible hardware glitches when switching
|
||||
the mode of the line.
|
||||
instead it will be switched to input, as input mode is an equivalent to
|
||||
high impedance, thus achieving an "open drain emulation" of sorts: electrically
|
||||
the behaviour will be identical, with the exception of possible hardware glitches
|
||||
when switching the mode of the line.
|
||||
|
||||
For open source configuration the same principle is used, just that instead
|
||||
of actively driving the line low, it is set to input.
|
||||
|
|
|
@ -238,8 +238,6 @@ setup or driver probe/teardown code, so this is an easy constraint.)::
|
|||
## gpio_free_array()
|
||||
|
||||
gpio_free()
|
||||
gpio_set_debounce()
|
||||
|
||||
|
||||
|
||||
Claiming and Releasing GPIOs
|
||||
|
@ -716,27 +714,6 @@ gpiochip nodes (possibly in conjunction with schematics) to determine
|
|||
the correct GPIO number to use for a given signal.
|
||||
|
||||
|
||||
Exporting from Kernel code
|
||||
--------------------------
|
||||
Kernel code can explicitly manage exports of GPIOs which have already been
|
||||
requested using gpio_request()::
|
||||
|
||||
/* export the GPIO to userspace */
|
||||
int gpio_export(unsigned gpio, bool direction_may_change);
|
||||
|
||||
/* reverse gpio_export() */
|
||||
void gpio_unexport();
|
||||
|
||||
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
|
||||
from accidentally clobbering important system state.
|
||||
|
||||
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.
|
||||
|
||||
|
||||
API Reference
|
||||
=============
|
||||
|
||||
|
|
|
@ -219,7 +219,6 @@ GPIO 值的命令需要等待其信息排到队首才发送命令,再获得其
|
|||
## gpio_free_array()
|
||||
|
||||
gpio_free()
|
||||
gpio_set_debounce()
|
||||
|
||||
|
||||
|
||||
|
@ -654,25 +653,6 @@ GPIO 控制器的路径类似 /sys/class/gpio/gpiochip42/ (对于从#42 GPIO
|
|||
确定给定信号所用的 GPIO 编号。
|
||||
|
||||
|
||||
从内核代码中导出
|
||||
----------------
|
||||
|
||||
内核代码可以明确地管理那些已通过 gpio_request()申请的 GPIO 的导出::
|
||||
|
||||
/* 导出 GPIO 到用户空间 */
|
||||
int gpio_export(unsigned gpio, bool direction_may_change);
|
||||
|
||||
/* gpio_export()的逆操作 */
|
||||
void gpio_unexport();
|
||||
|
||||
在一个内核驱动申请一个 GPIO 之后,它可以通过 gpio_export()使其在 sysfs
|
||||
接口中可见。该驱动可以控制信号方向是否可修改。这有助于防止用户空间代码无意间
|
||||
破坏重要的系统状态。
|
||||
|
||||
这个明确的导出有助于(通过使某些实验更容易来)调试,也可以提供一个始终存在的接口,
|
||||
与文档配合作为板级支持包的一部分。
|
||||
|
||||
|
||||
API参考
|
||||
=======
|
||||
|
||||
|
|
|
@ -226,7 +226,6 @@ GPIO 值的命令需要等待其信息排到隊首才發送命令,再獲得其
|
|||
## gpio_free_array()
|
||||
|
||||
gpio_free()
|
||||
gpio_set_debounce()
|
||||
|
||||
|
||||
|
||||
|
@ -615,21 +614,3 @@ GPIO 控制器的路徑類似 /sys/class/gpio/gpiochip42/ (對於從#42 GPIO
|
|||
固定的,例如在擴展卡上的 GPIO會根據所使用的主板或所在堆疊架構中其他的板子而
|
||||
有所不同。在這種情況下,你可能需要使用 gpiochip 節點(儘可能地結合電路圖)來
|
||||
確定給定信號所用的 GPIO 編號。
|
||||
|
||||
|
||||
從內核代碼中導出
|
||||
-------------
|
||||
內核代碼可以明確地管理那些已通過 gpio_request()申請的 GPIO 的導出:
|
||||
|
||||
/* 導出 GPIO 到用戶空間 */
|
||||
int gpio_export(unsigned gpio, bool direction_may_change);
|
||||
|
||||
/* gpio_export()的逆操作 */
|
||||
void gpio_unexport();
|
||||
|
||||
在一個內核驅動申請一個 GPIO 之後,它可以通過 gpio_export()使其在 sysfs
|
||||
接口中可見。該驅動可以控制信號方向是否可修改。這有助於防止用戶空間代碼無意間
|
||||
破壞重要的系統狀態。
|
||||
|
||||
這個明確的導出有助於(通過使某些實驗更容易來)調試,也可以提供一個始終存在的接口,
|
||||
與文檔配合作爲板級支持包的一部分。
|
||||
|
|
11
MAINTAINERS
11
MAINTAINERS
|
@ -8762,7 +8762,6 @@ F: Documentation/admin-guide/gpio/
|
|||
F: Documentation/devicetree/bindings/gpio/
|
||||
F: Documentation/driver-api/gpio/
|
||||
F: drivers/gpio/
|
||||
F: include/asm-generic/gpio.h
|
||||
F: include/dt-bindings/gpio/
|
||||
F: include/linux/gpio.h
|
||||
F: include/linux/gpio/
|
||||
|
@ -10292,12 +10291,14 @@ M: Andy Shevchenko <andy@kernel.org>
|
|||
L: linux-gpio@vger.kernel.org
|
||||
S: Supported
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/andy/linux-gpio-intel.git
|
||||
F: drivers/gpio/gpio-elkhartlake.c
|
||||
F: drivers/gpio/gpio-ich.c
|
||||
F: drivers/gpio/gpio-merrifield.c
|
||||
F: drivers/gpio/gpio-ml-ioh.c
|
||||
F: drivers/gpio/gpio-pch.c
|
||||
F: drivers/gpio/gpio-sch.c
|
||||
F: drivers/gpio/gpio-sodaville.c
|
||||
F: drivers/gpio/gpio-tangier.c
|
||||
|
||||
INTEL GVT-g DRIVERS (Intel GPU Virtualization)
|
||||
M: Zhenyu Wang <zhenyuw@linux.intel.com>
|
||||
|
@ -12126,6 +12127,13 @@ S: Maintained
|
|||
F: Documentation/devicetree/bindings/pinctrl/loongson,ls2k-pinctrl.yaml
|
||||
F: drivers/pinctrl/pinctrl-loongson2.c
|
||||
|
||||
LOONGSON GPIO DRIVER
|
||||
M: Yinbo Zhu <zhuyinbo@loongson.cn>
|
||||
L: linux-gpio@vger.kernel.org
|
||||
S: Maintained
|
||||
F: Documentation/devicetree/bindings/gpio/loongson,ls-gpio.yaml
|
||||
F: drivers/gpio/gpio-loongson-64bit.c
|
||||
|
||||
LOONGSON-2 SOC SERIES CLOCK DRIVER
|
||||
M: Yinbo Zhu <zhuyinbo@loongson.cn>
|
||||
L: linux-clk@vger.kernel.org
|
||||
|
@ -23075,7 +23083,6 @@ F: drivers/i2c/busses/i2c-xlp9xx.c
|
|||
|
||||
XRA1403 GPIO EXPANDER
|
||||
M: Nandor Han <nandor.han@ge.com>
|
||||
M: Semi Malinen <semi.malinen@ge.com>
|
||||
L: linux-gpio@vger.kernel.org
|
||||
S: Maintained
|
||||
F: Documentation/devicetree/bindings/gpio/gpio-xra1403.txt
|
||||
|
|
|
@ -24,7 +24,6 @@ config ARM
|
|||
select ARCH_HAS_SYNC_DMA_FOR_CPU
|
||||
select ARCH_HAS_TEARDOWN_DMA_OPS if MMU
|
||||
select ARCH_HAS_TICK_BROADCAST if GENERIC_CLOCKEVENTS_BROADCAST
|
||||
select ARCH_HAVE_CUSTOM_GPIO_H
|
||||
select ARCH_HAVE_NMI_SAFE_CMPXCHG if CPU_V7 || CPU_V7M || CPU_V6K
|
||||
select ARCH_HAS_GCOV_PROFILE_ALL
|
||||
select ARCH_KEEP_MEMBLOCK
|
||||
|
|
|
@ -1,21 +0,0 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#ifndef _ARCH_ARM_GPIO_H
|
||||
#define _ARCH_ARM_GPIO_H
|
||||
|
||||
#include <asm-generic/gpio.h>
|
||||
|
||||
/* The trivial gpiolib dispatchers */
|
||||
#define gpio_get_value __gpio_get_value
|
||||
#define gpio_set_value __gpio_set_value
|
||||
#define gpio_cansleep __gpio_cansleep
|
||||
|
||||
/*
|
||||
* Provide a default gpio_to_irq() which should satisfy every case.
|
||||
* However, some platforms want to do this differently, so allow them
|
||||
* to override it.
|
||||
*/
|
||||
#ifndef gpio_to_irq
|
||||
#define gpio_to_irq __gpio_to_irq
|
||||
#endif
|
||||
|
||||
#endif /* _ARCH_ARM_GPIO_H */
|
|
@ -41,6 +41,7 @@
|
|||
#include <linux/sched.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/irqdomain.h>
|
||||
|
||||
#include <asm/irq.h>
|
||||
#include <asm/exception.h>
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
*/
|
||||
#include <linux/clk.h>
|
||||
#include <linux/davinci_emac.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
|
@ -108,7 +109,7 @@ static int omap3_sbc_t3730_twl_callback(struct device *dev,
|
|||
if (res)
|
||||
return res;
|
||||
|
||||
gpio_export(gpio, 0);
|
||||
gpiod_export(gpio_to_desc(gpio), 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -123,7 +124,7 @@ static void __init omap3_sbc_t3x_usb_hub_init(int gpio, char *hub_name)
|
|||
return;
|
||||
}
|
||||
|
||||
gpio_export(gpio, 0);
|
||||
gpiod_export(gpio_to_desc(gpio), 0);
|
||||
|
||||
udelay(10);
|
||||
gpio_set_value(gpio, 1);
|
||||
|
@ -200,8 +201,8 @@ static void __init omap3_sbc_t3517_wifi_init(void)
|
|||
return;
|
||||
}
|
||||
|
||||
gpio_export(cm_t3517_wlan_gpios[0].gpio, 0);
|
||||
gpio_export(cm_t3517_wlan_gpios[1].gpio, 0);
|
||||
gpiod_export(gpio_to_desc(cm_t3517_wlan_gpios[0].gpio), 0);
|
||||
gpiod_export(gpio_to_desc(cm_t3517_wlan_gpios[1].gpio), 0);
|
||||
|
||||
msleep(100);
|
||||
gpio_set_value(cm_t3517_wlan_gpios[1].gpio, 0);
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#include <linux/gpio.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/irq.h>
|
||||
|
|
|
@ -21,13 +21,13 @@
|
|||
#include <linux/ioport.h>
|
||||
#include <linux/serial_core.h>
|
||||
#include <linux/serial_s3c.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/reboot.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/clk/samsung.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/irqchip/arm-vic.h>
|
||||
#include <clocksource/samsung_pwm.h>
|
||||
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/gpio/driver.h>
|
||||
#include <linux/gpio/gpio-reg.h>
|
||||
#include <linux/gpio/machine.h>
|
||||
#include <linux/gpio_keys.h>
|
||||
|
|
|
@ -18,7 +18,8 @@
|
|||
#include <linux/spinlock.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/gpio/driver.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/leds.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_irq.h>
|
||||
|
@ -312,7 +313,7 @@ int orion_gpio_led_blink_set(struct gpio_desc *desc, int state,
|
|||
case GPIO_LED_NO_BLINK_LOW:
|
||||
case GPIO_LED_NO_BLINK_HIGH:
|
||||
orion_gpio_set_blink(gpio, 0);
|
||||
gpio_set_value(gpio, state);
|
||||
gpiod_set_raw_value(desc, state);
|
||||
break;
|
||||
case GPIO_LED_BLINK:
|
||||
orion_gpio_set_blink(gpio, 1);
|
||||
|
|
|
@ -24,7 +24,6 @@ config M68KCLASSIC
|
|||
|
||||
config COLDFIRE
|
||||
bool "Coldfire CPU family support"
|
||||
select ARCH_HAVE_CUSTOM_GPIO_H
|
||||
select CPU_HAS_NO_BITFIELDS
|
||||
select CPU_HAS_NO_CAS
|
||||
select CPU_HAS_NO_MULDIV64
|
||||
|
|
|
@ -1,95 +0,0 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Coldfire generic GPIO support
|
||||
*
|
||||
* (C) Copyright 2009, Steven King <sfking@fdwdc.com>
|
||||
*/
|
||||
|
||||
#ifndef coldfire_gpio_h
|
||||
#define coldfire_gpio_h
|
||||
|
||||
#include <linux/io.h>
|
||||
#include <asm/coldfire.h>
|
||||
#include <asm/mcfsim.h>
|
||||
#include <asm/mcfgpio.h>
|
||||
/*
|
||||
* The Generic GPIO functions
|
||||
*
|
||||
* If the gpio is a compile time constant and is one of the Coldfire gpios,
|
||||
* use the inline version, otherwise dispatch thru gpiolib.
|
||||
*/
|
||||
|
||||
static inline int gpio_get_value(unsigned gpio)
|
||||
{
|
||||
if (__builtin_constant_p(gpio) && gpio < MCFGPIO_PIN_MAX)
|
||||
return mcfgpio_read(__mcfgpio_ppdr(gpio)) & mcfgpio_bit(gpio);
|
||||
else
|
||||
return __gpio_get_value(gpio);
|
||||
}
|
||||
|
||||
static inline void gpio_set_value(unsigned gpio, int value)
|
||||
{
|
||||
if (__builtin_constant_p(gpio) && gpio < MCFGPIO_PIN_MAX) {
|
||||
if (gpio < MCFGPIO_SCR_START) {
|
||||
unsigned long flags;
|
||||
MCFGPIO_PORTTYPE data;
|
||||
|
||||
local_irq_save(flags);
|
||||
data = mcfgpio_read(__mcfgpio_podr(gpio));
|
||||
if (value)
|
||||
data |= mcfgpio_bit(gpio);
|
||||
else
|
||||
data &= ~mcfgpio_bit(gpio);
|
||||
mcfgpio_write(data, __mcfgpio_podr(gpio));
|
||||
local_irq_restore(flags);
|
||||
} else {
|
||||
if (value)
|
||||
mcfgpio_write(mcfgpio_bit(gpio),
|
||||
MCFGPIO_SETR_PORT(gpio));
|
||||
else
|
||||
mcfgpio_write(~mcfgpio_bit(gpio),
|
||||
MCFGPIO_CLRR_PORT(gpio));
|
||||
}
|
||||
} else
|
||||
__gpio_set_value(gpio, value);
|
||||
}
|
||||
|
||||
static inline int gpio_to_irq(unsigned gpio)
|
||||
{
|
||||
#if defined(MCFGPIO_IRQ_MIN)
|
||||
if ((gpio >= MCFGPIO_IRQ_MIN) && (gpio < MCFGPIO_IRQ_MAX))
|
||||
#else
|
||||
if (gpio < MCFGPIO_IRQ_MAX)
|
||||
#endif
|
||||
return gpio + MCFGPIO_IRQ_VECBASE;
|
||||
else
|
||||
return __gpio_to_irq(gpio);
|
||||
}
|
||||
|
||||
static inline int gpio_cansleep(unsigned gpio)
|
||||
{
|
||||
return gpio < MCFGPIO_PIN_MAX ? 0 : __gpio_cansleep(gpio);
|
||||
}
|
||||
|
||||
#ifndef CONFIG_GPIOLIB
|
||||
static inline int gpio_request_one(unsigned gpio, unsigned long flags, const char *label)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = gpio_request(gpio, label);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (flags & GPIOF_DIR_IN)
|
||||
err = gpio_direction_input(gpio);
|
||||
else
|
||||
err = gpio_direction_output(gpio,
|
||||
(flags & GPIOF_INIT_HIGH) ? 1 : 0);
|
||||
|
||||
if (err)
|
||||
gpio_free(gpio);
|
||||
|
||||
return err;
|
||||
}
|
||||
#endif /* !CONFIG_GPIOLIB */
|
||||
#endif
|
|
@ -9,7 +9,7 @@
|
|||
#define mcfgpio_h
|
||||
|
||||
#ifdef CONFIG_GPIOLIB
|
||||
#include <asm-generic/gpio.h>
|
||||
#include <linux/gpio.h>
|
||||
#else
|
||||
|
||||
int __mcfgpio_get_value(unsigned gpio);
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
#include <linux/init.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/gpio/driver.h>
|
||||
|
||||
#include <asm/mach-ar7/ar7.h>
|
||||
|
||||
|
|
|
@ -65,6 +65,7 @@ config PPC4xx_GPIO
|
|||
bool "PPC4xx GPIO support"
|
||||
depends on 40x
|
||||
select GPIOLIB
|
||||
select OF_GPIO_MM_GPIOCHIP
|
||||
help
|
||||
Enable gpiolib support for ppc40x based boards
|
||||
|
||||
|
|
|
@ -230,6 +230,7 @@ config PPC4xx_GPIO
|
|||
bool "PPC4xx GPIO support"
|
||||
depends on 44x
|
||||
select GPIOLIB
|
||||
select OF_GPIO_MM_GPIOCHIP
|
||||
help
|
||||
Enable gpiolib support for ppc440 based boards
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
#include <linux/spinlock.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_gpio.h>
|
||||
#include <linux/gpio/legacy-of-mm-gpiochip.h>
|
||||
#include <linux/gpio/driver.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/slab.h>
|
||||
|
|
|
@ -101,6 +101,7 @@ comment "Generic MPC8xx Options"
|
|||
config 8xx_GPIO
|
||||
bool "GPIO API Support"
|
||||
select GPIOLIB
|
||||
select OF_GPIO_MM_GPIOCHIP
|
||||
help
|
||||
Saying Y here will cause the ports on an MPC8xx processor to be used
|
||||
with the GPIO API. If you say N here, the kernel needs less memory.
|
||||
|
|
|
@ -44,7 +44,7 @@
|
|||
#include <asm/fs_pd.h>
|
||||
|
||||
#ifdef CONFIG_8xx_GPIO
|
||||
#include <linux/of_gpio.h>
|
||||
#include <linux/gpio/legacy-of-mm-gpiochip.h>
|
||||
#endif
|
||||
|
||||
#define CPM_MAP_SIZE (0x4000)
|
||||
|
|
|
@ -244,6 +244,7 @@ config QE_GPIO
|
|||
bool "QE GPIO support"
|
||||
depends on QUICC_ENGINE
|
||||
select GPIOLIB
|
||||
select OF_GPIO_MM_GPIOCHIP
|
||||
help
|
||||
Say Y here if you're going to use hardware that connects to the
|
||||
QE GPIOs.
|
||||
|
@ -254,6 +255,7 @@ config CPM2
|
|||
select CPM
|
||||
select HAVE_PCI
|
||||
select GPIOLIB
|
||||
select OF_GPIO_MM_GPIOCHIP
|
||||
help
|
||||
The CPM2 (Communications Processor Module) is a coprocessor on
|
||||
embedded CPUs made by Freescale. Selecting this option means that
|
||||
|
|
|
@ -31,7 +31,7 @@
|
|||
#include <mm/mmu_decl.h>
|
||||
|
||||
#if defined(CONFIG_CPM2) || defined(CONFIG_8xx_GPIO)
|
||||
#include <linux/of_gpio.h>
|
||||
#include <linux/gpio/legacy-of-mm-gpiochip.h>
|
||||
#endif
|
||||
|
||||
static int __init cpm_init(void)
|
||||
|
|
|
@ -4,7 +4,6 @@ config SUPERH
|
|||
select ARCH_32BIT_OFF_T
|
||||
select ARCH_ENABLE_MEMORY_HOTPLUG if SPARSEMEM && MMU
|
||||
select ARCH_ENABLE_MEMORY_HOTREMOVE if SPARSEMEM && MMU
|
||||
select ARCH_HAVE_CUSTOM_GPIO_H
|
||||
select ARCH_HAVE_NMI_SAFE_CMPXCHG if (GUSA_RB || CPU_SH4A)
|
||||
select ARCH_HAS_BINFMT_FLAT if !MMU
|
||||
select ARCH_HAS_CURRENT_STACK_POINTER
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include <linux/sh_intc.h>
|
||||
#include <mach/magicpanelr2.h>
|
||||
#include <asm/heartbeat.h>
|
||||
#include <cpu/gpio.h>
|
||||
#include <cpu/sh7720.h>
|
||||
|
||||
/* Dummy supplies, where voltage doesn't matter */
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#include <linux/delay.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/gpio/machine.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/init.h>
|
||||
|
@ -411,16 +412,16 @@ static int __init ap325rxa_devices_setup(void)
|
|||
/* LD3 and LD4 LEDs */
|
||||
gpio_request(GPIO_PTX5, NULL); /* RUN */
|
||||
gpio_direction_output(GPIO_PTX5, 1);
|
||||
gpio_export(GPIO_PTX5, 0);
|
||||
gpiod_export(gpio_to_desc(GPIO_PTX5), 0);
|
||||
|
||||
gpio_request(GPIO_PTX4, NULL); /* INDICATOR */
|
||||
gpio_direction_output(GPIO_PTX4, 0);
|
||||
gpio_export(GPIO_PTX4, 0);
|
||||
gpiod_export(gpio_to_desc(GPIO_PTX4), 0);
|
||||
|
||||
/* SW1 input */
|
||||
gpio_request(GPIO_PTF7, NULL); /* MODE */
|
||||
gpio_direction_input(GPIO_PTF7);
|
||||
gpio_export(GPIO_PTF7, 0);
|
||||
gpiod_export(gpio_to_desc(GPIO_PTF7), 0);
|
||||
|
||||
/* LCDC */
|
||||
gpio_request(GPIO_FN_LCDD15, NULL);
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
#include <linux/input.h>
|
||||
#include <linux/usb/r8a66597.h>
|
||||
#include <linux/usb/m66592.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/gpio/driver.h>
|
||||
#include <linux/gpio_keys.h>
|
||||
#include <mach/ilsel.h>
|
||||
#include <mach/hardware.h>
|
||||
|
|
|
@ -1,45 +0,0 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0
|
||||
*
|
||||
* include/asm-sh/gpio.h
|
||||
*
|
||||
* Generic GPIO API and pinmux table support for SuperH.
|
||||
*
|
||||
* Copyright (c) 2008 Magnus Damm
|
||||
*/
|
||||
#ifndef __ASM_SH_GPIO_H
|
||||
#define __ASM_SH_GPIO_H
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/errno.h>
|
||||
|
||||
#if defined(CONFIG_CPU_SH3)
|
||||
#include <cpu/gpio.h>
|
||||
#endif
|
||||
|
||||
#include <asm-generic/gpio.h>
|
||||
|
||||
#ifdef CONFIG_GPIOLIB
|
||||
|
||||
static inline int gpio_get_value(unsigned gpio)
|
||||
{
|
||||
return __gpio_get_value(gpio);
|
||||
}
|
||||
|
||||
static inline void gpio_set_value(unsigned gpio, int value)
|
||||
{
|
||||
__gpio_set_value(gpio, value);
|
||||
}
|
||||
|
||||
static inline int gpio_cansleep(unsigned gpio)
|
||||
{
|
||||
return __gpio_cansleep(gpio);
|
||||
}
|
||||
|
||||
static inline int gpio_to_irq(unsigned gpio)
|
||||
{
|
||||
return __gpio_to_irq(gpio);
|
||||
}
|
||||
|
||||
#endif /* CONFIG_GPIOLIB */
|
||||
|
||||
#endif /* __ASM_SH_GPIO_H */
|
|
@ -3,14 +3,6 @@
|
|||
# GPIO infrastructure and drivers
|
||||
#
|
||||
|
||||
config ARCH_HAVE_CUSTOM_GPIO_H
|
||||
bool
|
||||
help
|
||||
Selecting this config option from the architecture Kconfig allows
|
||||
the architecture to provide a custom asm/gpio.h implementation
|
||||
overriding the default implementations. New uses of this are
|
||||
strongly discouraged.
|
||||
|
||||
menuconfig GPIOLIB
|
||||
bool "GPIO Support"
|
||||
help
|
||||
|
@ -47,6 +39,14 @@ config GPIOLIB_IRQCHIP
|
|||
select IRQ_DOMAIN
|
||||
bool
|
||||
|
||||
config OF_GPIO_MM_GPIOCHIP
|
||||
bool
|
||||
help
|
||||
This adds support for the legacy 'struct of_mm_gpio_chip' interface
|
||||
from PowerPC. Existing drivers using this interface need to select
|
||||
this symbol, but new drivers should use the generic gpio-regmap
|
||||
infrastructure instead.
|
||||
|
||||
config DEBUG_GPIO
|
||||
bool "Debug GPIO calls"
|
||||
depends on DEBUG_KERNEL
|
||||
|
@ -139,6 +139,7 @@ config GPIO_ALTERA
|
|||
tristate "Altera GPIO"
|
||||
depends on OF_GPIO
|
||||
select GPIOLIB_IRQCHIP
|
||||
select OF_GPIO_MM_GPIOCHIP
|
||||
help
|
||||
Say Y or M here to build support for the Altera PIO device.
|
||||
|
||||
|
@ -380,6 +381,18 @@ config GPIO_LOONGSON
|
|||
help
|
||||
Driver for GPIO functionality on Loongson-2F/3A/3B processors.
|
||||
|
||||
config GPIO_LOONGSON_64BIT
|
||||
tristate "Loongson 64 bit GPIO support"
|
||||
depends on LOONGARCH || COMPILE_TEST
|
||||
depends on OF_GPIO
|
||||
select GPIO_GENERIC
|
||||
help
|
||||
Say yes here to support the GPIO functionality of a number of
|
||||
Loongson series of chips. The Loongson GPIO controller supports
|
||||
up to 60 GPIOS in total, 4 of which are dedicated GPIO pins, and
|
||||
the remaining 56 are reused with other functions, with edge or
|
||||
level triggered interrupts.
|
||||
|
||||
config GPIO_LPC18XX
|
||||
tristate "NXP LPC18XX/43XX GPIO support"
|
||||
default y if ARCH_LPC18XX
|
||||
|
@ -411,6 +424,7 @@ config GPIO_MENZ127
|
|||
config GPIO_MM_LANTIQ
|
||||
bool "Lantiq Memory mapped GPIOs"
|
||||
depends on LANTIQ && SOC_XWAY
|
||||
select OF_GPIO_MM_GPIOCHIP
|
||||
help
|
||||
This enables support for memory mapped GPIOs on the External Bus Unit
|
||||
(EBU) found on Lantiq SoCs. The GPIOs are output only as they are
|
||||
|
@ -419,6 +433,7 @@ config GPIO_MM_LANTIQ
|
|||
config GPIO_MPC5200
|
||||
def_bool y
|
||||
depends on PPC_MPC52xx
|
||||
select OF_GPIO_MM_GPIOCHIP
|
||||
|
||||
config GPIO_MPC8XXX
|
||||
bool "MPC512x/MPC8xxx/QorIQ GPIO support"
|
||||
|
@ -485,14 +500,6 @@ config GPIO_PL061
|
|||
help
|
||||
Say yes here to support the PrimeCell PL061 GPIO device.
|
||||
|
||||
config GPIO_PMIC_EIC_SPRD
|
||||
tristate "Spreadtrum PMIC EIC support"
|
||||
depends on MFD_SC27XX_PMIC || COMPILE_TEST
|
||||
depends on OF_GPIO
|
||||
select GPIOLIB_IRQCHIP
|
||||
help
|
||||
Say yes here to support Spreadtrum PMIC EIC device.
|
||||
|
||||
config GPIO_PXA
|
||||
bool "PXA GPIO support"
|
||||
depends on ARCH_PXA || ARCH_MMP || COMPILE_TEST
|
||||
|
@ -616,6 +623,17 @@ config GPIO_SYSCON
|
|||
help
|
||||
Say yes here to support GPIO functionality though SYSCON driver.
|
||||
|
||||
config GPIO_TANGIER
|
||||
tristate
|
||||
select GPIOLIB_IRQCHIP
|
||||
help
|
||||
GPIO support for Intel Tangier and compatible platforms.
|
||||
Currently supported:
|
||||
- Elkhart Lake
|
||||
- Merrifield
|
||||
|
||||
If built as a module its name will be gpio-tangier.
|
||||
|
||||
config GPIO_TB10X
|
||||
bool
|
||||
select GPIO_GENERIC
|
||||
|
@ -1000,6 +1018,16 @@ config GPIO_ADNP
|
|||
enough to represent all pins, but the driver will assume a
|
||||
register layout for 64 pins (8 registers).
|
||||
|
||||
config GPIO_FXL6408
|
||||
tristate "FXL6408 I2C GPIO expander"
|
||||
select GPIO_REGMAP
|
||||
select REGMAP_I2C
|
||||
help
|
||||
GPIO driver for Fairchild Semiconductor FXL6408 GPIO expander.
|
||||
|
||||
To compile this driver as a module, choose M here: the module will
|
||||
be called gpio-fxl6408.
|
||||
|
||||
config GPIO_GW_PLD
|
||||
tristate "Gateworks PLD GPIO Expander"
|
||||
depends on OF_GPIO
|
||||
|
@ -1235,6 +1263,17 @@ config HTC_EGPIO
|
|||
several HTC phones. It provides basic support for input
|
||||
pins, output pins, and IRQs.
|
||||
|
||||
config GPIO_ELKHARTLAKE
|
||||
tristate "Intel Elkhart Lake PSE GPIO support"
|
||||
depends on X86 || COMPILE_TEST
|
||||
select GPIO_TANGIER
|
||||
help
|
||||
Select this option to enable GPIO support for Intel Elkhart Lake
|
||||
PSE GPIO IP.
|
||||
|
||||
To compile this driver as a module, choose M here: the module will
|
||||
be called gpio-elkhartlake.
|
||||
|
||||
config GPIO_JANZ_TTL
|
||||
tristate "Janz VMOD-TTL Digital IO Module"
|
||||
depends on MFD_JANZ_CMODIO
|
||||
|
@ -1311,6 +1350,14 @@ config GPIO_PALMAS
|
|||
Select this option to enable GPIO driver for the TI PALMAS
|
||||
series chip family.
|
||||
|
||||
config GPIO_PMIC_EIC_SPRD
|
||||
tristate "Spreadtrum PMIC EIC support"
|
||||
depends on MFD_SC27XX_PMIC || COMPILE_TEST
|
||||
depends on OF_GPIO
|
||||
select GPIOLIB_IRQCHIP
|
||||
help
|
||||
Say yes here to support Spreadtrum PMIC EIC device.
|
||||
|
||||
config GPIO_RC5T583
|
||||
bool "RICOH RC5T583 GPIO"
|
||||
depends on MFD_RC5T583
|
||||
|
@ -1505,7 +1552,7 @@ config GPIO_BT8XX
|
|||
config GPIO_MERRIFIELD
|
||||
tristate "Intel Merrifield GPIO support"
|
||||
depends on X86_INTEL_MID
|
||||
select GPIOLIB_IRQCHIP
|
||||
select GPIO_TANGIER
|
||||
help
|
||||
Say Y here to support Intel Merrifield GPIO.
|
||||
|
||||
|
|
|
@ -54,12 +54,14 @@ obj-$(CONFIG_GPIO_DAVINCI) += gpio-davinci.o
|
|||
obj-$(CONFIG_GPIO_DLN2) += gpio-dln2.o
|
||||
obj-$(CONFIG_GPIO_DWAPB) += gpio-dwapb.o
|
||||
obj-$(CONFIG_GPIO_EIC_SPRD) += gpio-eic-sprd.o
|
||||
obj-$(CONFIG_GPIO_ELKHARTLAKE) += gpio-elkhartlake.o
|
||||
obj-$(CONFIG_GPIO_EM) += gpio-em.o
|
||||
obj-$(CONFIG_GPIO_EN7523) += gpio-en7523.o
|
||||
obj-$(CONFIG_GPIO_EP93XX) += gpio-ep93xx.o
|
||||
obj-$(CONFIG_GPIO_EXAR) += gpio-exar.o
|
||||
obj-$(CONFIG_GPIO_F7188X) += gpio-f7188x.o
|
||||
obj-$(CONFIG_GPIO_FTGPIO010) += gpio-ftgpio010.o
|
||||
obj-$(CONFIG_GPIO_FXL6408) += gpio-fxl6408.o
|
||||
obj-$(CONFIG_GPIO_GE_FPGA) += gpio-ge.o
|
||||
obj-$(CONFIG_GPIO_GPIO_MM) += gpio-gpio-mm.o
|
||||
obj-$(CONFIG_GPIO_GRGPIO) += gpio-grgpio.o
|
||||
|
@ -80,6 +82,7 @@ obj-$(CONFIG_GPIO_LATCH) += gpio-latch.o
|
|||
obj-$(CONFIG_GPIO_LOGICVC) += gpio-logicvc.o
|
||||
obj-$(CONFIG_GPIO_LOONGSON1) += gpio-loongson1.o
|
||||
obj-$(CONFIG_GPIO_LOONGSON) += gpio-loongson.o
|
||||
obj-$(CONFIG_GPIO_LOONGSON_64BIT) += gpio-loongson-64bit.o
|
||||
obj-$(CONFIG_GPIO_LP3943) += gpio-lp3943.o
|
||||
obj-$(CONFIG_GPIO_LP873X) += gpio-lp873x.o
|
||||
obj-$(CONFIG_GPIO_LP87565) += gpio-lp87565.o
|
||||
|
@ -145,6 +148,7 @@ obj-$(CONFIG_GPIO_SPRD) += gpio-sprd.o
|
|||
obj-$(CONFIG_GPIO_STMPE) += gpio-stmpe.o
|
||||
obj-$(CONFIG_GPIO_STP_XWAY) += gpio-stp-xway.o
|
||||
obj-$(CONFIG_GPIO_SYSCON) += gpio-syscon.o
|
||||
obj-$(CONFIG_GPIO_TANGIER) += gpio-tangier.o
|
||||
obj-$(CONFIG_GPIO_TB10X) += gpio-tb10x.o
|
||||
obj-$(CONFIG_GPIO_TC3589X) += gpio-tc3589x.o
|
||||
obj-$(CONFIG_GPIO_TEGRA186) += gpio-tegra186.o
|
||||
|
|
|
@ -59,11 +59,6 @@ the device tree back-end. It is legacy and should not be used in new code.
|
|||
|
||||
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_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
|
||||
GPIO lines from the device tree. This can be tricky and often ivolves
|
||||
|
@ -81,6 +76,16 @@ Work items:
|
|||
uses <linux/gpio/consumer.h> or <linux/gpio/driver.h> instead.
|
||||
|
||||
|
||||
Get rid of <linux/gpio/legacy-of-mm-gpiochip.h>
|
||||
|
||||
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_remove(),
|
||||
CONFIG_OF_GPIO_MM_GPIOCHIP from the kernel.
|
||||
|
||||
|
||||
Get rid of <linux/gpio.h>
|
||||
|
||||
This legacy header is a one stop shop for anything GPIO is closely tied
|
||||
|
|
|
@ -107,7 +107,6 @@ static int dio48e_handle_mask_sync(struct regmap *const map, const int index,
|
|||
{
|
||||
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;
|
||||
|
||||
|
@ -119,7 +118,7 @@ static int dio48e_handle_mask_sync(struct regmap *const map, const int index,
|
|||
*irq_mask = mask_buf;
|
||||
|
||||
/* if all previously masked, enable interrupts when unmasking */
|
||||
if (prev_mask == all_masked) {
|
||||
if (prev_mask == mask_buf_def) {
|
||||
err = regmap_write(map, DIO48E_CLEAR_INTERRUPT, 0x00);
|
||||
if (err)
|
||||
return err;
|
||||
|
@ -127,7 +126,7 @@ static int dio48e_handle_mask_sync(struct regmap *const map, const int index,
|
|||
}
|
||||
|
||||
/* if all are currently masked, disable interrupts */
|
||||
if (mask_buf == all_masked)
|
||||
if (mask_buf == mask_buf_def)
|
||||
return regmap_read(map, DIO48E_DISABLE_INTERRUPT, &val);
|
||||
|
||||
return 0;
|
||||
|
@ -196,13 +195,9 @@ static int dio48e_probe(struct device *dev, unsigned int id)
|
|||
return -ENOMEM;
|
||||
|
||||
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->no_status = true;
|
||||
chip->num_regs = 1;
|
||||
chip->irqs = dio48e_regmap_irqs;
|
||||
chip->num_irqs = ARRAY_SIZE(dio48e_regmap_irqs);
|
||||
|
|
|
@ -307,6 +307,7 @@ static void adnp_irq_mask(struct irq_data *d)
|
|||
unsigned int pos = d->hwirq & 7;
|
||||
|
||||
adnp->irq_enable[reg] &= ~BIT(pos);
|
||||
gpiochip_disable_irq(gc, irqd_to_hwirq(d));
|
||||
}
|
||||
|
||||
static void adnp_irq_unmask(struct irq_data *d)
|
||||
|
@ -316,6 +317,7 @@ static void adnp_irq_unmask(struct irq_data *d)
|
|||
unsigned int reg = d->hwirq >> adnp->reg_shift;
|
||||
unsigned int pos = d->hwirq & 7;
|
||||
|
||||
gpiochip_enable_irq(gc, irqd_to_hwirq(d));
|
||||
adnp->irq_enable[reg] |= BIT(pos);
|
||||
}
|
||||
|
||||
|
@ -372,13 +374,15 @@ static void adnp_irq_bus_unlock(struct irq_data *d)
|
|||
mutex_unlock(&adnp->irq_lock);
|
||||
}
|
||||
|
||||
static struct irq_chip adnp_irq_chip = {
|
||||
static const struct irq_chip adnp_irq_chip = {
|
||||
.name = "gpio-adnp",
|
||||
.irq_mask = adnp_irq_mask,
|
||||
.irq_unmask = adnp_irq_unmask,
|
||||
.irq_set_type = adnp_irq_set_type,
|
||||
.irq_bus_lock = adnp_irq_bus_lock,
|
||||
.irq_bus_sync_unlock = adnp_irq_bus_unlock,
|
||||
.flags = IRQCHIP_IMMUTABLE,
|
||||
GPIOCHIP_IRQ_RESOURCE_HELPERS,
|
||||
};
|
||||
|
||||
static int adnp_irq_setup(struct adnp *adnp)
|
||||
|
@ -469,7 +473,8 @@ static int adnp_gpio_setup(struct adnp *adnp, unsigned int num_gpios,
|
|||
return err;
|
||||
|
||||
girq = &chip->irq;
|
||||
girq->chip = &adnp_irq_chip;
|
||||
gpio_irq_chip_set_chip(girq, &adnp_irq_chip);
|
||||
|
||||
/* This will let us handle the parent IRQ in the driver */
|
||||
girq->parent_handler = NULL;
|
||||
girq->num_parents = 0;
|
||||
|
|
|
@ -10,19 +10,20 @@
|
|||
#include <linux/bitmap.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/ctype.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/gpio/driver.h>
|
||||
#include <linux/gpio/machine.h>
|
||||
#include <linux/idr.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/overflow.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/string.h>
|
||||
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/gpio/driver.h>
|
||||
#include <linux/gpio/machine.h>
|
||||
|
||||
#define AGGREGATOR_MAX_GPIOS 512
|
||||
|
||||
/*
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
#include <linux/io.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/gpio/driver.h>
|
||||
#include <linux/of_gpio.h> /* For of_mm_gpio_chip */
|
||||
#include <linux/gpio/legacy-of-mm-gpiochip.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#define ALTERA_GPIO_MAX_NGPIO 32
|
||||
|
@ -24,14 +24,12 @@
|
|||
* @interrupt_trigger : specifies the hardware configured IRQ trigger type
|
||||
* (rising, falling, both, high)
|
||||
* @mapped_irq : kernel mapped irq number.
|
||||
* @irq_chip : IRQ chip configuration
|
||||
*/
|
||||
struct altera_gpio_chip {
|
||||
struct of_mm_gpio_chip mmchip;
|
||||
raw_spinlock_t gpio_lock;
|
||||
int interrupt_trigger;
|
||||
int mapped_irq;
|
||||
struct irq_chip irq_chip;
|
||||
};
|
||||
|
||||
static void altera_gpio_irq_unmask(struct irq_data *d)
|
||||
|
@ -43,6 +41,7 @@ static void altera_gpio_irq_unmask(struct irq_data *d)
|
|||
|
||||
altera_gc = gpiochip_get_data(irq_data_get_irq_chip_data(d));
|
||||
mm_gc = &altera_gc->mmchip;
|
||||
gpiochip_enable_irq(&mm_gc->gc, irqd_to_hwirq(d));
|
||||
|
||||
raw_spin_lock_irqsave(&altera_gc->gpio_lock, flags);
|
||||
intmask = readl(mm_gc->regs + ALTERA_GPIO_IRQ_MASK);
|
||||
|
@ -68,6 +67,7 @@ static void altera_gpio_irq_mask(struct irq_data *d)
|
|||
intmask &= ~BIT(irqd_to_hwirq(d));
|
||||
writel(intmask, mm_gc->regs + ALTERA_GPIO_IRQ_MASK);
|
||||
raw_spin_unlock_irqrestore(&altera_gc->gpio_lock, flags);
|
||||
gpiochip_disable_irq(&mm_gc->gc, irqd_to_hwirq(d));
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -233,6 +233,17 @@ static void altera_gpio_irq_leveL_high_handler(struct irq_desc *desc)
|
|||
chained_irq_exit(chip, desc);
|
||||
}
|
||||
|
||||
static const struct irq_chip altera_gpio_irq_chip = {
|
||||
.name = "altera-gpio",
|
||||
.irq_mask = altera_gpio_irq_mask,
|
||||
.irq_unmask = altera_gpio_irq_unmask,
|
||||
.irq_set_type = altera_gpio_irq_set_type,
|
||||
.irq_startup = altera_gpio_irq_startup,
|
||||
.irq_shutdown = altera_gpio_irq_mask,
|
||||
.flags = IRQCHIP_IMMUTABLE,
|
||||
GPIOCHIP_IRQ_RESOURCE_HELPERS,
|
||||
};
|
||||
|
||||
static int altera_gpio_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device_node *node = pdev->dev.of_node;
|
||||
|
@ -278,15 +289,9 @@ static int altera_gpio_probe(struct platform_device *pdev)
|
|||
}
|
||||
altera_gc->interrupt_trigger = reg;
|
||||
|
||||
altera_gc->irq_chip.name = "altera-gpio";
|
||||
altera_gc->irq_chip.irq_mask = altera_gpio_irq_mask;
|
||||
altera_gc->irq_chip.irq_unmask = altera_gpio_irq_unmask;
|
||||
altera_gc->irq_chip.irq_set_type = altera_gpio_irq_set_type;
|
||||
altera_gc->irq_chip.irq_startup = altera_gpio_irq_startup;
|
||||
altera_gc->irq_chip.irq_shutdown = altera_gpio_irq_mask;
|
||||
|
||||
girq = &altera_gc->mmchip.gc.irq;
|
||||
girq->chip = &altera_gc->irq_chip;
|
||||
gpio_irq_chip_set_chip(girq, &altera_gpio_irq_chip);
|
||||
|
||||
if (altera_gc->interrupt_trigger == IRQ_TYPE_LEVEL_HIGH)
|
||||
girq->parent_handler = altera_gpio_irq_leveL_high_handler;
|
||||
else
|
||||
|
@ -330,7 +335,7 @@ MODULE_DEVICE_TABLE(of, altera_gpio_of_match);
|
|||
static struct platform_driver altera_gpio_driver = {
|
||||
.driver = {
|
||||
.name = "altera_gpio",
|
||||
.of_match_table = of_match_ptr(altera_gpio_of_match),
|
||||
.of_match_table = altera_gpio_of_match,
|
||||
},
|
||||
.probe = altera_gpio_probe,
|
||||
.remove = altera_gpio_remove,
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/string.h>
|
||||
|
||||
|
@ -29,7 +30,7 @@ struct aspeed_sgpio_pdata {
|
|||
|
||||
struct aspeed_sgpio {
|
||||
struct gpio_chip chip;
|
||||
struct irq_chip intc;
|
||||
struct device *dev;
|
||||
struct clk *pclk;
|
||||
raw_spinlock_t lock;
|
||||
void __iomem *base;
|
||||
|
@ -296,6 +297,10 @@ static void aspeed_sgpio_irq_set_mask(struct irq_data *d, bool set)
|
|||
irqd_to_aspeed_sgpio_data(d, &gpio, &bank, &bit, &offset);
|
||||
addr = bank_reg(gpio, bank, reg_irq_enable);
|
||||
|
||||
/* Unmasking the IRQ */
|
||||
if (set)
|
||||
gpiochip_enable_irq(&gpio->chip, irqd_to_hwirq(d));
|
||||
|
||||
raw_spin_lock_irqsave(&gpio->lock, flags);
|
||||
|
||||
reg = ioread32(addr);
|
||||
|
@ -307,6 +312,12 @@ static void aspeed_sgpio_irq_set_mask(struct irq_data *d, bool set)
|
|||
iowrite32(reg, addr);
|
||||
|
||||
raw_spin_unlock_irqrestore(&gpio->lock, flags);
|
||||
|
||||
/* Masking the IRQ */
|
||||
if (!set)
|
||||
gpiochip_disable_irq(&gpio->chip, irqd_to_hwirq(d));
|
||||
|
||||
|
||||
}
|
||||
|
||||
static void aspeed_sgpio_irq_mask(struct irq_data *d)
|
||||
|
@ -401,6 +412,27 @@ static void aspeed_sgpio_irq_handler(struct irq_desc *desc)
|
|||
chained_irq_exit(ic, desc);
|
||||
}
|
||||
|
||||
static void aspeed_sgpio_irq_print_chip(struct irq_data *d, struct seq_file *p)
|
||||
{
|
||||
const struct aspeed_sgpio_bank *bank;
|
||||
struct aspeed_sgpio *gpio;
|
||||
u32 bit;
|
||||
int offset;
|
||||
|
||||
irqd_to_aspeed_sgpio_data(d, &gpio, &bank, &bit, &offset);
|
||||
seq_printf(p, dev_name(gpio->dev));
|
||||
}
|
||||
|
||||
static const struct irq_chip aspeed_sgpio_irq_chip = {
|
||||
.irq_ack = aspeed_sgpio_irq_ack,
|
||||
.irq_mask = aspeed_sgpio_irq_mask,
|
||||
.irq_unmask = aspeed_sgpio_irq_unmask,
|
||||
.irq_set_type = aspeed_sgpio_set_type,
|
||||
.irq_print_chip = aspeed_sgpio_irq_print_chip,
|
||||
.flags = IRQCHIP_IMMUTABLE,
|
||||
GPIOCHIP_IRQ_RESOURCE_HELPERS,
|
||||
};
|
||||
|
||||
static int aspeed_sgpio_setup_irqs(struct aspeed_sgpio *gpio,
|
||||
struct platform_device *pdev)
|
||||
{
|
||||
|
@ -423,14 +455,8 @@ static int aspeed_sgpio_setup_irqs(struct aspeed_sgpio *gpio,
|
|||
iowrite32(0xffffffff, bank_reg(gpio, bank, reg_irq_status));
|
||||
}
|
||||
|
||||
gpio->intc.name = dev_name(&pdev->dev);
|
||||
gpio->intc.irq_ack = aspeed_sgpio_irq_ack;
|
||||
gpio->intc.irq_mask = aspeed_sgpio_irq_mask;
|
||||
gpio->intc.irq_unmask = aspeed_sgpio_irq_unmask;
|
||||
gpio->intc.irq_set_type = aspeed_sgpio_set_type;
|
||||
|
||||
irq = &gpio->chip.irq;
|
||||
irq->chip = &gpio->intc;
|
||||
gpio_irq_chip_set_chip(irq, &aspeed_sgpio_irq_chip);
|
||||
irq->init_valid_mask = aspeed_sgpio_irq_init_valid_mask;
|
||||
irq->handler = handle_bad_irq;
|
||||
irq->default_type = IRQ_TYPE_NONE;
|
||||
|
@ -524,6 +550,8 @@ static int __init aspeed_sgpio_probe(struct platform_device *pdev)
|
|||
if (IS_ERR(gpio->base))
|
||||
return PTR_ERR(gpio->base);
|
||||
|
||||
gpio->dev = &pdev->dev;
|
||||
|
||||
pdata = device_get_match_data(&pdev->dev);
|
||||
if (!pdata)
|
||||
return -EINVAL;
|
||||
|
@ -609,4 +637,3 @@ static struct platform_driver aspeed_sgpio_driver = {
|
|||
|
||||
module_platform_driver_probe(aspeed_sgpio_driver, aspeed_sgpio_probe);
|
||||
MODULE_DESCRIPTION("Aspeed Serial GPIO Driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include <linux/module.h>
|
||||
#include <linux/pinctrl/consumer.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/string.h>
|
||||
|
||||
|
@ -53,7 +54,7 @@ struct aspeed_gpio_config {
|
|||
*/
|
||||
struct aspeed_gpio {
|
||||
struct gpio_chip chip;
|
||||
struct irq_chip irqc;
|
||||
struct device *dev;
|
||||
raw_spinlock_t lock;
|
||||
void __iomem *base;
|
||||
int irq;
|
||||
|
@ -566,6 +567,10 @@ static void aspeed_gpio_irq_set_mask(struct irq_data *d, bool set)
|
|||
|
||||
addr = bank_reg(gpio, bank, reg_irq_enable);
|
||||
|
||||
/* Unmasking the IRQ */
|
||||
if (set)
|
||||
gpiochip_enable_irq(&gpio->chip, irqd_to_hwirq(d));
|
||||
|
||||
raw_spin_lock_irqsave(&gpio->lock, flags);
|
||||
copro = aspeed_gpio_copro_request(gpio, offset);
|
||||
|
||||
|
@ -579,6 +584,10 @@ static void aspeed_gpio_irq_set_mask(struct irq_data *d, bool set)
|
|||
if (copro)
|
||||
aspeed_gpio_copro_release(gpio, offset);
|
||||
raw_spin_unlock_irqrestore(&gpio->lock, flags);
|
||||
|
||||
/* Masking the IRQ */
|
||||
if (!set)
|
||||
gpiochip_disable_irq(&gpio->chip, irqd_to_hwirq(d));
|
||||
}
|
||||
|
||||
static void aspeed_gpio_irq_mask(struct irq_data *d)
|
||||
|
@ -1080,6 +1089,30 @@ int aspeed_gpio_copro_release_gpio(struct gpio_desc *desc)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(aspeed_gpio_copro_release_gpio);
|
||||
|
||||
static void aspeed_gpio_irq_print_chip(struct irq_data *d, struct seq_file *p)
|
||||
{
|
||||
const struct aspeed_gpio_bank *bank;
|
||||
struct aspeed_gpio *gpio;
|
||||
u32 bit;
|
||||
int rc, offset;
|
||||
|
||||
rc = irqd_to_aspeed_gpio_data(d, &gpio, &bank, &bit, &offset);
|
||||
if (rc)
|
||||
return;
|
||||
|
||||
seq_printf(p, dev_name(gpio->dev));
|
||||
}
|
||||
|
||||
static const struct irq_chip aspeed_gpio_irq_chip = {
|
||||
.irq_ack = aspeed_gpio_irq_ack,
|
||||
.irq_mask = aspeed_gpio_irq_mask,
|
||||
.irq_unmask = aspeed_gpio_irq_unmask,
|
||||
.irq_set_type = aspeed_gpio_set_type,
|
||||
.irq_print_chip = aspeed_gpio_irq_print_chip,
|
||||
.flags = IRQCHIP_IMMUTABLE,
|
||||
GPIOCHIP_IRQ_RESOURCE_HELPERS,
|
||||
};
|
||||
|
||||
/*
|
||||
* Any banks not specified in a struct aspeed_bank_props array are assumed to
|
||||
* have the properties:
|
||||
|
@ -1137,8 +1170,9 @@ MODULE_DEVICE_TABLE(of, aspeed_gpio_of_table);
|
|||
static int __init aspeed_gpio_probe(struct platform_device *pdev)
|
||||
{
|
||||
const struct of_device_id *gpio_id;
|
||||
struct gpio_irq_chip *girq;
|
||||
struct aspeed_gpio *gpio;
|
||||
int rc, i, banks, err;
|
||||
int rc, irq, i, banks, err;
|
||||
u32 ngpio;
|
||||
|
||||
gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL);
|
||||
|
@ -1149,6 +1183,8 @@ static int __init aspeed_gpio_probe(struct platform_device *pdev)
|
|||
if (IS_ERR(gpio->base))
|
||||
return PTR_ERR(gpio->base);
|
||||
|
||||
gpio->dev = &pdev->dev;
|
||||
|
||||
raw_spin_lock_init(&gpio->lock);
|
||||
|
||||
gpio_id = of_match_node(aspeed_gpio_of_table, pdev->dev.of_node);
|
||||
|
@ -1201,31 +1237,23 @@ static int __init aspeed_gpio_probe(struct platform_device *pdev)
|
|||
aspeed_gpio_change_cmd_source(gpio, bank, 3, GPIO_CMDSRC_ARM);
|
||||
}
|
||||
|
||||
/* Optionally set up an irqchip if there is an IRQ */
|
||||
rc = platform_get_irq(pdev, 0);
|
||||
if (rc > 0) {
|
||||
struct gpio_irq_chip *girq;
|
||||
/* Set up an irqchip */
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq < 0)
|
||||
return irq;
|
||||
gpio->irq = irq;
|
||||
girq = &gpio->chip.irq;
|
||||
gpio_irq_chip_set_chip(girq, &aspeed_gpio_irq_chip);
|
||||
|
||||
gpio->irq = rc;
|
||||
girq = &gpio->chip.irq;
|
||||
girq->chip = &gpio->irqc;
|
||||
girq->chip->name = dev_name(&pdev->dev);
|
||||
girq->chip->irq_ack = aspeed_gpio_irq_ack;
|
||||
girq->chip->irq_mask = aspeed_gpio_irq_mask;
|
||||
girq->chip->irq_unmask = aspeed_gpio_irq_unmask;
|
||||
girq->chip->irq_set_type = aspeed_gpio_set_type;
|
||||
girq->parent_handler = aspeed_gpio_irq_handler;
|
||||
girq->num_parents = 1;
|
||||
girq->parents = devm_kcalloc(&pdev->dev, 1,
|
||||
sizeof(*girq->parents),
|
||||
GFP_KERNEL);
|
||||
if (!girq->parents)
|
||||
return -ENOMEM;
|
||||
girq->parents[0] = gpio->irq;
|
||||
girq->default_type = IRQ_TYPE_NONE;
|
||||
girq->handler = handle_bad_irq;
|
||||
girq->init_valid_mask = aspeed_init_irq_valid_mask;
|
||||
}
|
||||
girq->parent_handler = aspeed_gpio_irq_handler;
|
||||
girq->num_parents = 1;
|
||||
girq->parents = devm_kcalloc(&pdev->dev, 1, sizeof(*girq->parents), GFP_KERNEL);
|
||||
if (!girq->parents)
|
||||
return -ENOMEM;
|
||||
girq->parents[0] = gpio->irq;
|
||||
girq->default_type = IRQ_TYPE_NONE;
|
||||
girq->handler = handle_bad_irq;
|
||||
girq->init_valid_mask = aspeed_init_irq_valid_mask;
|
||||
|
||||
gpio->offset_timer =
|
||||
devm_kzalloc(&pdev->dev, gpio->chip.ngpio, GFP_KERNEL);
|
||||
|
|
|
@ -71,6 +71,7 @@ static void ath79_gpio_irq_unmask(struct irq_data *data)
|
|||
u32 mask = BIT(irqd_to_hwirq(data));
|
||||
unsigned long flags;
|
||||
|
||||
gpiochip_enable_irq(&ctrl->gc, irqd_to_hwirq(data));
|
||||
raw_spin_lock_irqsave(&ctrl->lock, flags);
|
||||
ath79_gpio_update_bits(ctrl, AR71XX_GPIO_REG_INT_MASK, mask, mask);
|
||||
raw_spin_unlock_irqrestore(&ctrl->lock, flags);
|
||||
|
@ -85,6 +86,7 @@ static void ath79_gpio_irq_mask(struct irq_data *data)
|
|||
raw_spin_lock_irqsave(&ctrl->lock, flags);
|
||||
ath79_gpio_update_bits(ctrl, AR71XX_GPIO_REG_INT_MASK, mask, 0);
|
||||
raw_spin_unlock_irqrestore(&ctrl->lock, flags);
|
||||
gpiochip_disable_irq(&ctrl->gc, irqd_to_hwirq(data));
|
||||
}
|
||||
|
||||
static void ath79_gpio_irq_enable(struct irq_data *data)
|
||||
|
@ -169,13 +171,15 @@ static int ath79_gpio_irq_set_type(struct irq_data *data,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static struct irq_chip ath79_gpio_irqchip = {
|
||||
static const struct irq_chip ath79_gpio_irqchip = {
|
||||
.name = "gpio-ath79",
|
||||
.irq_enable = ath79_gpio_irq_enable,
|
||||
.irq_disable = ath79_gpio_irq_disable,
|
||||
.irq_mask = ath79_gpio_irq_mask,
|
||||
.irq_unmask = ath79_gpio_irq_unmask,
|
||||
.irq_set_type = ath79_gpio_irq_set_type,
|
||||
.flags = IRQCHIP_IMMUTABLE,
|
||||
GPIOCHIP_IRQ_RESOURCE_HELPERS,
|
||||
};
|
||||
|
||||
static void ath79_gpio_irq_handler(struct irq_desc *desc)
|
||||
|
@ -274,7 +278,7 @@ static int ath79_gpio_probe(struct platform_device *pdev)
|
|||
/* Optional interrupt setup */
|
||||
if (!np || of_property_read_bool(np, "interrupt-controller")) {
|
||||
girq = &ctrl->gc.irq;
|
||||
girq->chip = &ath79_gpio_irqchip;
|
||||
gpio_irq_chip_set_chip(girq, &ath79_gpio_irqchip);
|
||||
girq->parent_handler = ath79_gpio_irq_handler;
|
||||
girq->num_parents = 1;
|
||||
girq->parents = devm_kcalloc(dev, 1, sizeof(*girq->parents),
|
||||
|
|
|
@ -70,6 +70,7 @@ static void cdns_gpio_irq_mask(struct irq_data *d)
|
|||
struct cdns_gpio_chip *cgpio = gpiochip_get_data(chip);
|
||||
|
||||
iowrite32(BIT(d->hwirq), cgpio->regs + CDNS_GPIO_IRQ_DIS);
|
||||
gpiochip_disable_irq(chip, irqd_to_hwirq(d));
|
||||
}
|
||||
|
||||
static void cdns_gpio_irq_unmask(struct irq_data *d)
|
||||
|
@ -77,6 +78,7 @@ static void cdns_gpio_irq_unmask(struct irq_data *d)
|
|||
struct gpio_chip *chip = irq_data_get_irq_chip_data(d);
|
||||
struct cdns_gpio_chip *cgpio = gpiochip_get_data(chip);
|
||||
|
||||
gpiochip_enable_irq(chip, irqd_to_hwirq(d));
|
||||
iowrite32(BIT(d->hwirq), cgpio->regs + CDNS_GPIO_IRQ_EN);
|
||||
}
|
||||
|
||||
|
@ -138,11 +140,13 @@ static void cdns_gpio_irq_handler(struct irq_desc *desc)
|
|||
chained_irq_exit(irqchip, desc);
|
||||
}
|
||||
|
||||
static struct irq_chip cdns_gpio_irqchip = {
|
||||
static const struct irq_chip cdns_gpio_irqchip = {
|
||||
.name = "cdns-gpio",
|
||||
.irq_mask = cdns_gpio_irq_mask,
|
||||
.irq_unmask = cdns_gpio_irq_unmask,
|
||||
.irq_set_type = cdns_gpio_irq_set_type
|
||||
.irq_set_type = cdns_gpio_irq_set_type,
|
||||
.flags = IRQCHIP_IMMUTABLE,
|
||||
GPIOCHIP_IRQ_RESOURCE_HELPERS,
|
||||
};
|
||||
|
||||
static int cdns_gpio_probe(struct platform_device *pdev)
|
||||
|
@ -222,7 +226,7 @@ static int cdns_gpio_probe(struct platform_device *pdev)
|
|||
struct gpio_irq_chip *girq;
|
||||
|
||||
girq = &cgpio->gc.irq;
|
||||
girq->chip = &cdns_gpio_irqchip;
|
||||
gpio_irq_chip_set_chip(girq, &cdns_gpio_irqchip);
|
||||
girq->parent_handler = cdns_gpio_irq_handler;
|
||||
girq->num_parents = 1;
|
||||
girq->parents = devm_kcalloc(&pdev->dev, 1,
|
||||
|
|
|
@ -24,8 +24,6 @@
|
|||
#include <linux/spinlock.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
|
||||
#include <asm-generic/gpio.h>
|
||||
|
||||
#define MAX_REGS_BANKS 5
|
||||
#define MAX_INT_PER_BANK 32
|
||||
|
||||
|
|
|
@ -0,0 +1,90 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Intel Elkhart Lake PSE GPIO driver
|
||||
*
|
||||
* Copyright (c) 2023 Intel Corporation.
|
||||
*
|
||||
* Authors: Pandith N <pandith.n@intel.com>
|
||||
* Raag Jadav <raag.jadav@intel.com>
|
||||
*/
|
||||
|
||||
#include <linux/device.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pm.h>
|
||||
|
||||
#include "gpio-tangier.h"
|
||||
|
||||
/* Each Intel EHL PSE GPIO Controller has 30 GPIO pins */
|
||||
#define EHL_PSE_NGPIO 30
|
||||
|
||||
static int ehl_gpio_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct tng_gpio *priv;
|
||||
int irq, ret;
|
||||
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq < 0)
|
||||
return irq;
|
||||
|
||||
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
|
||||
priv->reg_base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(priv->reg_base))
|
||||
return PTR_ERR(priv->reg_base);
|
||||
|
||||
priv->dev = dev;
|
||||
priv->irq = irq;
|
||||
|
||||
priv->info.base = -1;
|
||||
priv->info.ngpio = EHL_PSE_NGPIO;
|
||||
|
||||
priv->wake_regs.gwmr = GWMR_EHL;
|
||||
priv->wake_regs.gwsr = GWSR_EHL;
|
||||
priv->wake_regs.gsir = GSIR_EHL;
|
||||
|
||||
ret = devm_tng_gpio_probe(dev, priv);
|
||||
if (ret)
|
||||
return dev_err_probe(dev, ret, "tng_gpio_probe error\n");
|
||||
|
||||
platform_set_drvdata(pdev, priv);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ehl_gpio_suspend(struct device *dev)
|
||||
{
|
||||
return tng_gpio_suspend(dev);
|
||||
}
|
||||
|
||||
static int ehl_gpio_resume(struct device *dev)
|
||||
{
|
||||
return tng_gpio_resume(dev);
|
||||
}
|
||||
|
||||
static DEFINE_SIMPLE_DEV_PM_OPS(ehl_gpio_pm_ops, ehl_gpio_suspend, ehl_gpio_resume);
|
||||
|
||||
static const struct platform_device_id ehl_gpio_ids[] = {
|
||||
{ "gpio-elkhartlake" },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(platform, ehl_gpio_ids);
|
||||
|
||||
static struct platform_driver ehl_gpio_driver = {
|
||||
.driver = {
|
||||
.name = "gpio-elkhartlake",
|
||||
.pm = pm_sleep_ptr(&ehl_gpio_pm_ops),
|
||||
},
|
||||
.probe = ehl_gpio_probe,
|
||||
.id_table = ehl_gpio_ids,
|
||||
};
|
||||
module_platform_driver(ehl_gpio_driver);
|
||||
|
||||
MODULE_AUTHOR("Pandith N <pandith.n@intel.com>");
|
||||
MODULE_AUTHOR("Raag Jadav <raag.jadav@intel.com>");
|
||||
MODULE_DESCRIPTION("Intel Elkhart Lake PSE GPIO driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_IMPORT_NS(GPIO_TANGIER);
|
|
@ -349,7 +349,7 @@ static const struct of_device_id ftgpio_gpio_of_match[] = {
|
|||
static struct platform_driver ftgpio_gpio_driver = {
|
||||
.driver = {
|
||||
.name = "ftgpio010-gpio",
|
||||
.of_match_table = of_match_ptr(ftgpio_gpio_of_match),
|
||||
.of_match_table = ftgpio_gpio_of_match,
|
||||
},
|
||||
.probe = ftgpio_gpio_probe,
|
||||
.remove = ftgpio_gpio_remove,
|
||||
|
|
|
@ -0,0 +1,158 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* FXL6408 GPIO driver
|
||||
*
|
||||
* Copyright 2023 Toradex
|
||||
*
|
||||
* Author: Emanuele Ghidoli <emanuele.ghidoli@toradex.com>
|
||||
*/
|
||||
|
||||
#include <linux/err.h>
|
||||
#include <linux/gpio/regmap.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/regmap.h>
|
||||
|
||||
#define FXL6408_REG_DEVICE_ID 0x01
|
||||
#define FXL6408_MF_FAIRCHILD 0b101
|
||||
#define FXL6408_MF_SHIFT 5
|
||||
|
||||
/* Bits set here indicate that the GPIO is an output. */
|
||||
#define FXL6408_REG_IO_DIR 0x03
|
||||
|
||||
/*
|
||||
* Bits set here, when the corresponding bit of IO_DIR is set, drive
|
||||
* the output high instead of low.
|
||||
*/
|
||||
#define FXL6408_REG_OUTPUT 0x05
|
||||
|
||||
/* Bits here make the output High-Z, instead of the OUTPUT value. */
|
||||
#define FXL6408_REG_OUTPUT_HIGH_Z 0x07
|
||||
|
||||
/* Returns the current status (1 = HIGH) of the input pins. */
|
||||
#define FXL6408_REG_INPUT_STATUS 0x0f
|
||||
|
||||
/*
|
||||
* Return the current interrupt status
|
||||
* This bit is HIGH if input GPIO != default state (register 09h).
|
||||
* The flag is cleared after being read (bit returns to 0).
|
||||
* The input must go back to default state and change again before this flag is raised again.
|
||||
*/
|
||||
#define FXL6408_REG_INT_STS 0x13
|
||||
|
||||
#define FXL6408_NGPIO 8
|
||||
|
||||
static const struct regmap_range rd_range[] = {
|
||||
{ FXL6408_REG_DEVICE_ID, FXL6408_REG_DEVICE_ID },
|
||||
{ FXL6408_REG_IO_DIR, FXL6408_REG_OUTPUT },
|
||||
{ FXL6408_REG_INPUT_STATUS, FXL6408_REG_INPUT_STATUS },
|
||||
};
|
||||
|
||||
static const struct regmap_range wr_range[] = {
|
||||
{ FXL6408_REG_DEVICE_ID, FXL6408_REG_DEVICE_ID },
|
||||
{ FXL6408_REG_IO_DIR, FXL6408_REG_OUTPUT },
|
||||
{ FXL6408_REG_OUTPUT_HIGH_Z, FXL6408_REG_OUTPUT_HIGH_Z },
|
||||
};
|
||||
|
||||
static const struct regmap_range volatile_range[] = {
|
||||
{ FXL6408_REG_DEVICE_ID, FXL6408_REG_DEVICE_ID },
|
||||
{ FXL6408_REG_INPUT_STATUS, FXL6408_REG_INPUT_STATUS },
|
||||
};
|
||||
|
||||
static const struct regmap_access_table rd_table = {
|
||||
.yes_ranges = rd_range,
|
||||
.n_yes_ranges = ARRAY_SIZE(rd_range),
|
||||
};
|
||||
|
||||
static const struct regmap_access_table wr_table = {
|
||||
.yes_ranges = wr_range,
|
||||
.n_yes_ranges = ARRAY_SIZE(wr_range),
|
||||
};
|
||||
|
||||
static const struct regmap_access_table volatile_table = {
|
||||
.yes_ranges = volatile_range,
|
||||
.n_yes_ranges = ARRAY_SIZE(volatile_range),
|
||||
};
|
||||
|
||||
static const struct regmap_config regmap = {
|
||||
.reg_bits = 8,
|
||||
.val_bits = 8,
|
||||
|
||||
.max_register = FXL6408_REG_INT_STS,
|
||||
.wr_table = &wr_table,
|
||||
.rd_table = &rd_table,
|
||||
.volatile_table = &volatile_table,
|
||||
|
||||
.cache_type = REGCACHE_RBTREE,
|
||||
.num_reg_defaults_raw = FXL6408_REG_INT_STS + 1,
|
||||
};
|
||||
|
||||
static int fxl6408_identify(struct device *dev, struct regmap *regmap)
|
||||
{
|
||||
int val, ret;
|
||||
|
||||
ret = regmap_read(regmap, FXL6408_REG_DEVICE_ID, &val);
|
||||
if (ret)
|
||||
return dev_err_probe(dev, ret, "error reading DEVICE_ID\n");
|
||||
if (val >> FXL6408_MF_SHIFT != FXL6408_MF_FAIRCHILD)
|
||||
return dev_err_probe(dev, -ENODEV, "invalid device id 0x%02x\n", val);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fxl6408_probe(struct i2c_client *client)
|
||||
{
|
||||
struct device *dev = &client->dev;
|
||||
int ret;
|
||||
struct gpio_regmap_config gpio_config = {
|
||||
.parent = dev,
|
||||
.ngpio = FXL6408_NGPIO,
|
||||
.reg_dat_base = GPIO_REGMAP_ADDR(FXL6408_REG_INPUT_STATUS),
|
||||
.reg_set_base = GPIO_REGMAP_ADDR(FXL6408_REG_OUTPUT),
|
||||
.reg_dir_out_base = GPIO_REGMAP_ADDR(FXL6408_REG_IO_DIR),
|
||||
.ngpio_per_reg = FXL6408_NGPIO,
|
||||
};
|
||||
|
||||
gpio_config.regmap = devm_regmap_init_i2c(client, ®map);
|
||||
if (IS_ERR(gpio_config.regmap))
|
||||
return dev_err_probe(dev, PTR_ERR(gpio_config.regmap),
|
||||
"failed to allocate register map\n");
|
||||
|
||||
ret = fxl6408_identify(dev, gpio_config.regmap);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Disable High-Z of outputs, so that our OUTPUT updates actually take effect. */
|
||||
ret = regmap_write(gpio_config.regmap, FXL6408_REG_OUTPUT_HIGH_Z, 0);
|
||||
if (ret)
|
||||
return dev_err_probe(dev, ret, "failed to write 'output high Z' register\n");
|
||||
|
||||
return PTR_ERR_OR_ZERO(devm_gpio_regmap_register(dev, &gpio_config));
|
||||
}
|
||||
|
||||
static const __maybe_unused struct of_device_id fxl6408_dt_ids[] = {
|
||||
{ .compatible = "fcs,fxl6408" },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, fxl6408_dt_ids);
|
||||
|
||||
static const struct i2c_device_id fxl6408_id[] = {
|
||||
{ "fxl6408", 0 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, fxl6408_id);
|
||||
|
||||
static struct i2c_driver fxl6408_driver = {
|
||||
.driver = {
|
||||
.name = "fxl6408",
|
||||
.of_match_table = fxl6408_dt_ids,
|
||||
},
|
||||
.probe_new = fxl6408_probe,
|
||||
.id_table = fxl6408_id,
|
||||
};
|
||||
module_i2c_driver(fxl6408_driver);
|
||||
|
||||
MODULE_AUTHOR("Emanuele Ghidoli <emanuele.ghidoli@toradex.com>");
|
||||
MODULE_DESCRIPTION("FXL6408 GPIO driver");
|
||||
MODULE_LICENSE("GPL");
|
|
@ -37,7 +37,6 @@ struct hisi_gpio {
|
|||
struct device *dev;
|
||||
void __iomem *reg_base;
|
||||
unsigned int line_num;
|
||||
struct irq_chip irq_chip;
|
||||
int irq;
|
||||
};
|
||||
|
||||
|
@ -100,12 +99,14 @@ static void hisi_gpio_irq_set_mask(struct irq_data *d)
|
|||
struct gpio_chip *chip = irq_data_get_irq_chip_data(d);
|
||||
|
||||
hisi_gpio_write_reg(chip, HISI_GPIO_INTMASK_SET_WX, BIT(irqd_to_hwirq(d)));
|
||||
gpiochip_disable_irq(chip, irqd_to_hwirq(d));
|
||||
}
|
||||
|
||||
static void hisi_gpio_irq_clr_mask(struct irq_data *d)
|
||||
{
|
||||
struct gpio_chip *chip = irq_data_get_irq_chip_data(d);
|
||||
|
||||
gpiochip_enable_irq(chip, irqd_to_hwirq(d));
|
||||
hisi_gpio_write_reg(chip, HISI_GPIO_INTMASK_CLR_WX, BIT(irqd_to_hwirq(d)));
|
||||
}
|
||||
|
||||
|
@ -191,20 +192,24 @@ static void hisi_gpio_irq_handler(struct irq_desc *desc)
|
|||
chained_irq_exit(irq_c, desc);
|
||||
}
|
||||
|
||||
static const struct irq_chip hisi_gpio_irq_chip = {
|
||||
.name = "HISI-GPIO",
|
||||
.irq_ack = hisi_gpio_set_ack,
|
||||
.irq_mask = hisi_gpio_irq_set_mask,
|
||||
.irq_unmask = hisi_gpio_irq_clr_mask,
|
||||
.irq_set_type = hisi_gpio_irq_set_type,
|
||||
.irq_enable = hisi_gpio_irq_enable,
|
||||
.irq_disable = hisi_gpio_irq_disable,
|
||||
.flags = IRQCHIP_IMMUTABLE,
|
||||
GPIOCHIP_IRQ_RESOURCE_HELPERS,
|
||||
};
|
||||
|
||||
static void hisi_gpio_init_irq(struct hisi_gpio *hisi_gpio)
|
||||
{
|
||||
struct gpio_chip *chip = &hisi_gpio->chip;
|
||||
struct gpio_irq_chip *girq_chip = &chip->irq;
|
||||
|
||||
/* Set hooks for irq_chip */
|
||||
hisi_gpio->irq_chip.irq_ack = hisi_gpio_set_ack;
|
||||
hisi_gpio->irq_chip.irq_mask = hisi_gpio_irq_set_mask;
|
||||
hisi_gpio->irq_chip.irq_unmask = hisi_gpio_irq_clr_mask;
|
||||
hisi_gpio->irq_chip.irq_set_type = hisi_gpio_irq_set_type;
|
||||
hisi_gpio->irq_chip.irq_enable = hisi_gpio_irq_enable;
|
||||
hisi_gpio->irq_chip.irq_disable = hisi_gpio_irq_disable;
|
||||
|
||||
girq_chip->chip = &hisi_gpio->irq_chip;
|
||||
gpio_irq_chip_set_chip(girq_chip, &hisi_gpio_irq_chip);
|
||||
girq_chip->default_type = IRQ_TYPE_NONE;
|
||||
girq_chip->num_parents = 1;
|
||||
girq_chip->parents = &hisi_gpio->irq;
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
/*
|
||||
|
@ -48,7 +49,7 @@
|
|||
|
||||
struct hlwd_gpio {
|
||||
struct gpio_chip gpioc;
|
||||
struct irq_chip irqc;
|
||||
struct device *dev;
|
||||
void __iomem *regs;
|
||||
int irq;
|
||||
u32 edge_emulation;
|
||||
|
@ -123,6 +124,7 @@ static void hlwd_gpio_irq_mask(struct irq_data *data)
|
|||
mask &= ~BIT(data->hwirq);
|
||||
iowrite32be(mask, hlwd->regs + HW_GPIOB_INTMASK);
|
||||
raw_spin_unlock_irqrestore(&hlwd->gpioc.bgpio_lock, flags);
|
||||
gpiochip_disable_irq(&hlwd->gpioc, irqd_to_hwirq(data));
|
||||
}
|
||||
|
||||
static void hlwd_gpio_irq_unmask(struct irq_data *data)
|
||||
|
@ -132,6 +134,7 @@ static void hlwd_gpio_irq_unmask(struct irq_data *data)
|
|||
unsigned long flags;
|
||||
u32 mask;
|
||||
|
||||
gpiochip_enable_irq(&hlwd->gpioc, irqd_to_hwirq(data));
|
||||
raw_spin_lock_irqsave(&hlwd->gpioc.bgpio_lock, flags);
|
||||
mask = ioread32be(hlwd->regs + HW_GPIOB_INTMASK);
|
||||
mask |= BIT(data->hwirq);
|
||||
|
@ -202,6 +205,24 @@ static int hlwd_gpio_irq_set_type(struct irq_data *data, unsigned int flow_type)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void hlwd_gpio_irq_print_chip(struct irq_data *data, struct seq_file *p)
|
||||
{
|
||||
struct hlwd_gpio *hlwd =
|
||||
gpiochip_get_data(irq_data_get_irq_chip_data(data));
|
||||
|
||||
seq_printf(p, dev_name(hlwd->dev));
|
||||
}
|
||||
|
||||
static const struct irq_chip hlwd_gpio_irq_chip = {
|
||||
.irq_mask = hlwd_gpio_irq_mask,
|
||||
.irq_unmask = hlwd_gpio_irq_unmask,
|
||||
.irq_enable = hlwd_gpio_irq_enable,
|
||||
.irq_set_type = hlwd_gpio_irq_set_type,
|
||||
.irq_print_chip = hlwd_gpio_irq_print_chip,
|
||||
.flags = IRQCHIP_IMMUTABLE,
|
||||
GPIOCHIP_IRQ_RESOURCE_HELPERS,
|
||||
};
|
||||
|
||||
static int hlwd_gpio_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct hlwd_gpio *hlwd;
|
||||
|
@ -216,6 +237,8 @@ static int hlwd_gpio_probe(struct platform_device *pdev)
|
|||
if (IS_ERR(hlwd->regs))
|
||||
return PTR_ERR(hlwd->regs);
|
||||
|
||||
hlwd->dev = &pdev->dev;
|
||||
|
||||
/*
|
||||
* Claim all GPIOs using the OWNER register. This will not work on
|
||||
* systems where the AHBPROT memory firewall hasn't been configured to
|
||||
|
@ -259,14 +282,8 @@ static int hlwd_gpio_probe(struct platform_device *pdev)
|
|||
return hlwd->irq;
|
||||
}
|
||||
|
||||
hlwd->irqc.name = dev_name(&pdev->dev);
|
||||
hlwd->irqc.irq_mask = hlwd_gpio_irq_mask;
|
||||
hlwd->irqc.irq_unmask = hlwd_gpio_irq_unmask;
|
||||
hlwd->irqc.irq_enable = hlwd_gpio_irq_enable;
|
||||
hlwd->irqc.irq_set_type = hlwd_gpio_irq_set_type;
|
||||
|
||||
girq = &hlwd->gpioc.irq;
|
||||
girq->chip = &hlwd->irqc;
|
||||
gpio_irq_chip_set_chip(girq, &hlwd_gpio_irq_chip);
|
||||
girq->parent_handler = hlwd_gpio_irqhandler;
|
||||
girq->num_parents = 1;
|
||||
girq->parents = devm_kcalloc(&pdev->dev, 1,
|
||||
|
|
|
@ -457,7 +457,7 @@ static int ichx_gpio_probe(struct platform_device *pdev)
|
|||
|
||||
init:
|
||||
ichx_gpiolib_setup(&ichx_priv.chip);
|
||||
err = gpiochip_add_data(&ichx_priv.chip, NULL);
|
||||
err = devm_gpiochip_add_data(dev, &ichx_priv.chip, NULL);
|
||||
if (err) {
|
||||
dev_err(dev, "Failed to register GPIOs\n");
|
||||
return err;
|
||||
|
@ -469,19 +469,11 @@ init:
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int ichx_gpio_remove(struct platform_device *pdev)
|
||||
{
|
||||
gpiochip_remove(&ichx_priv.chip);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver ichx_gpio_driver = {
|
||||
.driver = {
|
||||
.name = DRV_NAME,
|
||||
},
|
||||
.probe = ichx_gpio_probe,
|
||||
.remove = ichx_gpio_remove,
|
||||
};
|
||||
|
||||
module_platform_driver(ichx_gpio_driver);
|
||||
|
|
|
@ -92,6 +92,8 @@ static void idt_gpio_mask(struct irq_data *d)
|
|||
writel(ctrl->mask_cache, ctrl->pic + IDT_PIC_IRQ_MASK);
|
||||
|
||||
raw_spin_unlock_irqrestore(&gc->bgpio_lock, flags);
|
||||
|
||||
gpiochip_disable_irq(gc, irqd_to_hwirq(d));
|
||||
}
|
||||
|
||||
static void idt_gpio_unmask(struct irq_data *d)
|
||||
|
@ -100,6 +102,7 @@ static void idt_gpio_unmask(struct irq_data *d)
|
|||
struct idt_gpio_ctrl *ctrl = gpiochip_get_data(gc);
|
||||
unsigned long flags;
|
||||
|
||||
gpiochip_enable_irq(gc, irqd_to_hwirq(d));
|
||||
raw_spin_lock_irqsave(&gc->bgpio_lock, flags);
|
||||
|
||||
ctrl->mask_cache &= ~BIT(d->hwirq);
|
||||
|
@ -119,12 +122,14 @@ static int idt_gpio_irq_init_hw(struct gpio_chip *gc)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static struct irq_chip idt_gpio_irqchip = {
|
||||
static const struct irq_chip idt_gpio_irqchip = {
|
||||
.name = "IDTGPIO",
|
||||
.irq_mask = idt_gpio_mask,
|
||||
.irq_ack = idt_gpio_ack,
|
||||
.irq_unmask = idt_gpio_unmask,
|
||||
.irq_set_type = idt_gpio_irq_set_type
|
||||
.irq_set_type = idt_gpio_irq_set_type,
|
||||
.flags = IRQCHIP_IMMUTABLE,
|
||||
GPIOCHIP_IRQ_RESOURCE_HELPERS,
|
||||
};
|
||||
|
||||
static int idt_gpio_probe(struct platform_device *pdev)
|
||||
|
@ -168,7 +173,7 @@ static int idt_gpio_probe(struct platform_device *pdev)
|
|||
return parent_irq;
|
||||
|
||||
girq = &ctrl->gc.irq;
|
||||
girq->chip = &idt_gpio_irqchip;
|
||||
gpio_irq_chip_set_chip(girq, &idt_gpio_irqchip);
|
||||
girq->init_hw = idt_gpio_irq_init_hw;
|
||||
girq->parent_handler = idt_gpio_dispatch;
|
||||
girq->num_parents = 1;
|
||||
|
|
|
@ -136,4 +136,3 @@ subsys_initcall_sync(_imx_scu_gpio_init);
|
|||
|
||||
MODULE_AUTHOR("Shenwei Wang <shenwei.wang@nxp.com>");
|
||||
MODULE_DESCRIPTION("NXP GPIO over IMX SCU API");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
|
|
@ -0,0 +1,238 @@
|
|||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Loongson GPIO Support
|
||||
*
|
||||
* Copyright (C) 2022-2023 Loongson Technology Corporation Limited
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/gpio/driver.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <asm/types.h>
|
||||
|
||||
enum loongson_gpio_mode {
|
||||
BIT_CTRL_MODE,
|
||||
BYTE_CTRL_MODE,
|
||||
};
|
||||
|
||||
struct loongson_gpio_chip_data {
|
||||
const char *label;
|
||||
enum loongson_gpio_mode mode;
|
||||
unsigned int conf_offset;
|
||||
unsigned int out_offset;
|
||||
unsigned int in_offset;
|
||||
};
|
||||
|
||||
struct loongson_gpio_chip {
|
||||
struct gpio_chip chip;
|
||||
struct fwnode_handle *fwnode;
|
||||
spinlock_t lock;
|
||||
void __iomem *reg_base;
|
||||
const struct loongson_gpio_chip_data *chip_data;
|
||||
};
|
||||
|
||||
static inline struct loongson_gpio_chip *to_loongson_gpio_chip(struct gpio_chip *chip)
|
||||
{
|
||||
return container_of(chip, struct loongson_gpio_chip, chip);
|
||||
}
|
||||
|
||||
static inline void loongson_commit_direction(struct loongson_gpio_chip *lgpio, unsigned int pin,
|
||||
int input)
|
||||
{
|
||||
u8 bval = input ? 1 : 0;
|
||||
|
||||
writeb(bval, lgpio->reg_base + lgpio->chip_data->conf_offset + pin);
|
||||
}
|
||||
|
||||
static void loongson_commit_level(struct loongson_gpio_chip *lgpio, unsigned int pin, int high)
|
||||
{
|
||||
u8 bval = high ? 1 : 0;
|
||||
|
||||
writeb(bval, lgpio->reg_base + lgpio->chip_data->out_offset + pin);
|
||||
}
|
||||
|
||||
static int loongson_gpio_direction_input(struct gpio_chip *chip, unsigned int pin)
|
||||
{
|
||||
unsigned long flags;
|
||||
struct loongson_gpio_chip *lgpio = to_loongson_gpio_chip(chip);
|
||||
|
||||
spin_lock_irqsave(&lgpio->lock, flags);
|
||||
loongson_commit_direction(lgpio, pin, 1);
|
||||
spin_unlock_irqrestore(&lgpio->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int loongson_gpio_direction_output(struct gpio_chip *chip, unsigned int pin, int value)
|
||||
{
|
||||
unsigned long flags;
|
||||
struct loongson_gpio_chip *lgpio = to_loongson_gpio_chip(chip);
|
||||
|
||||
spin_lock_irqsave(&lgpio->lock, flags);
|
||||
loongson_commit_level(lgpio, pin, value);
|
||||
loongson_commit_direction(lgpio, pin, 0);
|
||||
spin_unlock_irqrestore(&lgpio->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int loongson_gpio_get(struct gpio_chip *chip, unsigned int pin)
|
||||
{
|
||||
u8 bval;
|
||||
int val;
|
||||
struct loongson_gpio_chip *lgpio = to_loongson_gpio_chip(chip);
|
||||
|
||||
bval = readb(lgpio->reg_base + lgpio->chip_data->in_offset + pin);
|
||||
val = bval & 1;
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
static int loongson_gpio_get_direction(struct gpio_chip *chip, unsigned int pin)
|
||||
{
|
||||
u8 bval;
|
||||
struct loongson_gpio_chip *lgpio = to_loongson_gpio_chip(chip);
|
||||
|
||||
bval = readb(lgpio->reg_base + lgpio->chip_data->conf_offset + pin);
|
||||
if (bval & 1)
|
||||
return GPIO_LINE_DIRECTION_IN;
|
||||
|
||||
return GPIO_LINE_DIRECTION_OUT;
|
||||
}
|
||||
|
||||
static void loongson_gpio_set(struct gpio_chip *chip, unsigned int pin, int value)
|
||||
{
|
||||
unsigned long flags;
|
||||
struct loongson_gpio_chip *lgpio = to_loongson_gpio_chip(chip);
|
||||
|
||||
spin_lock_irqsave(&lgpio->lock, flags);
|
||||
loongson_commit_level(lgpio, pin, value);
|
||||
spin_unlock_irqrestore(&lgpio->lock, flags);
|
||||
}
|
||||
|
||||
static int loongson_gpio_to_irq(struct gpio_chip *chip, unsigned int offset)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(chip->parent);
|
||||
|
||||
return platform_get_irq(pdev, offset);
|
||||
}
|
||||
|
||||
static int loongson_gpio_init(struct device *dev, struct loongson_gpio_chip *lgpio,
|
||||
struct device_node *np, void __iomem *reg_base)
|
||||
{
|
||||
int ret;
|
||||
u32 ngpios;
|
||||
|
||||
lgpio->reg_base = reg_base;
|
||||
|
||||
if (lgpio->chip_data->mode == BIT_CTRL_MODE) {
|
||||
ret = bgpio_init(&lgpio->chip, dev, 8,
|
||||
lgpio->reg_base + lgpio->chip_data->in_offset,
|
||||
lgpio->reg_base + lgpio->chip_data->out_offset,
|
||||
NULL, NULL,
|
||||
lgpio->reg_base + lgpio->chip_data->conf_offset,
|
||||
0);
|
||||
if (ret) {
|
||||
dev_err(dev, "unable to init generic GPIO\n");
|
||||
return ret;
|
||||
}
|
||||
} else {
|
||||
lgpio->chip.direction_input = loongson_gpio_direction_input;
|
||||
lgpio->chip.get = loongson_gpio_get;
|
||||
lgpio->chip.get_direction = loongson_gpio_get_direction;
|
||||
lgpio->chip.direction_output = loongson_gpio_direction_output;
|
||||
lgpio->chip.set = loongson_gpio_set;
|
||||
lgpio->chip.parent = dev;
|
||||
spin_lock_init(&lgpio->lock);
|
||||
}
|
||||
|
||||
device_property_read_u32(dev, "ngpios", &ngpios);
|
||||
|
||||
lgpio->chip.can_sleep = 0;
|
||||
lgpio->chip.ngpio = ngpios;
|
||||
lgpio->chip.label = lgpio->chip_data->label;
|
||||
lgpio->chip.to_irq = loongson_gpio_to_irq;
|
||||
|
||||
return devm_gpiochip_add_data(dev, &lgpio->chip, lgpio);
|
||||
}
|
||||
|
||||
static int loongson_gpio_probe(struct platform_device *pdev)
|
||||
{
|
||||
void __iomem *reg_base;
|
||||
struct loongson_gpio_chip *lgpio;
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
struct device *dev = &pdev->dev;
|
||||
|
||||
lgpio = devm_kzalloc(dev, sizeof(*lgpio), GFP_KERNEL);
|
||||
if (!lgpio)
|
||||
return -ENOMEM;
|
||||
|
||||
lgpio->chip_data = device_get_match_data(dev);
|
||||
|
||||
reg_base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(reg_base))
|
||||
return PTR_ERR(reg_base);
|
||||
|
||||
return loongson_gpio_init(dev, lgpio, np, reg_base);
|
||||
}
|
||||
|
||||
static const struct loongson_gpio_chip_data loongson_gpio_ls2k_data = {
|
||||
.label = "ls2k_gpio",
|
||||
.mode = BIT_CTRL_MODE,
|
||||
.conf_offset = 0x0,
|
||||
.in_offset = 0x20,
|
||||
.out_offset = 0x10,
|
||||
};
|
||||
|
||||
static const struct loongson_gpio_chip_data loongson_gpio_ls7a_data = {
|
||||
.label = "ls7a_gpio",
|
||||
.mode = BYTE_CTRL_MODE,
|
||||
.conf_offset = 0x800,
|
||||
.in_offset = 0xa00,
|
||||
.out_offset = 0x900,
|
||||
};
|
||||
|
||||
static const struct of_device_id loongson_gpio_of_match[] = {
|
||||
{
|
||||
.compatible = "loongson,ls2k-gpio",
|
||||
.data = &loongson_gpio_ls2k_data,
|
||||
},
|
||||
{
|
||||
.compatible = "loongson,ls7a-gpio",
|
||||
.data = &loongson_gpio_ls7a_data,
|
||||
},
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, loongson_gpio_of_match);
|
||||
|
||||
static const struct acpi_device_id loongson_gpio_acpi_match[] = {
|
||||
{
|
||||
.id = "LOON0002",
|
||||
.driver_data = (kernel_ulong_t)&loongson_gpio_ls7a_data,
|
||||
},
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(acpi, loongson_gpio_acpi_match);
|
||||
|
||||
static struct platform_driver loongson_gpio_driver = {
|
||||
.driver = {
|
||||
.name = "loongson-gpio",
|
||||
.of_match_table = loongson_gpio_of_match,
|
||||
.acpi_match_table = loongson_gpio_acpi_match,
|
||||
},
|
||||
.probe = loongson_gpio_probe,
|
||||
};
|
||||
|
||||
static int __init loongson_gpio_setup(void)
|
||||
{
|
||||
return platform_driver_register(&loongson_gpio_driver);
|
||||
}
|
||||
postcore_initcall(loongson_gpio_setup);
|
||||
|
||||
MODULE_DESCRIPTION("Loongson gpio driver");
|
||||
MODULE_LICENSE("GPL");
|
|
@ -1,11 +1,8 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* GPIO Driver for Loongson 1 SoC
|
||||
*
|
||||
* Copyright (C) 2015-2016 Zhang, Keguang <keguang.zhang@gmail.com>
|
||||
*
|
||||
* This file is licensed under the terms of the GNU General Public
|
||||
* License version 2. This program is licensed "as is" without any
|
||||
* warranty of any kind, whether express or implied.
|
||||
* Copyright (C) 2015-2023 Keguang Zhang <keguang.zhang@gmail.com>
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
|
@ -19,15 +16,19 @@
|
|||
#define GPIO_DATA 0x20
|
||||
#define GPIO_OUTPUT 0x30
|
||||
|
||||
static void __iomem *gpio_reg_base;
|
||||
struct ls1x_gpio_chip {
|
||||
struct gpio_chip gc;
|
||||
void __iomem *reg_base;
|
||||
};
|
||||
|
||||
static int ls1x_gpio_request(struct gpio_chip *gc, unsigned int offset)
|
||||
{
|
||||
struct ls1x_gpio_chip *ls1x_gc = gpiochip_get_data(gc);
|
||||
unsigned long flags;
|
||||
|
||||
raw_spin_lock_irqsave(&gc->bgpio_lock, flags);
|
||||
__raw_writel(__raw_readl(gpio_reg_base + GPIO_CFG) | BIT(offset),
|
||||
gpio_reg_base + GPIO_CFG);
|
||||
__raw_writel(__raw_readl(ls1x_gc->reg_base + GPIO_CFG) | BIT(offset),
|
||||
ls1x_gc->reg_base + GPIO_CFG);
|
||||
raw_spin_unlock_irqrestore(&gc->bgpio_lock, flags);
|
||||
|
||||
return 0;
|
||||
|
@ -35,61 +36,75 @@ static int ls1x_gpio_request(struct gpio_chip *gc, unsigned int offset)
|
|||
|
||||
static void ls1x_gpio_free(struct gpio_chip *gc, unsigned int offset)
|
||||
{
|
||||
struct ls1x_gpio_chip *ls1x_gc = gpiochip_get_data(gc);
|
||||
unsigned long flags;
|
||||
|
||||
raw_spin_lock_irqsave(&gc->bgpio_lock, flags);
|
||||
__raw_writel(__raw_readl(gpio_reg_base + GPIO_CFG) & ~BIT(offset),
|
||||
gpio_reg_base + GPIO_CFG);
|
||||
__raw_writel(__raw_readl(ls1x_gc->reg_base + GPIO_CFG) & ~BIT(offset),
|
||||
ls1x_gc->reg_base + GPIO_CFG);
|
||||
raw_spin_unlock_irqrestore(&gc->bgpio_lock, flags);
|
||||
}
|
||||
|
||||
static int ls1x_gpio_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct gpio_chip *gc;
|
||||
struct ls1x_gpio_chip *ls1x_gc;
|
||||
int ret;
|
||||
|
||||
gc = devm_kzalloc(dev, sizeof(*gc), GFP_KERNEL);
|
||||
if (!gc)
|
||||
ls1x_gc = devm_kzalloc(dev, sizeof(*ls1x_gc), GFP_KERNEL);
|
||||
if (!ls1x_gc)
|
||||
return -ENOMEM;
|
||||
|
||||
gpio_reg_base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(gpio_reg_base))
|
||||
return PTR_ERR(gpio_reg_base);
|
||||
ls1x_gc->reg_base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(ls1x_gc->reg_base))
|
||||
return PTR_ERR(ls1x_gc->reg_base);
|
||||
|
||||
ret = bgpio_init(gc, dev, 4, gpio_reg_base + GPIO_DATA,
|
||||
gpio_reg_base + GPIO_OUTPUT, NULL,
|
||||
NULL, gpio_reg_base + GPIO_DIR, 0);
|
||||
ret = bgpio_init(&ls1x_gc->gc, dev, 4, ls1x_gc->reg_base + GPIO_DATA,
|
||||
ls1x_gc->reg_base + GPIO_OUTPUT, NULL,
|
||||
NULL, ls1x_gc->reg_base + GPIO_DIR, 0);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
gc->owner = THIS_MODULE;
|
||||
gc->request = ls1x_gpio_request;
|
||||
gc->free = ls1x_gpio_free;
|
||||
gc->base = pdev->id * 32;
|
||||
ls1x_gc->gc.owner = THIS_MODULE;
|
||||
ls1x_gc->gc.request = ls1x_gpio_request;
|
||||
ls1x_gc->gc.free = ls1x_gpio_free;
|
||||
/*
|
||||
* Clear ngpio to let gpiolib get the correct number
|
||||
* by reading ngpios property
|
||||
*/
|
||||
ls1x_gc->gc.ngpio = 0;
|
||||
|
||||
ret = devm_gpiochip_add_data(dev, gc, NULL);
|
||||
ret = devm_gpiochip_add_data(dev, &ls1x_gc->gc, ls1x_gc);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
platform_set_drvdata(pdev, gc);
|
||||
dev_info(dev, "Loongson1 GPIO driver registered\n");
|
||||
platform_set_drvdata(pdev, ls1x_gc);
|
||||
|
||||
dev_info(dev, "GPIO controller registered with %d pins\n",
|
||||
ls1x_gc->gc.ngpio);
|
||||
|
||||
return 0;
|
||||
err:
|
||||
dev_err(dev, "failed to register GPIO device\n");
|
||||
dev_err(dev, "failed to register GPIO controller\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct of_device_id ls1x_gpio_dt_ids[] = {
|
||||
{ .compatible = "loongson,ls1x-gpio" },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, ls1x_gpio_dt_ids);
|
||||
|
||||
static struct platform_driver ls1x_gpio_driver = {
|
||||
.probe = ls1x_gpio_probe,
|
||||
.driver = {
|
||||
.name = "ls1x-gpio",
|
||||
.of_match_table = ls1x_gpio_dt_ids,
|
||||
},
|
||||
};
|
||||
|
||||
module_platform_driver(ls1x_gpio_driver);
|
||||
|
||||
MODULE_AUTHOR("Kelvin Cheung <keguang.zhang@gmail.com>");
|
||||
MODULE_AUTHOR("Keguang Zhang <keguang.zhang@gmail.com>");
|
||||
MODULE_DESCRIPTION("Loongson1 GPIO driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
|
|
@ -351,6 +351,7 @@ static void max732x_irq_mask(struct irq_data *d)
|
|||
struct max732x_chip *chip = gpiochip_get_data(gc);
|
||||
|
||||
chip->irq_mask_cur &= ~(1 << d->hwirq);
|
||||
gpiochip_disable_irq(gc, irqd_to_hwirq(d));
|
||||
}
|
||||
|
||||
static void max732x_irq_unmask(struct irq_data *d)
|
||||
|
@ -358,6 +359,7 @@ static void max732x_irq_unmask(struct irq_data *d)
|
|||
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
|
||||
struct max732x_chip *chip = gpiochip_get_data(gc);
|
||||
|
||||
gpiochip_enable_irq(gc, irqd_to_hwirq(d));
|
||||
chip->irq_mask_cur |= 1 << d->hwirq;
|
||||
}
|
||||
|
||||
|
@ -429,7 +431,7 @@ static int max732x_irq_set_wake(struct irq_data *data, unsigned int on)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static struct irq_chip max732x_irq_chip = {
|
||||
static const struct irq_chip max732x_irq_chip = {
|
||||
.name = "max732x",
|
||||
.irq_mask = max732x_irq_mask,
|
||||
.irq_unmask = max732x_irq_unmask,
|
||||
|
@ -437,6 +439,8 @@ static struct irq_chip max732x_irq_chip = {
|
|||
.irq_bus_sync_unlock = max732x_irq_bus_sync_unlock,
|
||||
.irq_set_type = max732x_irq_set_type,
|
||||
.irq_set_wake = max732x_irq_set_wake,
|
||||
.flags = IRQCHIP_IMMUTABLE,
|
||||
GPIOCHIP_IRQ_RESOURCE_HELPERS,
|
||||
};
|
||||
|
||||
static uint8_t max732x_irq_pending(struct max732x_chip *chip)
|
||||
|
@ -517,7 +521,7 @@ static int max732x_irq_setup(struct max732x_chip *chip,
|
|||
}
|
||||
|
||||
girq = &chip->gpio_chip.irq;
|
||||
girq->chip = &max732x_irq_chip;
|
||||
gpio_irq_chip_set_chip(girq, &max732x_irq_chip);
|
||||
/* This will let us handle the parent IRQ in the driver */
|
||||
girq->parent_handler = NULL;
|
||||
girq->num_parents = 0;
|
||||
|
|
|
@ -2,60 +2,25 @@
|
|||
/*
|
||||
* Intel Merrifield SoC GPIO driver
|
||||
*
|
||||
* Copyright (c) 2016 Intel Corporation.
|
||||
* Copyright (c) 2016, 2023 Intel Corporation.
|
||||
* Author: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
|
||||
*/
|
||||
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/gpio/driver.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/pinctrl/consumer.h>
|
||||
#include <linux/string_helpers.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#define GCCR 0x000 /* controller configuration */
|
||||
#define GPLR 0x004 /* pin level r/o */
|
||||
#define GPDR 0x01c /* pin direction */
|
||||
#define GPSR 0x034 /* pin set w/o */
|
||||
#define GPCR 0x04c /* pin clear w/o */
|
||||
#define GRER 0x064 /* rising edge detect */
|
||||
#define GFER 0x07c /* falling edge detect */
|
||||
#define GFBR 0x094 /* glitch filter bypass */
|
||||
#define GIMR 0x0ac /* interrupt mask */
|
||||
#define GISR 0x0c4 /* interrupt source */
|
||||
#define GITR 0x300 /* input type */
|
||||
#define GLPR 0x318 /* level input polarity */
|
||||
#define GWMR 0x400 /* wake mask */
|
||||
#define GWSR 0x418 /* wake source */
|
||||
#define GSIR 0xc00 /* secure input */
|
||||
#include "gpio-tangier.h"
|
||||
|
||||
/* Intel Merrifield has 192 GPIO pins */
|
||||
#define MRFLD_NGPIO 192
|
||||
|
||||
struct mrfld_gpio_pinrange {
|
||||
unsigned int gpio_base;
|
||||
unsigned int pin_base;
|
||||
unsigned int npins;
|
||||
};
|
||||
|
||||
#define GPIO_PINRANGE(gstart, gend, pstart) \
|
||||
{ \
|
||||
.gpio_base = (gstart), \
|
||||
.pin_base = (pstart), \
|
||||
.npins = (gend) - (gstart) + 1, \
|
||||
}
|
||||
|
||||
struct mrfld_gpio {
|
||||
struct gpio_chip chip;
|
||||
void __iomem *reg_base;
|
||||
raw_spinlock_t lock;
|
||||
struct device *dev;
|
||||
};
|
||||
|
||||
static const struct mrfld_gpio_pinrange mrfld_gpio_ranges[] = {
|
||||
static const struct tng_gpio_pinrange mrfld_gpio_ranges[] = {
|
||||
GPIO_PINRANGE(0, 11, 146),
|
||||
GPIO_PINRANGE(12, 13, 144),
|
||||
GPIO_PINRANGE(14, 15, 35),
|
||||
|
@ -84,323 +49,15 @@ static const struct mrfld_gpio_pinrange mrfld_gpio_ranges[] = {
|
|||
GPIO_PINRANGE(190, 191, 178),
|
||||
};
|
||||
|
||||
static void __iomem *gpio_reg(struct gpio_chip *chip, unsigned int offset,
|
||||
unsigned int reg_type_offset)
|
||||
{
|
||||
struct mrfld_gpio *priv = gpiochip_get_data(chip);
|
||||
u8 reg = offset / 32;
|
||||
|
||||
return priv->reg_base + reg_type_offset + reg * 4;
|
||||
}
|
||||
|
||||
static int mrfld_gpio_get(struct gpio_chip *chip, unsigned int offset)
|
||||
{
|
||||
void __iomem *gplr = gpio_reg(chip, offset, GPLR);
|
||||
|
||||
return !!(readl(gplr) & BIT(offset % 32));
|
||||
}
|
||||
|
||||
static void mrfld_gpio_set(struct gpio_chip *chip, unsigned int offset,
|
||||
int value)
|
||||
{
|
||||
struct mrfld_gpio *priv = gpiochip_get_data(chip);
|
||||
void __iomem *gpsr, *gpcr;
|
||||
unsigned long flags;
|
||||
|
||||
raw_spin_lock_irqsave(&priv->lock, flags);
|
||||
|
||||
if (value) {
|
||||
gpsr = gpio_reg(chip, offset, GPSR);
|
||||
writel(BIT(offset % 32), gpsr);
|
||||
} else {
|
||||
gpcr = gpio_reg(chip, offset, GPCR);
|
||||
writel(BIT(offset % 32), gpcr);
|
||||
}
|
||||
|
||||
raw_spin_unlock_irqrestore(&priv->lock, flags);
|
||||
}
|
||||
|
||||
static int mrfld_gpio_direction_input(struct gpio_chip *chip,
|
||||
unsigned int offset)
|
||||
{
|
||||
struct mrfld_gpio *priv = gpiochip_get_data(chip);
|
||||
void __iomem *gpdr = gpio_reg(chip, offset, GPDR);
|
||||
unsigned long flags;
|
||||
u32 value;
|
||||
|
||||
raw_spin_lock_irqsave(&priv->lock, flags);
|
||||
|
||||
value = readl(gpdr);
|
||||
value &= ~BIT(offset % 32);
|
||||
writel(value, gpdr);
|
||||
|
||||
raw_spin_unlock_irqrestore(&priv->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mrfld_gpio_direction_output(struct gpio_chip *chip,
|
||||
unsigned int offset, int value)
|
||||
{
|
||||
struct mrfld_gpio *priv = gpiochip_get_data(chip);
|
||||
void __iomem *gpdr = gpio_reg(chip, offset, GPDR);
|
||||
unsigned long flags;
|
||||
|
||||
mrfld_gpio_set(chip, offset, value);
|
||||
|
||||
raw_spin_lock_irqsave(&priv->lock, flags);
|
||||
|
||||
value = readl(gpdr);
|
||||
value |= BIT(offset % 32);
|
||||
writel(value, gpdr);
|
||||
|
||||
raw_spin_unlock_irqrestore(&priv->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mrfld_gpio_get_direction(struct gpio_chip *chip, unsigned int offset)
|
||||
{
|
||||
void __iomem *gpdr = gpio_reg(chip, offset, GPDR);
|
||||
|
||||
if (readl(gpdr) & BIT(offset % 32))
|
||||
return GPIO_LINE_DIRECTION_OUT;
|
||||
|
||||
return GPIO_LINE_DIRECTION_IN;
|
||||
}
|
||||
|
||||
static int mrfld_gpio_set_debounce(struct gpio_chip *chip, unsigned int offset,
|
||||
unsigned int debounce)
|
||||
{
|
||||
struct mrfld_gpio *priv = gpiochip_get_data(chip);
|
||||
void __iomem *gfbr = gpio_reg(chip, offset, GFBR);
|
||||
unsigned long flags;
|
||||
u32 value;
|
||||
|
||||
raw_spin_lock_irqsave(&priv->lock, flags);
|
||||
|
||||
if (debounce)
|
||||
value = readl(gfbr) & ~BIT(offset % 32);
|
||||
else
|
||||
value = readl(gfbr) | BIT(offset % 32);
|
||||
writel(value, gfbr);
|
||||
|
||||
raw_spin_unlock_irqrestore(&priv->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mrfld_gpio_set_config(struct gpio_chip *chip, unsigned int offset,
|
||||
unsigned long config)
|
||||
{
|
||||
u32 debounce;
|
||||
|
||||
if ((pinconf_to_config_param(config) == PIN_CONFIG_BIAS_DISABLE) ||
|
||||
(pinconf_to_config_param(config) == PIN_CONFIG_BIAS_PULL_UP) ||
|
||||
(pinconf_to_config_param(config) == PIN_CONFIG_BIAS_PULL_DOWN))
|
||||
return gpiochip_generic_config(chip, offset, config);
|
||||
|
||||
if (pinconf_to_config_param(config) != PIN_CONFIG_INPUT_DEBOUNCE)
|
||||
return -ENOTSUPP;
|
||||
|
||||
debounce = pinconf_to_config_argument(config);
|
||||
return mrfld_gpio_set_debounce(chip, offset, debounce);
|
||||
}
|
||||
|
||||
static void mrfld_irq_ack(struct irq_data *d)
|
||||
{
|
||||
struct mrfld_gpio *priv = irq_data_get_irq_chip_data(d);
|
||||
u32 gpio = irqd_to_hwirq(d);
|
||||
void __iomem *gisr = gpio_reg(&priv->chip, gpio, GISR);
|
||||
unsigned long flags;
|
||||
|
||||
raw_spin_lock_irqsave(&priv->lock, flags);
|
||||
|
||||
writel(BIT(gpio % 32), gisr);
|
||||
|
||||
raw_spin_unlock_irqrestore(&priv->lock, flags);
|
||||
}
|
||||
|
||||
static void mrfld_irq_unmask_mask(struct mrfld_gpio *priv, u32 gpio, bool unmask)
|
||||
{
|
||||
void __iomem *gimr = gpio_reg(&priv->chip, gpio, GIMR);
|
||||
unsigned long flags;
|
||||
u32 value;
|
||||
|
||||
raw_spin_lock_irqsave(&priv->lock, flags);
|
||||
|
||||
if (unmask)
|
||||
value = readl(gimr) | BIT(gpio % 32);
|
||||
else
|
||||
value = readl(gimr) & ~BIT(gpio % 32);
|
||||
writel(value, gimr);
|
||||
|
||||
raw_spin_unlock_irqrestore(&priv->lock, flags);
|
||||
}
|
||||
|
||||
static void mrfld_irq_mask(struct irq_data *d)
|
||||
{
|
||||
struct mrfld_gpio *priv = irq_data_get_irq_chip_data(d);
|
||||
u32 gpio = irqd_to_hwirq(d);
|
||||
|
||||
mrfld_irq_unmask_mask(priv, gpio, false);
|
||||
gpiochip_disable_irq(&priv->chip, gpio);
|
||||
}
|
||||
|
||||
static void mrfld_irq_unmask(struct irq_data *d)
|
||||
{
|
||||
struct mrfld_gpio *priv = irq_data_get_irq_chip_data(d);
|
||||
u32 gpio = irqd_to_hwirq(d);
|
||||
|
||||
gpiochip_enable_irq(&priv->chip, gpio);
|
||||
mrfld_irq_unmask_mask(priv, gpio, true);
|
||||
}
|
||||
|
||||
static int mrfld_irq_set_type(struct irq_data *d, unsigned int type)
|
||||
{
|
||||
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
|
||||
struct mrfld_gpio *priv = gpiochip_get_data(gc);
|
||||
u32 gpio = irqd_to_hwirq(d);
|
||||
void __iomem *grer = gpio_reg(&priv->chip, gpio, GRER);
|
||||
void __iomem *gfer = gpio_reg(&priv->chip, gpio, GFER);
|
||||
void __iomem *gitr = gpio_reg(&priv->chip, gpio, GITR);
|
||||
void __iomem *glpr = gpio_reg(&priv->chip, gpio, GLPR);
|
||||
unsigned long flags;
|
||||
u32 value;
|
||||
|
||||
raw_spin_lock_irqsave(&priv->lock, flags);
|
||||
|
||||
if (type & IRQ_TYPE_EDGE_RISING)
|
||||
value = readl(grer) | BIT(gpio % 32);
|
||||
else
|
||||
value = readl(grer) & ~BIT(gpio % 32);
|
||||
writel(value, grer);
|
||||
|
||||
if (type & IRQ_TYPE_EDGE_FALLING)
|
||||
value = readl(gfer) | BIT(gpio % 32);
|
||||
else
|
||||
value = readl(gfer) & ~BIT(gpio % 32);
|
||||
writel(value, gfer);
|
||||
|
||||
/*
|
||||
* To prevent glitches from triggering an unintended level interrupt,
|
||||
* configure GLPR register first and then configure GITR.
|
||||
*/
|
||||
if (type & IRQ_TYPE_LEVEL_LOW)
|
||||
value = readl(glpr) | BIT(gpio % 32);
|
||||
else
|
||||
value = readl(glpr) & ~BIT(gpio % 32);
|
||||
writel(value, glpr);
|
||||
|
||||
if (type & IRQ_TYPE_LEVEL_MASK) {
|
||||
value = readl(gitr) | BIT(gpio % 32);
|
||||
writel(value, gitr);
|
||||
|
||||
irq_set_handler_locked(d, handle_level_irq);
|
||||
} else if (type & IRQ_TYPE_EDGE_BOTH) {
|
||||
value = readl(gitr) & ~BIT(gpio % 32);
|
||||
writel(value, gitr);
|
||||
|
||||
irq_set_handler_locked(d, handle_edge_irq);
|
||||
}
|
||||
|
||||
raw_spin_unlock_irqrestore(&priv->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mrfld_irq_set_wake(struct irq_data *d, unsigned int on)
|
||||
{
|
||||
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
|
||||
struct mrfld_gpio *priv = gpiochip_get_data(gc);
|
||||
u32 gpio = irqd_to_hwirq(d);
|
||||
void __iomem *gwmr = gpio_reg(&priv->chip, gpio, GWMR);
|
||||
void __iomem *gwsr = gpio_reg(&priv->chip, gpio, GWSR);
|
||||
unsigned long flags;
|
||||
u32 value;
|
||||
|
||||
raw_spin_lock_irqsave(&priv->lock, flags);
|
||||
|
||||
/* Clear the existing wake status */
|
||||
writel(BIT(gpio % 32), gwsr);
|
||||
|
||||
if (on)
|
||||
value = readl(gwmr) | BIT(gpio % 32);
|
||||
else
|
||||
value = readl(gwmr) & ~BIT(gpio % 32);
|
||||
writel(value, gwmr);
|
||||
|
||||
raw_spin_unlock_irqrestore(&priv->lock, flags);
|
||||
|
||||
dev_dbg(priv->dev, "%s wake for gpio %u\n", str_enable_disable(on), gpio);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct irq_chip mrfld_irqchip = {
|
||||
.name = "gpio-merrifield",
|
||||
.irq_ack = mrfld_irq_ack,
|
||||
.irq_mask = mrfld_irq_mask,
|
||||
.irq_unmask = mrfld_irq_unmask,
|
||||
.irq_set_type = mrfld_irq_set_type,
|
||||
.irq_set_wake = mrfld_irq_set_wake,
|
||||
.flags = IRQCHIP_IMMUTABLE,
|
||||
GPIOCHIP_IRQ_RESOURCE_HELPERS,
|
||||
};
|
||||
|
||||
static void mrfld_irq_handler(struct irq_desc *desc)
|
||||
{
|
||||
struct gpio_chip *gc = irq_desc_get_handler_data(desc);
|
||||
struct mrfld_gpio *priv = gpiochip_get_data(gc);
|
||||
struct irq_chip *irqchip = irq_desc_get_chip(desc);
|
||||
unsigned long base, gpio;
|
||||
|
||||
chained_irq_enter(irqchip, desc);
|
||||
|
||||
/* Check GPIO controller to check which pin triggered the interrupt */
|
||||
for (base = 0; base < priv->chip.ngpio; base += 32) {
|
||||
void __iomem *gisr = gpio_reg(&priv->chip, base, GISR);
|
||||
void __iomem *gimr = gpio_reg(&priv->chip, base, GIMR);
|
||||
unsigned long pending, enabled;
|
||||
|
||||
pending = readl(gisr);
|
||||
enabled = readl(gimr);
|
||||
|
||||
/* Only interrupts that are enabled */
|
||||
pending &= enabled;
|
||||
|
||||
for_each_set_bit(gpio, &pending, 32)
|
||||
generic_handle_domain_irq(gc->irq.domain, base + gpio);
|
||||
}
|
||||
|
||||
chained_irq_exit(irqchip, desc);
|
||||
}
|
||||
|
||||
static int mrfld_irq_init_hw(struct gpio_chip *chip)
|
||||
{
|
||||
struct mrfld_gpio *priv = gpiochip_get_data(chip);
|
||||
void __iomem *reg;
|
||||
unsigned int base;
|
||||
|
||||
for (base = 0; base < priv->chip.ngpio; base += 32) {
|
||||
/* Clear the rising-edge detect register */
|
||||
reg = gpio_reg(&priv->chip, base, GRER);
|
||||
writel(0, reg);
|
||||
/* Clear the falling-edge detect register */
|
||||
reg = gpio_reg(&priv->chip, base, GFER);
|
||||
writel(0, reg);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const char *mrfld_gpio_get_pinctrl_dev_name(struct mrfld_gpio *priv)
|
||||
static const char *mrfld_gpio_get_pinctrl_dev_name(struct tng_gpio *priv)
|
||||
{
|
||||
struct device *dev = priv->dev;
|
||||
struct acpi_device *adev;
|
||||
const char *name;
|
||||
|
||||
adev = acpi_dev_get_first_match_dev("INTC1002", NULL, -1);
|
||||
if (adev) {
|
||||
name = devm_kstrdup(priv->dev, acpi_dev_name(adev), GFP_KERNEL);
|
||||
name = devm_kstrdup(dev, acpi_dev_name(adev), GFP_KERNEL);
|
||||
acpi_dev_put(adev);
|
||||
} else {
|
||||
name = "pinctrl-merrifield";
|
||||
|
@ -409,37 +66,10 @@ static const char *mrfld_gpio_get_pinctrl_dev_name(struct mrfld_gpio *priv)
|
|||
return name;
|
||||
}
|
||||
|
||||
static int mrfld_gpio_add_pin_ranges(struct gpio_chip *chip)
|
||||
{
|
||||
struct mrfld_gpio *priv = gpiochip_get_data(chip);
|
||||
const struct mrfld_gpio_pinrange *range;
|
||||
const char *pinctrl_dev_name;
|
||||
unsigned int i;
|
||||
int retval;
|
||||
|
||||
pinctrl_dev_name = mrfld_gpio_get_pinctrl_dev_name(priv);
|
||||
if (!pinctrl_dev_name)
|
||||
return -ENOMEM;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(mrfld_gpio_ranges); i++) {
|
||||
range = &mrfld_gpio_ranges[i];
|
||||
retval = gpiochip_add_pin_range(&priv->chip, pinctrl_dev_name,
|
||||
range->gpio_base,
|
||||
range->pin_base,
|
||||
range->npins);
|
||||
if (retval) {
|
||||
dev_err(priv->dev, "failed to add GPIO pin range\n");
|
||||
return retval;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mrfld_gpio_probe(struct pci_dev *pdev, const struct pci_device_id *id)
|
||||
{
|
||||
struct gpio_irq_chip *girq;
|
||||
struct mrfld_gpio *priv;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct tng_gpio *priv;
|
||||
u32 gpio_base, irq_base;
|
||||
void __iomem *base;
|
||||
int retval;
|
||||
|
@ -449,10 +79,8 @@ static int mrfld_gpio_probe(struct pci_dev *pdev, const struct pci_device_id *id
|
|||
return retval;
|
||||
|
||||
retval = pcim_iomap_regions(pdev, BIT(1) | BIT(0), pci_name(pdev));
|
||||
if (retval) {
|
||||
dev_err(&pdev->dev, "I/O memory mapping error\n");
|
||||
return retval;
|
||||
}
|
||||
if (retval)
|
||||
return dev_err_probe(dev, retval, "I/O memory mapping error\n");
|
||||
|
||||
base = pcim_iomap_table(pdev)[1];
|
||||
|
||||
|
@ -462,53 +90,36 @@ static int mrfld_gpio_probe(struct pci_dev *pdev, const struct pci_device_id *id
|
|||
/* Release the IO mapping, since we already get the info from BAR1 */
|
||||
pcim_iounmap_regions(pdev, BIT(1));
|
||||
|
||||
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
|
||||
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
|
||||
priv->dev = &pdev->dev;
|
||||
priv->dev = dev;
|
||||
priv->reg_base = pcim_iomap_table(pdev)[0];
|
||||
|
||||
priv->chip.label = dev_name(&pdev->dev);
|
||||
priv->chip.parent = &pdev->dev;
|
||||
priv->chip.request = gpiochip_generic_request;
|
||||
priv->chip.free = gpiochip_generic_free;
|
||||
priv->chip.direction_input = mrfld_gpio_direction_input;
|
||||
priv->chip.direction_output = mrfld_gpio_direction_output;
|
||||
priv->chip.get = mrfld_gpio_get;
|
||||
priv->chip.set = mrfld_gpio_set;
|
||||
priv->chip.get_direction = mrfld_gpio_get_direction;
|
||||
priv->chip.set_config = mrfld_gpio_set_config;
|
||||
priv->chip.base = gpio_base;
|
||||
priv->chip.ngpio = MRFLD_NGPIO;
|
||||
priv->chip.can_sleep = false;
|
||||
priv->chip.add_pin_ranges = mrfld_gpio_add_pin_ranges;
|
||||
priv->pin_info.pin_ranges = mrfld_gpio_ranges;
|
||||
priv->pin_info.nranges = ARRAY_SIZE(mrfld_gpio_ranges);
|
||||
priv->pin_info.name = mrfld_gpio_get_pinctrl_dev_name(priv);
|
||||
if (!priv->pin_info.name)
|
||||
return -ENOMEM;
|
||||
|
||||
raw_spin_lock_init(&priv->lock);
|
||||
priv->info.base = gpio_base;
|
||||
priv->info.ngpio = MRFLD_NGPIO;
|
||||
priv->info.first = irq_base;
|
||||
|
||||
retval = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_ALL_TYPES);
|
||||
if (retval < 0)
|
||||
return retval;
|
||||
|
||||
girq = &priv->chip.irq;
|
||||
gpio_irq_chip_set_chip(girq, &mrfld_irqchip);
|
||||
girq->init_hw = mrfld_irq_init_hw;
|
||||
girq->parent_handler = mrfld_irq_handler;
|
||||
girq->num_parents = 1;
|
||||
girq->parents = devm_kcalloc(&pdev->dev, girq->num_parents,
|
||||
sizeof(*girq->parents), GFP_KERNEL);
|
||||
if (!girq->parents)
|
||||
return -ENOMEM;
|
||||
girq->parents[0] = pci_irq_vector(pdev, 0);
|
||||
girq->first = irq_base;
|
||||
girq->default_type = IRQ_TYPE_NONE;
|
||||
girq->handler = handle_bad_irq;
|
||||
priv->irq = pci_irq_vector(pdev, 0);
|
||||
|
||||
retval = devm_gpiochip_add_data(&pdev->dev, &priv->chip, priv);
|
||||
if (retval) {
|
||||
dev_err(&pdev->dev, "gpiochip_add error %d\n", retval);
|
||||
return retval;
|
||||
}
|
||||
priv->wake_regs.gwmr = GWMR_MRFLD;
|
||||
priv->wake_regs.gwsr = GWSR_MRFLD;
|
||||
priv->wake_regs.gsir = GSIR_MRFLD;
|
||||
|
||||
retval = devm_tng_gpio_probe(dev, priv);
|
||||
if (retval)
|
||||
return dev_err_probe(dev, retval, "tng_gpio_probe error\n");
|
||||
|
||||
pci_set_drvdata(pdev, priv);
|
||||
return 0;
|
||||
|
@ -525,9 +136,9 @@ static struct pci_driver mrfld_gpio_driver = {
|
|||
.id_table = mrfld_gpio_ids,
|
||||
.probe = mrfld_gpio_probe,
|
||||
};
|
||||
|
||||
module_pci_driver(mrfld_gpio_driver);
|
||||
|
||||
MODULE_AUTHOR("Andy Shevchenko <andriy.shevchenko@linux.intel.com>");
|
||||
MODULE_DESCRIPTION("Intel Merrifield SoC GPIO driver");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_IMPORT_NS(GPIO_TANGIER);
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#include <linux/platform_device.h>
|
||||
#include <linux/pm.h>
|
||||
#include <linux/resource.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
|
@ -65,10 +66,10 @@ struct mlxbf2_gpio_context_save_regs {
|
|||
/* BlueField-2 gpio block context structure. */
|
||||
struct mlxbf2_gpio_context {
|
||||
struct gpio_chip gc;
|
||||
struct irq_chip irq_chip;
|
||||
|
||||
/* YU GPIO blocks address */
|
||||
void __iomem *gpio_io;
|
||||
struct device *dev;
|
||||
|
||||
struct mlxbf2_gpio_context_save_regs *csave_regs;
|
||||
};
|
||||
|
@ -237,6 +238,7 @@ static void mlxbf2_gpio_irq_enable(struct irq_data *irqd)
|
|||
unsigned long flags;
|
||||
u32 val;
|
||||
|
||||
gpiochip_enable_irq(gc, irqd_to_hwirq(irqd));
|
||||
raw_spin_lock_irqsave(&gs->gc.bgpio_lock, flags);
|
||||
val = readl(gs->gpio_io + YU_GPIO_CAUSE_OR_CLRCAUSE);
|
||||
val |= BIT(offset);
|
||||
|
@ -261,6 +263,7 @@ static void mlxbf2_gpio_irq_disable(struct irq_data *irqd)
|
|||
val &= ~BIT(offset);
|
||||
writel(val, gs->gpio_io + YU_GPIO_CAUSE_OR_EVTEN0);
|
||||
raw_spin_unlock_irqrestore(&gs->gc.bgpio_lock, flags);
|
||||
gpiochip_disable_irq(gc, irqd_to_hwirq(irqd));
|
||||
}
|
||||
|
||||
static irqreturn_t mlxbf2_gpio_irq_handler(int irq, void *ptr)
|
||||
|
@ -322,6 +325,24 @@ mlxbf2_gpio_irq_set_type(struct irq_data *irqd, unsigned int type)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void mlxbf2_gpio_irq_print_chip(struct irq_data *irqd,
|
||||
struct seq_file *p)
|
||||
{
|
||||
struct gpio_chip *gc = irq_data_get_irq_chip_data(irqd);
|
||||
struct mlxbf2_gpio_context *gs = gpiochip_get_data(gc);
|
||||
|
||||
seq_printf(p, dev_name(gs->dev));
|
||||
}
|
||||
|
||||
static const struct irq_chip mlxbf2_gpio_irq_chip = {
|
||||
.irq_set_type = mlxbf2_gpio_irq_set_type,
|
||||
.irq_enable = mlxbf2_gpio_irq_enable,
|
||||
.irq_disable = mlxbf2_gpio_irq_disable,
|
||||
.irq_print_chip = mlxbf2_gpio_irq_print_chip,
|
||||
.flags = IRQCHIP_IMMUTABLE,
|
||||
GPIOCHIP_IRQ_RESOURCE_HELPERS,
|
||||
};
|
||||
|
||||
/* BlueField-2 GPIO driver initialization routine. */
|
||||
static int
|
||||
mlxbf2_gpio_probe(struct platform_device *pdev)
|
||||
|
@ -340,6 +361,8 @@ mlxbf2_gpio_probe(struct platform_device *pdev)
|
|||
if (!gs)
|
||||
return -ENOMEM;
|
||||
|
||||
gs->dev = dev;
|
||||
|
||||
/* YU GPIO block address */
|
||||
gs->gpio_io = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(gs->gpio_io))
|
||||
|
@ -376,13 +399,8 @@ mlxbf2_gpio_probe(struct platform_device *pdev)
|
|||
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq >= 0) {
|
||||
gs->irq_chip.name = name;
|
||||
gs->irq_chip.irq_set_type = mlxbf2_gpio_irq_set_type;
|
||||
gs->irq_chip.irq_enable = mlxbf2_gpio_irq_enable;
|
||||
gs->irq_chip.irq_disable = mlxbf2_gpio_irq_disable;
|
||||
|
||||
girq = &gs->gc.irq;
|
||||
girq->chip = &gs->irq_chip;
|
||||
gpio_irq_chip_set_chip(girq, &mlxbf2_gpio_irq_chip);
|
||||
girq->handler = handle_simple_irq;
|
||||
girq->default_type = IRQ_TYPE_NONE;
|
||||
/* This will let us handle the parent IRQ in the driver */
|
||||
|
|
|
@ -10,8 +10,8 @@
|
|||
#include <linux/platform_device.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/gpio/driver.h>
|
||||
#include <linux/gpio/legacy-of-mm-gpiochip.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_gpio.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
#include <linux/of.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/of_gpio.h>
|
||||
#include <linux/gpio/legacy-of-mm-gpiochip.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/module.h>
|
||||
|
|
|
@ -532,17 +532,35 @@ static int msc313_gpio_direction_output(struct gpio_chip *chip, unsigned int off
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void msc313_gpio_irq_mask(struct irq_data *d)
|
||||
{
|
||||
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
|
||||
|
||||
irq_chip_mask_parent(d);
|
||||
gpiochip_disable_irq(gc, d->hwirq);
|
||||
}
|
||||
|
||||
static void msc313_gpio_irq_unmask(struct irq_data *d)
|
||||
{
|
||||
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
|
||||
|
||||
gpiochip_enable_irq(gc, d->hwirq);
|
||||
irq_chip_unmask_parent(d);
|
||||
}
|
||||
|
||||
/*
|
||||
* The interrupt handling happens in the parent interrupt controller,
|
||||
* we don't do anything here.
|
||||
*/
|
||||
static struct irq_chip msc313_gpio_irqchip = {
|
||||
static const struct irq_chip msc313_gpio_irqchip = {
|
||||
.name = "GPIO",
|
||||
.irq_eoi = irq_chip_eoi_parent,
|
||||
.irq_mask = irq_chip_mask_parent,
|
||||
.irq_unmask = irq_chip_unmask_parent,
|
||||
.irq_mask = msc313_gpio_irq_mask,
|
||||
.irq_unmask = msc313_gpio_irq_unmask,
|
||||
.irq_set_type = irq_chip_set_type_parent,
|
||||
.irq_set_affinity = irq_chip_set_affinity_parent,
|
||||
.flags = IRQCHIP_IMMUTABLE,
|
||||
GPIOCHIP_IRQ_RESOURCE_HELPERS,
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -644,7 +662,7 @@ static int msc313_gpio_probe(struct platform_device *pdev)
|
|||
gpiochip->names = gpio->gpio_data->names;
|
||||
|
||||
gpioirqchip = &gpiochip->irq;
|
||||
gpioirqchip->chip = &msc313_gpio_irqchip;
|
||||
gpio_irq_chip_set_chip(gpioirqchip, &msc313_gpio_irqchip);
|
||||
gpioirqchip->fwnode = of_node_to_fwnode(dev->of_node);
|
||||
gpioirqchip->parent_domain = parent_domain;
|
||||
gpioirqchip->child_to_parent_hwirq = msc313e_gpio_child_to_parent_hwirq;
|
||||
|
|
|
@ -364,4 +364,3 @@ MODULE_AUTHOR("Freescale Semiconductor, "
|
|||
"Daniel Mack <danielncaiaq.de>, "
|
||||
"Juergen Beisert <kernel@pengutronix.de>");
|
||||
MODULE_DESCRIPTION("Freescale MXS GPIO");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/syscore_ops.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/clk.h>
|
||||
|
@ -47,6 +48,7 @@ struct gpio_regs {
|
|||
struct gpio_bank {
|
||||
void __iomem *base;
|
||||
const struct omap_gpio_reg_offs *regs;
|
||||
struct device *dev;
|
||||
|
||||
int irq;
|
||||
u32 non_wakeup_gpios;
|
||||
|
@ -681,6 +683,7 @@ static void omap_gpio_mask_irq(struct irq_data *d)
|
|||
omap_set_gpio_triggering(bank, offset, IRQ_TYPE_NONE);
|
||||
omap_set_gpio_irqenable(bank, offset, 0);
|
||||
raw_spin_unlock_irqrestore(&bank->lock, flags);
|
||||
gpiochip_disable_irq(&bank->chip, offset);
|
||||
}
|
||||
|
||||
static void omap_gpio_unmask_irq(struct irq_data *d)
|
||||
|
@ -690,6 +693,7 @@ static void omap_gpio_unmask_irq(struct irq_data *d)
|
|||
u32 trigger = irqd_get_trigger_type(d);
|
||||
unsigned long flags;
|
||||
|
||||
gpiochip_enable_irq(&bank->chip, offset);
|
||||
raw_spin_lock_irqsave(&bank->lock, flags);
|
||||
omap_set_gpio_irqenable(bank, offset, 1);
|
||||
|
||||
|
@ -708,6 +712,40 @@ static void omap_gpio_unmask_irq(struct irq_data *d)
|
|||
raw_spin_unlock_irqrestore(&bank->lock, flags);
|
||||
}
|
||||
|
||||
static void omap_gpio_irq_print_chip(struct irq_data *d, struct seq_file *p)
|
||||
{
|
||||
struct gpio_bank *bank = omap_irq_data_get_bank(d);
|
||||
|
||||
seq_printf(p, dev_name(bank->dev));
|
||||
}
|
||||
|
||||
static const struct irq_chip omap_gpio_irq_chip = {
|
||||
.irq_startup = omap_gpio_irq_startup,
|
||||
.irq_shutdown = omap_gpio_irq_shutdown,
|
||||
.irq_mask = omap_gpio_mask_irq,
|
||||
.irq_unmask = omap_gpio_unmask_irq,
|
||||
.irq_set_type = omap_gpio_irq_type,
|
||||
.irq_set_wake = omap_gpio_wake_enable,
|
||||
.irq_bus_lock = omap_gpio_irq_bus_lock,
|
||||
.irq_bus_sync_unlock = gpio_irq_bus_sync_unlock,
|
||||
.irq_print_chip = omap_gpio_irq_print_chip,
|
||||
.flags = IRQCHIP_MASK_ON_SUSPEND | IRQCHIP_IMMUTABLE,
|
||||
GPIOCHIP_IRQ_RESOURCE_HELPERS,
|
||||
};
|
||||
|
||||
static const struct irq_chip omap_gpio_irq_chip_nowake = {
|
||||
.irq_startup = omap_gpio_irq_startup,
|
||||
.irq_shutdown = omap_gpio_irq_shutdown,
|
||||
.irq_mask = omap_gpio_mask_irq,
|
||||
.irq_unmask = omap_gpio_unmask_irq,
|
||||
.irq_set_type = omap_gpio_irq_type,
|
||||
.irq_bus_lock = omap_gpio_irq_bus_lock,
|
||||
.irq_bus_sync_unlock = gpio_irq_bus_sync_unlock,
|
||||
.irq_print_chip = omap_gpio_irq_print_chip,
|
||||
.flags = IRQCHIP_MASK_ON_SUSPEND | IRQCHIP_IMMUTABLE,
|
||||
GPIOCHIP_IRQ_RESOURCE_HELPERS,
|
||||
};
|
||||
|
||||
/*---------------------------------------------------------------------*/
|
||||
|
||||
static int omap_mpuio_suspend_noirq(struct device *dev)
|
||||
|
@ -986,13 +1024,11 @@ static void omap_gpio_mod_init(struct gpio_bank *bank)
|
|||
writel_relaxed(0, base + bank->regs->ctrl);
|
||||
}
|
||||
|
||||
static int omap_gpio_chip_init(struct gpio_bank *bank, struct irq_chip *irqc,
|
||||
struct device *pm_dev)
|
||||
static int omap_gpio_chip_init(struct gpio_bank *bank, struct device *pm_dev)
|
||||
{
|
||||
struct gpio_irq_chip *irq;
|
||||
static int gpio;
|
||||
const char *label;
|
||||
int irq_base = 0;
|
||||
int ret;
|
||||
|
||||
/*
|
||||
|
@ -1024,30 +1060,16 @@ static int omap_gpio_chip_init(struct gpio_bank *bank, struct irq_chip *irqc,
|
|||
}
|
||||
bank->chip.ngpio = bank->width;
|
||||
|
||||
#ifdef CONFIG_ARCH_OMAP1
|
||||
/*
|
||||
* REVISIT: Once we have OMAP1 supporting SPARSE_IRQ, we can drop
|
||||
* irq_alloc_descs() since a base IRQ offset will no longer be needed.
|
||||
*/
|
||||
irq_base = devm_irq_alloc_descs(bank->chip.parent,
|
||||
-1, 0, bank->width, 0);
|
||||
if (irq_base < 0) {
|
||||
dev_err(bank->chip.parent, "Couldn't allocate IRQ numbers\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
#endif
|
||||
|
||||
irq = &bank->chip.irq;
|
||||
/* MPUIO is a bit different, reading IRQ status clears it */
|
||||
if (bank->is_mpuio && !bank->regs->wkup_en)
|
||||
irqc->irq_set_wake = NULL;
|
||||
|
||||
irq = &bank->chip.irq;
|
||||
irq->chip = irqc;
|
||||
gpio_irq_chip_set_chip(irq, &omap_gpio_irq_chip_nowake);
|
||||
else
|
||||
gpio_irq_chip_set_chip(irq, &omap_gpio_irq_chip);
|
||||
irq->handler = handle_bad_irq;
|
||||
irq->default_type = IRQ_TYPE_NONE;
|
||||
irq->num_parents = 1;
|
||||
irq->parents = &bank->irq;
|
||||
irq->first = irq_base;
|
||||
|
||||
ret = gpiochip_add_data(&bank->chip, bank);
|
||||
if (ret)
|
||||
|
@ -1376,7 +1398,6 @@ static int omap_gpio_probe(struct platform_device *pdev)
|
|||
struct device_node *node = dev->of_node;
|
||||
const struct omap_gpio_platform_data *pdata;
|
||||
struct gpio_bank *bank;
|
||||
struct irq_chip *irqc;
|
||||
int ret;
|
||||
|
||||
pdata = device_get_match_data(dev);
|
||||
|
@ -1389,21 +1410,7 @@ static int omap_gpio_probe(struct platform_device *pdev)
|
|||
if (!bank)
|
||||
return -ENOMEM;
|
||||
|
||||
irqc = devm_kzalloc(dev, sizeof(*irqc), GFP_KERNEL);
|
||||
if (!irqc)
|
||||
return -ENOMEM;
|
||||
|
||||
irqc->irq_startup = omap_gpio_irq_startup,
|
||||
irqc->irq_shutdown = omap_gpio_irq_shutdown,
|
||||
irqc->irq_ack = dummy_irq_chip.irq_ack,
|
||||
irqc->irq_mask = omap_gpio_mask_irq,
|
||||
irqc->irq_unmask = omap_gpio_unmask_irq,
|
||||
irqc->irq_set_type = omap_gpio_irq_type,
|
||||
irqc->irq_set_wake = omap_gpio_wake_enable,
|
||||
irqc->irq_bus_lock = omap_gpio_irq_bus_lock,
|
||||
irqc->irq_bus_sync_unlock = gpio_irq_bus_sync_unlock,
|
||||
irqc->name = dev_name(&pdev->dev);
|
||||
irqc->flags = IRQCHIP_MASK_ON_SUSPEND;
|
||||
bank->dev = dev;
|
||||
|
||||
bank->irq = platform_get_irq(pdev, 0);
|
||||
if (bank->irq <= 0) {
|
||||
|
@ -1467,7 +1474,7 @@ static int omap_gpio_probe(struct platform_device *pdev)
|
|||
|
||||
omap_gpio_mod_init(bank);
|
||||
|
||||
ret = omap_gpio_chip_init(bank, irqc, dev);
|
||||
ret = omap_gpio_chip_init(bank, dev);
|
||||
if (ret) {
|
||||
pm_runtime_put_sync(dev);
|
||||
pm_runtime_disable(dev);
|
||||
|
|
|
@ -107,6 +107,8 @@ static void idio_16_irq_mask(struct irq_data *data)
|
|||
|
||||
raw_spin_unlock_irqrestore(&idio16gpio->lock, flags);
|
||||
}
|
||||
|
||||
gpiochip_disable_irq(chip, irqd_to_hwirq(data));
|
||||
}
|
||||
|
||||
static void idio_16_irq_unmask(struct irq_data *data)
|
||||
|
@ -117,6 +119,8 @@ static void idio_16_irq_unmask(struct irq_data *data)
|
|||
const unsigned long prev_irq_mask = idio16gpio->irq_mask;
|
||||
unsigned long flags;
|
||||
|
||||
gpiochip_enable_irq(chip, irqd_to_hwirq(data));
|
||||
|
||||
idio16gpio->irq_mask |= mask;
|
||||
|
||||
if (!prev_irq_mask) {
|
||||
|
@ -138,12 +142,14 @@ static int idio_16_irq_set_type(struct irq_data *data, unsigned int flow_type)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static struct irq_chip idio_16_irqchip = {
|
||||
static const struct irq_chip idio_16_irqchip = {
|
||||
.name = "pci-idio-16",
|
||||
.irq_ack = idio_16_irq_ack,
|
||||
.irq_mask = idio_16_irq_mask,
|
||||
.irq_unmask = idio_16_irq_unmask,
|
||||
.irq_set_type = idio_16_irq_set_type
|
||||
.irq_set_type = idio_16_irq_set_type,
|
||||
.flags = IRQCHIP_IMMUTABLE,
|
||||
GPIOCHIP_IRQ_RESOURCE_HELPERS,
|
||||
};
|
||||
|
||||
static irqreturn_t idio_16_irq_handler(int irq, void *dev_id)
|
||||
|
@ -242,7 +248,7 @@ static int idio_16_probe(struct pci_dev *pdev, const struct pci_device_id *id)
|
|||
idio_16_state_init(&idio16gpio->state);
|
||||
|
||||
girq = &idio16gpio->chip.irq;
|
||||
girq->chip = &idio_16_irqchip;
|
||||
gpio_irq_chip_set_chip(girq, &idio_16_irqchip);
|
||||
/* This will let us handle the parent IRQ in the driver */
|
||||
girq->parent_handler = NULL;
|
||||
girq->num_parents = 0;
|
||||
|
|
|
@ -3,15 +3,6 @@
|
|||
* GPIO driver for the ACCES PCIe-IDIO-24 family
|
||||
* Copyright (C) 2018 William Breathitt Gray
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License, version 2, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* This driver supports the following ACCES devices: PCIe-IDIO-24,
|
||||
* PCIe-IDI-24, PCIe-IDO-24, and PCIe-IDIO-12.
|
||||
*/
|
||||
|
@ -396,6 +387,8 @@ static void idio_24_irq_mask(struct irq_data *data)
|
|||
}
|
||||
|
||||
raw_spin_unlock_irqrestore(&idio24gpio->lock, flags);
|
||||
|
||||
gpiochip_disable_irq(chip, irqd_to_hwirq(data));
|
||||
}
|
||||
|
||||
static void idio_24_irq_unmask(struct irq_data *data)
|
||||
|
@ -408,6 +401,8 @@ static void idio_24_irq_unmask(struct irq_data *data)
|
|||
const unsigned long bank_offset = bit_offset / 8;
|
||||
unsigned char cos_enable_state;
|
||||
|
||||
gpiochip_enable_irq(chip, irqd_to_hwirq(data));
|
||||
|
||||
raw_spin_lock_irqsave(&idio24gpio->lock, flags);
|
||||
|
||||
prev_irq_mask = idio24gpio->irq_mask >> bank_offset * 8;
|
||||
|
@ -437,12 +432,14 @@ static int idio_24_irq_set_type(struct irq_data *data, unsigned int flow_type)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static struct irq_chip idio_24_irqchip = {
|
||||
static const struct irq_chip idio_24_irqchip = {
|
||||
.name = "pcie-idio-24",
|
||||
.irq_ack = idio_24_irq_ack,
|
||||
.irq_mask = idio_24_irq_mask,
|
||||
.irq_unmask = idio_24_irq_unmask,
|
||||
.irq_set_type = idio_24_irq_set_type
|
||||
.irq_set_type = idio_24_irq_set_type,
|
||||
.flags = IRQCHIP_IMMUTABLE,
|
||||
GPIOCHIP_IRQ_RESOURCE_HELPERS,
|
||||
};
|
||||
|
||||
static irqreturn_t idio_24_irq_handler(int irq, void *dev_id)
|
||||
|
@ -535,7 +532,7 @@ static int idio_24_probe(struct pci_dev *pdev, const struct pci_device_id *id)
|
|||
idio24gpio->chip.set_multiple = idio_24_gpio_set_multiple;
|
||||
|
||||
girq = &idio24gpio->chip.irq;
|
||||
girq->chip = &idio_24_irqchip;
|
||||
gpio_irq_chip_set_chip(girq, &idio_24_irqchip);
|
||||
/* This will let us handle the parent IRQ in the driver */
|
||||
girq->parent_handler = NULL;
|
||||
girq->num_parents = 0;
|
||||
|
|
|
@ -171,11 +171,6 @@ static inline struct pxa_gpio_bank *gpio_to_pxabank(struct gpio_chip *c,
|
|||
return chip_to_pxachip(c)->banks + gpio / 32;
|
||||
}
|
||||
|
||||
static inline int gpio_is_pxa_type(int type)
|
||||
{
|
||||
return (type & MMP_GPIO) == 0;
|
||||
}
|
||||
|
||||
static inline int gpio_is_mmp_type(int type)
|
||||
{
|
||||
return (type & MMP_GPIO) != 0;
|
||||
|
|
|
@ -234,7 +234,7 @@ static int rpi_exp_gpio_probe(struct platform_device *pdev)
|
|||
return devm_gpiochip_add_data(dev, &rpi_gpio->gc, rpi_gpio);
|
||||
}
|
||||
|
||||
static const struct of_device_id rpi_exp_gpio_ids[] = {
|
||||
static const struct of_device_id rpi_exp_gpio_ids[] __maybe_unused = {
|
||||
{ .compatible = "raspberrypi,firmware-gpio" },
|
||||
{ }
|
||||
};
|
||||
|
|
|
@ -663,7 +663,7 @@ static struct platform_driver gpio_rcar_device_driver = {
|
|||
.driver = {
|
||||
.name = "gpio_rcar",
|
||||
.pm = &gpio_rcar_pm_ops,
|
||||
.of_match_table = of_match_ptr(gpio_rcar_of_table),
|
||||
.of_match_table = gpio_rcar_of_table,
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -38,7 +38,6 @@ struct rda_gpio {
|
|||
struct gpio_chip chip;
|
||||
void __iomem *base;
|
||||
spinlock_t lock;
|
||||
struct irq_chip irq_chip;
|
||||
int irq;
|
||||
};
|
||||
|
||||
|
@ -74,6 +73,7 @@ static void rda_gpio_irq_mask(struct irq_data *data)
|
|||
value |= BIT(offset) << RDA_GPIO_IRQ_FALL_SHIFT;
|
||||
|
||||
writel_relaxed(value, base + RDA_GPIO_INT_CTRL_CLR);
|
||||
gpiochip_disable_irq(chip, offset);
|
||||
}
|
||||
|
||||
static void rda_gpio_irq_ack(struct irq_data *data)
|
||||
|
@ -154,6 +154,7 @@ static void rda_gpio_irq_unmask(struct irq_data *data)
|
|||
u32 offset = irqd_to_hwirq(data);
|
||||
u32 trigger = irqd_get_trigger_type(data);
|
||||
|
||||
gpiochip_enable_irq(chip, offset);
|
||||
rda_gpio_set_irq(chip, offset, trigger);
|
||||
}
|
||||
|
||||
|
@ -195,6 +196,16 @@ static void rda_gpio_irq_handler(struct irq_desc *desc)
|
|||
chained_irq_exit(ic, desc);
|
||||
}
|
||||
|
||||
static const struct irq_chip rda_gpio_irq_chip = {
|
||||
.name = "rda-gpio",
|
||||
.irq_ack = rda_gpio_irq_ack,
|
||||
.irq_mask = rda_gpio_irq_mask,
|
||||
.irq_unmask = rda_gpio_irq_unmask,
|
||||
.irq_set_type = rda_gpio_irq_set_type,
|
||||
.flags = IRQCHIP_SKIP_SET_WAKE | IRQCHIP_IMMUTABLE,
|
||||
GPIOCHIP_IRQ_RESOURCE_HELPERS,
|
||||
};
|
||||
|
||||
static int rda_gpio_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
|
@ -241,15 +252,8 @@ static int rda_gpio_probe(struct platform_device *pdev)
|
|||
rda_gpio->chip.base = -1;
|
||||
|
||||
if (rda_gpio->irq >= 0) {
|
||||
rda_gpio->irq_chip.name = "rda-gpio",
|
||||
rda_gpio->irq_chip.irq_ack = rda_gpio_irq_ack,
|
||||
rda_gpio->irq_chip.irq_mask = rda_gpio_irq_mask,
|
||||
rda_gpio->irq_chip.irq_unmask = rda_gpio_irq_unmask,
|
||||
rda_gpio->irq_chip.irq_set_type = rda_gpio_irq_set_type,
|
||||
rda_gpio->irq_chip.flags = IRQCHIP_SKIP_SET_WAKE,
|
||||
|
||||
girq = &rda_gpio->chip.irq;
|
||||
girq->chip = &rda_gpio->irq_chip;
|
||||
gpio_irq_chip_set_chip(girq, &rda_gpio_irq_chip);
|
||||
girq->handler = handle_bad_irq;
|
||||
girq->default_type = IRQ_TYPE_NONE;
|
||||
girq->parent_handler = rda_gpio_irq_handler;
|
||||
|
@ -286,4 +290,3 @@ module_platform_driver_probe(rda_gpio_driver, rda_gpio_probe);
|
|||
|
||||
MODULE_DESCRIPTION("RDA Micro GPIO driver");
|
||||
MODULE_AUTHOR("Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
|
|
@ -4,11 +4,19 @@
|
|||
*
|
||||
* Copyright (C) 2016 Russell King
|
||||
*/
|
||||
#include <linux/gpio/driver.h>
|
||||
#include <linux/gpio/gpio-reg.h>
|
||||
#include <linux/bits.h>
|
||||
#include <linux/container_of.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/irqdomain.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#include <linux/gpio/driver.h>
|
||||
#include <linux/gpio/gpio-reg.h>
|
||||
|
||||
struct gpio_reg {
|
||||
struct gpio_chip gc;
|
||||
|
|
|
@ -5,11 +5,17 @@
|
|||
* Copyright 2020 Michael Walle <michael@walle.cc>
|
||||
*/
|
||||
|
||||
#include <linux/gpio/driver.h>
|
||||
#include <linux/gpio/regmap.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/bits.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#include <linux/gpio/driver.h>
|
||||
#include <linux/gpio/regmap.h>
|
||||
|
||||
struct gpio_regmap {
|
||||
struct device *parent;
|
||||
|
|
|
@ -236,7 +236,7 @@ MODULE_DEVICE_TABLE(of, sama5d2_piobu_ids);
|
|||
static struct platform_driver sama5d2_piobu_driver = {
|
||||
.driver = {
|
||||
.name = "sama5d2-piobu",
|
||||
.of_match_table = of_match_ptr(sama5d2_piobu_ids)
|
||||
.of_match_table = sama5d2_piobu_ids,
|
||||
},
|
||||
.probe = sama5d2_piobu_probe,
|
||||
};
|
||||
|
|
|
@ -270,7 +270,7 @@ static struct platform_driver sifive_gpio_driver = {
|
|||
.probe = sifive_gpio_probe,
|
||||
.driver = {
|
||||
.name = "sifive_gpio",
|
||||
.of_match_table = of_match_ptr(sifive_gpio_match),
|
||||
.of_match_table = sifive_gpio_match,
|
||||
},
|
||||
};
|
||||
builtin_platform_driver(sifive_gpio_driver)
|
||||
|
|
|
@ -953,9 +953,9 @@ static void gpio_sim_device_deactivate_unlocked(struct gpio_sim_device *dev)
|
|||
|
||||
swnode = dev_fwnode(&dev->pdev->dev);
|
||||
platform_device_unregister(dev->pdev);
|
||||
gpio_sim_remove_hogs(dev);
|
||||
gpio_sim_remove_swnode_recursive(swnode);
|
||||
dev->pdev = NULL;
|
||||
gpio_sim_remove_hogs(dev);
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
|
|
|
@ -10,7 +10,6 @@
|
|||
|
||||
struct gpio_siox_ddata {
|
||||
struct gpio_chip gchip;
|
||||
struct irq_chip ichip;
|
||||
struct mutex lock;
|
||||
u8 setdata[1];
|
||||
u8 getdata[3];
|
||||
|
@ -97,9 +96,8 @@ static int gpio_siox_get_data(struct siox_device *sdevice, const u8 buf[])
|
|||
|
||||
static void gpio_siox_irq_ack(struct irq_data *d)
|
||||
{
|
||||
struct irq_chip *ic = irq_data_get_irq_chip(d);
|
||||
struct gpio_siox_ddata *ddata =
|
||||
container_of(ic, struct gpio_siox_ddata, ichip);
|
||||
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
|
||||
struct gpio_siox_ddata *ddata = gpiochip_get_data(gc);
|
||||
|
||||
raw_spin_lock(&ddata->irqlock);
|
||||
ddata->irq_status &= ~(1 << d->hwirq);
|
||||
|
@ -108,21 +106,21 @@ static void gpio_siox_irq_ack(struct irq_data *d)
|
|||
|
||||
static void gpio_siox_irq_mask(struct irq_data *d)
|
||||
{
|
||||
struct irq_chip *ic = irq_data_get_irq_chip(d);
|
||||
struct gpio_siox_ddata *ddata =
|
||||
container_of(ic, struct gpio_siox_ddata, ichip);
|
||||
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
|
||||
struct gpio_siox_ddata *ddata = gpiochip_get_data(gc);
|
||||
|
||||
raw_spin_lock(&ddata->irqlock);
|
||||
ddata->irq_enable &= ~(1 << d->hwirq);
|
||||
raw_spin_unlock(&ddata->irqlock);
|
||||
gpiochip_disable_irq(gc, irqd_to_hwirq(d));
|
||||
}
|
||||
|
||||
static void gpio_siox_irq_unmask(struct irq_data *d)
|
||||
{
|
||||
struct irq_chip *ic = irq_data_get_irq_chip(d);
|
||||
struct gpio_siox_ddata *ddata =
|
||||
container_of(ic, struct gpio_siox_ddata, ichip);
|
||||
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
|
||||
struct gpio_siox_ddata *ddata = gpiochip_get_data(gc);
|
||||
|
||||
gpiochip_enable_irq(gc, irqd_to_hwirq(d));
|
||||
raw_spin_lock(&ddata->irqlock);
|
||||
ddata->irq_enable |= 1 << d->hwirq;
|
||||
raw_spin_unlock(&ddata->irqlock);
|
||||
|
@ -130,9 +128,8 @@ static void gpio_siox_irq_unmask(struct irq_data *d)
|
|||
|
||||
static int gpio_siox_irq_set_type(struct irq_data *d, u32 type)
|
||||
{
|
||||
struct irq_chip *ic = irq_data_get_irq_chip(d);
|
||||
struct gpio_siox_ddata *ddata =
|
||||
container_of(ic, struct gpio_siox_ddata, ichip);
|
||||
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
|
||||
struct gpio_siox_ddata *ddata = gpiochip_get_data(gc);
|
||||
|
||||
raw_spin_lock(&ddata->irqlock);
|
||||
ddata->irq_type[d->hwirq] = type;
|
||||
|
@ -143,8 +140,7 @@ static int gpio_siox_irq_set_type(struct irq_data *d, u32 type)
|
|||
|
||||
static int gpio_siox_get(struct gpio_chip *chip, unsigned int offset)
|
||||
{
|
||||
struct gpio_siox_ddata *ddata =
|
||||
container_of(chip, struct gpio_siox_ddata, gchip);
|
||||
struct gpio_siox_ddata *ddata = gpiochip_get_data(chip);
|
||||
int ret;
|
||||
|
||||
mutex_lock(&ddata->lock);
|
||||
|
@ -167,8 +163,7 @@ static int gpio_siox_get(struct gpio_chip *chip, unsigned int offset)
|
|||
static void gpio_siox_set(struct gpio_chip *chip,
|
||||
unsigned int offset, int value)
|
||||
{
|
||||
struct gpio_siox_ddata *ddata =
|
||||
container_of(chip, struct gpio_siox_ddata, gchip);
|
||||
struct gpio_siox_ddata *ddata = gpiochip_get_data(chip);
|
||||
u8 mask = 1 << (19 - offset);
|
||||
|
||||
mutex_lock(&ddata->lock);
|
||||
|
@ -208,11 +203,22 @@ static int gpio_siox_get_direction(struct gpio_chip *chip, unsigned int offset)
|
|||
return GPIO_LINE_DIRECTION_OUT;
|
||||
}
|
||||
|
||||
static const struct irq_chip gpio_siox_irq_chip = {
|
||||
.name = "siox-gpio",
|
||||
.irq_ack = gpio_siox_irq_ack,
|
||||
.irq_mask = gpio_siox_irq_mask,
|
||||
.irq_unmask = gpio_siox_irq_unmask,
|
||||
.irq_set_type = gpio_siox_irq_set_type,
|
||||
.flags = IRQCHIP_IMMUTABLE,
|
||||
GPIOCHIP_IRQ_RESOURCE_HELPERS,
|
||||
};
|
||||
|
||||
static int gpio_siox_probe(struct siox_device *sdevice)
|
||||
{
|
||||
struct gpio_siox_ddata *ddata;
|
||||
struct gpio_irq_chip *girq;
|
||||
struct device *dev = &sdevice->dev;
|
||||
struct gpio_chip *gc;
|
||||
int ret;
|
||||
|
||||
ddata = devm_kzalloc(dev, sizeof(*ddata), GFP_KERNEL);
|
||||
|
@ -224,30 +230,25 @@ static int gpio_siox_probe(struct siox_device *sdevice)
|
|||
mutex_init(&ddata->lock);
|
||||
raw_spin_lock_init(&ddata->irqlock);
|
||||
|
||||
ddata->gchip.base = -1;
|
||||
ddata->gchip.can_sleep = 1;
|
||||
ddata->gchip.parent = dev;
|
||||
ddata->gchip.owner = THIS_MODULE;
|
||||
ddata->gchip.get = gpio_siox_get;
|
||||
ddata->gchip.set = gpio_siox_set;
|
||||
ddata->gchip.direction_input = gpio_siox_direction_input;
|
||||
ddata->gchip.direction_output = gpio_siox_direction_output;
|
||||
ddata->gchip.get_direction = gpio_siox_get_direction;
|
||||
ddata->gchip.ngpio = 20;
|
||||
gc = &ddata->gchip;
|
||||
gc->base = -1;
|
||||
gc->can_sleep = 1;
|
||||
gc->parent = dev;
|
||||
gc->owner = THIS_MODULE;
|
||||
gc->get = gpio_siox_get;
|
||||
gc->set = gpio_siox_set;
|
||||
gc->direction_input = gpio_siox_direction_input;
|
||||
gc->direction_output = gpio_siox_direction_output;
|
||||
gc->get_direction = gpio_siox_get_direction;
|
||||
gc->ngpio = 20;
|
||||
|
||||
ddata->ichip.name = "siox-gpio";
|
||||
ddata->ichip.irq_ack = gpio_siox_irq_ack;
|
||||
ddata->ichip.irq_mask = gpio_siox_irq_mask;
|
||||
ddata->ichip.irq_unmask = gpio_siox_irq_unmask;
|
||||
ddata->ichip.irq_set_type = gpio_siox_irq_set_type;
|
||||
|
||||
girq = &ddata->gchip.irq;
|
||||
girq->chip = &ddata->ichip;
|
||||
girq = &gc->irq;
|
||||
gpio_irq_chip_set_chip(girq, &gpio_siox_irq_chip);
|
||||
girq->default_type = IRQ_TYPE_NONE;
|
||||
girq->handler = handle_level_irq;
|
||||
girq->threaded = true;
|
||||
|
||||
ret = devm_gpiochip_add_data(dev, &ddata->gchip, NULL);
|
||||
ret = devm_gpiochip_add_data(dev, gc, ddata);
|
||||
if (ret)
|
||||
dev_err(dev, "Failed to register gpio chip (%d)\n", ret);
|
||||
|
||||
|
|
|
@ -234,6 +234,7 @@ static void stmpe_gpio_irq_mask(struct irq_data *d)
|
|||
int mask = BIT(offset % 8);
|
||||
|
||||
stmpe_gpio->regs[REG_IE][regoffset] &= ~mask;
|
||||
gpiochip_disable_irq(gc, offset);
|
||||
}
|
||||
|
||||
static void stmpe_gpio_irq_unmask(struct irq_data *d)
|
||||
|
@ -244,6 +245,7 @@ static void stmpe_gpio_irq_unmask(struct irq_data *d)
|
|||
int regoffset = offset / 8;
|
||||
int mask = BIT(offset % 8);
|
||||
|
||||
gpiochip_enable_irq(gc, offset);
|
||||
stmpe_gpio->regs[REG_IE][regoffset] |= mask;
|
||||
}
|
||||
|
||||
|
@ -357,13 +359,15 @@ static void stmpe_dbg_show(struct seq_file *s, struct gpio_chip *gc)
|
|||
}
|
||||
}
|
||||
|
||||
static struct irq_chip stmpe_gpio_irq_chip = {
|
||||
static const struct irq_chip stmpe_gpio_irq_chip = {
|
||||
.name = "stmpe-gpio",
|
||||
.irq_bus_lock = stmpe_gpio_irq_lock,
|
||||
.irq_bus_sync_unlock = stmpe_gpio_irq_sync_unlock,
|
||||
.irq_mask = stmpe_gpio_irq_mask,
|
||||
.irq_unmask = stmpe_gpio_irq_unmask,
|
||||
.irq_set_type = stmpe_gpio_irq_set_type,
|
||||
.flags = IRQCHIP_IMMUTABLE,
|
||||
GPIOCHIP_IRQ_RESOURCE_HELPERS,
|
||||
};
|
||||
|
||||
#define MAX_GPIOS 24
|
||||
|
@ -511,7 +515,7 @@ static int stmpe_gpio_probe(struct platform_device *pdev)
|
|||
}
|
||||
|
||||
girq = &stmpe_gpio->chip.irq;
|
||||
girq->chip = &stmpe_gpio_irq_chip;
|
||||
gpio_irq_chip_set_chip(girq, &stmpe_gpio_irq_chip);
|
||||
/* This will let us handle the parent IRQ in the driver */
|
||||
girq->parent_handler = NULL;
|
||||
girq->num_parents = 0;
|
||||
|
|
|
@ -292,7 +292,7 @@ static int xway_stp_probe(struct platform_device *pdev)
|
|||
}
|
||||
|
||||
/* check which edge trigger we should use, default to a falling edge */
|
||||
if (!of_find_property(pdev->dev.of_node, "lantiq,rising", NULL))
|
||||
if (!of_property_read_bool(pdev->dev.of_node, "lantiq,rising"))
|
||||
chip->edge = XWAY_STP_FALLING;
|
||||
|
||||
clk = devm_clk_get(&pdev->dev, NULL);
|
||||
|
|
|
@ -0,0 +1,536 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Intel Tangier GPIO driver
|
||||
*
|
||||
* Copyright (c) 2016, 2021, 2023 Intel Corporation.
|
||||
*
|
||||
* Authors: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
|
||||
* Pandith N <pandith.n@intel.com>
|
||||
* Raag Jadav <raag.jadav@intel.com>
|
||||
*/
|
||||
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/pinctrl/pinconf-generic.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/string_helpers.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#include <linux/gpio/driver.h>
|
||||
|
||||
#include "gpio-tangier.h"
|
||||
|
||||
#define GCCR 0x000 /* Controller configuration */
|
||||
#define GPLR 0x004 /* Pin level r/o */
|
||||
#define GPDR 0x01c /* Pin direction */
|
||||
#define GPSR 0x034 /* Pin set w/o */
|
||||
#define GPCR 0x04c /* Pin clear w/o */
|
||||
#define GRER 0x064 /* Rising edge detect */
|
||||
#define GFER 0x07c /* Falling edge detect */
|
||||
#define GFBR 0x094 /* Glitch filter bypass */
|
||||
#define GIMR 0x0ac /* Interrupt mask */
|
||||
#define GISR 0x0c4 /* Interrupt source */
|
||||
#define GITR 0x300 /* Input type */
|
||||
#define GLPR 0x318 /* Level input polarity */
|
||||
|
||||
/**
|
||||
* struct tng_gpio_context - Context to be saved during suspend-resume
|
||||
* @level: Pin level
|
||||
* @gpdr: Pin direction
|
||||
* @grer: Rising edge detect enable
|
||||
* @gfer: Falling edge detect enable
|
||||
* @gimr: Interrupt mask
|
||||
* @gwmr: Wake mask
|
||||
*/
|
||||
struct tng_gpio_context {
|
||||
u32 level;
|
||||
u32 gpdr;
|
||||
u32 grer;
|
||||
u32 gfer;
|
||||
u32 gimr;
|
||||
u32 gwmr;
|
||||
};
|
||||
|
||||
static void __iomem *gpio_reg(struct gpio_chip *chip, unsigned int offset,
|
||||
unsigned int reg)
|
||||
{
|
||||
struct tng_gpio *priv = gpiochip_get_data(chip);
|
||||
u8 reg_offset = offset / 32;
|
||||
|
||||
return priv->reg_base + reg + reg_offset * 4;
|
||||
}
|
||||
|
||||
static void __iomem *gpio_reg_and_bit(struct gpio_chip *chip, unsigned int offset,
|
||||
unsigned int reg, u8 *bit)
|
||||
{
|
||||
struct tng_gpio *priv = gpiochip_get_data(chip);
|
||||
u8 reg_offset = offset / 32;
|
||||
u8 shift = offset % 32;
|
||||
|
||||
*bit = shift;
|
||||
return priv->reg_base + reg + reg_offset * 4;
|
||||
}
|
||||
|
||||
static int tng_gpio_get(struct gpio_chip *chip, unsigned int offset)
|
||||
{
|
||||
void __iomem *gplr;
|
||||
u8 shift;
|
||||
|
||||
gplr = gpio_reg_and_bit(chip, offset, GPLR, &shift);
|
||||
|
||||
return !!(readl(gplr) & BIT(shift));
|
||||
}
|
||||
|
||||
static void tng_gpio_set(struct gpio_chip *chip, unsigned int offset, int value)
|
||||
{
|
||||
struct tng_gpio *priv = gpiochip_get_data(chip);
|
||||
unsigned long flags;
|
||||
void __iomem *reg;
|
||||
u8 shift;
|
||||
|
||||
reg = gpio_reg_and_bit(chip, offset, value ? GPSR : GPCR, &shift);
|
||||
|
||||
raw_spin_lock_irqsave(&priv->lock, flags);
|
||||
|
||||
writel(BIT(shift), reg);
|
||||
|
||||
raw_spin_unlock_irqrestore(&priv->lock, flags);
|
||||
}
|
||||
|
||||
static int tng_gpio_direction_input(struct gpio_chip *chip, unsigned int offset)
|
||||
{
|
||||
struct tng_gpio *priv = gpiochip_get_data(chip);
|
||||
unsigned long flags;
|
||||
void __iomem *gpdr;
|
||||
u32 value;
|
||||
u8 shift;
|
||||
|
||||
gpdr = gpio_reg_and_bit(chip, offset, GPDR, &shift);
|
||||
|
||||
raw_spin_lock_irqsave(&priv->lock, flags);
|
||||
|
||||
value = readl(gpdr);
|
||||
value &= ~BIT(shift);
|
||||
writel(value, gpdr);
|
||||
|
||||
raw_spin_unlock_irqrestore(&priv->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tng_gpio_direction_output(struct gpio_chip *chip, unsigned int offset,
|
||||
int value)
|
||||
{
|
||||
struct tng_gpio *priv = gpiochip_get_data(chip);
|
||||
unsigned long flags;
|
||||
void __iomem *gpdr;
|
||||
u8 shift;
|
||||
|
||||
gpdr = gpio_reg_and_bit(chip, offset, GPDR, &shift);
|
||||
tng_gpio_set(chip, offset, value);
|
||||
|
||||
raw_spin_lock_irqsave(&priv->lock, flags);
|
||||
|
||||
value = readl(gpdr);
|
||||
value |= BIT(shift);
|
||||
writel(value, gpdr);
|
||||
|
||||
raw_spin_unlock_irqrestore(&priv->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tng_gpio_get_direction(struct gpio_chip *chip, unsigned int offset)
|
||||
{
|
||||
void __iomem *gpdr;
|
||||
u8 shift;
|
||||
|
||||
gpdr = gpio_reg_and_bit(chip, offset, GPDR, &shift);
|
||||
|
||||
if (readl(gpdr) & BIT(shift))
|
||||
return GPIO_LINE_DIRECTION_OUT;
|
||||
|
||||
return GPIO_LINE_DIRECTION_IN;
|
||||
}
|
||||
|
||||
static int tng_gpio_set_debounce(struct gpio_chip *chip, unsigned int offset,
|
||||
unsigned int debounce)
|
||||
{
|
||||
struct tng_gpio *priv = gpiochip_get_data(chip);
|
||||
unsigned long flags;
|
||||
void __iomem *gfbr;
|
||||
u32 value;
|
||||
u8 shift;
|
||||
|
||||
gfbr = gpio_reg_and_bit(chip, offset, GFBR, &shift);
|
||||
|
||||
raw_spin_lock_irqsave(&priv->lock, flags);
|
||||
|
||||
value = readl(gfbr);
|
||||
if (debounce)
|
||||
value &= ~BIT(shift);
|
||||
else
|
||||
value |= BIT(shift);
|
||||
writel(value, gfbr);
|
||||
|
||||
raw_spin_unlock_irqrestore(&priv->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tng_gpio_set_config(struct gpio_chip *chip, unsigned int offset,
|
||||
unsigned long config)
|
||||
{
|
||||
u32 debounce;
|
||||
|
||||
switch (pinconf_to_config_param(config)) {
|
||||
case PIN_CONFIG_BIAS_DISABLE:
|
||||
case PIN_CONFIG_BIAS_PULL_UP:
|
||||
case PIN_CONFIG_BIAS_PULL_DOWN:
|
||||
return gpiochip_generic_config(chip, offset, config);
|
||||
case PIN_CONFIG_INPUT_DEBOUNCE:
|
||||
debounce = pinconf_to_config_argument(config);
|
||||
return tng_gpio_set_debounce(chip, offset, debounce);
|
||||
default:
|
||||
return -ENOTSUPP;
|
||||
}
|
||||
}
|
||||
|
||||
static void tng_irq_ack(struct irq_data *d)
|
||||
{
|
||||
struct tng_gpio *priv = irq_data_get_irq_chip_data(d);
|
||||
irq_hw_number_t gpio = irqd_to_hwirq(d);
|
||||
unsigned long flags;
|
||||
void __iomem *gisr;
|
||||
u8 shift;
|
||||
|
||||
gisr = gpio_reg_and_bit(&priv->chip, gpio, GISR, &shift);
|
||||
|
||||
raw_spin_lock_irqsave(&priv->lock, flags);
|
||||
writel(BIT(shift), gisr);
|
||||
raw_spin_unlock_irqrestore(&priv->lock, flags);
|
||||
}
|
||||
|
||||
static void tng_irq_unmask_mask(struct tng_gpio *priv, u32 gpio, bool unmask)
|
||||
{
|
||||
unsigned long flags;
|
||||
void __iomem *gimr;
|
||||
u32 value;
|
||||
u8 shift;
|
||||
|
||||
gimr = gpio_reg_and_bit(&priv->chip, gpio, GIMR, &shift);
|
||||
|
||||
raw_spin_lock_irqsave(&priv->lock, flags);
|
||||
|
||||
value = readl(gimr);
|
||||
if (unmask)
|
||||
value |= BIT(shift);
|
||||
else
|
||||
value &= ~BIT(shift);
|
||||
writel(value, gimr);
|
||||
|
||||
raw_spin_unlock_irqrestore(&priv->lock, flags);
|
||||
}
|
||||
|
||||
static void tng_irq_mask(struct irq_data *d)
|
||||
{
|
||||
struct tng_gpio *priv = irq_data_get_irq_chip_data(d);
|
||||
irq_hw_number_t gpio = irqd_to_hwirq(d);
|
||||
|
||||
tng_irq_unmask_mask(priv, gpio, false);
|
||||
gpiochip_disable_irq(&priv->chip, gpio);
|
||||
}
|
||||
|
||||
static void tng_irq_unmask(struct irq_data *d)
|
||||
{
|
||||
struct tng_gpio *priv = irq_data_get_irq_chip_data(d);
|
||||
irq_hw_number_t gpio = irqd_to_hwirq(d);
|
||||
|
||||
gpiochip_enable_irq(&priv->chip, gpio);
|
||||
tng_irq_unmask_mask(priv, gpio, true);
|
||||
}
|
||||
|
||||
static int tng_irq_set_type(struct irq_data *d, unsigned int type)
|
||||
{
|
||||
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
|
||||
struct tng_gpio *priv = gpiochip_get_data(gc);
|
||||
irq_hw_number_t gpio = irqd_to_hwirq(d);
|
||||
void __iomem *grer = gpio_reg(&priv->chip, gpio, GRER);
|
||||
void __iomem *gfer = gpio_reg(&priv->chip, gpio, GFER);
|
||||
void __iomem *gitr = gpio_reg(&priv->chip, gpio, GITR);
|
||||
void __iomem *glpr = gpio_reg(&priv->chip, gpio, GLPR);
|
||||
u8 shift = gpio % 32;
|
||||
unsigned long flags;
|
||||
u32 value;
|
||||
|
||||
raw_spin_lock_irqsave(&priv->lock, flags);
|
||||
|
||||
value = readl(grer);
|
||||
if (type & IRQ_TYPE_EDGE_RISING)
|
||||
value |= BIT(shift);
|
||||
else
|
||||
value &= ~BIT(shift);
|
||||
writel(value, grer);
|
||||
|
||||
value = readl(gfer);
|
||||
if (type & IRQ_TYPE_EDGE_FALLING)
|
||||
value |= BIT(shift);
|
||||
else
|
||||
value &= ~BIT(shift);
|
||||
writel(value, gfer);
|
||||
|
||||
/*
|
||||
* To prevent glitches from triggering an unintended level interrupt,
|
||||
* configure GLPR register first and then configure GITR.
|
||||
*/
|
||||
value = readl(glpr);
|
||||
if (type & IRQ_TYPE_LEVEL_LOW)
|
||||
value |= BIT(shift);
|
||||
else
|
||||
value &= ~BIT(shift);
|
||||
writel(value, glpr);
|
||||
|
||||
if (type & IRQ_TYPE_LEVEL_MASK) {
|
||||
value = readl(gitr);
|
||||
value |= BIT(shift);
|
||||
writel(value, gitr);
|
||||
|
||||
irq_set_handler_locked(d, handle_level_irq);
|
||||
} else if (type & IRQ_TYPE_EDGE_BOTH) {
|
||||
value = readl(gitr);
|
||||
value &= ~BIT(shift);
|
||||
writel(value, gitr);
|
||||
|
||||
irq_set_handler_locked(d, handle_edge_irq);
|
||||
}
|
||||
|
||||
raw_spin_unlock_irqrestore(&priv->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tng_irq_set_wake(struct irq_data *d, unsigned int on)
|
||||
{
|
||||
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
|
||||
struct tng_gpio *priv = gpiochip_get_data(gc);
|
||||
irq_hw_number_t gpio = irqd_to_hwirq(d);
|
||||
void __iomem *gwmr = gpio_reg(&priv->chip, gpio, priv->wake_regs.gwmr);
|
||||
void __iomem *gwsr = gpio_reg(&priv->chip, gpio, priv->wake_regs.gwsr);
|
||||
u8 shift = gpio % 32;
|
||||
unsigned long flags;
|
||||
u32 value;
|
||||
|
||||
raw_spin_lock_irqsave(&priv->lock, flags);
|
||||
|
||||
/* Clear the existing wake status */
|
||||
writel(BIT(shift), gwsr);
|
||||
|
||||
value = readl(gwmr);
|
||||
if (on)
|
||||
value |= BIT(shift);
|
||||
else
|
||||
value &= ~BIT(shift);
|
||||
writel(value, gwmr);
|
||||
|
||||
raw_spin_unlock_irqrestore(&priv->lock, flags);
|
||||
|
||||
dev_dbg(priv->dev, "%s wake for gpio %lu\n", str_enable_disable(on), gpio);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct irq_chip tng_irqchip = {
|
||||
.name = "gpio-tangier",
|
||||
.irq_ack = tng_irq_ack,
|
||||
.irq_mask = tng_irq_mask,
|
||||
.irq_unmask = tng_irq_unmask,
|
||||
.irq_set_type = tng_irq_set_type,
|
||||
.irq_set_wake = tng_irq_set_wake,
|
||||
.flags = IRQCHIP_IMMUTABLE,
|
||||
GPIOCHIP_IRQ_RESOURCE_HELPERS,
|
||||
};
|
||||
|
||||
static void tng_irq_handler(struct irq_desc *desc)
|
||||
{
|
||||
struct gpio_chip *gc = irq_desc_get_handler_data(desc);
|
||||
struct tng_gpio *priv = gpiochip_get_data(gc);
|
||||
struct irq_chip *irqchip = irq_desc_get_chip(desc);
|
||||
unsigned long base, gpio;
|
||||
|
||||
chained_irq_enter(irqchip, desc);
|
||||
|
||||
/* Check GPIO controller to check which pin triggered the interrupt */
|
||||
for (base = 0; base < priv->chip.ngpio; base += 32) {
|
||||
void __iomem *gisr = gpio_reg(&priv->chip, base, GISR);
|
||||
void __iomem *gimr = gpio_reg(&priv->chip, base, GIMR);
|
||||
unsigned long pending, enabled;
|
||||
|
||||
pending = readl(gisr);
|
||||
enabled = readl(gimr);
|
||||
|
||||
/* Only interrupts that are enabled */
|
||||
pending &= enabled;
|
||||
|
||||
for_each_set_bit(gpio, &pending, 32)
|
||||
generic_handle_domain_irq(gc->irq.domain, base + gpio);
|
||||
}
|
||||
|
||||
chained_irq_exit(irqchip, desc);
|
||||
}
|
||||
|
||||
static int tng_irq_init_hw(struct gpio_chip *chip)
|
||||
{
|
||||
struct tng_gpio *priv = gpiochip_get_data(chip);
|
||||
void __iomem *reg;
|
||||
unsigned int base;
|
||||
|
||||
for (base = 0; base < priv->chip.ngpio; base += 32) {
|
||||
/* Clear the rising-edge detect register */
|
||||
reg = gpio_reg(&priv->chip, base, GRER);
|
||||
writel(0, reg);
|
||||
|
||||
/* Clear the falling-edge detect register */
|
||||
reg = gpio_reg(&priv->chip, base, GFER);
|
||||
writel(0, reg);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tng_gpio_add_pin_ranges(struct gpio_chip *chip)
|
||||
{
|
||||
struct tng_gpio *priv = gpiochip_get_data(chip);
|
||||
const struct tng_gpio_pinrange *range;
|
||||
unsigned int i;
|
||||
int ret;
|
||||
|
||||
for (i = 0; i < priv->pin_info.nranges; i++) {
|
||||
range = &priv->pin_info.pin_ranges[i];
|
||||
ret = gpiochip_add_pin_range(&priv->chip,
|
||||
priv->pin_info.name,
|
||||
range->gpio_base,
|
||||
range->pin_base,
|
||||
range->npins);
|
||||
if (ret) {
|
||||
dev_err(priv->dev, "failed to add GPIO pin range\n");
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int devm_tng_gpio_probe(struct device *dev, struct tng_gpio *gpio)
|
||||
{
|
||||
const struct tng_gpio_info *info = &gpio->info;
|
||||
struct gpio_irq_chip *girq;
|
||||
int ret;
|
||||
|
||||
gpio->ctx = devm_kcalloc(dev, DIV_ROUND_UP(info->ngpio, 32), sizeof(*gpio->ctx), GFP_KERNEL);
|
||||
if (!gpio->ctx)
|
||||
return -ENOMEM;
|
||||
|
||||
gpio->chip.label = dev_name(dev);
|
||||
gpio->chip.parent = dev;
|
||||
gpio->chip.request = gpiochip_generic_request;
|
||||
gpio->chip.free = gpiochip_generic_free;
|
||||
gpio->chip.direction_input = tng_gpio_direction_input;
|
||||
gpio->chip.direction_output = tng_gpio_direction_output;
|
||||
gpio->chip.get = tng_gpio_get;
|
||||
gpio->chip.set = tng_gpio_set;
|
||||
gpio->chip.get_direction = tng_gpio_get_direction;
|
||||
gpio->chip.set_config = tng_gpio_set_config;
|
||||
gpio->chip.base = info->base;
|
||||
gpio->chip.ngpio = info->ngpio;
|
||||
gpio->chip.can_sleep = false;
|
||||
gpio->chip.add_pin_ranges = tng_gpio_add_pin_ranges;
|
||||
|
||||
raw_spin_lock_init(&gpio->lock);
|
||||
|
||||
girq = &gpio->chip.irq;
|
||||
gpio_irq_chip_set_chip(girq, &tng_irqchip);
|
||||
girq->init_hw = tng_irq_init_hw;
|
||||
girq->parent_handler = tng_irq_handler;
|
||||
girq->num_parents = 1;
|
||||
girq->parents = devm_kcalloc(dev, girq->num_parents,
|
||||
sizeof(*girq->parents), GFP_KERNEL);
|
||||
if (!girq->parents)
|
||||
return -ENOMEM;
|
||||
|
||||
girq->parents[0] = gpio->irq;
|
||||
girq->first = info->first;
|
||||
girq->default_type = IRQ_TYPE_NONE;
|
||||
girq->handler = handle_bad_irq;
|
||||
|
||||
ret = devm_gpiochip_add_data(dev, &gpio->chip, gpio);
|
||||
if (ret)
|
||||
return dev_err_probe(dev, ret, "gpiochip_add error\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(devm_tng_gpio_probe, GPIO_TANGIER);
|
||||
|
||||
int tng_gpio_suspend(struct device *dev)
|
||||
{
|
||||
struct tng_gpio *priv = dev_get_drvdata(dev);
|
||||
struct tng_gpio_context *ctx = priv->ctx;
|
||||
unsigned long flags;
|
||||
unsigned int base;
|
||||
|
||||
raw_spin_lock_irqsave(&priv->lock, flags);
|
||||
|
||||
for (base = 0; base < priv->chip.ngpio; base += 32, ctx++) {
|
||||
/* GPLR is RO, values read will be restored using GPSR */
|
||||
ctx->level = readl(gpio_reg(&priv->chip, base, GPLR));
|
||||
|
||||
ctx->gpdr = readl(gpio_reg(&priv->chip, base, GPDR));
|
||||
ctx->grer = readl(gpio_reg(&priv->chip, base, GRER));
|
||||
ctx->gfer = readl(gpio_reg(&priv->chip, base, GFER));
|
||||
ctx->gimr = readl(gpio_reg(&priv->chip, base, GIMR));
|
||||
|
||||
ctx->gwmr = readl(gpio_reg(&priv->chip, base, priv->wake_regs.gwmr));
|
||||
}
|
||||
|
||||
raw_spin_unlock_irqrestore(&priv->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(tng_gpio_suspend, GPIO_TANGIER);
|
||||
|
||||
int tng_gpio_resume(struct device *dev)
|
||||
{
|
||||
struct tng_gpio *priv = dev_get_drvdata(dev);
|
||||
struct tng_gpio_context *ctx = priv->ctx;
|
||||
unsigned long flags;
|
||||
unsigned int base;
|
||||
|
||||
raw_spin_lock_irqsave(&priv->lock, flags);
|
||||
|
||||
for (base = 0; base < priv->chip.ngpio; base += 32, ctx++) {
|
||||
/* GPLR is RO, values read will be restored using GPSR */
|
||||
writel(ctx->level, gpio_reg(&priv->chip, base, GPSR));
|
||||
|
||||
writel(ctx->gpdr, gpio_reg(&priv->chip, base, GPDR));
|
||||
writel(ctx->grer, gpio_reg(&priv->chip, base, GRER));
|
||||
writel(ctx->gfer, gpio_reg(&priv->chip, base, GFER));
|
||||
writel(ctx->gimr, gpio_reg(&priv->chip, base, GIMR));
|
||||
|
||||
writel(ctx->gwmr, gpio_reg(&priv->chip, base, priv->wake_regs.gwmr));
|
||||
}
|
||||
|
||||
raw_spin_unlock_irqrestore(&priv->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(tng_gpio_resume, GPIO_TANGIER);
|
||||
|
||||
MODULE_AUTHOR("Andy Shevchenko <andriy.shevchenko@linux.intel.com>");
|
||||
MODULE_AUTHOR("Pandith N <pandith.n@intel.com>");
|
||||
MODULE_AUTHOR("Raag Jadav <raag.jadav@intel.com>");
|
||||
MODULE_DESCRIPTION("Intel Tangier GPIO driver");
|
||||
MODULE_LICENSE("GPL");
|
|
@ -0,0 +1,117 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Intel Tangier GPIO functions
|
||||
*
|
||||
* Copyright (c) 2016, 2021, 2023 Intel Corporation.
|
||||
*
|
||||
* Authors: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
|
||||
* Pandith N <pandith.n@intel.com>
|
||||
* Raag Jadav <raag.jadav@intel.com>
|
||||
*/
|
||||
|
||||
#ifndef _GPIO_TANGIER_H_
|
||||
#define _GPIO_TANGIER_H_
|
||||
|
||||
#include <linux/gpio/driver.h>
|
||||
#include <linux/spinlock_types.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
struct device;
|
||||
|
||||
struct tng_gpio_context;
|
||||
|
||||
/* Elkhart Lake specific wake registers */
|
||||
#define GWMR_EHL 0x100 /* Wake mask */
|
||||
#define GWSR_EHL 0x118 /* Wake source */
|
||||
#define GSIR_EHL 0x130 /* Secure input */
|
||||
|
||||
/* Merrifield specific wake registers */
|
||||
#define GWMR_MRFLD 0x400 /* Wake mask */
|
||||
#define GWSR_MRFLD 0x418 /* Wake source */
|
||||
#define GSIR_MRFLD 0xc00 /* Secure input */
|
||||
|
||||
/**
|
||||
* struct tng_wake_regs - Platform specific wake registers
|
||||
* @gwmr: Wake mask
|
||||
* @gwsr: Wake source
|
||||
* @gsir: Secure input
|
||||
*/
|
||||
struct tng_wake_regs {
|
||||
u32 gwmr;
|
||||
u32 gwsr;
|
||||
u32 gsir;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct tng_gpio_pinrange - Map pin numbers to gpio numbers
|
||||
* @gpio_base: Starting GPIO number of this range
|
||||
* @pin_base: Starting pin number of this range
|
||||
* @npins: Number of pins in this range
|
||||
*/
|
||||
struct tng_gpio_pinrange {
|
||||
unsigned int gpio_base;
|
||||
unsigned int pin_base;
|
||||
unsigned int npins;
|
||||
};
|
||||
|
||||
#define GPIO_PINRANGE(gstart, gend, pstart) \
|
||||
(struct tng_gpio_pinrange) { \
|
||||
.gpio_base = (gstart), \
|
||||
.pin_base = (pstart), \
|
||||
.npins = (gend) - (gstart) + 1, \
|
||||
}
|
||||
|
||||
/**
|
||||
* struct tng_gpio_pin_info - Platform specific pinout information
|
||||
* @pin_ranges: Pin to GPIO mapping
|
||||
* @nranges: Number of pin ranges
|
||||
* @name: Respective pinctrl device name
|
||||
*/
|
||||
struct tng_gpio_pin_info {
|
||||
const struct tng_gpio_pinrange *pin_ranges;
|
||||
unsigned int nranges;
|
||||
const char *name;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct tng_gpio_info - Platform specific GPIO and IRQ information
|
||||
* @base: GPIO base to start numbering with
|
||||
* @ngpio: Amount of GPIOs supported by the controller
|
||||
* @first: First IRQ to start numbering with
|
||||
*/
|
||||
struct tng_gpio_info {
|
||||
int base;
|
||||
u16 ngpio;
|
||||
unsigned int first;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct tng_gpio - Platform specific private data
|
||||
* @chip: Instance of the struct gpio_chip
|
||||
* @reg_base: Base address of MMIO registers
|
||||
* @irq: Interrupt for the GPIO device
|
||||
* @lock: Synchronization lock to prevent I/O race conditions
|
||||
* @dev: The GPIO device
|
||||
* @ctx: Context to be saved during suspend-resume
|
||||
* @wake_regs: Platform specific wake registers
|
||||
* @pin_info: Platform specific pinout information
|
||||
* @info: Platform specific GPIO and IRQ information
|
||||
*/
|
||||
struct tng_gpio {
|
||||
struct gpio_chip chip;
|
||||
void __iomem *reg_base;
|
||||
int irq;
|
||||
raw_spinlock_t lock;
|
||||
struct device *dev;
|
||||
struct tng_gpio_context *ctx;
|
||||
struct tng_wake_regs wake_regs;
|
||||
struct tng_gpio_pin_info pin_info;
|
||||
struct tng_gpio_info info;
|
||||
};
|
||||
|
||||
int devm_tng_gpio_probe(struct device *dev, struct tng_gpio *gpio);
|
||||
|
||||
int tng_gpio_suspend(struct device *dev);
|
||||
int tng_gpio_resume(struct device *dev);
|
||||
|
||||
#endif /* _GPIO_TANGIER_H_ */
|
|
@ -167,7 +167,7 @@ static int tb10x_gpio_probe(struct platform_device *pdev)
|
|||
|
||||
platform_set_drvdata(pdev, tb10x_gpio);
|
||||
|
||||
if (of_find_property(np, "interrupt-controller", NULL)) {
|
||||
if (of_property_read_bool(np, "interrupt-controller")) {
|
||||
struct irq_chip_generic *gc;
|
||||
|
||||
ret = platform_get_irq(pdev, 0);
|
||||
|
|
|
@ -354,16 +354,22 @@ static int thunderx_gpio_irq_set_type(struct irq_data *d,
|
|||
return IRQ_SET_MASK_OK;
|
||||
}
|
||||
|
||||
static void thunderx_gpio_irq_enable(struct irq_data *data)
|
||||
static void thunderx_gpio_irq_enable(struct irq_data *d)
|
||||
{
|
||||
irq_chip_enable_parent(data);
|
||||
thunderx_gpio_irq_unmask(data);
|
||||
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
|
||||
|
||||
gpiochip_enable_irq(gc, irqd_to_hwirq(d));
|
||||
irq_chip_enable_parent(d);
|
||||
thunderx_gpio_irq_unmask(d);
|
||||
}
|
||||
|
||||
static void thunderx_gpio_irq_disable(struct irq_data *data)
|
||||
static void thunderx_gpio_irq_disable(struct irq_data *d)
|
||||
{
|
||||
thunderx_gpio_irq_mask(data);
|
||||
irq_chip_disable_parent(data);
|
||||
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
|
||||
|
||||
thunderx_gpio_irq_mask(d);
|
||||
irq_chip_disable_parent(d);
|
||||
gpiochip_disable_irq(gc, irqd_to_hwirq(d));
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -372,7 +378,7 @@ static void thunderx_gpio_irq_disable(struct irq_data *data)
|
|||
* semantics and other acknowledgment tasks associated with the GPIO
|
||||
* mechanism.
|
||||
*/
|
||||
static struct irq_chip thunderx_gpio_irq_chip = {
|
||||
static const struct irq_chip thunderx_gpio_irq_chip = {
|
||||
.name = "GPIO",
|
||||
.irq_enable = thunderx_gpio_irq_enable,
|
||||
.irq_disable = thunderx_gpio_irq_disable,
|
||||
|
@ -383,8 +389,8 @@ static struct irq_chip thunderx_gpio_irq_chip = {
|
|||
.irq_eoi = irq_chip_eoi_parent,
|
||||
.irq_set_affinity = irq_chip_set_affinity_parent,
|
||||
.irq_set_type = thunderx_gpio_irq_set_type,
|
||||
|
||||
.flags = IRQCHIP_SET_TYPE_MASKED
|
||||
.flags = IRQCHIP_SET_TYPE_MASKED | IRQCHIP_IMMUTABLE,
|
||||
GPIOCHIP_IRQ_RESOURCE_HELPERS,
|
||||
};
|
||||
|
||||
static int thunderx_gpio_child_to_parent_hwirq(struct gpio_chip *gc,
|
||||
|
@ -526,7 +532,7 @@ static int thunderx_gpio_probe(struct pci_dev *pdev,
|
|||
chip->set_multiple = thunderx_gpio_set_multiple;
|
||||
chip->set_config = thunderx_gpio_set_config;
|
||||
girq = &chip->irq;
|
||||
girq->chip = &thunderx_gpio_irq_chip;
|
||||
gpio_irq_chip_set_chip(girq, &thunderx_gpio_irq_chip);
|
||||
girq->fwnode = of_node_to_fwnode(dev->of_node);
|
||||
girq->parent_domain =
|
||||
irq_get_irq_data(txgpio->msix_entries[0].vector)->domain;
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#define TQMX86_NGPIO 8
|
||||
|
@ -34,7 +35,6 @@
|
|||
|
||||
struct tqmx86_gpio_data {
|
||||
struct gpio_chip chip;
|
||||
struct irq_chip irq_chip;
|
||||
void __iomem *io_base;
|
||||
int irq;
|
||||
raw_spinlock_t spinlock;
|
||||
|
@ -122,6 +122,7 @@ static void tqmx86_gpio_irq_mask(struct irq_data *data)
|
|||
gpiic &= ~mask;
|
||||
tqmx86_gpio_write(gpio, gpiic, TQMX86_GPIIC);
|
||||
raw_spin_unlock_irqrestore(&gpio->spinlock, flags);
|
||||
gpiochip_disable_irq(&gpio->chip, irqd_to_hwirq(data));
|
||||
}
|
||||
|
||||
static void tqmx86_gpio_irq_unmask(struct irq_data *data)
|
||||
|
@ -134,6 +135,7 @@ static void tqmx86_gpio_irq_unmask(struct irq_data *data)
|
|||
|
||||
mask = TQMX86_GPII_MASK << (offset * TQMX86_GPII_BITS);
|
||||
|
||||
gpiochip_enable_irq(&gpio->chip, irqd_to_hwirq(data));
|
||||
raw_spin_lock_irqsave(&gpio->spinlock, flags);
|
||||
gpiic = tqmx86_gpio_read(gpio, TQMX86_GPIIC);
|
||||
gpiic &= ~mask;
|
||||
|
@ -226,6 +228,22 @@ static void tqmx86_init_irq_valid_mask(struct gpio_chip *chip,
|
|||
clear_bit(3, valid_mask);
|
||||
}
|
||||
|
||||
static void tqmx86_gpio_irq_print_chip(struct irq_data *d, struct seq_file *p)
|
||||
{
|
||||
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
|
||||
|
||||
seq_printf(p, gc->label);
|
||||
}
|
||||
|
||||
static const struct irq_chip tqmx86_gpio_irq_chip = {
|
||||
.irq_mask = tqmx86_gpio_irq_mask,
|
||||
.irq_unmask = tqmx86_gpio_irq_unmask,
|
||||
.irq_set_type = tqmx86_gpio_irq_set_type,
|
||||
.irq_print_chip = tqmx86_gpio_irq_print_chip,
|
||||
.flags = IRQCHIP_IMMUTABLE,
|
||||
GPIOCHIP_IRQ_RESOURCE_HELPERS,
|
||||
};
|
||||
|
||||
static int tqmx86_gpio_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
|
@ -277,14 +295,8 @@ static int tqmx86_gpio_probe(struct platform_device *pdev)
|
|||
pm_runtime_enable(&pdev->dev);
|
||||
|
||||
if (irq > 0) {
|
||||
struct irq_chip *irq_chip = &gpio->irq_chip;
|
||||
u8 irq_status;
|
||||
|
||||
irq_chip->name = chip->label;
|
||||
irq_chip->irq_mask = tqmx86_gpio_irq_mask;
|
||||
irq_chip->irq_unmask = tqmx86_gpio_irq_unmask;
|
||||
irq_chip->irq_set_type = tqmx86_gpio_irq_set_type;
|
||||
|
||||
/* Mask all interrupts */
|
||||
tqmx86_gpio_write(gpio, 0, TQMX86_GPIIC);
|
||||
|
||||
|
@ -293,7 +305,7 @@ static int tqmx86_gpio_probe(struct platform_device *pdev)
|
|||
tqmx86_gpio_write(gpio, irq_status, TQMX86_GPIIS);
|
||||
|
||||
girq = &chip->irq;
|
||||
girq->chip = irq_chip;
|
||||
gpio_irq_chip_set_chip(girq, &tqmx86_gpio_irq_chip);
|
||||
girq->parent_handler = tqmx86_gpio_irq_handler;
|
||||
girq->num_parents = 1;
|
||||
girq->parents = devm_kcalloc(&pdev->dev, 1,
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include <linux/io.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/bitops.h>
|
||||
|
||||
/* register offset */
|
||||
|
@ -31,7 +32,7 @@ struct visconti_gpio {
|
|||
void __iomem *base;
|
||||
spinlock_t lock; /* protect gpio register */
|
||||
struct gpio_chip gpio_chip;
|
||||
struct irq_chip irq_chip;
|
||||
struct device *dev;
|
||||
};
|
||||
|
||||
static int visconti_gpio_irq_set_type(struct irq_data *d, unsigned int type)
|
||||
|
@ -119,11 +120,45 @@ static int visconti_gpio_populate_parent_fwspec(struct gpio_chip *chip,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void visconti_gpio_mask_irq(struct irq_data *d)
|
||||
{
|
||||
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
|
||||
|
||||
irq_chip_mask_parent(d);
|
||||
gpiochip_disable_irq(gc, irqd_to_hwirq(d));
|
||||
}
|
||||
|
||||
static void visconti_gpio_unmask_irq(struct irq_data *d)
|
||||
{
|
||||
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
|
||||
|
||||
gpiochip_enable_irq(gc, irqd_to_hwirq(d));
|
||||
irq_chip_unmask_parent(d);
|
||||
}
|
||||
|
||||
static void visconti_gpio_irq_print_chip(struct irq_data *d, struct seq_file *p)
|
||||
{
|
||||
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
|
||||
struct visconti_gpio *priv = gpiochip_get_data(gc);
|
||||
|
||||
seq_printf(p, dev_name(priv->dev));
|
||||
}
|
||||
|
||||
static const struct irq_chip visconti_gpio_irq_chip = {
|
||||
.irq_mask = visconti_gpio_mask_irq,
|
||||
.irq_unmask = visconti_gpio_unmask_irq,
|
||||
.irq_eoi = irq_chip_eoi_parent,
|
||||
.irq_set_type = visconti_gpio_irq_set_type,
|
||||
.irq_print_chip = visconti_gpio_irq_print_chip,
|
||||
.flags = IRQCHIP_SET_TYPE_MASKED | IRQCHIP_MASK_ON_SUSPEND |
|
||||
IRQCHIP_IMMUTABLE,
|
||||
GPIOCHIP_IRQ_RESOURCE_HELPERS,
|
||||
};
|
||||
|
||||
static int visconti_gpio_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct visconti_gpio *priv;
|
||||
struct irq_chip *irq_chip;
|
||||
struct gpio_irq_chip *girq;
|
||||
struct irq_domain *parent;
|
||||
struct device_node *irq_parent;
|
||||
|
@ -134,6 +169,7 @@ static int visconti_gpio_probe(struct platform_device *pdev)
|
|||
return -ENOMEM;
|
||||
|
||||
spin_lock_init(&priv->lock);
|
||||
priv->dev = dev;
|
||||
|
||||
priv->base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(priv->base))
|
||||
|
@ -164,16 +200,8 @@ static int visconti_gpio_probe(struct platform_device *pdev)
|
|||
return ret;
|
||||
}
|
||||
|
||||
irq_chip = &priv->irq_chip;
|
||||
irq_chip->name = dev_name(dev);
|
||||
irq_chip->irq_mask = irq_chip_mask_parent;
|
||||
irq_chip->irq_unmask = irq_chip_unmask_parent;
|
||||
irq_chip->irq_eoi = irq_chip_eoi_parent;
|
||||
irq_chip->irq_set_type = visconti_gpio_irq_set_type;
|
||||
irq_chip->flags = IRQCHIP_SET_TYPE_MASKED | IRQCHIP_MASK_ON_SUSPEND;
|
||||
|
||||
girq = &priv->gpio_chip.irq;
|
||||
girq->chip = irq_chip;
|
||||
gpio_irq_chip_set_chip(girq, &visconti_gpio_irq_chip);
|
||||
girq->fwnode = of_node_to_fwnode(dev->of_node);
|
||||
girq->parent_domain = parent;
|
||||
girq->child_to_parent_hwirq = visconti_gpio_child_to_parent_hwirq;
|
||||
|
@ -194,7 +222,7 @@ static struct platform_driver visconti_gpio_driver = {
|
|||
.probe = visconti_gpio_probe,
|
||||
.driver = {
|
||||
.name = "visconti_gpio",
|
||||
.of_match_table = of_match_ptr(visconti_gpio_of_match),
|
||||
.of_match_table = visconti_gpio_of_match,
|
||||
}
|
||||
};
|
||||
module_platform_driver(visconti_gpio_driver);
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/spinlock.h>
|
||||
|
||||
#define IPROC_CCA_INT_F_GPIOINT BIT(0)
|
||||
|
@ -27,7 +28,6 @@
|
|||
#define IPROC_GPIO_CCA_INT_EDGE 0x24
|
||||
|
||||
struct iproc_gpio_chip {
|
||||
struct irq_chip irqchip;
|
||||
struct gpio_chip gc;
|
||||
spinlock_t lock;
|
||||
struct device *dev;
|
||||
|
@ -69,6 +69,7 @@ static void iproc_gpio_irq_unmask(struct irq_data *d)
|
|||
u32 irq = d->irq;
|
||||
u32 int_mask, irq_type, event_mask;
|
||||
|
||||
gpiochip_enable_irq(gc, pin);
|
||||
spin_lock_irqsave(&chip->lock, flags);
|
||||
irq_type = irq_get_trigger_type(irq);
|
||||
event_mask = readl_relaxed(chip->base + IPROC_GPIO_CCA_INT_EVENT_MASK);
|
||||
|
@ -110,6 +111,7 @@ static void iproc_gpio_irq_mask(struct irq_data *d)
|
|||
chip->base + IPROC_GPIO_CCA_INT_LEVEL_MASK);
|
||||
}
|
||||
spin_unlock_irqrestore(&chip->lock, flags);
|
||||
gpiochip_disable_irq(gc, pin);
|
||||
}
|
||||
|
||||
static int iproc_gpio_irq_set_type(struct irq_data *d, u32 type)
|
||||
|
@ -191,6 +193,24 @@ static irqreturn_t iproc_gpio_irq_handler(int irq, void *data)
|
|||
return int_bits ? IRQ_HANDLED : IRQ_NONE;
|
||||
}
|
||||
|
||||
static void iproc_gpio_irq_print_chip(struct irq_data *d, struct seq_file *p)
|
||||
{
|
||||
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
|
||||
struct iproc_gpio_chip *chip = to_iproc_gpio(gc);
|
||||
|
||||
seq_printf(p, dev_name(chip->dev));
|
||||
}
|
||||
|
||||
static const struct irq_chip iproc_gpio_irq_chip = {
|
||||
.irq_ack = iproc_gpio_irq_ack,
|
||||
.irq_mask = iproc_gpio_irq_mask,
|
||||
.irq_unmask = iproc_gpio_irq_unmask,
|
||||
.irq_set_type = iproc_gpio_irq_set_type,
|
||||
.irq_print_chip = iproc_gpio_irq_print_chip,
|
||||
.flags = IRQCHIP_IMMUTABLE,
|
||||
GPIOCHIP_IRQ_RESOURCE_HELPERS,
|
||||
};
|
||||
|
||||
static int iproc_gpio_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
|
@ -230,16 +250,8 @@ static int iproc_gpio_probe(struct platform_device *pdev)
|
|||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq > 0) {
|
||||
struct gpio_irq_chip *girq;
|
||||
struct irq_chip *irqc;
|
||||
u32 val;
|
||||
|
||||
irqc = &chip->irqchip;
|
||||
irqc->name = dev_name(dev);
|
||||
irqc->irq_ack = iproc_gpio_irq_ack;
|
||||
irqc->irq_mask = iproc_gpio_irq_mask;
|
||||
irqc->irq_unmask = iproc_gpio_irq_unmask;
|
||||
irqc->irq_set_type = iproc_gpio_irq_set_type;
|
||||
|
||||
chip->intr = devm_platform_ioremap_resource(pdev, 1);
|
||||
if (IS_ERR(chip->intr))
|
||||
return PTR_ERR(chip->intr);
|
||||
|
@ -261,7 +273,7 @@ static int iproc_gpio_probe(struct platform_device *pdev)
|
|||
}
|
||||
|
||||
girq = &chip->gc.irq;
|
||||
girq->chip = irqc;
|
||||
gpio_irq_chip_set_chip(girq, &iproc_gpio_irq_chip);
|
||||
/* This will let us handle the parent IRQ in the driver */
|
||||
girq->parent_handler = NULL;
|
||||
girq->num_parents = 0;
|
||||
|
|
|
@ -68,7 +68,6 @@ struct xgpio_instance {
|
|||
DECLARE_BITMAP(dir, 64);
|
||||
spinlock_t gpio_lock; /* For serializing operations */
|
||||
int irq;
|
||||
struct irq_chip irqchip;
|
||||
DECLARE_BITMAP(enable, 64);
|
||||
DECLARE_BITMAP(rising_edge, 64);
|
||||
DECLARE_BITMAP(falling_edge, 64);
|
||||
|
@ -416,6 +415,8 @@ static void xgpio_irq_mask(struct irq_data *irq_data)
|
|||
xgpio_writereg(chip->regs + XGPIO_IPIER_OFFSET, temp);
|
||||
}
|
||||
spin_unlock_irqrestore(&chip->gpio_lock, flags);
|
||||
|
||||
gpiochip_disable_irq(&chip->gc, irq_offset);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -431,6 +432,8 @@ static void xgpio_irq_unmask(struct irq_data *irq_data)
|
|||
u32 old_enable = xgpio_get_value32(chip->enable, bit);
|
||||
u32 mask = BIT(bit / 32), val;
|
||||
|
||||
gpiochip_enable_irq(&chip->gc, irq_offset);
|
||||
|
||||
spin_lock_irqsave(&chip->gpio_lock, flags);
|
||||
|
||||
__set_bit(bit, chip->enable);
|
||||
|
@ -544,6 +547,16 @@ static void xgpio_irqhandler(struct irq_desc *desc)
|
|||
chained_irq_exit(irqchip, desc);
|
||||
}
|
||||
|
||||
static const struct irq_chip xgpio_irq_chip = {
|
||||
.name = "gpio-xilinx",
|
||||
.irq_ack = xgpio_irq_ack,
|
||||
.irq_mask = xgpio_irq_mask,
|
||||
.irq_unmask = xgpio_irq_unmask,
|
||||
.irq_set_type = xgpio_set_irq_type,
|
||||
.flags = IRQCHIP_IMMUTABLE,
|
||||
GPIOCHIP_IRQ_RESOURCE_HELPERS,
|
||||
};
|
||||
|
||||
/**
|
||||
* xgpio_probe - Probe method for the GPIO device.
|
||||
* @pdev: pointer to the platform device
|
||||
|
@ -653,12 +666,6 @@ static int xgpio_probe(struct platform_device *pdev)
|
|||
if (chip->irq <= 0)
|
||||
goto skip_irq;
|
||||
|
||||
chip->irqchip.name = "gpio-xilinx";
|
||||
chip->irqchip.irq_ack = xgpio_irq_ack;
|
||||
chip->irqchip.irq_mask = xgpio_irq_mask;
|
||||
chip->irqchip.irq_unmask = xgpio_irq_unmask;
|
||||
chip->irqchip.irq_set_type = xgpio_set_irq_type;
|
||||
|
||||
/* Disable per-channel interrupts */
|
||||
xgpio_writereg(chip->regs + XGPIO_IPIER_OFFSET, 0);
|
||||
/* Clear any existing per-channel interrupts */
|
||||
|
@ -668,7 +675,7 @@ static int xgpio_probe(struct platform_device *pdev)
|
|||
xgpio_writereg(chip->regs + XGPIO_GIER_OFFSET, XGPIO_GIER_IE);
|
||||
|
||||
girq = &chip->gc.irq;
|
||||
girq->chip = &chip->irqchip;
|
||||
gpio_irq_chip_set_chip(girq, &xgpio_irq_chip);
|
||||
girq->parent_handler = xgpio_irqhandler;
|
||||
girq->num_parents = 1;
|
||||
girq->parents = devm_kcalloc(&pdev->dev, 1,
|
||||
|
|
|
@ -90,6 +90,13 @@ static void xlp_gpio_set_reg(void __iomem *addr, unsigned gpio, int state)
|
|||
writel(value, addr + regset);
|
||||
}
|
||||
|
||||
static void xlp_gpio_irq_enable(struct irq_data *d)
|
||||
{
|
||||
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
|
||||
|
||||
gpiochip_enable_irq(gc, irqd_to_hwirq(d));
|
||||
}
|
||||
|
||||
static void xlp_gpio_irq_disable(struct irq_data *d)
|
||||
{
|
||||
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
|
||||
|
@ -100,6 +107,7 @@ static void xlp_gpio_irq_disable(struct irq_data *d)
|
|||
xlp_gpio_set_reg(priv->gpio_intr_en, d->hwirq, 0x0);
|
||||
__clear_bit(d->hwirq, priv->gpio_enabled_mask);
|
||||
spin_unlock_irqrestore(&priv->lock, flags);
|
||||
gpiochip_disable_irq(gc, irqd_to_hwirq(d));
|
||||
}
|
||||
|
||||
static void xlp_gpio_irq_mask_ack(struct irq_data *d)
|
||||
|
@ -163,10 +171,12 @@ static int xlp_gpio_set_irq_type(struct irq_data *d, unsigned int type)
|
|||
static struct irq_chip xlp_gpio_irq_chip = {
|
||||
.name = "XLP-GPIO",
|
||||
.irq_mask_ack = xlp_gpio_irq_mask_ack,
|
||||
.irq_enable = xlp_gpio_irq_enable,
|
||||
.irq_disable = xlp_gpio_irq_disable,
|
||||
.irq_set_type = xlp_gpio_set_irq_type,
|
||||
.irq_unmask = xlp_gpio_irq_unmask,
|
||||
.flags = IRQCHIP_ONESHOT_SAFE,
|
||||
.flags = IRQCHIP_ONESHOT_SAFE | IRQCHIP_IMMUTABLE,
|
||||
GPIOCHIP_IRQ_RESOURCE_HELPERS,
|
||||
};
|
||||
|
||||
static void xlp_gpio_generic_handler(struct irq_desc *desc)
|
||||
|
@ -272,7 +282,7 @@ static int xlp_gpio_probe(struct platform_device *pdev)
|
|||
spin_lock_init(&priv->lock);
|
||||
|
||||
girq = &gc->irq;
|
||||
girq->chip = &xlp_gpio_irq_chip;
|
||||
gpio_irq_chip_set_chip(girq, &xlp_gpio_irq_chip);
|
||||
girq->parent_handler = xlp_gpio_generic_handler;
|
||||
girq->num_parents = 1;
|
||||
girq->parents = devm_kcalloc(&pdev->dev, 1,
|
||||
|
|
|
@ -195,7 +195,7 @@ static const struct spi_device_id xra1403_ids[] = {
|
|||
};
|
||||
MODULE_DEVICE_TABLE(spi, xra1403_ids);
|
||||
|
||||
static const struct of_device_id xra1403_spi_of_match[] = {
|
||||
static const struct of_device_id xra1403_spi_of_match[] __maybe_unused = {
|
||||
{ .compatible = "exar,xra1403" },
|
||||
{},
|
||||
};
|
||||
|
|
|
@ -7,16 +7,18 @@
|
|||
* Mika Westerberg <mika.westerberg@linux.intel.com>
|
||||
*/
|
||||
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/dmi.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/pinctrl/pinctrl.h>
|
||||
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/gpio/driver.h>
|
||||
#include <linux/gpio/machine.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/pinctrl/pinctrl.h>
|
||||
|
||||
#include "gpiolib.h"
|
||||
#include "gpiolib-acpi.h"
|
||||
|
@ -126,7 +128,7 @@ static bool acpi_gpio_deferred_req_irqs_done;
|
|||
|
||||
static int acpi_gpiochip_find(struct gpio_chip *gc, void *data)
|
||||
{
|
||||
return gc->parent && device_match_acpi_handle(gc->parent, data);
|
||||
return ACPI_HANDLE_FWNODE(gc->fwnode) == data;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -646,7 +648,7 @@ static bool acpi_get_driver_gpio_data(struct acpi_device *adev,
|
|||
{
|
||||
const struct acpi_gpio_mapping *gm;
|
||||
|
||||
if (!adev->driver_gpios)
|
||||
if (!adev || !adev->driver_gpios)
|
||||
return false;
|
||||
|
||||
for (gm = adev->driver_gpios; gm->name; gm++)
|
||||
|
@ -840,13 +842,10 @@ static int acpi_gpio_property_lookup(struct fwnode_handle *fwnode,
|
|||
ret = __acpi_node_get_property_reference(fwnode, propname, index, 3,
|
||||
&args);
|
||||
if (ret) {
|
||||
struct acpi_device *adev = to_acpi_device_node(fwnode);
|
||||
struct acpi_device *adev;
|
||||
|
||||
if (!adev)
|
||||
return ret;
|
||||
|
||||
if (!acpi_get_driver_gpio_data(adev, propname, index, &args,
|
||||
&quirks))
|
||||
adev = to_acpi_device_node(fwnode);
|
||||
if (!acpi_get_driver_gpio_data(adev, propname, index, &args, &quirks))
|
||||
return ret;
|
||||
}
|
||||
/*
|
||||
|
@ -1617,6 +1616,19 @@ static const struct dmi_system_id gpiolib_acpi_quirks[] __initconst = {
|
|||
.ignore_interrupt = "AMDI0030:00@18",
|
||||
},
|
||||
},
|
||||
{
|
||||
/*
|
||||
* Spurious wakeups from TP_ATTN# pin
|
||||
* Found in BIOS 1.7.8
|
||||
* https://gitlab.freedesktop.org/drm/amd/-/issues/1722#note_1720627
|
||||
*/
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_BOARD_NAME, "NL5xNU"),
|
||||
},
|
||||
.driver_data = &(struct acpi_gpiolib_dmi_quirk) {
|
||||
.ignore_wake = "ELAN0415:00@9",
|
||||
},
|
||||
},
|
||||
{
|
||||
/*
|
||||
* Spurious wakeups from TP_ATTN# pin
|
||||
|
|
|
@ -9,7 +9,6 @@
|
|||
#define GPIOLIB_ACPI_H
|
||||
|
||||
#include <linux/err.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#include <linux/gpio/consumer.h>
|
||||
|
|
|
@ -10,14 +10,16 @@
|
|||
#include <linux/device.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_gpio.h>
|
||||
#include <linux/pinctrl/pinctrl.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/string.h>
|
||||
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/gpio/machine.h>
|
||||
|
||||
#include "gpiolib.h"
|
||||
|
@ -892,6 +894,8 @@ static int of_gpio_simple_xlate(struct gpio_chip *gc,
|
|||
return gpiospec->args[0];
|
||||
}
|
||||
|
||||
#if IS_ENABLED(CONFIG_OF_GPIO_MM_GPIOCHIP)
|
||||
#include <linux/gpio/legacy-of-mm-gpiochip.h>
|
||||
/**
|
||||
* of_mm_gpiochip_add_data - Add memory mapped GPIO chip (bank)
|
||||
* @np: device node of the GPIO chip
|
||||
|
@ -964,6 +968,7 @@ void of_mm_gpiochip_remove(struct of_mm_gpio_chip *mm_gc)
|
|||
kfree(gc->label);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(of_mm_gpiochip_remove);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_PINCTRL
|
||||
static int of_gpiochip_add_pin_range(struct gpio_chip *chip)
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
#define GPIOLIB_OF_H
|
||||
|
||||
#include <linux/err.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#include <linux/notifier.h>
|
||||
|
|
|
@ -6,13 +6,14 @@
|
|||
*/
|
||||
#include <linux/err.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/gpio/driver.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/printk.h>
|
||||
#include <linux/property.h>
|
||||
#include <linux/string.h>
|
||||
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/gpio/driver.h>
|
||||
|
||||
#include "gpiolib.h"
|
||||
#include "gpiolib-swnode.h"
|
||||
|
||||
|
|
|
@ -1,18 +1,29 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
#include <linux/idr.h>
|
||||
#include <linux/mutex.h>
|
||||
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/sysfs.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/gpio/driver.h>
|
||||
#include <linux/idr.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/kdev_t.h>
|
||||
#include <linux/kstrtox.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/printk.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/ctype.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/sysfs.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/gpio/driver.h>
|
||||
|
||||
#include "gpiolib.h"
|
||||
#include "gpiolib-sysfs.h"
|
||||
|
||||
struct kernfs_node;
|
||||
|
||||
#define GPIO_IRQF_TRIGGER_NONE 0
|
||||
#define GPIO_IRQF_TRIGGER_FALLING BIT(0)
|
||||
#define GPIO_IRQF_TRIGGER_RISING BIT(1)
|
||||
|
@ -491,7 +502,7 @@ static ssize_t unexport_store(struct class *class,
|
|||
goto done;
|
||||
|
||||
desc = gpio_to_desc(gpio);
|
||||
/* reject bogus commands (gpio_unexport ignores them) */
|
||||
/* reject bogus commands (gpiod_unexport() ignores them) */
|
||||
if (!desc) {
|
||||
pr_warn("%s: invalid GPIO %ld\n", __func__, gpio);
|
||||
return -EINVAL;
|
||||
|
@ -790,7 +801,7 @@ static int __init gpiolib_sysfs_init(void)
|
|||
* early (e.g. before the class_register above was called).
|
||||
*
|
||||
* We run before arch_initcall() so chip->dev nodes can have
|
||||
* registered, and so arch_initcall() can always gpio_export().
|
||||
* registered, and so arch_initcall() can always gpiod_export().
|
||||
*/
|
||||
spin_lock_irqsave(&gpio_lock, flags);
|
||||
list_for_each_entry(gdev, &gpio_devices, list) {
|
||||
|
|
|
@ -6,22 +6,25 @@
|
|||
#include <linux/debugfs.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/file.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/gpio.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/of.h>
|
||||
#include <linux/pinctrl/consumer.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/spinlock.h>
|
||||
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/gpio/driver.h>
|
||||
#include <linux/gpio/machine.h>
|
||||
|
||||
#include <uapi/linux/gpio.h>
|
||||
|
||||
#include "gpiolib-acpi.h"
|
||||
|
@ -58,7 +61,20 @@
|
|||
static DEFINE_IDA(gpio_ida);
|
||||
static dev_t gpio_devt;
|
||||
#define GPIO_DEV_MAX 256 /* 256 GPIO chip devices supported */
|
||||
static int gpio_bus_match(struct device *dev, struct device_driver *drv);
|
||||
|
||||
static int gpio_bus_match(struct device *dev, struct device_driver *drv)
|
||||
{
|
||||
struct fwnode_handle *fwnode = dev_fwnode(dev);
|
||||
|
||||
/*
|
||||
* Only match if the fwnode doesn't already have a proper struct device
|
||||
* created for it.
|
||||
*/
|
||||
if (fwnode && fwnode->dev != dev)
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static struct bus_type gpio_bus_type = {
|
||||
.name = "gpio",
|
||||
.match = gpio_bus_match,
|
||||
|
@ -357,7 +373,7 @@ static int gpiochip_set_desc_names(struct gpio_chip *gc)
|
|||
}
|
||||
|
||||
/*
|
||||
* devprop_gpiochip_set_names - Set GPIO line names using device properties
|
||||
* gpiochip_set_names - Set GPIO line names using device properties
|
||||
* @chip: GPIO chip whose lines should be named, if possible
|
||||
*
|
||||
* Looks for device property "gpio-line-names" and if it exists assigns
|
||||
|
@ -365,7 +381,7 @@ static int gpiochip_set_desc_names(struct gpio_chip *gc)
|
|||
* names belong to the underlying firmware node and should not be released
|
||||
* by the caller.
|
||||
*/
|
||||
static int devprop_gpiochip_set_names(struct gpio_chip *chip)
|
||||
static int gpiochip_set_names(struct gpio_chip *chip)
|
||||
{
|
||||
struct gpio_device *gdev = chip->gpiodev;
|
||||
struct device *dev = &gdev->dev;
|
||||
|
@ -556,7 +572,7 @@ bool gpiochip_line_is_valid(const struct gpio_chip *gc,
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(gpiochip_line_is_valid);
|
||||
|
||||
static void gpiodevice_release(struct device *dev)
|
||||
static void gpiodev_release(struct device *dev)
|
||||
{
|
||||
struct gpio_device *gdev = to_gpio_device(dev);
|
||||
unsigned long flags;
|
||||
|
@ -585,21 +601,22 @@ static void gpiodevice_release(struct device *dev)
|
|||
|
||||
static int gpiochip_setup_dev(struct gpio_device *gdev)
|
||||
{
|
||||
struct fwnode_handle *fwnode = dev_fwnode(&gdev->dev);
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* If fwnode doesn't belong to another device, it's safe to clear its
|
||||
* initialized flag.
|
||||
*/
|
||||
if (gdev->dev.fwnode && !gdev->dev.fwnode->dev)
|
||||
fwnode_dev_initialized(gdev->dev.fwnode, false);
|
||||
if (fwnode && !fwnode->dev)
|
||||
fwnode_dev_initialized(fwnode, false);
|
||||
|
||||
ret = gcdev_register(gdev, gpio_devt);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* From this point, the .release() function cleans up gpio_device */
|
||||
gdev->dev.release = gpiodevice_release;
|
||||
gdev->dev.release = gpiodev_release;
|
||||
|
||||
ret = gpiochip_sysfs_register(gdev);
|
||||
if (ret)
|
||||
|
@ -663,11 +680,28 @@ static void gpiochip_setup_devs(void)
|
|||
}
|
||||
}
|
||||
|
||||
static void gpiochip_set_data(struct gpio_chip *gc, void *data)
|
||||
{
|
||||
gc->gpiodev->data = data;
|
||||
}
|
||||
|
||||
/**
|
||||
* gpiochip_get_data() - get per-subdriver data for the chip
|
||||
* @gc: GPIO chip
|
||||
*
|
||||
* Returns:
|
||||
* The per-subdriver data for the chip.
|
||||
*/
|
||||
void *gpiochip_get_data(struct gpio_chip *gc)
|
||||
{
|
||||
return gc->gpiodev->data;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(gpiochip_get_data);
|
||||
|
||||
int gpiochip_add_data_with_key(struct gpio_chip *gc, void *data,
|
||||
struct lock_class_key *lock_key,
|
||||
struct lock_class_key *request_key)
|
||||
{
|
||||
struct fwnode_handle *fwnode = NULL;
|
||||
struct gpio_device *gdev;
|
||||
unsigned long flags;
|
||||
unsigned int i;
|
||||
|
@ -675,12 +709,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;
|
||||
/*
|
||||
* If the calling driver did not initialize firmware node, do it here
|
||||
* using the parent device, if any.
|
||||
*/
|
||||
if (!gc->fwnode && gc->parent)
|
||||
gc->fwnode = dev_fwnode(gc->parent);
|
||||
|
||||
/*
|
||||
* First: allocate and populate the internal stat container, and
|
||||
|
@ -692,7 +726,9 @@ int gpiochip_add_data_with_key(struct gpio_chip *gc, void *data,
|
|||
gdev->dev.bus = &gpio_bus_type;
|
||||
gdev->dev.parent = gc->parent;
|
||||
gdev->chip = gc;
|
||||
|
||||
gc->gpiodev = gdev;
|
||||
gpiochip_set_data(gc, data);
|
||||
|
||||
device_set_node(&gdev->dev, gc->fwnode);
|
||||
|
||||
|
@ -759,7 +795,6 @@ int gpiochip_add_data_with_key(struct gpio_chip *gc, void *data,
|
|||
}
|
||||
|
||||
gdev->ngpio = gc->ngpio;
|
||||
gdev->data = data;
|
||||
|
||||
spin_lock_irqsave(&gpio_lock, flags);
|
||||
|
||||
|
@ -816,7 +851,7 @@ int gpiochip_add_data_with_key(struct gpio_chip *gc, void *data,
|
|||
if (ret)
|
||||
goto err_remove_from_list;
|
||||
}
|
||||
ret = devprop_gpiochip_set_names(gc);
|
||||
ret = gpiochip_set_names(gc);
|
||||
if (ret)
|
||||
goto err_remove_from_list;
|
||||
|
||||
|
@ -921,19 +956,6 @@ err_print_message:
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(gpiochip_add_data_with_key);
|
||||
|
||||
/**
|
||||
* gpiochip_get_data() - get per-subdriver data for the chip
|
||||
* @gc: GPIO chip
|
||||
*
|
||||
* Returns:
|
||||
* The per-subdriver data for the chip.
|
||||
*/
|
||||
void *gpiochip_get_data(struct gpio_chip *gc)
|
||||
{
|
||||
return gc->gpiodev->data;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(gpiochip_get_data);
|
||||
|
||||
/**
|
||||
* gpiochip_remove() - unregister a gpio_chip
|
||||
* @gc: the chip to unregister
|
||||
|
@ -960,9 +982,9 @@ void gpiochip_remove(struct gpio_chip *gc)
|
|||
gpiochip_free_valid_mask(gc);
|
||||
/*
|
||||
* We accept no more calls into the driver from this point, so
|
||||
* NULL the driver data pointer
|
||||
* NULL the driver data pointer.
|
||||
*/
|
||||
gdev->data = NULL;
|
||||
gpiochip_set_data(gc, NULL);
|
||||
|
||||
spin_lock_irqsave(&gpio_lock, flags);
|
||||
for (i = 0; i < gdev->ngpio; i++) {
|
||||
|
@ -1201,7 +1223,7 @@ static int gpiochip_hierarchy_irq_domain_alloc(struct irq_domain *d,
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
chip_dbg(gc, "allocate IRQ %d, hwirq %lu\n", irq, hwirq);
|
||||
chip_dbg(gc, "allocate IRQ %d, hwirq %lu\n", irq, hwirq);
|
||||
|
||||
ret = girq->child_to_parent_hwirq(gc, hwirq, type,
|
||||
&parent_hwirq, &parent_type);
|
||||
|
@ -1369,8 +1391,7 @@ static bool gpiochip_hierarchy_is_hierarchical(struct gpio_chip *gc)
|
|||
* gpiochip by assigning the gpiochip as chip data, and using the irqchip
|
||||
* stored inside the gpiochip.
|
||||
*/
|
||||
int gpiochip_irq_map(struct irq_domain *d, unsigned int irq,
|
||||
irq_hw_number_t hwirq)
|
||||
int gpiochip_irq_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hwirq)
|
||||
{
|
||||
struct gpio_chip *gc = d->host_data;
|
||||
int ret = 0;
|
||||
|
@ -1446,8 +1467,9 @@ int gpiochip_irq_domain_activate(struct irq_domain *domain,
|
|||
struct irq_data *data, bool reserve)
|
||||
{
|
||||
struct gpio_chip *gc = domain->host_data;
|
||||
unsigned int hwirq = irqd_to_hwirq(data);
|
||||
|
||||
return gpiochip_lock_as_irq(gc, data->hwirq);
|
||||
return gpiochip_lock_as_irq(gc, hwirq);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(gpiochip_irq_domain_activate);
|
||||
|
||||
|
@ -1464,8 +1486,9 @@ void gpiochip_irq_domain_deactivate(struct irq_domain *domain,
|
|||
struct irq_data *data)
|
||||
{
|
||||
struct gpio_chip *gc = domain->host_data;
|
||||
unsigned int hwirq = irqd_to_hwirq(data);
|
||||
|
||||
return gpiochip_unlock_as_irq(gc, data->hwirq);
|
||||
return gpiochip_unlock_as_irq(gc, hwirq);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(gpiochip_irq_domain_deactivate);
|
||||
|
||||
|
@ -1505,33 +1528,37 @@ static int gpiochip_to_irq(struct gpio_chip *gc, unsigned int offset)
|
|||
int gpiochip_irq_reqres(struct irq_data *d)
|
||||
{
|
||||
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
|
||||
unsigned int hwirq = irqd_to_hwirq(d);
|
||||
|
||||
return gpiochip_reqres_irq(gc, d->hwirq);
|
||||
return gpiochip_reqres_irq(gc, hwirq);
|
||||
}
|
||||
EXPORT_SYMBOL(gpiochip_irq_reqres);
|
||||
|
||||
void gpiochip_irq_relres(struct irq_data *d)
|
||||
{
|
||||
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
|
||||
unsigned int hwirq = irqd_to_hwirq(d);
|
||||
|
||||
gpiochip_relres_irq(gc, d->hwirq);
|
||||
gpiochip_relres_irq(gc, hwirq);
|
||||
}
|
||||
EXPORT_SYMBOL(gpiochip_irq_relres);
|
||||
|
||||
static void gpiochip_irq_mask(struct irq_data *d)
|
||||
{
|
||||
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
|
||||
unsigned int hwirq = irqd_to_hwirq(d);
|
||||
|
||||
if (gc->irq.irq_mask)
|
||||
gc->irq.irq_mask(d);
|
||||
gpiochip_disable_irq(gc, d->hwirq);
|
||||
gpiochip_disable_irq(gc, hwirq);
|
||||
}
|
||||
|
||||
static void gpiochip_irq_unmask(struct irq_data *d)
|
||||
{
|
||||
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
|
||||
unsigned int hwirq = irqd_to_hwirq(d);
|
||||
|
||||
gpiochip_enable_irq(gc, d->hwirq);
|
||||
gpiochip_enable_irq(gc, hwirq);
|
||||
if (gc->irq.irq_unmask)
|
||||
gc->irq.irq_unmask(d);
|
||||
}
|
||||
|
@ -1539,17 +1566,19 @@ static void gpiochip_irq_unmask(struct irq_data *d)
|
|||
static void gpiochip_irq_enable(struct irq_data *d)
|
||||
{
|
||||
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
|
||||
unsigned int hwirq = irqd_to_hwirq(d);
|
||||
|
||||
gpiochip_enable_irq(gc, d->hwirq);
|
||||
gpiochip_enable_irq(gc, hwirq);
|
||||
gc->irq.irq_enable(d);
|
||||
}
|
||||
|
||||
static void gpiochip_irq_disable(struct irq_data *d)
|
||||
{
|
||||
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
|
||||
unsigned int hwirq = irqd_to_hwirq(d);
|
||||
|
||||
gc->irq.irq_disable(d);
|
||||
gpiochip_disable_irq(gc, d->hwirq);
|
||||
gpiochip_disable_irq(gc, hwirq);
|
||||
}
|
||||
|
||||
static void gpiochip_set_irq_hooks(struct gpio_chip *gc)
|
||||
|
@ -3909,13 +3938,10 @@ static struct gpio_desc *gpiod_find_and_request(struct device *consumer,
|
|||
bool platform_lookup_allowed)
|
||||
{
|
||||
unsigned long lookupflags = GPIO_LOOKUP_FLAGS_DEFAULT;
|
||||
struct gpio_desc *desc = ERR_PTR(-ENOENT);
|
||||
struct gpio_desc *desc;
|
||||
int ret;
|
||||
|
||||
if (!IS_ERR_OR_NULL(fwnode))
|
||||
desc = gpiod_find_by_fwnode(fwnode, consumer, con_id, idx,
|
||||
&flags, &lookupflags);
|
||||
|
||||
desc = gpiod_find_by_fwnode(fwnode, consumer, con_id, idx, &flags, &lookupflags);
|
||||
if (gpiod_not_found(desc) && platform_lookup_allowed) {
|
||||
/*
|
||||
* Either we are not using DT or ACPI, or their lookup did not
|
||||
|
@ -4256,16 +4282,18 @@ struct gpio_descs *__must_check gpiod_get_array(struct device *dev,
|
|||
struct gpio_array *array_info = NULL;
|
||||
struct gpio_chip *gc;
|
||||
int count, bitmap_size;
|
||||
size_t descs_size;
|
||||
|
||||
count = gpiod_count(dev, con_id);
|
||||
if (count < 0)
|
||||
return ERR_PTR(count);
|
||||
|
||||
descs = kzalloc(struct_size(descs, desc, count), GFP_KERNEL);
|
||||
descs_size = struct_size(descs, desc, count);
|
||||
descs = kzalloc(descs_size, GFP_KERNEL);
|
||||
if (!descs)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
for (descs->ndescs = 0; descs->ndescs < count; ) {
|
||||
for (descs->ndescs = 0; descs->ndescs < count; descs->ndescs++) {
|
||||
desc = gpiod_get_index(dev, con_id, descs->ndescs, flags);
|
||||
if (IS_ERR(desc)) {
|
||||
gpiod_put_array(descs);
|
||||
|
@ -4285,20 +4313,17 @@ struct gpio_descs *__must_check gpiod_get_array(struct device *dev,
|
|||
bitmap_size = BITS_TO_LONGS(gc->ngpio > count ?
|
||||
gc->ngpio : count);
|
||||
|
||||
array = kzalloc(struct_size(descs, desc, count) +
|
||||
struct_size(array_info, invert_mask,
|
||||
3 * bitmap_size), GFP_KERNEL);
|
||||
array = krealloc(descs, descs_size +
|
||||
struct_size(array_info, invert_mask, 3 * bitmap_size),
|
||||
GFP_KERNEL | __GFP_ZERO);
|
||||
if (!array) {
|
||||
gpiod_put_array(descs);
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
|
||||
memcpy(array, descs,
|
||||
struct_size(descs, desc, descs->ndescs + 1));
|
||||
kfree(descs);
|
||||
|
||||
descs = array;
|
||||
array_info = (void *)(descs->desc + count);
|
||||
|
||||
array_info = (void *)descs + descs_size;
|
||||
array_info->get_mask = array_info->invert_mask +
|
||||
bitmap_size;
|
||||
array_info->set_mask = array_info->get_mask +
|
||||
|
@ -4313,8 +4338,13 @@ struct gpio_descs *__must_check gpiod_get_array(struct device *dev,
|
|||
count - descs->ndescs);
|
||||
descs->info = array_info;
|
||||
}
|
||||
|
||||
/* If there is no cache for fast bitmap processing path, continue */
|
||||
if (!array_info)
|
||||
continue;
|
||||
|
||||
/* Unmark array members which don't belong to the 'fast' chip */
|
||||
if (array_info && array_info->chip != gc) {
|
||||
if (array_info->chip != gc) {
|
||||
__clear_bit(descs->ndescs, array_info->get_mask);
|
||||
__clear_bit(descs->ndescs, array_info->set_mask);
|
||||
}
|
||||
|
@ -4322,8 +4352,7 @@ struct gpio_descs *__must_check gpiod_get_array(struct device *dev,
|
|||
* Detect array members which belong to the 'fast' chip
|
||||
* but their pins are not in hardware order.
|
||||
*/
|
||||
else if (array_info &&
|
||||
gpio_chip_hwgpio(desc) != descs->ndescs) {
|
||||
else if (gpio_chip_hwgpio(desc) != descs->ndescs) {
|
||||
/*
|
||||
* Don't use fast path if all array members processed so
|
||||
* far belong to the same chip as this one but its pin
|
||||
|
@ -4337,7 +4366,7 @@ struct gpio_descs *__must_check gpiod_get_array(struct device *dev,
|
|||
__clear_bit(descs->ndescs,
|
||||
array_info->set_mask);
|
||||
}
|
||||
} else if (array_info) {
|
||||
} else {
|
||||
/* Exclude open drain or open source from fast output */
|
||||
if (gpiochip_line_is_open_drain(gc, descs->ndescs) ||
|
||||
gpiochip_line_is_open_source(gc, descs->ndescs))
|
||||
|
@ -4348,8 +4377,6 @@ struct gpio_descs *__must_check gpiod_get_array(struct device *dev,
|
|||
__set_bit(descs->ndescs,
|
||||
array_info->invert_mask);
|
||||
}
|
||||
|
||||
descs->ndescs++;
|
||||
}
|
||||
if (array_info)
|
||||
dev_dbg(dev,
|
||||
|
@ -4413,20 +4440,6 @@ void gpiod_put_array(struct gpio_descs *descs)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(gpiod_put_array);
|
||||
|
||||
|
||||
static int gpio_bus_match(struct device *dev, struct device_driver *drv)
|
||||
{
|
||||
struct fwnode_handle *fwnode = dev_fwnode(dev);
|
||||
|
||||
/*
|
||||
* Only match if the fwnode doesn't already have a proper struct device
|
||||
* created for it.
|
||||
*/
|
||||
if (fwnode && fwnode->dev != dev)
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int gpio_stub_drv_probe(struct device *dev)
|
||||
{
|
||||
/*
|
||||
|
|
|
@ -6,14 +6,14 @@
|
|||
*/
|
||||
|
||||
#include <linux/err.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/timer.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/hte.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/timer.h>
|
||||
#include <linux/workqueue.h>
|
||||
|
||||
/*
|
||||
* This sample HTE GPIO test driver demonstrates HTE API usage by enabling
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
#include <linux/of.h>
|
||||
#include <linux/of_gpio.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/spi/ads7846.h>
|
||||
|
@ -1012,8 +1013,8 @@ static int ads7846_setup_pendown(struct spi_device *spi,
|
|||
ts->gpio_pendown = pdata->gpio_pendown;
|
||||
|
||||
if (pdata->gpio_pendown_debounce)
|
||||
gpio_set_debounce(pdata->gpio_pendown,
|
||||
pdata->gpio_pendown_debounce);
|
||||
gpiod_set_debounce(gpio_to_desc(ts->gpio_pendown),
|
||||
pdata->gpio_pendown_debounce);
|
||||
} else {
|
||||
dev_err(&spi->dev, "no get_pendown_state nor gpio_pendown?\n");
|
||||
return -EINVAL;
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#include <linux/pci.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/delay.h>
|
||||
|
@ -889,6 +890,7 @@ static int sta2x11_vip_init_controls(struct sta2x11_vip *vip)
|
|||
static int vip_gpio_reserve(struct device *dev, int pin, int dir,
|
||||
const char *name)
|
||||
{
|
||||
struct gpio_desc *desc = gpio_to_desc(pin);
|
||||
int ret = -ENODEV;
|
||||
|
||||
if (!gpio_is_valid(pin))
|
||||
|
@ -900,7 +902,7 @@ static int vip_gpio_reserve(struct device *dev, int pin, int dir,
|
|||
return ret;
|
||||
}
|
||||
|
||||
ret = gpio_direction_output(pin, dir);
|
||||
ret = gpiod_direction_output(desc, dir);
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to set direction for pin %d (%s)\n",
|
||||
pin, name);
|
||||
|
@ -908,7 +910,7 @@ static int vip_gpio_reserve(struct device *dev, int pin, int dir,
|
|||
return ret;
|
||||
}
|
||||
|
||||
ret = gpio_export(pin, false);
|
||||
ret = gpiod_export(desc, false);
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to export pin %d (%s)\n", pin, name);
|
||||
gpio_free(pin);
|
||||
|
@ -928,8 +930,10 @@ static int vip_gpio_reserve(struct device *dev, int pin, int dir,
|
|||
static void vip_gpio_release(struct device *dev, int pin, const char *name)
|
||||
{
|
||||
if (gpio_is_valid(pin)) {
|
||||
struct gpio_desc *desc = gpio_to_desc(pin);
|
||||
|
||||
dev_dbg(dev, "releasing pin %d (%s)\n", pin, name);
|
||||
gpio_unexport(pin);
|
||||
gpiod_unexport(desc);
|
||||
gpio_free(pin);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -51,6 +51,7 @@
|
|||
#include <linux/clk-provider.h>
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/ieee802154.h>
|
||||
#include <linux/io.h>
|
||||
|
@ -2854,7 +2855,7 @@ static int ca8210_interrupt_init(struct spi_device *spi)
|
|||
);
|
||||
if (ret) {
|
||||
dev_crit(&spi->dev, "request_irq %d failed\n", pdata->irq_id);
|
||||
gpio_unexport(pdata->gpio_irq);
|
||||
gpiod_unexport(gpio_to_desc(pdata->gpio_irq));
|
||||
gpio_free(pdata->gpio_irq);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
#include <net/mac80211.h>
|
||||
#include <linux/bcma/bcma_driver_chipcommon.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/gpio/driver.h>
|
||||
#include <linux/gpio/machine.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче