mirror of https://github.com/torvalds/linux.git
gpio updates for v6.19-rc1
GPIO core:
- add proper support for shared GPIOs that's aiming to replace the
current sharing mechanism (which provides no synchronization ot enable
counting) and enable it for Qualcomm platforms
- improve the software node GPIO lookup by using the fwnode
representation instead of the software node's name which was prone to
bugs (GPIO controllers don't have to use the software node's name as
their kernel label)
- remove the last user of legacy-of-mm-gpiochip.h and drop the header
- move closer to removing the legacy gpio_request_one() routine
- rename some symbols for consistency
- shrink GPIO printk() helpers by reusing existing code
- remove some redundant kernel messages
- use min() instead of min_t() in GPIO ACPI code
- use system_percpu_wq instead of system_wq in GPIO character device code
New drivers:
- add a driver for the QIXIS FPGA GPIO controller
Driver improvements:
- use modernized variants of power management macros across a wide array
of drivers in order to avoid having to use the __maybe_unused attribute
- convert gpio-elkhartlake and reset-gpio to using the auxiliary bus
instead of the platform bus as they are not really described in
firmware
- use lock guards and update symbol prefixes in gpio-mmio
- support the bryx radio interface kit in gpio-mpsse + refactor the
driver
- use software nodes for configuring the reset-gpio driver, including
setting up the reference to the shared "reset" pin
- check and propagate the return value of gpiod_set_value() to user-space
in gpio-virtuser (this was previously not possible as this function
returned void)
- extend the gpio-regmap helper with more features (bypass cache for
aliased inputs, force writes for aliased data registers, add a new
configuration parameter)
- remove unneeded includes from gpio-aspeed and gpio-latch
- add support for Tegra410 to gpio-tegra186
- replace PCI-specific PM with generic device-level PM in gpio-bt8xx
- use dynamic GPIO range allocation in gpio-loongson-64bit
- improve handling of level-triggered interrupts in gpio-pca953x
- add suspend/resume support to gpio-fxl6408
- add support for more models to gpio-menz127
- optimize gpio-mvebu interrupt handling by avoiding unnecessary calls
to mvebu_gpio_irq_handler()
- make locking more consistent in gpio-grgpio
Device-tree bindings:
- document new NXP and Microchip models
Documentation:
- add a comprehensive compatibility and feature list for gpio-pca953x,
which is a great addition as it's probably the most commonly used GPIO
expander driver
- kernel-doc tweaks
Late fixes:
- use BYTE_CTRL_MODE for 2K2000/3000 models in gpio-loongson
-----BEGIN PGP SIGNATURE-----
iQIzBAABCgAdFiEEkeUTLeW1Rh17omX8BZ0uy/82hMMFAmktpZkACgkQBZ0uy/82
hMPRNg/+PEhBT1Sm9GZDL2c3urSfEyIIA97nxvV6rad75Xfj8IVy+orvyhJHJgni
ksjlvLUQLYQ1j82TlCIZDlj3dAmk3rkb6wwbcUubOb7G/xkvWHQztrnmDk4bvSdr
0vR/dEGOUDRLJxPjeQdFzEoDqLrCqy5QwugH3hd6NASBy+n/g7j2Gb4Pc8IA14wL
ogkBlP8nXVv2w7GMFESjNldWvxFnOasGuzIfM7mIBDBSjLzEANcuH/E5dNXPFIO7
kNN8eSnSfMGH0Z0DjdU9tkaAiLypw9FHqSwU6JKNjE/nzzcGV3OzDMM2vgKLETin
z9tNPBtvXOSBuFbxydWUgX20AmNo5ZEfqGXCwinTHOLwABGZPigi7Ogwxeox0SZ4
OKm37GUtZlO+dJC8bWUA82l9CwM9GDcxn7/Fv4s4vLaULUfeZHXn1OP4JZ4WmuZi
J7D5lMIiXKI9EBH95AX3c/r5drZQh1T4Rr7GJ4GG9uceYGTzsE65idI0KXTT1mbx
nMfQYvNSHGk123rN1bLQov1jZE7foXE9mQ+MzMNSWI3C1WdCGRBorqN8+wMrBU29
OLS66UorNwSCIl0XY+lIgdiW6OXBTc65jF1v+EdSZaFknEYHQm9TIxQNH+tQDYfz
irl2dhxz/iaekxO7p516iY3NeqO9Af4SfITVmAX4xDvak3tcYsU=
=Mw+x
-----END PGP SIGNATURE-----
Merge tag 'gpio-updates-for-v6.19-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/brgl/linux
Pull gpio updates from Bartosz Golaszewski:
"There's one new driver, lots of various updates to existing ones, some
refactoring support for new models and misc tweaks and fixes.
The biggest new feature in GPIO core is adding support for managed,
enable-counted sharing of GPIO pins, something that - until now - was
only hacked around with the GPIOD_FLAGS_BIT_NONEXCLUSIVE request flag
which basically allowed drivers to "fight it out" for the descriptor
and provided no synchronization. It was enabled on Qualcomm platforms
(and thus is enabled on arm64 defconfig) and I plan on removing
GPIOD_FLAGS_BIT_NONEXCLUSIVE once all drivers using it are switched to
the new mechanism.
GPIO core:
- add proper support for shared GPIOs that's aiming to replace the
current sharing mechanism (which provides no synchronization ot
enable counting) and enable it for Qualcomm platforms
- improve the software node GPIO lookup by using the fwnode
representation instead of the software node's name which was prone
to bugs (GPIO controllers don't have to use the software node's
name as their kernel label)
- remove the last user of legacy-of-mm-gpiochip.h and drop the header
- move closer to removing the legacy gpio_request_one() routine
- rename some symbols for consistency
- shrink GPIO printk() helpers by reusing existing code
- remove some redundant kernel messages
- use min() instead of min_t() in GPIO ACPI code
- use system_percpu_wq instead of system_wq in GPIO character device
code
New drivers:
- add a driver for the QIXIS FPGA GPIO controller
Driver improvements:
- use modernized variants of power management macros across a wide
array of drivers in order to avoid having to use the __maybe_unused
attribute
- convert gpio-elkhartlake and reset-gpio to using the auxiliary bus
instead of the platform bus as they are not really described in
firmware
- use lock guards and update symbol prefixes in gpio-mmio
- support the bryx radio interface kit in gpio-mpsse + refactor the
driver
- use software nodes for configuring the reset-gpio driver, including
setting up the reference to the shared "reset" pin
- check and propagate the return value of gpiod_set_value() to
user-space in gpio-virtuser (this was previously not possible as
this function returned void)
- extend the gpio-regmap helper with more features (bypass cache for
aliased inputs, force writes for aliased data registers, add a new
configuration parameter)
- remove unneeded includes from gpio-aspeed and gpio-latch
- add support for Tegra410 to gpio-tegra186
- replace PCI-specific PM with generic device-level PM in gpio-bt8xx
- use dynamic GPIO range allocation in gpio-loongson-64bit
- improve handling of level-triggered interrupts in gpio-pca953x
- add suspend/resume support to gpio-fxl6408
- add support for more models to gpio-menz127
- optimize gpio-mvebu interrupt handling by avoiding unnecessary
calls to mvebu_gpio_irq_handler()
- make locking more consistent in gpio-grgpio
Device-tree bindings:
- document new NXP and Microchip models
Documentation:
- add a comprehensive compatibility and feature list for
gpio-pca953x, which is a great addition as it's probably the most
commonly used GPIO expander driver
- kernel-doc tweaks
Late fixes:
- use BYTE_CTRL_MODE for 2K2000/3000 models in gpio-loongson"
* tag 'gpio-updates-for-v6.19-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/brgl/linux: (80 commits)
gpio: loongson: Switch 2K2000/3000 GPIO to BYTE_CTRL_MODE
gpio: regmap: fix kernel-doc notation
gpio: shared: fix a deadlock
gpio: shared-proxy: set suppress_bind_attrs
gpio: shared: ignore GPIO hogs when traversing the device tree
gpio: shared: ignore special __symbols__ node when traversing device tree
gpio: shared: handle the reset-gpios corner case
gpio: zynq: Use modern PM macros
gpio: xilinx: Use modern PM macros
gpio: xgene: Use modern PM macros
gpio: uniphier: Use modern PM macros
gpio: tqmx86: Use modern PM macros
gpio: pch: Use modern PM macros
gpio: omap: Use modern PM macros
gpio: msc313: Use modern PM macros
gpio: mlxbf2: Use modern PM macros
gpio: ml-ioh: Use modern PM macros
gpio: pl061: Use modern PM macros
gpio: htc-egpio: Use modern PM macros
gpio: brcmstb: Use modern PM macros
...
This commit is contained in:
commit
500920fa76
|
|
@ -11,7 +11,10 @@ maintainers:
|
|||
|
||||
properties:
|
||||
compatible:
|
||||
items:
|
||||
oneOf:
|
||||
- items:
|
||||
- const: microchip,pic64gx-gpio
|
||||
- const: microchip,mpfs-gpio
|
||||
- enum:
|
||||
- microchip,mpfs-gpio
|
||||
- microchip,coregpio-rtl-v3
|
||||
|
|
|
|||
|
|
@ -22,6 +22,8 @@ properties:
|
|||
- cznic,moxtet-gpio
|
||||
- dlg,slg7xl45106
|
||||
- fcs,fxl6408
|
||||
- fsl,ls1046aqds-fpga-gpio-stat-pres2
|
||||
- fsl,lx2160ardb-fpga-gpio-sfp
|
||||
- gateworks,pld-gpio
|
||||
- ibm,ppc4xx-gpio
|
||||
- loongson,ls1x-gpio
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ Contents:
|
|||
legacy-boards
|
||||
drivers-on-gpio
|
||||
bt8xxgpio
|
||||
pca953x
|
||||
|
||||
Core
|
||||
====
|
||||
|
|
|
|||
|
|
@ -0,0 +1,552 @@
|
|||
============================================
|
||||
PCA953x I²C GPIO expander compatibility list
|
||||
============================================
|
||||
|
||||
:Author: Levente Révész <levente.revesz@eilabs.com>
|
||||
|
||||
I went through all the datasheets and created this note listing
|
||||
chip functions and register layouts.
|
||||
|
||||
Overview of chips
|
||||
=================
|
||||
|
||||
Chips with the basic 4 registers
|
||||
--------------------------------
|
||||
|
||||
These chips have 4 register banks: input, output, invert and direction.
|
||||
Each of these banks contains (lines/8) registers, one for each GPIO port.
|
||||
|
||||
Banks offset is always a power of 2:
|
||||
|
||||
- 4 lines -> bank offset is 1
|
||||
- 8 lines -> bank offset is 1
|
||||
- 16 lines -> bank offset is 2
|
||||
- 24 lines -> bank offset is 4
|
||||
- 32 lines -> bank offset is 4
|
||||
- 40 lines -> bank offset is 8
|
||||
|
||||
For example, register layout of GPIO expander with 24 lines:
|
||||
|
||||
+------+-----------------+--------+
|
||||
| addr | function | bank |
|
||||
+======+=================+========+
|
||||
| 00 | input port0 | |
|
||||
+------+-----------------+ |
|
||||
| 01 | input port1 | bank 0 |
|
||||
+------+-----------------+ |
|
||||
| 02 | input port2 | |
|
||||
+------+-----------------+--------+
|
||||
| 03 | n/a | |
|
||||
+------+-----------------+--------+
|
||||
| 04 | output port0 | |
|
||||
+------+-----------------+ |
|
||||
| 05 | output port1 | bank 1 |
|
||||
+------+-----------------+ |
|
||||
| 06 | output port2 | |
|
||||
+------+-----------------+--------+
|
||||
| 07 | n/a | |
|
||||
+------+-----------------+--------+
|
||||
| 08 | invert port0 | |
|
||||
+------+-----------------+ |
|
||||
| 09 | invert port1 | bank 2 |
|
||||
+------+-----------------+ |
|
||||
| 0A | invert port2 | |
|
||||
+------+-----------------+--------+
|
||||
| 0B | n/a | |
|
||||
+------+-----------------+--------+
|
||||
| 0C | direction port0 | |
|
||||
+------+-----------------+ |
|
||||
| 0D | direction port1 | bank 3 |
|
||||
+------+-----------------+ |
|
||||
| 0E | direction port2 | |
|
||||
+------+-----------------+--------+
|
||||
| 0F | n/a | |
|
||||
+------+-----------------+--------+
|
||||
|
||||
.. note::
|
||||
This is followed by all supported chips, except by pcal6534.
|
||||
|
||||
The table below shows the offsets for each of the compatible chips:
|
||||
|
||||
========== ===== ========= ===== ====== ====== =========
|
||||
compatible lines interrupt input output invert direction
|
||||
========== ===== ========= ===== ====== ====== =========
|
||||
pca9536 4 no 00 01 02 03
|
||||
pca9537 4 yes 00 01 02 03
|
||||
pca6408 8 yes 00 01 02 03
|
||||
tca6408 8 yes 00 01 02 03
|
||||
pca9534 8 yes 00 01 02 03
|
||||
pca9538 8 yes 00 01 02 03
|
||||
pca9554 8 yes 00 01 02 03
|
||||
tca9554 8 yes 00 01 02 03
|
||||
pca9556 8 no 00 01 02 03
|
||||
pca9557 8 no 00 01 02 03
|
||||
pca6107 8 yes 00 01 02 03
|
||||
pca6416 16 yes 00 02 04 06
|
||||
tca6416 16 yes 00 02 04 06
|
||||
pca9535 16 yes 00 02 04 06
|
||||
pca9539 16 yes 00 02 04 06
|
||||
tca9539 16 yes 00 02 04 06
|
||||
pca9555 16 yes 00 02 04 06
|
||||
max7318 16 yes 00 02 04 06
|
||||
tca6424 24 yes 00 04 08 0C
|
||||
========== ===== ========= ===== ====== ====== =========
|
||||
|
||||
Chips with additional timeout_en register
|
||||
-----------------------------------------
|
||||
|
||||
These Maxim chips have a bus timeout function which can be enabled in
|
||||
the timeout_en register. This is present in only two chips. Defaults to
|
||||
timeout disabled.
|
||||
|
||||
========== ===== ========= ===== ====== ====== ========= ==========
|
||||
compatible lines interrupt input output invert direction timeout_en
|
||||
========== ===== ========= ===== ====== ====== ========= ==========
|
||||
max7310 8 no 00 01 02 03 04
|
||||
max7312 16 yes 00 02 04 06 08
|
||||
========== ===== ========= ===== ====== ====== ========= ==========
|
||||
|
||||
Chips with additional int_mask register
|
||||
---------------------------------------
|
||||
|
||||
These chips have an interrupt mask register in addition to the 4 basic
|
||||
registers. The interrupt masks default to all interrupts disabled. To
|
||||
use interrupts with these chips, the driver has to set the int_mask
|
||||
register.
|
||||
|
||||
========== ===== ========= ===== ====== ====== ========= ========
|
||||
compatible lines interrupt input output invert direction int_mask
|
||||
========== ===== ========= ===== ====== ====== ========= ========
|
||||
pca9505 40 yes 00 08 10 18 20
|
||||
pca9506 40 yes 00 08 10 18 20
|
||||
========== ===== ========= ===== ====== ====== ========= ========
|
||||
|
||||
Chips with additional int_mask and out_conf registers
|
||||
-----------------------------------------------------
|
||||
|
||||
This chip has an interrupt mask register, and an output port
|
||||
configuration register, which can select between push-pull and
|
||||
open-drain modes. Each bit controls two lines. Both of these registers
|
||||
are present in PCAL chips as well, albeit the out_conf works
|
||||
differently.
|
||||
|
||||
========== ===== ========= ===== ====== ====== ========= ======== ========
|
||||
compatible lines interrupt input output invert direction int_mask out_conf
|
||||
========== ===== ========= ===== ====== ====== ========= ======== ========
|
||||
pca9698 40 yes 00 08 10 18 20 28
|
||||
========== ===== ========= ===== ====== ====== ========= ======== ========
|
||||
|
||||
pca9698 also has a "master output" register for setting all outputs per
|
||||
port to the same value simultaneously, and a chip specific mode register
|
||||
for various additional chip settings.
|
||||
|
||||
========== ============= ====
|
||||
compatible master_output mode
|
||||
========== ============= ====
|
||||
pca9698 29 2A
|
||||
========== ============= ====
|
||||
|
||||
Chips with LED blink and intensity control
|
||||
------------------------------------------
|
||||
|
||||
These Maxim chips have no invert register.
|
||||
|
||||
They have two sets of output registers (output0 and output1). An internal
|
||||
timer alternates the effective output between the values set in these
|
||||
registers, if blink mode is enabled in the blink register. The
|
||||
master_intensity register and the intensity registers together define
|
||||
the PWM intensity value for each pair of outputs.
|
||||
|
||||
These chips can be used as simple GPIO expanders if the driver handles the
|
||||
input, output0 and direction registers.
|
||||
|
||||
========== ===== ========= ===== ======= ========= ======= ================ ===== =========
|
||||
compatible lines interrupt input output0 direction output1 master_intensity blink intensity
|
||||
========== ===== ========= ===== ======= ========= ======= ================ ===== =========
|
||||
max7315 8 yes 00 01 03 09 0E 0F 10
|
||||
max7313 16 yes 00 02 06 0A 0E 0F 10
|
||||
========== ===== ========= ===== ======= ========= ======= ================ ===== =========
|
||||
|
||||
Basic PCAL chips
|
||||
----------------
|
||||
|
||||
========== ===== ========= ===== ====== ====== =========
|
||||
compatible lines interrupt input output invert direction
|
||||
========== ===== ========= ===== ====== ====== =========
|
||||
pcal6408 8 yes 00 01 02 03
|
||||
pcal9554b 8 yes 00 01 02 03
|
||||
pcal6416 16 yes 00 02 04 06
|
||||
pcal9535 16 yes 00 02 04 06
|
||||
pcal9555a 16 yes 00 02 04 06
|
||||
========== ===== ========= ===== ====== ====== =========
|
||||
|
||||
These chips have several additional features:
|
||||
|
||||
1. output drive strength setting (out_strength)
|
||||
2. input latch (in_latch)
|
||||
3. pull-up/pull-down (pull_in, pull_sel)
|
||||
4. push-pull/open-drain outputs (out_conf)
|
||||
5. interrupt mask and interrupt status (int_mask, int_status)
|
||||
|
||||
========== ============ ======== ======= ======== ======== ========== ========
|
||||
compatible out_strength in_latch pull_en pull_sel int_mask int_status out_conf
|
||||
========== ============ ======== ======= ======== ======== ========== ========
|
||||
pcal6408 40 42 43 44 45 46 4F
|
||||
pcal9554b 40 42 43 44 45 46 4F
|
||||
pcal6416 40 44 46 48 4A 4C 4F
|
||||
pcal9535 40 44 46 48 4A 4C 4F
|
||||
pcal9555a 40 44 46 48 4A 4C 4F
|
||||
========== ============ ======== ======= ======== ======== ========== ========
|
||||
|
||||
Currently the driver has support for the input latch, pull-up/pull-down
|
||||
and uses int_mask and int_status for interrupts.
|
||||
|
||||
PCAL chips with extended interrupt and output configuration functions
|
||||
---------------------------------------------------------------------
|
||||
|
||||
========== ===== ========= ===== ====== ====== =========
|
||||
compatible lines interrupt input output invert direction
|
||||
========== ===== ========= ===== ====== ====== =========
|
||||
pcal6524 24 yes 00 04 08 0C
|
||||
pcal6534 34 yes 00 05 0A 0F
|
||||
========== ===== ========= ===== ====== ====== =========
|
||||
|
||||
These chips have the full PCAL register set, plus the following functions:
|
||||
|
||||
1. interrupt event selection: level, rising, falling, any edge
|
||||
2. clear interrupt status per line
|
||||
3. read input without clearing interrupt status
|
||||
4. individual output config (push-pull/open-drain) per output line
|
||||
5. debounce inputs
|
||||
|
||||
========== ============ ======== ======= ======== ======== ========== ========
|
||||
compatible out_strength in_latch pull_en pull_sel int_mask int_status out_conf
|
||||
========== ============ ======== ======= ======== ======== ========== ========
|
||||
pcal6524 40 48 4C 50 54 58 5C
|
||||
pcal6534 30 3A 3F 44 49 4E 53
|
||||
========== ============ ======== ======= ======== ======== ========== ========
|
||||
|
||||
========== ======== ========= ============ ============== ======== ==============
|
||||
compatible int_edge int_clear input_status indiv_out_conf debounce debounce_count
|
||||
========== ======== ========= ============ ============== ======== ==============
|
||||
pcal6524 60 68 6C 70 74 76
|
||||
pcal6534 54 5E 63 68 6D 6F
|
||||
========== ======== ========= ============ ============== ======== ==============
|
||||
|
||||
As can be seen in the table above, pcal6534 does not follow the usual
|
||||
bank spacing rule. Its banks are closely packed instead.
|
||||
|
||||
PCA957X chips with a completely different register layout
|
||||
---------------------------------------------------------
|
||||
|
||||
These chips have the basic 4 registers, but at unusual addresses.
|
||||
|
||||
Additionally, they have:
|
||||
|
||||
1. pull-up/pull-down (pull_sel)
|
||||
2. a global pull enable, defaults to disabled (config)
|
||||
3. interrupt mask, interrupt status (int_mask, int_status)
|
||||
|
||||
========== ===== ========= ===== ====== ====== ======== ========= ====== ======== ==========
|
||||
compatible lines interrupt input invert config pull_sel direction output int_mask int_status
|
||||
========== ===== ========= ===== ====== ====== ======== ========= ====== ======== ==========
|
||||
pca9574 8 yes 00 01 02 03 04 05 06 07
|
||||
pca9575 16 yes 00 02 04 06 08 0A 0C 0E
|
||||
========== ===== ========= ===== ====== ====== ======== ========= ====== ======== ==========
|
||||
|
||||
Currently the driver supports none of the advanced features.
|
||||
|
||||
XRA1202
|
||||
-------
|
||||
|
||||
Basic 4 registers, plus advanced features:
|
||||
|
||||
1. interrupt mask, defaults to interrupts disabled
|
||||
2. interrupt status
|
||||
3. interrupt event selection, level, rising, falling, any edge
|
||||
(int_mask, rising_mask, falling_mask)
|
||||
4. pull-up (no pull-down)
|
||||
5. tri-state
|
||||
6. debounce
|
||||
|
||||
========== ===== ========= ===== ====== ====== ========= =========
|
||||
compatible lines interrupt input output invert direction pullup_en
|
||||
========== ===== ========= ===== ====== ====== ========= =========
|
||||
xra1202 8 yes 00 01 02 03 04
|
||||
========== ===== ========= ===== ====== ====== ========= =========
|
||||
|
||||
========== ======== ======== ========== =========== ============ ========
|
||||
compatible int_mask tristate int_status rising_mask falling_mask debounce
|
||||
========== ======== ======== ========== =========== ============ ========
|
||||
xra1202 05 06 07 08 09 0A
|
||||
========== ======== ======== ========== =========== ============ ========
|
||||
|
||||
Overview of functions
|
||||
=====================
|
||||
|
||||
This section lists chip functions that are supported by the driver
|
||||
already, or are at least common in multiple chips.
|
||||
|
||||
Input, Output, Invert, Direction
|
||||
--------------------------------
|
||||
|
||||
The basic 4 GPIO functions are present in all but one chip category, i.e.
|
||||
`Chips with LED blink and intensity control`_ are missing the invert
|
||||
register.
|
||||
|
||||
3 different layouts are used for these registers:
|
||||
|
||||
1. banks 0, 1, 2, 3 with bank offsets of 2^n
|
||||
- all other chips
|
||||
|
||||
2. banks 0, 1, 2, 3 with closely packed banks
|
||||
- pcal6534
|
||||
|
||||
3. banks 0, 5, 1, 4 with bank offsets of 2^n
|
||||
- pca9574
|
||||
- pca9575
|
||||
|
||||
Interrupts
|
||||
----------
|
||||
|
||||
Only an interrupt mask register
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
The same layout is used for all of these:
|
||||
|
||||
1. bank 5 with bank offsets of 2^n
|
||||
- pca9505
|
||||
- pca9506
|
||||
- pca9698
|
||||
|
||||
Interrupt mask and interrupt status registers
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
These work the same way in all of the chips: mask and status have
|
||||
one bit per line, 1 in the mask means interrupt enabled.
|
||||
|
||||
Layouts:
|
||||
|
||||
1. base offset 0x40, bank 5 and bank 6, bank offsets of 2^n
|
||||
- pcal6408
|
||||
- pcal6416
|
||||
- pcal9535
|
||||
- pcal9554b
|
||||
- pcal9555a
|
||||
- pcal6524
|
||||
|
||||
2. base offset 0x30, bank 5 and 6, closely packed banks
|
||||
- pcal6534
|
||||
|
||||
3. bank 6 and 7, bank offsets of 2^n
|
||||
- pca9574
|
||||
- pca9575
|
||||
|
||||
4. bank 5 and 7, bank offsets of 2^n
|
||||
- xra1202
|
||||
|
||||
Interrupt on specific edges
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
`PCAL chips with extended interrupt and output configuration functions`_
|
||||
have an int_edge register. This contains 2 bits per line, one of 4 events
|
||||
can be selected for each line:
|
||||
|
||||
0: level, 1: rising edge, 2: falling edge, 3: any edge
|
||||
|
||||
Layouts:
|
||||
|
||||
1. base offset 0x40, bank 7, bank offsets of 2^n
|
||||
|
||||
- pcal6524
|
||||
|
||||
2. base offset 0x30, bank 7 + offset 0x01, closely packed banks
|
||||
(out_conf is 1 byte, not (lines/8) bytes, hence the 0x01 offset)
|
||||
|
||||
- pcal6534
|
||||
|
||||
`XRA1202`_ chips have a different mechanism for the same thing: they have
|
||||
a rising mask and a falling mask, with one bit per line.
|
||||
|
||||
Layout:
|
||||
|
||||
1. bank 5, bank offsets of 2^n
|
||||
|
||||
Input latch
|
||||
-----------
|
||||
|
||||
Only `Basic PCAL chips`_ and
|
||||
`PCAL chips with extended interrupt and output configuration functions`_
|
||||
have this function. When the latch is enabled, the interrupt is not cleared
|
||||
until the input port is read. When the latch is disabled, the interrupt
|
||||
is cleared even if the input register is not read, if the input pin returns
|
||||
to the logic value it had before generating the interrupt. Defaults to latch
|
||||
disabled.
|
||||
|
||||
Currently the driver enables the latch for each line with interrupt
|
||||
enabled.
|
||||
|
||||
1. base offset 0x40, bank 2, bank offsets of 2^n
|
||||
- pcal6408
|
||||
- pcal6416
|
||||
- pcal9535
|
||||
- pcal9554b
|
||||
- pcal9555a
|
||||
- pcal6524
|
||||
|
||||
2. base offset 0x30, bank 2, closely packed banks
|
||||
- pcal6534
|
||||
|
||||
Pull-up and pull-down
|
||||
---------------------
|
||||
|
||||
`Basic PCAL chips`_ and
|
||||
`PCAL chips with extended interrupt and output configuration functions`_
|
||||
use the same mechanism: their pull_en register enables the pull-up or pull-down
|
||||
function, and their pull_sel register chooses the direction. They all use one
|
||||
bit per line.
|
||||
|
||||
0: pull-down, 1: pull-up
|
||||
|
||||
Layouts:
|
||||
|
||||
1. base offset 0x40, bank 3 (en) and 4 (sel), bank offsets of 2^n
|
||||
- pcal6408
|
||||
- pcal6416
|
||||
- pcal9535
|
||||
- pcal9554b
|
||||
- pcal9555a
|
||||
- pcal6524
|
||||
|
||||
2. base offset 0x30, bank 3 (en) and 4 (sel), closely packed banks
|
||||
- pcal6534
|
||||
|
||||
`PCA957X chips with a completely different register layout`_ have a pull_sel
|
||||
register with one bit per line, and a global pull_en bit in their config
|
||||
register.
|
||||
|
||||
Layout:
|
||||
|
||||
1. bank 2 (config), bank 3 (sel), bank offsets of 2^n
|
||||
- pca9574
|
||||
- pca9575
|
||||
|
||||
`XRA1202`_ chips can only pull-up. They have a pullup_en register.
|
||||
|
||||
Layout:
|
||||
|
||||
1. bank 4, bank offsets of 2^n
|
||||
- xra1202
|
||||
|
||||
Push-pull and open-drain
|
||||
------------------------
|
||||
|
||||
`Chips with additional int_mask and out_conf registers`_ have this function,
|
||||
but only for select IO ports. Register has 1 bit per 2 lines. In pca9698,
|
||||
only port0 and port1 have this function.
|
||||
|
||||
0: open-drain, 1: push-pull
|
||||
|
||||
Layout:
|
||||
|
||||
1. base offset 5*bankoffset
|
||||
- pca9698
|
||||
|
||||
`Basic PCAL chips`_ have 1 bit per port in one single out_conf register.
|
||||
Only whole ports can be configured.
|
||||
|
||||
0: push-pull, 1: open-drain
|
||||
|
||||
Layout:
|
||||
|
||||
1. base offset 0x4F
|
||||
- pcal6408
|
||||
- pcal6416
|
||||
- pcal9535
|
||||
- pcal9554b
|
||||
- pcal9555a
|
||||
|
||||
`PCAL chips with extended interrupt and output configuration functions`_
|
||||
can set this for each line individually. They have the same per-port out_conf
|
||||
register as `Basic PCAL chips`_, but they also have an indiv_out_conf register
|
||||
with one bit per line, which inverts the effect of the port-wise setting.
|
||||
|
||||
0: push-pull, 1: open-drain
|
||||
|
||||
Layouts:
|
||||
|
||||
1. base offset 0x40 + 7*bankoffset (out_conf),
|
||||
base offset 0x60, bank 4 (indiv_out_conf) with bank offset of 2^n
|
||||
|
||||
- pcal6524
|
||||
|
||||
2. base offset 0x30 + 7*banksize (out_conf),
|
||||
base offset 0x54, bank 4 (indiv_out_conf), closely packed banks
|
||||
|
||||
- pcal6534
|
||||
|
||||
This function is currently not supported by the driver.
|
||||
|
||||
Output drive strength
|
||||
---------------------
|
||||
|
||||
Only PCAL chips have this function. 2 bits per line.
|
||||
|
||||
==== ==============
|
||||
bits drive strength
|
||||
==== ==============
|
||||
00 0.25x
|
||||
01 0.50x
|
||||
10 0.75x
|
||||
11 1.00x
|
||||
==== ==============
|
||||
|
||||
1. base offset 0x40, bank 0 and 1, bank offsets of 2^n
|
||||
- pcal6408
|
||||
- pcal6416
|
||||
- pcal9535
|
||||
- pcal9554b
|
||||
- pcal9555a
|
||||
- pcal6524
|
||||
|
||||
2. base offset 0x30, bank 0 and 1, closely packed banks
|
||||
- pcal6534
|
||||
|
||||
Currently not supported by the driver.
|
||||
|
||||
Datasheets
|
||||
==========
|
||||
|
||||
- MAX7310: https://datasheets.maximintegrated.com/en/ds/MAX7310.pdf
|
||||
- MAX7312: https://datasheets.maximintegrated.com/en/ds/MAX7312.pdf
|
||||
- MAX7313: https://datasheets.maximintegrated.com/en/ds/MAX7313.pdf
|
||||
- MAX7315: https://datasheets.maximintegrated.com/en/ds/MAX7315.pdf
|
||||
- MAX7318: https://datasheets.maximintegrated.com/en/ds/MAX7318.pdf
|
||||
- PCA6107: https://pdf1.alldatasheet.com/datasheet-pdf/view/161780/TI/PCA6107.html
|
||||
- PCA6408A: https://www.nxp.com/docs/en/data-sheet/PCA6408A.pdf
|
||||
- PCA6416A: https://www.nxp.com/docs/en/data-sheet/PCA6416A.pdf
|
||||
- PCA9505: https://www.nxp.com/docs/en/data-sheet/PCA9505_9506.pdf
|
||||
- PCA9505: https://www.nxp.com/docs/en/data-sheet/PCA9505_9506.pdf
|
||||
- PCA9534: https://www.nxp.com/docs/en/data-sheet/PCA9534.pdf
|
||||
- PCA9535: https://www.nxp.com/docs/en/data-sheet/PCA9535_PCA9535C.pdf
|
||||
- PCA9536: https://www.nxp.com/docs/en/data-sheet/PCA9536.pdf
|
||||
- PCA9537: https://www.nxp.com/docs/en/data-sheet/PCA9537.pdf
|
||||
- PCA9538: https://www.nxp.com/docs/en/data-sheet/PCA9538.pdf
|
||||
- PCA9539: https://www.nxp.com/docs/en/data-sheet/PCA9539_PCA9539R.pdf
|
||||
- PCA9554: https://www.nxp.com/docs/en/data-sheet/PCA9554_9554A.pdf
|
||||
- PCA9555: https://www.nxp.com/docs/en/data-sheet/PCA9555.pdf
|
||||
- PCA9556: https://www.nxp.com/docs/en/data-sheet/PCA9556.pdf
|
||||
- PCA9557: https://www.nxp.com/docs/en/data-sheet/PCA9557.pdf
|
||||
- PCA9574: https://www.nxp.com/docs/en/data-sheet/PCA9574.pdf
|
||||
- PCA9575: https://www.nxp.com/docs/en/data-sheet/PCA9575.pdf
|
||||
- PCA9698: https://www.nxp.com/docs/en/data-sheet/PCA9698.pdf
|
||||
- PCAL6408A: https://www.nxp.com/docs/en/data-sheet/PCAL6408A.pdf
|
||||
- PCAL6416A: https://www.nxp.com/docs/en/data-sheet/PCAL6416A.pdf
|
||||
- PCAL6524: https://www.nxp.com/docs/en/data-sheet/PCAL6524.pdf
|
||||
- PCAL6534: https://www.nxp.com/docs/en/data-sheet/PCAL6534.pdf
|
||||
- PCAL9535A: https://www.nxp.com/docs/en/data-sheet/PCAL9535A.pdf
|
||||
- PCAL9554B: https://www.nxp.com/docs/en/data-sheet/PCAL9554B_PCAL9554C.pdf
|
||||
- PCAL9555A: https://www.nxp.com/docs/en/data-sheet/PCAL9555A.pdf
|
||||
- TCA6408A: https://www.ti.com/lit/gpn/tca6408a
|
||||
- TCA6416: https://www.ti.com/lit/gpn/tca6416
|
||||
- TCA6424: https://www.ti.com/lit/gpn/tca6424
|
||||
- TCA9539: https://www.ti.com/lit/gpn/tca9539
|
||||
- TCA9554: https://www.ti.com/lit/gpn/tca9554
|
||||
- XRA1202: https://assets.maxlinear.com/web/documents/xra1202_1202p_101_042213.pdf
|
||||
|
|
@ -12548,6 +12548,13 @@ F: drivers/gpu/drm/xe/
|
|||
F: include/drm/intel/
|
||||
F: include/uapi/drm/xe_drm.h
|
||||
|
||||
INTEL ELKHART LAKE PSE I/O DRIVER
|
||||
M: Raag Jadav <raag.jadav@intel.com>
|
||||
L: platform-driver-x86@vger.kernel.org
|
||||
S: Supported
|
||||
F: drivers/platform/x86/intel/ehl_pse_io.c
|
||||
F: include/linux/ehl_pse_io_aux.h
|
||||
|
||||
INTEL ETHERNET DRIVERS
|
||||
M: Tony Nguyen <anthony.l.nguyen@intel.com>
|
||||
M: Przemek Kitszel <przemyslaw.kitszel@intel.com>
|
||||
|
|
|
|||
|
|
@ -316,6 +316,7 @@ config ARCH_QCOM
|
|||
select GPIOLIB
|
||||
select PINCTRL
|
||||
select HAVE_PWRCTRL if PCI
|
||||
select HAVE_SHARED_GPIOS
|
||||
help
|
||||
This enables support for the ARMv8 based Qualcomm chipsets.
|
||||
|
||||
|
|
|
|||
|
|
@ -535,14 +535,29 @@ software_node_get_reference_args(const struct fwnode_handle *fwnode,
|
|||
ref_array = prop->pointer;
|
||||
ref = &ref_array[index];
|
||||
|
||||
refnode = software_node_fwnode(ref->node);
|
||||
/*
|
||||
* A software node can reference other software nodes or firmware
|
||||
* nodes (which are the abstraction layer sitting on top of them).
|
||||
* This is done to ensure we can create references to static software
|
||||
* nodes before they're registered with the firmware node framework.
|
||||
* At the time the reference is being resolved, we expect the swnodes
|
||||
* in question to already have been registered and to be backed by
|
||||
* a firmware node. This is why we use the fwnode API below to read the
|
||||
* relevant properties and bump the reference count.
|
||||
*/
|
||||
|
||||
if (ref->swnode)
|
||||
refnode = software_node_fwnode(ref->swnode);
|
||||
else if (ref->fwnode)
|
||||
refnode = ref->fwnode;
|
||||
else
|
||||
return -EINVAL;
|
||||
|
||||
if (!refnode)
|
||||
return -ENOENT;
|
||||
|
||||
if (nargs_prop) {
|
||||
error = property_entry_read_int_array(ref->node->properties,
|
||||
nargs_prop, sizeof(u32),
|
||||
&nargs_prop_val, 1);
|
||||
error = fwnode_property_read_u32(refnode, nargs_prop, &nargs_prop_val);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
|
|
@ -555,7 +570,7 @@ software_node_get_reference_args(const struct fwnode_handle *fwnode,
|
|||
if (!args)
|
||||
return 0;
|
||||
|
||||
args->fwnode = software_node_get(refnode);
|
||||
args->fwnode = fwnode_handle_get(refnode);
|
||||
args->nargs = nargs;
|
||||
|
||||
for (i = 0; i < nargs; i++)
|
||||
|
|
@ -635,7 +650,10 @@ software_node_graph_get_remote_endpoint(const struct fwnode_handle *fwnode)
|
|||
|
||||
ref = prop->pointer;
|
||||
|
||||
return software_node_get(software_node_fwnode(ref[0].node));
|
||||
if (!ref->swnode)
|
||||
return NULL;
|
||||
|
||||
return software_node_get(software_node_fwnode(ref->swnode));
|
||||
}
|
||||
|
||||
static struct fwnode_handle *
|
||||
|
|
|
|||
|
|
@ -45,14 +45,6 @@ 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 GPIO_SHARED
|
||||
def_bool y
|
||||
depends on HAVE_SHARED_GPIOS || COMPILE_TEST
|
||||
|
|
@ -484,7 +476,6 @@ 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
|
||||
|
|
@ -1421,7 +1412,7 @@ config HTC_EGPIO
|
|||
|
||||
config GPIO_ELKHARTLAKE
|
||||
tristate "Intel Elkhart Lake PSE GPIO support"
|
||||
depends on X86 || COMPILE_TEST
|
||||
depends on INTEL_EHL_PSE_IO
|
||||
select GPIO_TANGIER
|
||||
help
|
||||
Select this option to enable GPIO support for Intel Elkhart Lake
|
||||
|
|
@ -1573,6 +1564,15 @@ config GPIO_PMIC_EIC_SPRD
|
|||
help
|
||||
Say yes here to support Spreadtrum PMIC EIC device.
|
||||
|
||||
config GPIO_QIXIS_FPGA
|
||||
tristate "NXP QIXIS FPGA GPIO support"
|
||||
depends on MFD_SIMPLE_MFD_I2C || COMPILE_TEST
|
||||
select GPIO_REGMAP
|
||||
help
|
||||
This enables support for the GPIOs found in the QIXIS FPGA which is
|
||||
integrated on some NXP Layerscape boards such as LX2160ARDB and
|
||||
LS1046AQDS.
|
||||
|
||||
config GPIO_RC5T583
|
||||
bool "RICOH RC5T583 GPIO"
|
||||
depends on MFD_RC5T583
|
||||
|
|
|
|||
|
|
@ -147,6 +147,7 @@ obj-$(CONFIG_GPIO_PL061) += gpio-pl061.o
|
|||
obj-$(CONFIG_GPIO_PMIC_EIC_SPRD) += gpio-pmic-eic-sprd.o
|
||||
obj-$(CONFIG_GPIO_POLARFIRE_SOC) += gpio-mpfs.o
|
||||
obj-$(CONFIG_GPIO_PXA) += gpio-pxa.o
|
||||
obj-$(CONFIG_GPIO_QIXIS_FPGA) += gpio-qixis-fpga.o
|
||||
obj-$(CONFIG_GPIO_RASPBERRYPI_EXP) += gpio-raspberrypi-exp.o
|
||||
obj-$(CONFIG_GPIO_RC5T583) += gpio-rc5t583.o
|
||||
obj-$(CONFIG_GPIO_RCAR) += gpio-rcar.o
|
||||
|
|
|
|||
|
|
@ -86,17 +86,6 @@ Work items:
|
|||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
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.
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
Collect drivers
|
||||
|
||||
Collect GPIO drivers from arch/* and other places that should be placed
|
||||
|
|
|
|||
|
|
@ -24,12 +24,11 @@
|
|||
|
||||
/*
|
||||
* These two headers aren't meant to be used by GPIO drivers. We need
|
||||
* them in order to access gpio_chip_hwgpio() which we need to implement
|
||||
* them in order to access gpiod_hwgpio() which we need to implement
|
||||
* the aspeed specific API which allows the coprocessor to request
|
||||
* access to some GPIOs and to arbitrate between coprocessor and ARM.
|
||||
*/
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include "gpiolib.h"
|
||||
|
||||
/* Non-constant mask variant of FIELD_GET() and FIELD_PREP() */
|
||||
#define field_get(_mask, _reg) (((_reg) & (_mask)) >> (ffs(_mask) - 1))
|
||||
|
|
@ -942,7 +941,7 @@ int aspeed_gpio_copro_grab_gpio(struct gpio_desc *desc,
|
|||
{
|
||||
struct gpio_chip *chip = gpiod_to_chip(desc);
|
||||
struct aspeed_gpio *gpio = gpiochip_get_data(chip);
|
||||
int rc = 0, bindex, offset = gpio_chip_hwgpio(desc);
|
||||
int rc = 0, bindex, offset = gpiod_hwgpio(desc);
|
||||
const struct aspeed_gpio_bank *bank = to_bank(offset);
|
||||
|
||||
if (!aspeed_gpio_support_copro(gpio))
|
||||
|
|
@ -987,7 +986,7 @@ int aspeed_gpio_copro_release_gpio(struct gpio_desc *desc)
|
|||
{
|
||||
struct gpio_chip *chip = gpiod_to_chip(desc);
|
||||
struct aspeed_gpio *gpio = gpiochip_get_data(chip);
|
||||
int rc = 0, bindex, offset = gpio_chip_hwgpio(desc);
|
||||
int rc = 0, bindex, offset = gpiod_hwgpio(desc);
|
||||
|
||||
if (!aspeed_gpio_support_copro(gpio))
|
||||
return -EOPNOTSUPP;
|
||||
|
|
|
|||
|
|
@ -533,7 +533,6 @@ static void brcmstb_gpio_shutdown(struct platform_device *pdev)
|
|||
brcmstb_gpio_quiesce(&pdev->dev, false);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static void brcmstb_gpio_bank_restore(struct brcmstb_gpio_priv *priv,
|
||||
struct brcmstb_gpio_bank *bank)
|
||||
{
|
||||
|
|
@ -572,14 +571,9 @@ static int brcmstb_gpio_resume(struct device *dev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
#else
|
||||
#define brcmstb_gpio_suspend NULL
|
||||
#define brcmstb_gpio_resume NULL
|
||||
#endif /* CONFIG_PM_SLEEP */
|
||||
|
||||
static const struct dev_pm_ops brcmstb_gpio_pm_ops = {
|
||||
.suspend_noirq = brcmstb_gpio_suspend,
|
||||
.resume_noirq = brcmstb_gpio_resume,
|
||||
.suspend_noirq = pm_sleep_ptr(brcmstb_gpio_suspend),
|
||||
.resume_noirq = pm_sleep_ptr(brcmstb_gpio_resume),
|
||||
};
|
||||
|
||||
static int brcmstb_gpio_probe(struct platform_device *pdev)
|
||||
|
|
@ -755,7 +749,7 @@ static struct platform_driver brcmstb_gpio_driver = {
|
|||
.driver = {
|
||||
.name = "brcmstb-gpio",
|
||||
.of_match_table = brcmstb_gpio_of_match,
|
||||
.pm = &brcmstb_gpio_pm_ops,
|
||||
.pm = pm_sleep_ptr(&brcmstb_gpio_pm_ops),
|
||||
},
|
||||
.probe = brcmstb_gpio_probe,
|
||||
.remove = brcmstb_gpio_remove,
|
||||
|
|
|
|||
|
|
@ -52,10 +52,8 @@ struct bt8xxgpio {
|
|||
struct pci_dev *pdev;
|
||||
struct gpio_chip gpio;
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
u32 saved_outen;
|
||||
u32 saved_data;
|
||||
#endif
|
||||
};
|
||||
|
||||
#define bgwrite(dat, adr) writel((dat), bg->mmio+(adr))
|
||||
|
|
@ -224,9 +222,10 @@ static void bt8xxgpio_remove(struct pci_dev *pdev)
|
|||
pci_disable_device(pdev);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int bt8xxgpio_suspend(struct pci_dev *pdev, pm_message_t state)
|
||||
|
||||
static int bt8xxgpio_suspend(struct device *dev)
|
||||
{
|
||||
struct pci_dev *pdev = to_pci_dev(dev);
|
||||
struct bt8xxgpio *bg = pci_get_drvdata(pdev);
|
||||
|
||||
scoped_guard(spinlock_irqsave, &bg->lock) {
|
||||
|
|
@ -238,23 +237,13 @@ static int bt8xxgpio_suspend(struct pci_dev *pdev, pm_message_t state)
|
|||
bgwrite(0x0, BT848_GPIO_OUT_EN);
|
||||
}
|
||||
|
||||
pci_save_state(pdev);
|
||||
pci_disable_device(pdev);
|
||||
pci_set_power_state(pdev, pci_choose_state(pdev, state));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bt8xxgpio_resume(struct pci_dev *pdev)
|
||||
static int bt8xxgpio_resume(struct device *dev)
|
||||
{
|
||||
struct pci_dev *pdev = to_pci_dev(dev);
|
||||
struct bt8xxgpio *bg = pci_get_drvdata(pdev);
|
||||
int err;
|
||||
|
||||
pci_set_power_state(pdev, PCI_D0);
|
||||
err = pci_enable_device(pdev);
|
||||
if (err)
|
||||
return err;
|
||||
pci_restore_state(pdev);
|
||||
|
||||
guard(spinlock_irqsave)(&bg->lock);
|
||||
|
||||
|
|
@ -267,10 +256,8 @@ static int bt8xxgpio_resume(struct pci_dev *pdev)
|
|||
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
#define bt8xxgpio_suspend NULL
|
||||
#define bt8xxgpio_resume NULL
|
||||
#endif /* CONFIG_PM */
|
||||
|
||||
static DEFINE_SIMPLE_DEV_PM_OPS(bt8xxgpio_pm_ops, bt8xxgpio_suspend, bt8xxgpio_resume);
|
||||
|
||||
static const struct pci_device_id bt8xxgpio_pci_tbl[] = {
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT848) },
|
||||
|
|
@ -286,8 +273,7 @@ static struct pci_driver bt8xxgpio_pci_driver = {
|
|||
.id_table = bt8xxgpio_pci_tbl,
|
||||
.probe = bt8xxgpio_probe,
|
||||
.remove = bt8xxgpio_remove,
|
||||
.suspend = bt8xxgpio_suspend,
|
||||
.resume = bt8xxgpio_resume,
|
||||
.driver.pm = &bt8xxgpio_pm_ops,
|
||||
};
|
||||
|
||||
module_pci_driver(bt8xxgpio_pci_driver);
|
||||
|
|
|
|||
|
|
@ -79,7 +79,6 @@ struct dwapb_platform_data {
|
|||
unsigned int nports;
|
||||
};
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
/* Store GPIO context across system-wide suspend/resume transitions */
|
||||
struct dwapb_context {
|
||||
u32 data;
|
||||
|
|
@ -92,7 +91,6 @@ struct dwapb_context {
|
|||
u32 int_deb;
|
||||
u32 wake_en;
|
||||
};
|
||||
#endif
|
||||
|
||||
struct dwapb_gpio_port_irqchip {
|
||||
unsigned int nr_irqs;
|
||||
|
|
@ -103,9 +101,7 @@ struct dwapb_gpio_port {
|
|||
struct gpio_generic_chip chip;
|
||||
struct dwapb_gpio_port_irqchip *pirq;
|
||||
struct dwapb_gpio *gpio;
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
struct dwapb_context *ctx;
|
||||
#endif
|
||||
unsigned int idx;
|
||||
};
|
||||
|
||||
|
|
@ -363,7 +359,6 @@ static int dwapb_irq_set_type(struct irq_data *d, u32 type)
|
|||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int dwapb_irq_set_wake(struct irq_data *d, unsigned int enable)
|
||||
{
|
||||
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
|
||||
|
|
@ -378,9 +373,6 @@ static int dwapb_irq_set_wake(struct irq_data *d, unsigned int enable)
|
|||
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
#define dwapb_irq_set_wake NULL
|
||||
#endif
|
||||
|
||||
static const struct irq_chip dwapb_irq_chip = {
|
||||
.name = DWAPB_DRIVER_NAME,
|
||||
|
|
@ -390,7 +382,7 @@ static const struct irq_chip dwapb_irq_chip = {
|
|||
.irq_set_type = dwapb_irq_set_type,
|
||||
.irq_enable = dwapb_irq_enable,
|
||||
.irq_disable = dwapb_irq_disable,
|
||||
.irq_set_wake = dwapb_irq_set_wake,
|
||||
.irq_set_wake = pm_sleep_ptr(dwapb_irq_set_wake),
|
||||
.flags = IRQCHIP_IMMUTABLE,
|
||||
GPIOCHIP_IRQ_RESOURCE_HELPERS,
|
||||
};
|
||||
|
|
@ -759,7 +751,6 @@ static int dwapb_gpio_probe(struct platform_device *pdev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int dwapb_gpio_suspend(struct device *dev)
|
||||
{
|
||||
struct dwapb_gpio *gpio = dev_get_drvdata(dev);
|
||||
|
|
@ -844,15 +835,14 @@ static int dwapb_gpio_resume(struct device *dev)
|
|||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(dwapb_gpio_pm_ops, dwapb_gpio_suspend,
|
||||
dwapb_gpio_resume);
|
||||
static DEFINE_SIMPLE_DEV_PM_OPS(dwapb_gpio_pm_ops,
|
||||
dwapb_gpio_suspend, dwapb_gpio_resume);
|
||||
|
||||
static struct platform_driver dwapb_gpio_driver = {
|
||||
.driver = {
|
||||
.name = DWAPB_DRIVER_NAME,
|
||||
.pm = &dwapb_gpio_pm_ops,
|
||||
.pm = pm_sleep_ptr(&dwapb_gpio_pm_ops),
|
||||
.of_match_table = dwapb_of_match,
|
||||
.acpi_match_table = dwapb_acpi_match,
|
||||
},
|
||||
|
|
|
|||
|
|
@ -2,43 +2,46 @@
|
|||
/*
|
||||
* Intel Elkhart Lake PSE GPIO driver
|
||||
*
|
||||
* Copyright (c) 2023 Intel Corporation.
|
||||
* Copyright (c) 2023, 2025 Intel Corporation.
|
||||
*
|
||||
* Authors: Pandith N <pandith.n@intel.com>
|
||||
* Raag Jadav <raag.jadav@intel.com>
|
||||
*/
|
||||
|
||||
#include <linux/auxiliary_bus.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pm.h>
|
||||
|
||||
#include <linux/ehl_pse_io_aux.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)
|
||||
static int ehl_gpio_probe(struct auxiliary_device *adev, const struct auxiliary_device_id *id)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct device *dev = &adev->dev;
|
||||
struct ehl_pse_io_data *data;
|
||||
struct tng_gpio *priv;
|
||||
int irq, ret;
|
||||
int ret;
|
||||
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq < 0)
|
||||
return irq;
|
||||
data = dev_get_platdata(dev);
|
||||
if (!data)
|
||||
return -ENODATA;
|
||||
|
||||
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
|
||||
priv->reg_base = devm_platform_ioremap_resource(pdev, 0);
|
||||
priv->reg_base = devm_ioremap_resource(dev, &data->mem);
|
||||
if (IS_ERR(priv->reg_base))
|
||||
return PTR_ERR(priv->reg_base);
|
||||
|
||||
priv->dev = dev;
|
||||
priv->irq = irq;
|
||||
priv->irq = data->irq;
|
||||
|
||||
priv->info.base = -1;
|
||||
priv->info.ngpio = EHL_PSE_NGPIO;
|
||||
|
|
@ -51,25 +54,24 @@ static int ehl_gpio_probe(struct platform_device *pdev)
|
|||
if (ret)
|
||||
return dev_err_probe(dev, ret, "tng_gpio_probe error\n");
|
||||
|
||||
platform_set_drvdata(pdev, priv);
|
||||
auxiliary_set_drvdata(adev, priv);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct platform_device_id ehl_gpio_ids[] = {
|
||||
{ "gpio-elkhartlake" },
|
||||
static const struct auxiliary_device_id ehl_gpio_ids[] = {
|
||||
{ EHL_PSE_IO_NAME "." EHL_PSE_GPIO_NAME },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(platform, ehl_gpio_ids);
|
||||
MODULE_DEVICE_TABLE(auxiliary, ehl_gpio_ids);
|
||||
|
||||
static struct platform_driver ehl_gpio_driver = {
|
||||
static struct auxiliary_driver ehl_gpio_driver = {
|
||||
.driver = {
|
||||
.name = "gpio-elkhartlake",
|
||||
.pm = pm_sleep_ptr(&tng_gpio_pm_ops),
|
||||
},
|
||||
.probe = ehl_gpio_probe,
|
||||
.id_table = ehl_gpio_ids,
|
||||
};
|
||||
module_platform_driver(ehl_gpio_driver);
|
||||
module_auxiliary_driver(ehl_gpio_driver);
|
||||
|
||||
MODULE_AUTHOR("Pandith N <pandith.n@intel.com>");
|
||||
MODULE_AUTHOR("Raag Jadav <raag.jadav@intel.com>");
|
||||
|
|
|
|||
|
|
@ -123,6 +123,8 @@ static int fxl6408_probe(struct i2c_client *client)
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
i2c_set_clientdata(client, gpio_config.regmap);
|
||||
|
||||
/* 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)
|
||||
|
|
@ -131,6 +133,16 @@ static int fxl6408_probe(struct i2c_client *client)
|
|||
return PTR_ERR_OR_ZERO(devm_gpio_regmap_register(dev, &gpio_config));
|
||||
}
|
||||
|
||||
static int fxl6408_resume(struct device *dev)
|
||||
{
|
||||
struct regmap *regmap = dev_get_drvdata(dev);
|
||||
|
||||
regcache_mark_dirty(regmap);
|
||||
return regcache_sync(regmap);
|
||||
}
|
||||
|
||||
static DEFINE_SIMPLE_DEV_PM_OPS(fxl6408_pm_ops, NULL, fxl6408_resume);
|
||||
|
||||
static const __maybe_unused struct of_device_id fxl6408_dt_ids[] = {
|
||||
{ .compatible = "fcs,fxl6408" },
|
||||
{ }
|
||||
|
|
@ -146,6 +158,7 @@ MODULE_DEVICE_TABLE(i2c, fxl6408_id);
|
|||
static struct i2c_driver fxl6408_driver = {
|
||||
.driver = {
|
||||
.name = "fxl6408",
|
||||
.pm = pm_sleep_ptr(&fxl6408_pm_ops),
|
||||
.of_match_table = fxl6408_dt_ids,
|
||||
},
|
||||
.probe = fxl6408_probe,
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@
|
|||
|
||||
/* Structure for an irq of the core - called an underlying irq */
|
||||
struct grgpio_uirq {
|
||||
u8 refcnt; /* Reference counter to manage requesting/freeing of uirq */
|
||||
atomic_t refcnt; /* Reference counter to manage requesting/freeing of uirq */
|
||||
u8 uirq; /* Underlying irq of the gpio driver */
|
||||
};
|
||||
|
||||
|
|
@ -242,30 +242,22 @@ static int grgpio_irq_map(struct irq_domain *d, unsigned int irq,
|
|||
irq, offset);
|
||||
|
||||
gpio_generic_chip_lock_irqsave(&priv->chip, flags);
|
||||
|
||||
/* Request underlying irq if not already requested */
|
||||
lirq->irq = irq;
|
||||
uirq = &priv->uirqs[lirq->index];
|
||||
if (uirq->refcnt == 0) {
|
||||
/*
|
||||
* FIXME: This is not how locking works at all, you can't just
|
||||
* release the lock for a moment to do something that can't
|
||||
* sleep...
|
||||
*/
|
||||
gpio_generic_chip_unlock_irqrestore(&priv->chip, flags);
|
||||
gpio_generic_chip_unlock_irqrestore(&priv->chip, flags);
|
||||
|
||||
/* Request underlying irq if not already requested */
|
||||
if (atomic_fetch_add(1, &uirq->refcnt) == 0) {
|
||||
ret = request_irq(uirq->uirq, grgpio_irq_handler, 0,
|
||||
dev_name(priv->dev), priv);
|
||||
if (ret) {
|
||||
dev_err(priv->dev,
|
||||
"Could not request underlying irq %d\n",
|
||||
uirq->uirq);
|
||||
atomic_dec(&uirq->refcnt); /* rollback */
|
||||
return ret;
|
||||
}
|
||||
gpio_generic_chip_lock_irqsave(&priv->chip, flags);
|
||||
}
|
||||
uirq->refcnt++;
|
||||
|
||||
gpio_generic_chip_unlock_irqrestore(&priv->chip, flags);
|
||||
|
||||
/* Setup irq */
|
||||
irq_set_chip_data(irq, priv);
|
||||
|
|
@ -306,8 +298,7 @@ static void grgpio_irq_unmap(struct irq_domain *d, unsigned int irq)
|
|||
|
||||
if (index >= 0) {
|
||||
uirq = &priv->uirqs[lirq->index];
|
||||
uirq->refcnt--;
|
||||
if (uirq->refcnt == 0) {
|
||||
if (atomic_dec_and_test(&uirq->refcnt)) {
|
||||
gpio_generic_chip_unlock_irqrestore(&priv->chip, flags);
|
||||
free_irq(uirq->uirq, priv);
|
||||
return;
|
||||
|
|
@ -434,6 +425,7 @@ static int grgpio_probe(struct platform_device *ofdev)
|
|||
continue;
|
||||
}
|
||||
priv->uirqs[lirq->index].uirq = ret;
|
||||
atomic_set(&priv->uirqs[lirq->index].refcnt, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -364,21 +364,20 @@ static int __init egpio_probe(struct platform_device *pdev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int egpio_suspend(struct platform_device *pdev, pm_message_t state)
|
||||
static int egpio_suspend(struct device *dev)
|
||||
{
|
||||
struct egpio_info *ei = platform_get_drvdata(pdev);
|
||||
struct egpio_info *ei = dev_get_drvdata(dev);
|
||||
|
||||
if (ei->chained_irq && device_may_wakeup(&pdev->dev))
|
||||
if (ei->chained_irq && device_may_wakeup(dev))
|
||||
enable_irq_wake(ei->chained_irq);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int egpio_resume(struct platform_device *pdev)
|
||||
static int egpio_resume(struct device *dev)
|
||||
{
|
||||
struct egpio_info *ei = platform_get_drvdata(pdev);
|
||||
struct egpio_info *ei = dev_get_drvdata(dev);
|
||||
|
||||
if (ei->chained_irq && device_may_wakeup(&pdev->dev))
|
||||
if (ei->chained_irq && device_may_wakeup(dev))
|
||||
disable_irq_wake(ei->chained_irq);
|
||||
|
||||
/* Update registers from the cache, in case
|
||||
|
|
@ -386,19 +385,15 @@ static int egpio_resume(struct platform_device *pdev)
|
|||
egpio_write_cache(ei);
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
#define egpio_suspend NULL
|
||||
#define egpio_resume NULL
|
||||
#endif
|
||||
|
||||
static DEFINE_SIMPLE_DEV_PM_OPS(egpio_pm_ops, egpio_suspend, egpio_resume);
|
||||
|
||||
static struct platform_driver egpio_driver = {
|
||||
.driver = {
|
||||
.name = "htc-egpio",
|
||||
.suppress_bind_attrs = true,
|
||||
.pm = pm_sleep_ptr(&egpio_pm_ops),
|
||||
},
|
||||
.suspend = egpio_suspend,
|
||||
.resume = egpio_resume,
|
||||
};
|
||||
|
||||
static int __init egpio_init(void)
|
||||
|
|
|
|||
|
|
@ -48,8 +48,6 @@
|
|||
#include <linux/property.h>
|
||||
#include <linux/delay.h>
|
||||
|
||||
#include "gpiolib.h"
|
||||
|
||||
struct gpio_latch_priv {
|
||||
struct gpio_chip gc;
|
||||
struct gpio_descs *clk_gpios;
|
||||
|
|
|
|||
|
|
@ -312,6 +312,7 @@ static int loongson_gpio_init(struct platform_device *pdev, struct loongson_gpio
|
|||
lgpio->chip.gc.direction_output = loongson_gpio_direction_output;
|
||||
lgpio->chip.gc.set = loongson_gpio_set;
|
||||
lgpio->chip.gc.parent = &pdev->dev;
|
||||
lgpio->chip.gc.base = -1;
|
||||
spin_lock_init(&lgpio->lock);
|
||||
}
|
||||
|
||||
|
|
@ -407,11 +408,11 @@ static const struct loongson_gpio_chip_data loongson_gpio_ls2k2000_data0 = {
|
|||
|
||||
static const struct loongson_gpio_chip_data loongson_gpio_ls2k2000_data1 = {
|
||||
.label = "ls2k2000_gpio",
|
||||
.mode = BIT_CTRL_MODE,
|
||||
.conf_offset = 0x0,
|
||||
.in_offset = 0x20,
|
||||
.out_offset = 0x10,
|
||||
.inten_offset = 0x30,
|
||||
.mode = BYTE_CTRL_MODE,
|
||||
.conf_offset = 0x800,
|
||||
.in_offset = 0xa00,
|
||||
.out_offset = 0x900,
|
||||
.inten_offset = 0xb00,
|
||||
};
|
||||
|
||||
static const struct loongson_gpio_chip_data loongson_gpio_ls2k2000_data2 = {
|
||||
|
|
|
|||
|
|
@ -24,6 +24,11 @@
|
|||
#define MEN_Z127_ODER 0x1C
|
||||
#define GPIO_TO_DBCNT_REG(gpio) ((gpio * 4) + 0x80)
|
||||
|
||||
/* MEN Z127 supported model ids*/
|
||||
#define MEN_Z127_ID 0x7f
|
||||
#define MEN_Z034_ID 0x22
|
||||
#define MEN_Z037_ID 0x25
|
||||
|
||||
#define MEN_Z127_DB_MIN_US 50
|
||||
/* 16 bit compare register. Each bit represents 50us */
|
||||
#define MEN_Z127_DB_MAX_US (0xffff * MEN_Z127_DB_MIN_US)
|
||||
|
|
@ -140,6 +145,7 @@ static int men_z127_probe(struct mcb_device *mdev,
|
|||
struct men_z127_gpio *men_z127_gpio;
|
||||
struct device *dev = &mdev->dev;
|
||||
int ret;
|
||||
unsigned long sz;
|
||||
|
||||
men_z127_gpio = devm_kzalloc(dev, sizeof(struct men_z127_gpio),
|
||||
GFP_KERNEL);
|
||||
|
|
@ -163,9 +169,21 @@ static int men_z127_probe(struct mcb_device *mdev,
|
|||
|
||||
mcb_set_drvdata(mdev, men_z127_gpio);
|
||||
|
||||
switch (mdev->id) {
|
||||
case MEN_Z127_ID:
|
||||
sz = 4;
|
||||
break;
|
||||
case MEN_Z034_ID:
|
||||
case MEN_Z037_ID:
|
||||
sz = 1;
|
||||
break;
|
||||
default:
|
||||
return dev_err_probe(&mdev->dev, -EINVAL, "no size found for id %d", mdev->id);
|
||||
}
|
||||
|
||||
config = (struct gpio_generic_chip_config) {
|
||||
.dev = &mdev->dev,
|
||||
.sz = 4,
|
||||
.sz = sz,
|
||||
.dat = men_z127_gpio->reg_base + MEN_Z127_PSR,
|
||||
.set = men_z127_gpio->reg_base + MEN_Z127_CTRL,
|
||||
.dirout = men_z127_gpio->reg_base + MEN_Z127_GPIODR,
|
||||
|
|
@ -186,7 +204,9 @@ static int men_z127_probe(struct mcb_device *mdev,
|
|||
}
|
||||
|
||||
static const struct mcb_device_id men_z127_ids[] = {
|
||||
{ .device = 0x7f },
|
||||
{ .device = MEN_Z127_ID },
|
||||
{ .device = MEN_Z034_ID },
|
||||
{ .device = MEN_Z037_ID },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(mcb, men_z127_ids);
|
||||
|
|
@ -201,7 +221,7 @@ static struct mcb_driver men_z127_driver = {
|
|||
module_mcb_driver(men_z127_driver);
|
||||
|
||||
MODULE_AUTHOR("Andreas Werner <andreas.werner@men.de>");
|
||||
MODULE_DESCRIPTION("MEN 16z127 GPIO Controller");
|
||||
MODULE_DESCRIPTION("MEN GPIO Controller");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_ALIAS("mcb:16z127");
|
||||
MODULE_IMPORT_NS("MCB");
|
||||
|
|
|
|||
|
|
@ -160,7 +160,7 @@ static int ioh_gpio_direction_input(struct gpio_chip *gpio, unsigned nr)
|
|||
/*
|
||||
* Save register configuration and disable interrupts.
|
||||
*/
|
||||
static void __maybe_unused ioh_gpio_save_reg_conf(struct ioh_gpio *chip)
|
||||
static void ioh_gpio_save_reg_conf(struct ioh_gpio *chip)
|
||||
{
|
||||
int i;
|
||||
|
||||
|
|
@ -186,7 +186,7 @@ static void __maybe_unused ioh_gpio_save_reg_conf(struct ioh_gpio *chip)
|
|||
/*
|
||||
* This function restores the register configuration of the GPIO device.
|
||||
*/
|
||||
static void __maybe_unused ioh_gpio_restore_reg_conf(struct ioh_gpio *chip)
|
||||
static void ioh_gpio_restore_reg_conf(struct ioh_gpio *chip)
|
||||
{
|
||||
int i;
|
||||
|
||||
|
|
@ -479,7 +479,7 @@ static int ioh_gpio_probe(struct pci_dev *pdev,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int __maybe_unused ioh_gpio_suspend(struct device *dev)
|
||||
static int ioh_gpio_suspend(struct device *dev)
|
||||
{
|
||||
struct ioh_gpio *chip = dev_get_drvdata(dev);
|
||||
unsigned long flags;
|
||||
|
|
@ -491,7 +491,7 @@ static int __maybe_unused ioh_gpio_suspend(struct device *dev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int __maybe_unused ioh_gpio_resume(struct device *dev)
|
||||
static int ioh_gpio_resume(struct device *dev)
|
||||
{
|
||||
struct ioh_gpio *chip = dev_get_drvdata(dev);
|
||||
unsigned long flags;
|
||||
|
|
@ -505,7 +505,7 @@ static int __maybe_unused ioh_gpio_resume(struct device *dev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(ioh_gpio_pm_ops, ioh_gpio_suspend, ioh_gpio_resume);
|
||||
static DEFINE_SIMPLE_DEV_PM_OPS(ioh_gpio_pm_ops, ioh_gpio_suspend, ioh_gpio_resume);
|
||||
|
||||
static const struct pci_device_id ioh_gpio_pcidev_id[] = {
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_ROHM, 0x802E) },
|
||||
|
|
@ -518,7 +518,7 @@ static struct pci_driver ioh_gpio_driver = {
|
|||
.id_table = ioh_gpio_pcidev_id,
|
||||
.probe = ioh_gpio_probe,
|
||||
.driver = {
|
||||
.pm = &ioh_gpio_pm_ops,
|
||||
.pm = pm_sleep_ptr(&ioh_gpio_pm_ops),
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -424,7 +424,7 @@ mlxbf2_gpio_probe(struct platform_device *pdev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int __maybe_unused mlxbf2_gpio_suspend(struct device *dev)
|
||||
static int mlxbf2_gpio_suspend(struct device *dev)
|
||||
{
|
||||
struct mlxbf2_gpio_context *gs = dev_get_drvdata(dev);
|
||||
|
||||
|
|
@ -436,7 +436,7 @@ static int __maybe_unused mlxbf2_gpio_suspend(struct device *dev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int __maybe_unused mlxbf2_gpio_resume(struct device *dev)
|
||||
static int mlxbf2_gpio_resume(struct device *dev)
|
||||
{
|
||||
struct mlxbf2_gpio_context *gs = dev_get_drvdata(dev);
|
||||
|
||||
|
|
@ -447,7 +447,7 @@ static int __maybe_unused mlxbf2_gpio_resume(struct device *dev)
|
|||
|
||||
return 0;
|
||||
}
|
||||
static SIMPLE_DEV_PM_OPS(mlxbf2_pm_ops, mlxbf2_gpio_suspend, mlxbf2_gpio_resume);
|
||||
static DEFINE_SIMPLE_DEV_PM_OPS(mlxbf2_pm_ops, mlxbf2_gpio_suspend, mlxbf2_gpio_resume);
|
||||
|
||||
static const struct acpi_device_id __maybe_unused mlxbf2_gpio_acpi_match[] = {
|
||||
{ "MLNXBF22", 0 },
|
||||
|
|
@ -459,7 +459,7 @@ static struct platform_driver mlxbf2_gpio_driver = {
|
|||
.driver = {
|
||||
.name = "mlxbf2_gpio",
|
||||
.acpi_match_table = mlxbf2_gpio_acpi_match,
|
||||
.pm = &mlxbf2_pm_ops,
|
||||
.pm = pm_sleep_ptr(&mlxbf2_pm_ops),
|
||||
},
|
||||
.probe = mlxbf2_gpio_probe,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@
|
|||
#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/io.h>
|
||||
#include <linux/slab.h>
|
||||
|
|
@ -27,7 +26,8 @@
|
|||
#define LTQ_EBU_WP 0x80000000 /* write protect bit */
|
||||
|
||||
struct ltq_mm {
|
||||
struct of_mm_gpio_chip mmchip;
|
||||
struct gpio_chip gc;
|
||||
void __iomem *regs;
|
||||
u16 shadow; /* shadow the latches state */
|
||||
};
|
||||
|
||||
|
|
@ -44,7 +44,7 @@ static void ltq_mm_apply(struct ltq_mm *chip)
|
|||
|
||||
spin_lock_irqsave(&ebu_lock, flags);
|
||||
ltq_ebu_w32(LTQ_EBU_BUSCON, LTQ_EBU_BUSCON1);
|
||||
__raw_writew(chip->shadow, chip->mmchip.regs);
|
||||
__raw_writew(chip->shadow, chip->regs);
|
||||
ltq_ebu_w32(LTQ_EBU_BUSCON | LTQ_EBU_WP, LTQ_EBU_BUSCON1);
|
||||
spin_unlock_irqrestore(&ebu_lock, flags);
|
||||
}
|
||||
|
|
@ -52,8 +52,8 @@ static void ltq_mm_apply(struct ltq_mm *chip)
|
|||
/**
|
||||
* ltq_mm_set() - gpio_chip->set - set gpios.
|
||||
* @gc: Pointer to gpio_chip device structure.
|
||||
* @gpio: GPIO signal number.
|
||||
* @val: Value to be written to specified signal.
|
||||
* @offset: GPIO signal number.
|
||||
* @value: Value to be written to specified signal.
|
||||
*
|
||||
* Set the shadow value and call ltq_mm_apply. Always returns 0.
|
||||
*/
|
||||
|
|
@ -73,8 +73,8 @@ static int ltq_mm_set(struct gpio_chip *gc, unsigned int offset, int value)
|
|||
/**
|
||||
* ltq_mm_dir_out() - gpio_chip->dir_out - set gpio direction.
|
||||
* @gc: Pointer to gpio_chip device structure.
|
||||
* @gpio: GPIO signal number.
|
||||
* @val: Value to be written to specified signal.
|
||||
* @offset: GPIO signal number.
|
||||
* @value: Value to be written to specified signal.
|
||||
*
|
||||
* Same as ltq_mm_set, always returns 0.
|
||||
*/
|
||||
|
|
@ -85,21 +85,21 @@ static int ltq_mm_dir_out(struct gpio_chip *gc, unsigned offset, int value)
|
|||
|
||||
/**
|
||||
* ltq_mm_save_regs() - Set initial values of GPIO pins
|
||||
* @mm_gc: pointer to memory mapped GPIO chip structure
|
||||
* @chip: Pointer to our private data structure.
|
||||
*/
|
||||
static void ltq_mm_save_regs(struct of_mm_gpio_chip *mm_gc)
|
||||
static void ltq_mm_save_regs(struct ltq_mm *chip)
|
||||
{
|
||||
struct ltq_mm *chip =
|
||||
container_of(mm_gc, struct ltq_mm, mmchip);
|
||||
|
||||
/* tell the ebu controller which memory address we will be using */
|
||||
ltq_ebu_w32(CPHYSADDR(chip->mmchip.regs) | 0x1, LTQ_EBU_ADDRSEL1);
|
||||
ltq_ebu_w32(CPHYSADDR((__force void *)chip->regs) | 0x1, LTQ_EBU_ADDRSEL1);
|
||||
|
||||
ltq_mm_apply(chip);
|
||||
}
|
||||
|
||||
static int ltq_mm_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct device_node *np = dev->of_node;
|
||||
struct gpio_chip *gc;
|
||||
struct ltq_mm *chip;
|
||||
u32 shadow;
|
||||
|
||||
|
|
@ -107,25 +107,29 @@ static int ltq_mm_probe(struct platform_device *pdev)
|
|||
if (!chip)
|
||||
return -ENOMEM;
|
||||
|
||||
platform_set_drvdata(pdev, chip);
|
||||
gc = &chip->gc;
|
||||
|
||||
chip->mmchip.gc.ngpio = 16;
|
||||
chip->mmchip.gc.direction_output = ltq_mm_dir_out;
|
||||
chip->mmchip.gc.set = ltq_mm_set;
|
||||
chip->mmchip.save_regs = ltq_mm_save_regs;
|
||||
gc->base = -1;
|
||||
gc->ngpio = 16;
|
||||
gc->direction_output = ltq_mm_dir_out;
|
||||
gc->set = ltq_mm_set;
|
||||
gc->parent = dev;
|
||||
gc->owner = THIS_MODULE;
|
||||
gc->label = devm_kasprintf(dev, GFP_KERNEL, "%pOF", np);
|
||||
if (!gc->label)
|
||||
return -ENOMEM;
|
||||
|
||||
chip->regs = devm_of_iomap(dev, np, 0, NULL);
|
||||
if (IS_ERR(chip->regs))
|
||||
return PTR_ERR(chip->regs);
|
||||
|
||||
ltq_mm_save_regs(chip);
|
||||
|
||||
/* store the shadow value if one was passed by the devicetree */
|
||||
if (!of_property_read_u32(pdev->dev.of_node, "lantiq,shadow", &shadow))
|
||||
chip->shadow = shadow;
|
||||
|
||||
return of_mm_gpiochip_add_data(pdev->dev.of_node, &chip->mmchip, chip);
|
||||
}
|
||||
|
||||
static void ltq_mm_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct ltq_mm *chip = platform_get_drvdata(pdev);
|
||||
|
||||
of_mm_gpiochip_remove(&chip->mmchip);
|
||||
return devm_gpiochip_add_data(dev, gc, chip);
|
||||
}
|
||||
|
||||
static const struct of_device_id ltq_mm_match[] = {
|
||||
|
|
@ -136,7 +140,6 @@ MODULE_DEVICE_TABLE(of, ltq_mm_match);
|
|||
|
||||
static struct platform_driver ltq_mm_driver = {
|
||||
.probe = ltq_mm_probe,
|
||||
.remove = ltq_mm_remove,
|
||||
.driver = {
|
||||
.name = "gpio-mm-ltq",
|
||||
.of_match_table = ltq_mm_match,
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@ o ` ~~~~\___/~~~~ ` controller in FPGA is ,.`
|
|||
*/
|
||||
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/cleanup.h>
|
||||
#include <linux/compiler.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/init.h>
|
||||
|
|
@ -61,69 +62,69 @@ o ` ~~~~\___/~~~~ ` controller in FPGA is ,.`
|
|||
|
||||
#include "gpiolib.h"
|
||||
|
||||
static void bgpio_write8(void __iomem *reg, unsigned long data)
|
||||
static void gpio_mmio_write8(void __iomem *reg, unsigned long data)
|
||||
{
|
||||
writeb(data, reg);
|
||||
}
|
||||
|
||||
static unsigned long bgpio_read8(void __iomem *reg)
|
||||
static unsigned long gpio_mmio_read8(void __iomem *reg)
|
||||
{
|
||||
return readb(reg);
|
||||
}
|
||||
|
||||
static void bgpio_write16(void __iomem *reg, unsigned long data)
|
||||
static void gpio_mmio_write16(void __iomem *reg, unsigned long data)
|
||||
{
|
||||
writew(data, reg);
|
||||
}
|
||||
|
||||
static unsigned long bgpio_read16(void __iomem *reg)
|
||||
static unsigned long gpio_mmio_read16(void __iomem *reg)
|
||||
{
|
||||
return readw(reg);
|
||||
}
|
||||
|
||||
static void bgpio_write32(void __iomem *reg, unsigned long data)
|
||||
static void gpio_mmio_write32(void __iomem *reg, unsigned long data)
|
||||
{
|
||||
writel(data, reg);
|
||||
}
|
||||
|
||||
static unsigned long bgpio_read32(void __iomem *reg)
|
||||
static unsigned long gpio_mmio_read32(void __iomem *reg)
|
||||
{
|
||||
return readl(reg);
|
||||
}
|
||||
|
||||
#if BITS_PER_LONG >= 64
|
||||
static void bgpio_write64(void __iomem *reg, unsigned long data)
|
||||
static void gpio_mmio_write64(void __iomem *reg, unsigned long data)
|
||||
{
|
||||
writeq(data, reg);
|
||||
}
|
||||
|
||||
static unsigned long bgpio_read64(void __iomem *reg)
|
||||
static unsigned long gpio_mmio_read64(void __iomem *reg)
|
||||
{
|
||||
return readq(reg);
|
||||
}
|
||||
#endif /* BITS_PER_LONG >= 64 */
|
||||
|
||||
static void bgpio_write16be(void __iomem *reg, unsigned long data)
|
||||
static void gpio_mmio_write16be(void __iomem *reg, unsigned long data)
|
||||
{
|
||||
iowrite16be(data, reg);
|
||||
}
|
||||
|
||||
static unsigned long bgpio_read16be(void __iomem *reg)
|
||||
static unsigned long gpio_mmio_read16be(void __iomem *reg)
|
||||
{
|
||||
return ioread16be(reg);
|
||||
}
|
||||
|
||||
static void bgpio_write32be(void __iomem *reg, unsigned long data)
|
||||
static void gpio_mmio_write32be(void __iomem *reg, unsigned long data)
|
||||
{
|
||||
iowrite32be(data, reg);
|
||||
}
|
||||
|
||||
static unsigned long bgpio_read32be(void __iomem *reg)
|
||||
static unsigned long gpio_mmio_read32be(void __iomem *reg)
|
||||
{
|
||||
return ioread32be(reg);
|
||||
}
|
||||
|
||||
static unsigned long bgpio_line2mask(struct gpio_chip *gc, unsigned int line)
|
||||
static unsigned long gpio_mmio_line2mask(struct gpio_chip *gc, unsigned int line)
|
||||
{
|
||||
struct gpio_generic_chip *chip = to_gpio_generic_chip(gc);
|
||||
|
||||
|
|
@ -132,10 +133,10 @@ static unsigned long bgpio_line2mask(struct gpio_chip *gc, unsigned int line)
|
|||
return BIT(line);
|
||||
}
|
||||
|
||||
static int bgpio_get_set(struct gpio_chip *gc, unsigned int gpio)
|
||||
static int gpio_mmio_get_set(struct gpio_chip *gc, unsigned int gpio)
|
||||
{
|
||||
struct gpio_generic_chip *chip = to_gpio_generic_chip(gc);
|
||||
unsigned long pinmask = bgpio_line2mask(gc, gpio);
|
||||
unsigned long pinmask = gpio_mmio_line2mask(gc, gpio);
|
||||
bool dir = !!(chip->sdir & pinmask);
|
||||
|
||||
if (dir)
|
||||
|
|
@ -148,8 +149,8 @@ static int bgpio_get_set(struct gpio_chip *gc, unsigned int gpio)
|
|||
* This assumes that the bits in the GPIO register are in native endianness.
|
||||
* We only assign the function pointer if we have that.
|
||||
*/
|
||||
static int bgpio_get_set_multiple(struct gpio_chip *gc, unsigned long *mask,
|
||||
unsigned long *bits)
|
||||
static int gpio_mmio_get_set_multiple(struct gpio_chip *gc, unsigned long *mask,
|
||||
unsigned long *bits)
|
||||
{
|
||||
struct gpio_generic_chip *chip = to_gpio_generic_chip(gc);
|
||||
unsigned long get_mask = 0, set_mask = 0;
|
||||
|
|
@ -168,18 +169,18 @@ static int bgpio_get_set_multiple(struct gpio_chip *gc, unsigned long *mask,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int bgpio_get(struct gpio_chip *gc, unsigned int gpio)
|
||||
static int gpio_mmio_get(struct gpio_chip *gc, unsigned int gpio)
|
||||
{
|
||||
struct gpio_generic_chip *chip = to_gpio_generic_chip(gc);
|
||||
|
||||
return !!(chip->read_reg(chip->reg_dat) & bgpio_line2mask(gc, gpio));
|
||||
return !!(chip->read_reg(chip->reg_dat) & gpio_mmio_line2mask(gc, gpio));
|
||||
}
|
||||
|
||||
/*
|
||||
* This only works if the bits in the GPIO register are in native endianness.
|
||||
*/
|
||||
static int bgpio_get_multiple(struct gpio_chip *gc, unsigned long *mask,
|
||||
unsigned long *bits)
|
||||
static int gpio_mmio_get_multiple(struct gpio_chip *gc, unsigned long *mask,
|
||||
unsigned long *bits)
|
||||
{
|
||||
struct gpio_generic_chip *chip = to_gpio_generic_chip(gc);
|
||||
|
||||
|
|
@ -192,8 +193,8 @@ static int bgpio_get_multiple(struct gpio_chip *gc, unsigned long *mask,
|
|||
/*
|
||||
* With big endian mirrored bit order it becomes more tedious.
|
||||
*/
|
||||
static int bgpio_get_multiple_be(struct gpio_chip *gc, unsigned long *mask,
|
||||
unsigned long *bits)
|
||||
static int gpio_mmio_get_multiple_be(struct gpio_chip *gc, unsigned long *mask,
|
||||
unsigned long *bits)
|
||||
{
|
||||
struct gpio_generic_chip *chip = to_gpio_generic_chip(gc);
|
||||
unsigned long readmask = 0;
|
||||
|
|
@ -205,7 +206,7 @@ static int bgpio_get_multiple_be(struct gpio_chip *gc, unsigned long *mask,
|
|||
|
||||
/* Create a mirrored mask */
|
||||
for_each_set_bit(bit, mask, gc->ngpio)
|
||||
readmask |= bgpio_line2mask(gc, bit);
|
||||
readmask |= gpio_mmio_line2mask(gc, bit);
|
||||
|
||||
/* Read the register */
|
||||
val = chip->read_reg(chip->reg_dat) & readmask;
|
||||
|
|
@ -215,23 +216,22 @@ static int bgpio_get_multiple_be(struct gpio_chip *gc, unsigned long *mask,
|
|||
* in bit 0 ... line 31 in bit 31 for a 32bit register.
|
||||
*/
|
||||
for_each_set_bit(bit, &val, gc->ngpio)
|
||||
*bits |= bgpio_line2mask(gc, bit);
|
||||
*bits |= gpio_mmio_line2mask(gc, bit);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bgpio_set_none(struct gpio_chip *gc, unsigned int gpio, int val)
|
||||
static int gpio_mmio_set_none(struct gpio_chip *gc, unsigned int gpio, int val)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bgpio_set(struct gpio_chip *gc, unsigned int gpio, int val)
|
||||
static int gpio_mmio_set(struct gpio_chip *gc, unsigned int gpio, int val)
|
||||
{
|
||||
struct gpio_generic_chip *chip = to_gpio_generic_chip(gc);
|
||||
unsigned long mask = bgpio_line2mask(gc, gpio);
|
||||
unsigned long flags;
|
||||
unsigned long mask = gpio_mmio_line2mask(gc, gpio);
|
||||
|
||||
raw_spin_lock_irqsave(&chip->lock, flags);
|
||||
guard(raw_spinlock)(&chip->lock);
|
||||
|
||||
if (val)
|
||||
chip->sdata |= mask;
|
||||
|
|
@ -240,16 +240,14 @@ static int bgpio_set(struct gpio_chip *gc, unsigned int gpio, int val)
|
|||
|
||||
chip->write_reg(chip->reg_dat, chip->sdata);
|
||||
|
||||
raw_spin_unlock_irqrestore(&chip->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bgpio_set_with_clear(struct gpio_chip *gc, unsigned int gpio,
|
||||
int val)
|
||||
static int gpio_mmio_set_with_clear(struct gpio_chip *gc, unsigned int gpio,
|
||||
int val)
|
||||
{
|
||||
struct gpio_generic_chip *chip = to_gpio_generic_chip(gc);
|
||||
unsigned long mask = bgpio_line2mask(gc, gpio);
|
||||
unsigned long mask = gpio_mmio_line2mask(gc, gpio);
|
||||
|
||||
if (val)
|
||||
chip->write_reg(chip->reg_set, mask);
|
||||
|
|
@ -259,12 +257,12 @@ static int bgpio_set_with_clear(struct gpio_chip *gc, unsigned int gpio,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int bgpio_set_set(struct gpio_chip *gc, unsigned int gpio, int val)
|
||||
static int gpio_mmio_set_set(struct gpio_chip *gc, unsigned int gpio, int val)
|
||||
{
|
||||
struct gpio_generic_chip *chip = to_gpio_generic_chip(gc);
|
||||
unsigned long mask = bgpio_line2mask(gc, gpio), flags;
|
||||
unsigned long mask = gpio_mmio_line2mask(gc, gpio);
|
||||
|
||||
raw_spin_lock_irqsave(&chip->lock, flags);
|
||||
guard(raw_spinlock)(&chip->lock);
|
||||
|
||||
if (val)
|
||||
chip->sdata |= mask;
|
||||
|
|
@ -273,15 +271,14 @@ static int bgpio_set_set(struct gpio_chip *gc, unsigned int gpio, int val)
|
|||
|
||||
chip->write_reg(chip->reg_set, chip->sdata);
|
||||
|
||||
raw_spin_unlock_irqrestore(&chip->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void bgpio_multiple_get_masks(struct gpio_chip *gc,
|
||||
unsigned long *mask, unsigned long *bits,
|
||||
unsigned long *set_mask,
|
||||
unsigned long *clear_mask)
|
||||
static void gpio_mmio_multiple_get_masks(struct gpio_chip *gc,
|
||||
unsigned long *mask,
|
||||
unsigned long *bits,
|
||||
unsigned long *set_mask,
|
||||
unsigned long *clear_mask)
|
||||
{
|
||||
struct gpio_generic_chip *chip = to_gpio_generic_chip(gc);
|
||||
int i;
|
||||
|
|
@ -291,60 +288,58 @@ static void bgpio_multiple_get_masks(struct gpio_chip *gc,
|
|||
|
||||
for_each_set_bit(i, mask, chip->bits) {
|
||||
if (test_bit(i, bits))
|
||||
*set_mask |= bgpio_line2mask(gc, i);
|
||||
*set_mask |= gpio_mmio_line2mask(gc, i);
|
||||
else
|
||||
*clear_mask |= bgpio_line2mask(gc, i);
|
||||
*clear_mask |= gpio_mmio_line2mask(gc, i);
|
||||
}
|
||||
}
|
||||
|
||||
static void bgpio_set_multiple_single_reg(struct gpio_chip *gc,
|
||||
unsigned long *mask,
|
||||
unsigned long *bits,
|
||||
void __iomem *reg)
|
||||
static void gpio_mmio_set_multiple_single_reg(struct gpio_chip *gc,
|
||||
unsigned long *mask,
|
||||
unsigned long *bits,
|
||||
void __iomem *reg)
|
||||
{
|
||||
struct gpio_generic_chip *chip = to_gpio_generic_chip(gc);
|
||||
unsigned long flags, set_mask, clear_mask;
|
||||
unsigned long set_mask, clear_mask;
|
||||
|
||||
raw_spin_lock_irqsave(&chip->lock, flags);
|
||||
guard(raw_spinlock)(&chip->lock);
|
||||
|
||||
bgpio_multiple_get_masks(gc, mask, bits, &set_mask, &clear_mask);
|
||||
gpio_mmio_multiple_get_masks(gc, mask, bits, &set_mask, &clear_mask);
|
||||
|
||||
chip->sdata |= set_mask;
|
||||
chip->sdata &= ~clear_mask;
|
||||
|
||||
chip->write_reg(reg, chip->sdata);
|
||||
|
||||
raw_spin_unlock_irqrestore(&chip->lock, flags);
|
||||
}
|
||||
|
||||
static int bgpio_set_multiple(struct gpio_chip *gc, unsigned long *mask,
|
||||
unsigned long *bits)
|
||||
{
|
||||
struct gpio_generic_chip *chip = to_gpio_generic_chip(gc);
|
||||
|
||||
bgpio_set_multiple_single_reg(gc, mask, bits, chip->reg_dat);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bgpio_set_multiple_set(struct gpio_chip *gc, unsigned long *mask,
|
||||
static int gpio_mmio_set_multiple(struct gpio_chip *gc, unsigned long *mask,
|
||||
unsigned long *bits)
|
||||
{
|
||||
struct gpio_generic_chip *chip = to_gpio_generic_chip(gc);
|
||||
|
||||
bgpio_set_multiple_single_reg(gc, mask, bits, chip->reg_set);
|
||||
gpio_mmio_set_multiple_single_reg(gc, mask, bits, chip->reg_dat);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bgpio_set_multiple_with_clear(struct gpio_chip *gc,
|
||||
unsigned long *mask,
|
||||
unsigned long *bits)
|
||||
static int gpio_mmio_set_multiple_set(struct gpio_chip *gc, unsigned long *mask,
|
||||
unsigned long *bits)
|
||||
{
|
||||
struct gpio_generic_chip *chip = to_gpio_generic_chip(gc);
|
||||
|
||||
gpio_mmio_set_multiple_single_reg(gc, mask, bits, chip->reg_set);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gpio_mmio_set_multiple_with_clear(struct gpio_chip *gc,
|
||||
unsigned long *mask,
|
||||
unsigned long *bits)
|
||||
{
|
||||
struct gpio_generic_chip *chip = to_gpio_generic_chip(gc);
|
||||
unsigned long set_mask, clear_mask;
|
||||
|
||||
bgpio_multiple_get_masks(gc, mask, bits, &set_mask, &clear_mask);
|
||||
gpio_mmio_multiple_get_masks(gc, mask, bits, &set_mask, &clear_mask);
|
||||
|
||||
if (set_mask)
|
||||
chip->write_reg(chip->reg_set, set_mask);
|
||||
|
|
@ -354,7 +349,8 @@ static int bgpio_set_multiple_with_clear(struct gpio_chip *gc,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int bgpio_dir_return(struct gpio_chip *gc, unsigned int gpio, bool dir_out)
|
||||
static int gpio_mmio_dir_return(struct gpio_chip *gc, unsigned int gpio,
|
||||
bool dir_out)
|
||||
{
|
||||
struct gpio_generic_chip *chip = to_gpio_generic_chip(gc);
|
||||
|
||||
|
|
@ -367,131 +363,125 @@ static int bgpio_dir_return(struct gpio_chip *gc, unsigned int gpio, bool dir_ou
|
|||
return pinctrl_gpio_direction_input(gc, gpio);
|
||||
}
|
||||
|
||||
static int bgpio_dir_in_err(struct gpio_chip *gc, unsigned int gpio)
|
||||
static int gpio_mmio_dir_in_err(struct gpio_chip *gc, unsigned int gpio)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int bgpio_simple_dir_in(struct gpio_chip *gc, unsigned int gpio)
|
||||
static int gpio_mmio_simple_dir_in(struct gpio_chip *gc, unsigned int gpio)
|
||||
{
|
||||
return bgpio_dir_return(gc, gpio, false);
|
||||
return gpio_mmio_dir_return(gc, gpio, false);
|
||||
}
|
||||
|
||||
static int bgpio_dir_out_err(struct gpio_chip *gc, unsigned int gpio,
|
||||
int val)
|
||||
static int gpio_mmio_dir_out_err(struct gpio_chip *gc, unsigned int gpio,
|
||||
int val)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int bgpio_simple_dir_out(struct gpio_chip *gc, unsigned int gpio,
|
||||
int val)
|
||||
static int gpio_mmio_simple_dir_out(struct gpio_chip *gc, unsigned int gpio,
|
||||
int val)
|
||||
{
|
||||
gc->set(gc, gpio, val);
|
||||
|
||||
return bgpio_dir_return(gc, gpio, true);
|
||||
return gpio_mmio_dir_return(gc, gpio, true);
|
||||
}
|
||||
|
||||
static int bgpio_dir_in(struct gpio_chip *gc, unsigned int gpio)
|
||||
static int gpio_mmio_dir_in(struct gpio_chip *gc, unsigned int gpio)
|
||||
{
|
||||
struct gpio_generic_chip *chip = to_gpio_generic_chip(gc);
|
||||
unsigned long flags;
|
||||
|
||||
raw_spin_lock_irqsave(&chip->lock, flags);
|
||||
scoped_guard(raw_spinlock, &chip->lock) {
|
||||
chip->sdir &= ~gpio_mmio_line2mask(gc, gpio);
|
||||
|
||||
chip->sdir &= ~bgpio_line2mask(gc, gpio);
|
||||
if (chip->reg_dir_in)
|
||||
chip->write_reg(chip->reg_dir_in, ~chip->sdir);
|
||||
if (chip->reg_dir_out)
|
||||
chip->write_reg(chip->reg_dir_out, chip->sdir);
|
||||
}
|
||||
|
||||
if (chip->reg_dir_in)
|
||||
chip->write_reg(chip->reg_dir_in, ~chip->sdir);
|
||||
if (chip->reg_dir_out)
|
||||
chip->write_reg(chip->reg_dir_out, chip->sdir);
|
||||
|
||||
raw_spin_unlock_irqrestore(&chip->lock, flags);
|
||||
|
||||
return bgpio_dir_return(gc, gpio, false);
|
||||
return gpio_mmio_dir_return(gc, gpio, false);
|
||||
}
|
||||
|
||||
static int bgpio_get_dir(struct gpio_chip *gc, unsigned int gpio)
|
||||
static int gpio_mmio_get_dir(struct gpio_chip *gc, unsigned int gpio)
|
||||
{
|
||||
struct gpio_generic_chip *chip = to_gpio_generic_chip(gc);
|
||||
|
||||
/* Return 0 if output, 1 if input */
|
||||
if (chip->dir_unreadable) {
|
||||
if (chip->sdir & bgpio_line2mask(gc, gpio))
|
||||
if (chip->sdir & gpio_mmio_line2mask(gc, gpio))
|
||||
return GPIO_LINE_DIRECTION_OUT;
|
||||
return GPIO_LINE_DIRECTION_IN;
|
||||
}
|
||||
|
||||
if (chip->reg_dir_out) {
|
||||
if (chip->read_reg(chip->reg_dir_out) & bgpio_line2mask(gc, gpio))
|
||||
if (chip->read_reg(chip->reg_dir_out) & gpio_mmio_line2mask(gc, gpio))
|
||||
return GPIO_LINE_DIRECTION_OUT;
|
||||
return GPIO_LINE_DIRECTION_IN;
|
||||
}
|
||||
|
||||
if (chip->reg_dir_in)
|
||||
if (!(chip->read_reg(chip->reg_dir_in) & bgpio_line2mask(gc, gpio)))
|
||||
if (!(chip->read_reg(chip->reg_dir_in) & gpio_mmio_line2mask(gc, gpio)))
|
||||
return GPIO_LINE_DIRECTION_OUT;
|
||||
|
||||
return GPIO_LINE_DIRECTION_IN;
|
||||
}
|
||||
|
||||
static void bgpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val)
|
||||
static void gpio_mmio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val)
|
||||
{
|
||||
struct gpio_generic_chip *chip = to_gpio_generic_chip(gc);
|
||||
unsigned long flags;
|
||||
|
||||
raw_spin_lock_irqsave(&chip->lock, flags);
|
||||
guard(raw_spinlock)(&chip->lock);
|
||||
|
||||
chip->sdir |= bgpio_line2mask(gc, gpio);
|
||||
chip->sdir |= gpio_mmio_line2mask(gc, gpio);
|
||||
|
||||
if (chip->reg_dir_in)
|
||||
chip->write_reg(chip->reg_dir_in, ~chip->sdir);
|
||||
if (chip->reg_dir_out)
|
||||
chip->write_reg(chip->reg_dir_out, chip->sdir);
|
||||
|
||||
raw_spin_unlock_irqrestore(&chip->lock, flags);
|
||||
}
|
||||
|
||||
static int bgpio_dir_out_dir_first(struct gpio_chip *gc, unsigned int gpio,
|
||||
int val)
|
||||
static int gpio_mmio_dir_out_dir_first(struct gpio_chip *gc, unsigned int gpio,
|
||||
int val)
|
||||
{
|
||||
bgpio_dir_out(gc, gpio, val);
|
||||
gpio_mmio_dir_out(gc, gpio, val);
|
||||
gc->set(gc, gpio, val);
|
||||
return bgpio_dir_return(gc, gpio, true);
|
||||
return gpio_mmio_dir_return(gc, gpio, true);
|
||||
}
|
||||
|
||||
static int bgpio_dir_out_val_first(struct gpio_chip *gc, unsigned int gpio,
|
||||
int val)
|
||||
static int gpio_mmio_dir_out_val_first(struct gpio_chip *gc, unsigned int gpio,
|
||||
int val)
|
||||
{
|
||||
gc->set(gc, gpio, val);
|
||||
bgpio_dir_out(gc, gpio, val);
|
||||
return bgpio_dir_return(gc, gpio, true);
|
||||
gpio_mmio_dir_out(gc, gpio, val);
|
||||
return gpio_mmio_dir_return(gc, gpio, true);
|
||||
}
|
||||
|
||||
static int bgpio_setup_accessors(struct device *dev,
|
||||
struct gpio_generic_chip *chip,
|
||||
bool byte_be)
|
||||
static int gpio_mmio_setup_accessors(struct device *dev,
|
||||
struct gpio_generic_chip *chip,
|
||||
bool byte_be)
|
||||
{
|
||||
switch (chip->bits) {
|
||||
case 8:
|
||||
chip->read_reg = bgpio_read8;
|
||||
chip->write_reg = bgpio_write8;
|
||||
chip->read_reg = gpio_mmio_read8;
|
||||
chip->write_reg = gpio_mmio_write8;
|
||||
break;
|
||||
case 16:
|
||||
if (byte_be) {
|
||||
chip->read_reg = bgpio_read16be;
|
||||
chip->write_reg = bgpio_write16be;
|
||||
chip->read_reg = gpio_mmio_read16be;
|
||||
chip->write_reg = gpio_mmio_write16be;
|
||||
} else {
|
||||
chip->read_reg = bgpio_read16;
|
||||
chip->write_reg = bgpio_write16;
|
||||
chip->read_reg = gpio_mmio_read16;
|
||||
chip->write_reg = gpio_mmio_write16;
|
||||
}
|
||||
break;
|
||||
case 32:
|
||||
if (byte_be) {
|
||||
chip->read_reg = bgpio_read32be;
|
||||
chip->write_reg = bgpio_write32be;
|
||||
chip->read_reg = gpio_mmio_read32be;
|
||||
chip->write_reg = gpio_mmio_write32be;
|
||||
} else {
|
||||
chip->read_reg = bgpio_read32;
|
||||
chip->write_reg = bgpio_write32;
|
||||
chip->read_reg = gpio_mmio_read32;
|
||||
chip->write_reg = gpio_mmio_write32;
|
||||
}
|
||||
break;
|
||||
#if BITS_PER_LONG >= 64
|
||||
|
|
@ -501,8 +491,8 @@ static int bgpio_setup_accessors(struct device *dev,
|
|||
"64 bit big endian byte order unsupported\n");
|
||||
return -EINVAL;
|
||||
} else {
|
||||
chip->read_reg = bgpio_read64;
|
||||
chip->write_reg = bgpio_write64;
|
||||
chip->read_reg = gpio_mmio_read64;
|
||||
chip->write_reg = gpio_mmio_write64;
|
||||
}
|
||||
break;
|
||||
#endif /* BITS_PER_LONG >= 64 */
|
||||
|
|
@ -536,8 +526,8 @@ static int bgpio_setup_accessors(struct device *dev,
|
|||
* - an input direction register (named "dirin") where a 1 bit indicates
|
||||
* the GPIO is an input.
|
||||
*/
|
||||
static int bgpio_setup_io(struct gpio_generic_chip *chip,
|
||||
const struct gpio_generic_chip_config *cfg)
|
||||
static int gpio_mmio_setup_io(struct gpio_generic_chip *chip,
|
||||
const struct gpio_generic_chip_config *cfg)
|
||||
{
|
||||
struct gpio_chip *gc = &chip->gc;
|
||||
|
||||
|
|
@ -548,25 +538,25 @@ static int bgpio_setup_io(struct gpio_generic_chip *chip,
|
|||
if (cfg->set && cfg->clr) {
|
||||
chip->reg_set = cfg->set;
|
||||
chip->reg_clr = cfg->clr;
|
||||
gc->set = bgpio_set_with_clear;
|
||||
gc->set_multiple = bgpio_set_multiple_with_clear;
|
||||
gc->set = gpio_mmio_set_with_clear;
|
||||
gc->set_multiple = gpio_mmio_set_multiple_with_clear;
|
||||
} else if (cfg->set && !cfg->clr) {
|
||||
chip->reg_set = cfg->set;
|
||||
gc->set = bgpio_set_set;
|
||||
gc->set_multiple = bgpio_set_multiple_set;
|
||||
gc->set = gpio_mmio_set_set;
|
||||
gc->set_multiple = gpio_mmio_set_multiple_set;
|
||||
} else if (cfg->flags & GPIO_GENERIC_NO_OUTPUT) {
|
||||
gc->set = bgpio_set_none;
|
||||
gc->set = gpio_mmio_set_none;
|
||||
gc->set_multiple = NULL;
|
||||
} else {
|
||||
gc->set = bgpio_set;
|
||||
gc->set_multiple = bgpio_set_multiple;
|
||||
gc->set = gpio_mmio_set;
|
||||
gc->set_multiple = gpio_mmio_set_multiple;
|
||||
}
|
||||
|
||||
if (!(cfg->flags & GPIO_GENERIC_UNREADABLE_REG_SET) &&
|
||||
(cfg->flags & GPIO_GENERIC_READ_OUTPUT_REG_SET)) {
|
||||
gc->get = bgpio_get_set;
|
||||
gc->get = gpio_mmio_get_set;
|
||||
if (!chip->be_bits)
|
||||
gc->get_multiple = bgpio_get_set_multiple;
|
||||
gc->get_multiple = gpio_mmio_get_set_multiple;
|
||||
/*
|
||||
* We deliberately avoid assigning the ->get_multiple() call
|
||||
* for big endian mirrored registers which are ALSO reflecting
|
||||
|
|
@ -575,18 +565,18 @@ static int bgpio_setup_io(struct gpio_generic_chip *chip,
|
|||
* reading each line individually in that fringe case.
|
||||
*/
|
||||
} else {
|
||||
gc->get = bgpio_get;
|
||||
gc->get = gpio_mmio_get;
|
||||
if (chip->be_bits)
|
||||
gc->get_multiple = bgpio_get_multiple_be;
|
||||
gc->get_multiple = gpio_mmio_get_multiple_be;
|
||||
else
|
||||
gc->get_multiple = bgpio_get_multiple;
|
||||
gc->get_multiple = gpio_mmio_get_multiple;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bgpio_setup_direction(struct gpio_generic_chip *chip,
|
||||
const struct gpio_generic_chip_config *cfg)
|
||||
static int gpio_mmio_setup_direction(struct gpio_generic_chip *chip,
|
||||
const struct gpio_generic_chip_config *cfg)
|
||||
{
|
||||
struct gpio_chip *gc = &chip->gc;
|
||||
|
||||
|
|
@ -594,27 +584,27 @@ static int bgpio_setup_direction(struct gpio_generic_chip *chip,
|
|||
chip->reg_dir_out = cfg->dirout;
|
||||
chip->reg_dir_in = cfg->dirin;
|
||||
if (cfg->flags & GPIO_GENERIC_NO_SET_ON_INPUT)
|
||||
gc->direction_output = bgpio_dir_out_dir_first;
|
||||
gc->direction_output = gpio_mmio_dir_out_dir_first;
|
||||
else
|
||||
gc->direction_output = bgpio_dir_out_val_first;
|
||||
gc->direction_input = bgpio_dir_in;
|
||||
gc->get_direction = bgpio_get_dir;
|
||||
gc->direction_output = gpio_mmio_dir_out_val_first;
|
||||
gc->direction_input = gpio_mmio_dir_in;
|
||||
gc->get_direction = gpio_mmio_get_dir;
|
||||
} else {
|
||||
if (cfg->flags & GPIO_GENERIC_NO_OUTPUT)
|
||||
gc->direction_output = bgpio_dir_out_err;
|
||||
gc->direction_output = gpio_mmio_dir_out_err;
|
||||
else
|
||||
gc->direction_output = bgpio_simple_dir_out;
|
||||
gc->direction_output = gpio_mmio_simple_dir_out;
|
||||
|
||||
if (cfg->flags & GPIO_GENERIC_NO_INPUT)
|
||||
gc->direction_input = bgpio_dir_in_err;
|
||||
gc->direction_input = gpio_mmio_dir_in_err;
|
||||
else
|
||||
gc->direction_input = bgpio_simple_dir_in;
|
||||
gc->direction_input = gpio_mmio_simple_dir_in;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bgpio_request(struct gpio_chip *gc, unsigned int gpio_pin)
|
||||
static int gpio_mmio_request(struct gpio_chip *gc, unsigned int gpio_pin)
|
||||
{
|
||||
struct gpio_generic_chip *chip = to_gpio_generic_chip(gc);
|
||||
|
||||
|
|
@ -653,23 +643,23 @@ int gpio_generic_chip_init(struct gpio_generic_chip *chip,
|
|||
gc->parent = dev;
|
||||
gc->label = dev_name(dev);
|
||||
gc->base = -1;
|
||||
gc->request = bgpio_request;
|
||||
gc->request = gpio_mmio_request;
|
||||
chip->be_bits = !!(flags & GPIO_GENERIC_BIG_ENDIAN);
|
||||
|
||||
ret = gpiochip_get_ngpios(gc, dev);
|
||||
if (ret)
|
||||
gc->ngpio = chip->bits;
|
||||
|
||||
ret = bgpio_setup_io(chip, cfg);
|
||||
ret = gpio_mmio_setup_io(chip, cfg);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = bgpio_setup_accessors(dev, chip,
|
||||
ret = gpio_mmio_setup_accessors(dev, chip,
|
||||
flags & GPIO_GENERIC_BIG_ENDIAN_BYTE_ORDER);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = bgpio_setup_direction(chip, cfg);
|
||||
ret = gpio_mmio_setup_direction(chip, cfg);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
|
@ -680,7 +670,7 @@ int gpio_generic_chip_init(struct gpio_generic_chip *chip,
|
|||
}
|
||||
|
||||
chip->sdata = chip->read_reg(chip->reg_dat);
|
||||
if (gc->set == bgpio_set_set &&
|
||||
if (gc->set == gpio_mmio_set_set &&
|
||||
!(flags & GPIO_GENERIC_UNREADABLE_REG_SET))
|
||||
chip->sdata = chip->read_reg(chip->reg_set);
|
||||
|
||||
|
|
@ -712,9 +702,8 @@ EXPORT_SYMBOL_GPL(gpio_generic_chip_init);
|
|||
|
||||
#if IS_ENABLED(CONFIG_GPIO_GENERIC_PLATFORM)
|
||||
|
||||
static void __iomem *bgpio_map(struct platform_device *pdev,
|
||||
const char *name,
|
||||
resource_size_t sane_sz)
|
||||
static void __iomem *gpio_mmio_map(struct platform_device *pdev,
|
||||
const char *name, resource_size_t sane_sz)
|
||||
{
|
||||
struct resource *r;
|
||||
resource_size_t sz;
|
||||
|
|
@ -730,16 +719,16 @@ static void __iomem *bgpio_map(struct platform_device *pdev,
|
|||
return devm_ioremap_resource(&pdev->dev, r);
|
||||
}
|
||||
|
||||
static const struct of_device_id bgpio_of_match[] = {
|
||||
static const struct of_device_id gpio_mmio_of_match[] = {
|
||||
{ .compatible = "brcm,bcm6345-gpio" },
|
||||
{ .compatible = "wd,mbl-gpio" },
|
||||
{ .compatible = "ni,169445-nand-gpio" },
|
||||
{ .compatible = "intel,ixp4xx-expansion-bus-mmio-gpio" },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, bgpio_of_match);
|
||||
MODULE_DEVICE_TABLE(of, gpio_mmio_of_match);
|
||||
|
||||
static int bgpio_pdev_probe(struct platform_device *pdev)
|
||||
static int gpio_mmio_pdev_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct gpio_generic_chip_config config;
|
||||
struct gpio_generic_chip *gen_gc;
|
||||
|
|
@ -762,23 +751,23 @@ static int bgpio_pdev_probe(struct platform_device *pdev)
|
|||
|
||||
sz = resource_size(r);
|
||||
|
||||
dat = bgpio_map(pdev, "dat", sz);
|
||||
dat = gpio_mmio_map(pdev, "dat", sz);
|
||||
if (IS_ERR(dat))
|
||||
return PTR_ERR(dat);
|
||||
|
||||
set = bgpio_map(pdev, "set", sz);
|
||||
set = gpio_mmio_map(pdev, "set", sz);
|
||||
if (IS_ERR(set))
|
||||
return PTR_ERR(set);
|
||||
|
||||
clr = bgpio_map(pdev, "clr", sz);
|
||||
clr = gpio_mmio_map(pdev, "clr", sz);
|
||||
if (IS_ERR(clr))
|
||||
return PTR_ERR(clr);
|
||||
|
||||
dirout = bgpio_map(pdev, "dirout", sz);
|
||||
dirout = gpio_mmio_map(pdev, "dirout", sz);
|
||||
if (IS_ERR(dirout))
|
||||
return PTR_ERR(dirout);
|
||||
|
||||
dirin = bgpio_map(pdev, "dirin", sz);
|
||||
dirin = gpio_mmio_map(pdev, "dirin", sz);
|
||||
if (IS_ERR(dirin))
|
||||
return PTR_ERR(dirin);
|
||||
|
||||
|
|
@ -824,25 +813,25 @@ static int bgpio_pdev_probe(struct platform_device *pdev)
|
|||
return devm_gpiochip_add_data(&pdev->dev, &gen_gc->gc, NULL);
|
||||
}
|
||||
|
||||
static const struct platform_device_id bgpio_id_table[] = {
|
||||
static const struct platform_device_id gpio_mmio_id_table[] = {
|
||||
{
|
||||
.name = "basic-mmio-gpio",
|
||||
.driver_data = 0,
|
||||
},
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(platform, bgpio_id_table);
|
||||
MODULE_DEVICE_TABLE(platform, gpio_mmio_id_table);
|
||||
|
||||
static struct platform_driver bgpio_driver = {
|
||||
static struct platform_driver gpio_mmio_driver = {
|
||||
.driver = {
|
||||
.name = "basic-mmio-gpio",
|
||||
.of_match_table = bgpio_of_match,
|
||||
.of_match_table = gpio_mmio_of_match,
|
||||
},
|
||||
.id_table = bgpio_id_table,
|
||||
.probe = bgpio_pdev_probe,
|
||||
.id_table = gpio_mmio_id_table,
|
||||
.probe = gpio_mmio_pdev_probe,
|
||||
};
|
||||
|
||||
module_platform_driver(bgpio_driver);
|
||||
module_platform_driver(gpio_mmio_driver);
|
||||
|
||||
#endif /* CONFIG_GPIO_GENERIC_PLATFORM */
|
||||
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
#include <linux/cleanup.h>
|
||||
#include <linux/gpio/driver.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/usb.h>
|
||||
|
||||
struct mpsse_priv {
|
||||
|
|
@ -17,8 +18,10 @@ struct mpsse_priv {
|
|||
struct usb_device *udev; /* USB device encompassing all MPSSEs */
|
||||
struct usb_interface *intf; /* USB interface for this MPSSE */
|
||||
u8 intf_id; /* USB interface number for this MPSSE */
|
||||
struct work_struct irq_work; /* polling work thread */
|
||||
struct list_head workers; /* polling work threads */
|
||||
struct mutex irq_mutex; /* lock over irq_data */
|
||||
struct mutex irq_race; /* race for polling worker teardown */
|
||||
raw_spinlock_t irq_spin; /* protects worker list */
|
||||
atomic_t irq_type[16]; /* pin -> edge detection type */
|
||||
atomic_t irq_enabled;
|
||||
int id;
|
||||
|
|
@ -26,6 +29,9 @@ struct mpsse_priv {
|
|||
u8 gpio_outputs[2]; /* Output states for GPIOs [L, H] */
|
||||
u8 gpio_dir[2]; /* Directions for GPIOs [L, H] */
|
||||
|
||||
unsigned long dir_in; /* Bitmask of valid input pins */
|
||||
unsigned long dir_out; /* Bitmask of valid output pins */
|
||||
|
||||
u8 *bulk_in_buf; /* Extra recv buffer to grab status bytes */
|
||||
|
||||
struct usb_endpoint_descriptor *bulk_in;
|
||||
|
|
@ -34,6 +40,14 @@ struct mpsse_priv {
|
|||
struct mutex io_mutex; /* sync I/O with disconnect */
|
||||
};
|
||||
|
||||
struct mpsse_worker {
|
||||
struct mpsse_priv *priv;
|
||||
struct work_struct work;
|
||||
atomic_t cancelled;
|
||||
struct list_head list; /* linked list */
|
||||
struct list_head destroy; /* teardown linked list */
|
||||
};
|
||||
|
||||
struct bulk_desc {
|
||||
bool tx; /* direction of bulk transfer */
|
||||
u8 *data; /* input (tx) or output (rx) */
|
||||
|
|
@ -43,8 +57,27 @@ struct bulk_desc {
|
|||
int timeout;
|
||||
};
|
||||
|
||||
#define MPSSE_NGPIO 16
|
||||
|
||||
struct mpsse_quirk {
|
||||
const char *names[MPSSE_NGPIO]; /* Pin names, if applicable */
|
||||
unsigned long dir_in; /* Bitmask of valid input pins */
|
||||
unsigned long dir_out; /* Bitmask of valid output pins */
|
||||
};
|
||||
|
||||
static struct mpsse_quirk bryx_brik_quirk = {
|
||||
.names = {
|
||||
[3] = "Push to Talk",
|
||||
[5] = "Channel Activity",
|
||||
},
|
||||
.dir_out = BIT(3), /* Push to Talk */
|
||||
.dir_in = BIT(5), /* Channel Activity */
|
||||
};
|
||||
|
||||
static const struct usb_device_id gpio_mpsse_table[] = {
|
||||
{ USB_DEVICE(0x0c52, 0xa064) }, /* SeaLevel Systems, Inc. */
|
||||
{ USB_DEVICE(0x0403, 0x6988), /* FTDI, assigned to Bryx */
|
||||
.driver_info = (kernel_ulong_t)&bryx_brik_quirk},
|
||||
{ } /* Terminating entry */
|
||||
};
|
||||
|
||||
|
|
@ -160,6 +193,32 @@ static int gpio_mpsse_get_bank(struct mpsse_priv *priv, u8 bank)
|
|||
return buf;
|
||||
}
|
||||
|
||||
static int mpsse_ensure_supported(struct gpio_chip *chip,
|
||||
unsigned long mask, int direction)
|
||||
{
|
||||
unsigned long supported, unsupported;
|
||||
char *type = "input";
|
||||
struct mpsse_priv *priv = gpiochip_get_data(chip);
|
||||
|
||||
supported = priv->dir_in;
|
||||
if (direction == GPIO_LINE_DIRECTION_OUT) {
|
||||
supported = priv->dir_out;
|
||||
type = "output";
|
||||
}
|
||||
|
||||
/* An invalid bit was in the provided mask */
|
||||
unsupported = mask & ~supported;
|
||||
if (unsupported) {
|
||||
dev_err(&priv->udev->dev,
|
||||
"mpsse: GPIO %lu doesn't support %s\n",
|
||||
find_first_bit(&unsupported, sizeof(unsupported) * 8),
|
||||
type);
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gpio_mpsse_set_multiple(struct gpio_chip *chip, unsigned long *mask,
|
||||
unsigned long *bits)
|
||||
{
|
||||
|
|
@ -167,6 +226,10 @@ static int gpio_mpsse_set_multiple(struct gpio_chip *chip, unsigned long *mask,
|
|||
int ret;
|
||||
struct mpsse_priv *priv = gpiochip_get_data(chip);
|
||||
|
||||
ret = mpsse_ensure_supported(chip, *mask, GPIO_LINE_DIRECTION_OUT);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
guard(mutex)(&priv->io_mutex);
|
||||
for_each_set_clump8(i, bank_mask, mask, chip->ngpio) {
|
||||
bank = i / 8;
|
||||
|
|
@ -194,6 +257,10 @@ static int gpio_mpsse_get_multiple(struct gpio_chip *chip, unsigned long *mask,
|
|||
int ret;
|
||||
struct mpsse_priv *priv = gpiochip_get_data(chip);
|
||||
|
||||
ret = mpsse_ensure_supported(chip, *mask, GPIO_LINE_DIRECTION_IN);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
guard(mutex)(&priv->io_mutex);
|
||||
for_each_set_clump8(i, bank_mask, mask, chip->ngpio) {
|
||||
bank = i / 8;
|
||||
|
|
@ -242,10 +309,15 @@ static int gpio_mpsse_gpio_set(struct gpio_chip *chip, unsigned int offset,
|
|||
static int gpio_mpsse_direction_output(struct gpio_chip *chip,
|
||||
unsigned int offset, int value)
|
||||
{
|
||||
int ret;
|
||||
struct mpsse_priv *priv = gpiochip_get_data(chip);
|
||||
int bank = (offset & 8) >> 3;
|
||||
int bank_offset = offset & 7;
|
||||
|
||||
ret = mpsse_ensure_supported(chip, BIT(offset), GPIO_LINE_DIRECTION_OUT);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
scoped_guard(mutex, &priv->io_mutex)
|
||||
priv->gpio_dir[bank] |= BIT(bank_offset);
|
||||
|
||||
|
|
@ -255,15 +327,19 @@ static int gpio_mpsse_direction_output(struct gpio_chip *chip,
|
|||
static int gpio_mpsse_direction_input(struct gpio_chip *chip,
|
||||
unsigned int offset)
|
||||
{
|
||||
int ret;
|
||||
struct mpsse_priv *priv = gpiochip_get_data(chip);
|
||||
int bank = (offset & 8) >> 3;
|
||||
int bank_offset = offset & 7;
|
||||
|
||||
ret = mpsse_ensure_supported(chip, BIT(offset), GPIO_LINE_DIRECTION_IN);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
guard(mutex)(&priv->io_mutex);
|
||||
priv->gpio_dir[bank] &= ~BIT(bank_offset);
|
||||
gpio_mpsse_set_bank(priv, bank);
|
||||
|
||||
return 0;
|
||||
return gpio_mpsse_set_bank(priv, bank);
|
||||
}
|
||||
|
||||
static int gpio_mpsse_get_direction(struct gpio_chip *chip,
|
||||
|
|
@ -284,18 +360,62 @@ static int gpio_mpsse_get_direction(struct gpio_chip *chip,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static void gpio_mpsse_poll(struct work_struct *work)
|
||||
/*
|
||||
* Stops all workers except `my_worker`.
|
||||
* Safe to call only when `irq_race` is held.
|
||||
*/
|
||||
static void gpio_mpsse_stop_all_except(struct mpsse_priv *priv,
|
||||
struct mpsse_worker *my_worker)
|
||||
{
|
||||
struct mpsse_worker *worker, *worker_tmp;
|
||||
struct list_head destructors = LIST_HEAD_INIT(destructors);
|
||||
|
||||
scoped_guard(raw_spinlock_irqsave, &priv->irq_spin) {
|
||||
list_for_each_entry_safe(worker, worker_tmp,
|
||||
&priv->workers, list) {
|
||||
/* Don't stop ourselves */
|
||||
if (worker == my_worker)
|
||||
continue;
|
||||
|
||||
list_del(&worker->list);
|
||||
|
||||
/* Give worker a chance to terminate itself */
|
||||
atomic_set(&worker->cancelled, 1);
|
||||
/* Keep track of stuff to cancel */
|
||||
INIT_LIST_HEAD(&worker->destroy);
|
||||
list_add(&worker->destroy, &destructors);
|
||||
}
|
||||
}
|
||||
|
||||
list_for_each_entry_safe(worker, worker_tmp,
|
||||
&destructors, destroy) {
|
||||
list_del(&worker->destroy);
|
||||
cancel_work_sync(&worker->work);
|
||||
kfree(worker);
|
||||
}
|
||||
}
|
||||
|
||||
static void gpio_mpsse_poll(struct work_struct *my_work)
|
||||
{
|
||||
unsigned long pin_mask, pin_states, flags;
|
||||
int irq_enabled, offset, err, value, fire_irq,
|
||||
irq, old_value[16], irq_type[16];
|
||||
struct mpsse_priv *priv = container_of(work, struct mpsse_priv,
|
||||
irq_work);
|
||||
struct mpsse_worker *my_worker = container_of(my_work, struct mpsse_worker, work);
|
||||
struct mpsse_priv *priv = my_worker->priv;
|
||||
|
||||
for (offset = 0; offset < priv->gpio.ngpio; ++offset)
|
||||
old_value[offset] = -1;
|
||||
|
||||
while ((irq_enabled = atomic_read(&priv->irq_enabled))) {
|
||||
/*
|
||||
* We only want one worker. Workers race to acquire irq_race and tear
|
||||
* down all other workers. This is a cond guard so that we don't deadlock
|
||||
* trying to cancel a worker.
|
||||
*/
|
||||
scoped_cond_guard(mutex_try, return, &priv->irq_race)
|
||||
gpio_mpsse_stop_all_except(priv, my_worker);
|
||||
|
||||
while ((irq_enabled = atomic_read(&priv->irq_enabled)) &&
|
||||
!atomic_read(&my_worker->cancelled)) {
|
||||
usleep_range(MPSSE_POLL_INTERVAL, MPSSE_POLL_INTERVAL + 1000);
|
||||
/* Cleanup will trigger at the end of the loop */
|
||||
guard(mutex)(&priv->irq_mutex);
|
||||
|
|
@ -370,21 +490,45 @@ static int gpio_mpsse_set_irq_type(struct irq_data *irqd, unsigned int type)
|
|||
|
||||
static void gpio_mpsse_irq_disable(struct irq_data *irqd)
|
||||
{
|
||||
struct mpsse_worker *worker;
|
||||
struct mpsse_priv *priv = irq_data_get_irq_chip_data(irqd);
|
||||
|
||||
atomic_and(~BIT(irqd->hwirq), &priv->irq_enabled);
|
||||
gpiochip_disable_irq(&priv->gpio, irqd->hwirq);
|
||||
|
||||
/*
|
||||
* Can't actually do teardown in IRQ context (it blocks).
|
||||
* As a result, these workers will stick around until irq is reenabled
|
||||
* or device gets disconnected
|
||||
*/
|
||||
scoped_guard(raw_spinlock_irqsave, &priv->irq_spin)
|
||||
list_for_each_entry(worker, &priv->workers, list)
|
||||
atomic_set(&worker->cancelled, 1);
|
||||
}
|
||||
|
||||
static void gpio_mpsse_irq_enable(struct irq_data *irqd)
|
||||
{
|
||||
struct mpsse_worker *worker;
|
||||
struct mpsse_priv *priv = irq_data_get_irq_chip_data(irqd);
|
||||
|
||||
gpiochip_enable_irq(&priv->gpio, irqd->hwirq);
|
||||
/* If no-one else was using the IRQ, enable it */
|
||||
if (!atomic_fetch_or(BIT(irqd->hwirq), &priv->irq_enabled)) {
|
||||
INIT_WORK(&priv->irq_work, gpio_mpsse_poll);
|
||||
schedule_work(&priv->irq_work);
|
||||
/*
|
||||
* Can't be devm because it uses a non-raw spinlock (illegal in
|
||||
* this context, where a raw spinlock is held by our caller)
|
||||
*/
|
||||
worker = kzalloc(sizeof(*worker), GFP_NOWAIT);
|
||||
if (!worker)
|
||||
return;
|
||||
|
||||
worker->priv = priv;
|
||||
INIT_LIST_HEAD(&worker->list);
|
||||
INIT_WORK(&worker->work, gpio_mpsse_poll);
|
||||
schedule_work(&worker->work);
|
||||
|
||||
scoped_guard(raw_spinlock_irqsave, &priv->irq_spin)
|
||||
list_add(&worker->list, &priv->workers);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -404,18 +548,49 @@ static void gpio_mpsse_ida_remove(void *data)
|
|||
ida_free(&gpio_mpsse_ida, priv->id);
|
||||
}
|
||||
|
||||
static int mpsse_init_valid_mask(struct gpio_chip *chip,
|
||||
unsigned long *valid_mask,
|
||||
unsigned int ngpios)
|
||||
{
|
||||
struct mpsse_priv *priv = gpiochip_get_data(chip);
|
||||
|
||||
if (WARN_ON(priv == NULL))
|
||||
return -ENODEV;
|
||||
|
||||
*valid_mask = priv->dir_in | priv->dir_out;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void mpsse_irq_init_valid_mask(struct gpio_chip *chip,
|
||||
unsigned long *valid_mask,
|
||||
unsigned int ngpios)
|
||||
{
|
||||
struct mpsse_priv *priv = gpiochip_get_data(chip);
|
||||
|
||||
if (WARN_ON(priv == NULL))
|
||||
return;
|
||||
|
||||
/* Can only use IRQ on input capable pins */
|
||||
*valid_mask = priv->dir_in;
|
||||
}
|
||||
|
||||
static int gpio_mpsse_probe(struct usb_interface *interface,
|
||||
const struct usb_device_id *id)
|
||||
{
|
||||
struct mpsse_priv *priv;
|
||||
struct device *dev;
|
||||
char *serial;
|
||||
int err;
|
||||
struct mpsse_quirk *quirk = (void *)id->driver_info;
|
||||
|
||||
dev = &interface->dev;
|
||||
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
|
||||
INIT_LIST_HEAD(&priv->workers);
|
||||
|
||||
priv->udev = usb_get_dev(interface_to_usbdev(interface));
|
||||
priv->intf = interface;
|
||||
priv->intf_id = interface->cur_altsetting->desc.bInterfaceNumber;
|
||||
|
|
@ -436,9 +611,21 @@ static int gpio_mpsse_probe(struct usb_interface *interface,
|
|||
if (err)
|
||||
return err;
|
||||
|
||||
err = devm_mutex_init(dev, &priv->irq_race);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
raw_spin_lock_init(&priv->irq_spin);
|
||||
|
||||
serial = priv->udev->serial;
|
||||
if (!serial)
|
||||
serial = "NONE";
|
||||
|
||||
priv->gpio.label = devm_kasprintf(dev, GFP_KERNEL,
|
||||
"gpio-mpsse.%d.%d",
|
||||
priv->id, priv->intf_id);
|
||||
"MPSSE%04x:%04x.%d.%d.%s",
|
||||
id->idVendor, id->idProduct,
|
||||
priv->intf_id, priv->id,
|
||||
serial);
|
||||
if (!priv->gpio.label)
|
||||
return -ENOMEM;
|
||||
|
||||
|
|
@ -452,10 +639,20 @@ static int gpio_mpsse_probe(struct usb_interface *interface,
|
|||
priv->gpio.get_multiple = gpio_mpsse_get_multiple;
|
||||
priv->gpio.set_multiple = gpio_mpsse_set_multiple;
|
||||
priv->gpio.base = -1;
|
||||
priv->gpio.ngpio = 16;
|
||||
priv->gpio.ngpio = MPSSE_NGPIO;
|
||||
priv->gpio.offset = priv->intf_id * priv->gpio.ngpio;
|
||||
priv->gpio.can_sleep = 1;
|
||||
|
||||
if (quirk) {
|
||||
priv->dir_out = quirk->dir_out;
|
||||
priv->dir_in = quirk->dir_in;
|
||||
priv->gpio.names = quirk->names;
|
||||
priv->gpio.init_valid_mask = mpsse_init_valid_mask;
|
||||
} else {
|
||||
priv->dir_in = U16_MAX;
|
||||
priv->dir_out = U16_MAX;
|
||||
}
|
||||
|
||||
err = usb_find_common_endpoints(interface->cur_altsetting,
|
||||
&priv->bulk_in, &priv->bulk_out,
|
||||
NULL, NULL);
|
||||
|
|
@ -494,6 +691,7 @@ static int gpio_mpsse_probe(struct usb_interface *interface,
|
|||
priv->gpio.irq.parents = NULL;
|
||||
priv->gpio.irq.default_type = IRQ_TYPE_NONE;
|
||||
priv->gpio.irq.handler = handle_simple_irq;
|
||||
priv->gpio.irq.init_valid_mask = mpsse_irq_init_valid_mask;
|
||||
|
||||
err = devm_gpiochip_add_data(dev, &priv->gpio, priv);
|
||||
if (err)
|
||||
|
|
@ -506,6 +704,13 @@ static void gpio_mpsse_disconnect(struct usb_interface *intf)
|
|||
{
|
||||
struct mpsse_priv *priv = usb_get_intfdata(intf);
|
||||
|
||||
/*
|
||||
* Lock prevents double-free of worker from here and the teardown
|
||||
* step at the beginning of gpio_mpsse_poll
|
||||
*/
|
||||
scoped_guard(mutex, &priv->irq_race)
|
||||
gpio_mpsse_stop_all_except(priv, NULL);
|
||||
|
||||
priv->intf = NULL;
|
||||
usb_set_intfdata(intf, NULL);
|
||||
usb_put_dev(priv->udev);
|
||||
|
|
|
|||
|
|
@ -694,7 +694,7 @@ static const struct of_device_id msc313_gpio_of_match[] = {
|
|||
* SoC goes into suspend to memory mode so we need to save some
|
||||
* of the register bits before suspending and put it back when resuming
|
||||
*/
|
||||
static int __maybe_unused msc313_gpio_suspend(struct device *dev)
|
||||
static int msc313_gpio_suspend(struct device *dev)
|
||||
{
|
||||
struct msc313_gpio *gpio = dev_get_drvdata(dev);
|
||||
int i;
|
||||
|
|
@ -705,7 +705,7 @@ static int __maybe_unused msc313_gpio_suspend(struct device *dev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int __maybe_unused msc313_gpio_resume(struct device *dev)
|
||||
static int msc313_gpio_resume(struct device *dev)
|
||||
{
|
||||
struct msc313_gpio *gpio = dev_get_drvdata(dev);
|
||||
int i;
|
||||
|
|
@ -716,13 +716,13 @@ static int __maybe_unused msc313_gpio_resume(struct device *dev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(msc313_gpio_ops, msc313_gpio_suspend, msc313_gpio_resume);
|
||||
static DEFINE_SIMPLE_DEV_PM_OPS(msc313_gpio_ops, msc313_gpio_suspend, msc313_gpio_resume);
|
||||
|
||||
static struct platform_driver msc313_gpio_driver = {
|
||||
.driver = {
|
||||
.name = DRIVER_NAME,
|
||||
.of_match_table = msc313_gpio_of_match,
|
||||
.pm = &msc313_gpio_ops,
|
||||
.pm = pm_sleep_ptr(&msc313_gpio_ops),
|
||||
},
|
||||
.probe = msc313_gpio_probe,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -573,11 +573,10 @@ static void mvebu_gpio_irq_handler(struct irq_desc *desc)
|
|||
for (i = 0; i < mvchip->chip.ngpio; i++) {
|
||||
int irq;
|
||||
|
||||
irq = irq_find_mapping(mvchip->domain, i);
|
||||
|
||||
if (!(cause & BIT(i)))
|
||||
continue;
|
||||
|
||||
irq = irq_find_mapping(mvchip->domain, i);
|
||||
type = irq_get_trigger_type(irq);
|
||||
if ((type & IRQ_TYPE_SENSE_MASK) == IRQ_TYPE_EDGE_BOTH) {
|
||||
/* Swap polarity (race with GPIO line) */
|
||||
|
|
|
|||
|
|
@ -1503,7 +1503,7 @@ static void omap_gpio_remove(struct platform_device *pdev)
|
|||
clk_unprepare(bank->dbck);
|
||||
}
|
||||
|
||||
static int __maybe_unused omap_gpio_runtime_suspend(struct device *dev)
|
||||
static int omap_gpio_runtime_suspend(struct device *dev)
|
||||
{
|
||||
struct gpio_bank *bank = dev_get_drvdata(dev);
|
||||
unsigned long flags;
|
||||
|
|
@ -1516,7 +1516,7 @@ static int __maybe_unused omap_gpio_runtime_suspend(struct device *dev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int __maybe_unused omap_gpio_runtime_resume(struct device *dev)
|
||||
static int omap_gpio_runtime_resume(struct device *dev)
|
||||
{
|
||||
struct gpio_bank *bank = dev_get_drvdata(dev);
|
||||
unsigned long flags;
|
||||
|
|
@ -1529,7 +1529,7 @@ static int __maybe_unused omap_gpio_runtime_resume(struct device *dev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int __maybe_unused omap_gpio_suspend(struct device *dev)
|
||||
static int omap_gpio_suspend(struct device *dev)
|
||||
{
|
||||
struct gpio_bank *bank = dev_get_drvdata(dev);
|
||||
|
||||
|
|
@ -1541,7 +1541,7 @@ static int __maybe_unused omap_gpio_suspend(struct device *dev)
|
|||
return omap_gpio_runtime_suspend(dev);
|
||||
}
|
||||
|
||||
static int __maybe_unused omap_gpio_resume(struct device *dev)
|
||||
static int omap_gpio_resume(struct device *dev)
|
||||
{
|
||||
struct gpio_bank *bank = dev_get_drvdata(dev);
|
||||
|
||||
|
|
@ -1554,9 +1554,8 @@ static int __maybe_unused omap_gpio_resume(struct device *dev)
|
|||
}
|
||||
|
||||
static const struct dev_pm_ops gpio_pm_ops = {
|
||||
SET_RUNTIME_PM_OPS(omap_gpio_runtime_suspend, omap_gpio_runtime_resume,
|
||||
NULL)
|
||||
SET_LATE_SYSTEM_SLEEP_PM_OPS(omap_gpio_suspend, omap_gpio_resume)
|
||||
RUNTIME_PM_OPS(omap_gpio_runtime_suspend, omap_gpio_runtime_resume, NULL)
|
||||
LATE_SYSTEM_SLEEP_PM_OPS(omap_gpio_suspend, omap_gpio_resume)
|
||||
};
|
||||
|
||||
static struct platform_driver omap_gpio_driver = {
|
||||
|
|
@ -1564,7 +1563,7 @@ static struct platform_driver omap_gpio_driver = {
|
|||
.remove = omap_gpio_remove,
|
||||
.driver = {
|
||||
.name = "omap_gpio",
|
||||
.pm = &gpio_pm_ops,
|
||||
.pm = pm_ptr(&gpio_pm_ops),
|
||||
.of_match_table = omap_gpio_match,
|
||||
},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -306,7 +306,7 @@ static inline u8 pca953x_get_bit_mask(struct pca953x_chip *chip, unsigned int of
|
|||
* Interrupt mask register 0x40 + 5 * bank_size RW
|
||||
* Interrupt status register 0x40 + 6 * bank_size R
|
||||
*
|
||||
* - Registers with bit 0x80 set, the AI bit
|
||||
* - Registers with bit 0x80 set, the AI bit (auto increment)
|
||||
* The bit is cleared and the registers fall into one of the
|
||||
* categories above.
|
||||
*/
|
||||
|
|
@ -854,10 +854,13 @@ static void pca953x_irq_bus_sync_unlock(struct irq_data *d)
|
|||
int level;
|
||||
|
||||
if (chip->driver_data & PCA_PCAL) {
|
||||
DECLARE_BITMAP(latched_inputs, MAX_LINE);
|
||||
guard(mutex)(&chip->i2c_lock);
|
||||
|
||||
/* Enable latch on interrupt-enabled inputs */
|
||||
pca953x_write_regs(chip, PCAL953X_IN_LATCH, chip->irq_mask);
|
||||
/* Enable latch on edge-triggered interrupt-enabled inputs */
|
||||
bitmap_or(latched_inputs, chip->irq_trig_fall, chip->irq_trig_raise, gc->ngpio);
|
||||
bitmap_and(latched_inputs, latched_inputs, chip->irq_mask, gc->ngpio);
|
||||
pca953x_write_regs(chip, PCAL953X_IN_LATCH, latched_inputs);
|
||||
|
||||
bitmap_complement(irq_mask, chip->irq_mask, gc->ngpio);
|
||||
|
||||
|
|
@ -1203,10 +1206,10 @@ static int pca953x_probe(struct i2c_client *client)
|
|||
pca953x_setup_gpio(chip, chip->driver_data & PCA_GPIO_MASK);
|
||||
|
||||
if (NBANK(chip) > 2 || PCA_CHIP_TYPE(chip->driver_data) == PCA957X_TYPE) {
|
||||
dev_info(dev, "using AI\n");
|
||||
dev_info(dev, "using auto increment\n");
|
||||
regmap_config = &pca953x_ai_i2c_regmap;
|
||||
} else {
|
||||
dev_info(dev, "using no AI\n");
|
||||
dev_info(dev, "using no auto increment\n");
|
||||
regmap_config = &pca953x_i2c_regmap;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -171,7 +171,7 @@ static int pch_gpio_direction_input(struct gpio_chip *gpio, unsigned int nr)
|
|||
/*
|
||||
* Save register configuration and disable interrupts.
|
||||
*/
|
||||
static void __maybe_unused pch_gpio_save_reg_conf(struct pch_gpio *chip)
|
||||
static void pch_gpio_save_reg_conf(struct pch_gpio *chip)
|
||||
{
|
||||
chip->pch_gpio_reg.ien_reg = ioread32(&chip->reg->ien);
|
||||
chip->pch_gpio_reg.imask_reg = ioread32(&chip->reg->imask);
|
||||
|
|
@ -187,7 +187,7 @@ static void __maybe_unused pch_gpio_save_reg_conf(struct pch_gpio *chip)
|
|||
/*
|
||||
* This function restores the register configuration of the GPIO device.
|
||||
*/
|
||||
static void __maybe_unused pch_gpio_restore_reg_conf(struct pch_gpio *chip)
|
||||
static void pch_gpio_restore_reg_conf(struct pch_gpio *chip)
|
||||
{
|
||||
iowrite32(chip->pch_gpio_reg.ien_reg, &chip->reg->ien);
|
||||
iowrite32(chip->pch_gpio_reg.imask_reg, &chip->reg->imask);
|
||||
|
|
@ -402,7 +402,7 @@ static int pch_gpio_probe(struct pci_dev *pdev,
|
|||
return pch_gpio_alloc_generic_chip(chip, irq_base, gpio_pins[chip->ioh]);
|
||||
}
|
||||
|
||||
static int __maybe_unused pch_gpio_suspend(struct device *dev)
|
||||
static int pch_gpio_suspend(struct device *dev)
|
||||
{
|
||||
struct pch_gpio *chip = dev_get_drvdata(dev);
|
||||
unsigned long flags;
|
||||
|
|
@ -414,7 +414,7 @@ static int __maybe_unused pch_gpio_suspend(struct device *dev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int __maybe_unused pch_gpio_resume(struct device *dev)
|
||||
static int pch_gpio_resume(struct device *dev)
|
||||
{
|
||||
struct pch_gpio *chip = dev_get_drvdata(dev);
|
||||
unsigned long flags;
|
||||
|
|
@ -428,7 +428,7 @@ static int __maybe_unused pch_gpio_resume(struct device *dev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(pch_gpio_pm_ops, pch_gpio_suspend, pch_gpio_resume);
|
||||
static DEFINE_SIMPLE_DEV_PM_OPS(pch_gpio_pm_ops, pch_gpio_suspend, pch_gpio_resume);
|
||||
|
||||
static const struct pci_device_id pch_gpio_pcidev_id[] = {
|
||||
{ PCI_DEVICE_DATA(INTEL, EG20T_PCH, INTEL_EG20T_PCH) },
|
||||
|
|
@ -444,7 +444,7 @@ static struct pci_driver pch_gpio_driver = {
|
|||
.id_table = pch_gpio_pcidev_id,
|
||||
.probe = pch_gpio_probe,
|
||||
.driver = {
|
||||
.pm = &pch_gpio_pm_ops,
|
||||
.pm = pm_sleep_ptr(&pch_gpio_pm_ops),
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -37,7 +37,6 @@
|
|||
|
||||
#define PL061_GPIO_NR 8
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
struct pl061_context_save_regs {
|
||||
u8 gpio_data;
|
||||
u8 gpio_dir;
|
||||
|
|
@ -46,7 +45,6 @@ struct pl061_context_save_regs {
|
|||
u8 gpio_iev;
|
||||
u8 gpio_ie;
|
||||
};
|
||||
#endif
|
||||
|
||||
struct pl061 {
|
||||
raw_spinlock_t lock;
|
||||
|
|
@ -55,9 +53,7 @@ struct pl061 {
|
|||
struct gpio_chip gc;
|
||||
int parent_irq;
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
struct pl061_context_save_regs csave_regs;
|
||||
#endif
|
||||
};
|
||||
|
||||
static int pl061_get_direction(struct gpio_chip *gc, unsigned offset)
|
||||
|
|
@ -367,7 +363,6 @@ static int pl061_probe(struct amba_device *adev, const struct amba_id *id)
|
|||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int pl061_suspend(struct device *dev)
|
||||
{
|
||||
struct pl061 *pl061 = dev_get_drvdata(dev);
|
||||
|
|
@ -411,13 +406,7 @@ static int pl061_resume(struct device *dev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static const struct dev_pm_ops pl061_dev_pm_ops = {
|
||||
.suspend = pl061_suspend,
|
||||
.resume = pl061_resume,
|
||||
.freeze = pl061_suspend,
|
||||
.restore = pl061_resume,
|
||||
};
|
||||
#endif
|
||||
static DEFINE_SIMPLE_DEV_PM_OPS(pl061_dev_pm_ops, pl061_suspend, pl061_resume);
|
||||
|
||||
static const struct amba_id pl061_ids[] = {
|
||||
{
|
||||
|
|
@ -431,9 +420,7 @@ MODULE_DEVICE_TABLE(amba, pl061_ids);
|
|||
static struct amba_driver pl061_gpio_driver = {
|
||||
.drv = {
|
||||
.name = "pl061_gpio",
|
||||
#ifdef CONFIG_PM
|
||||
.pm = &pl061_dev_pm_ops,
|
||||
#endif
|
||||
.pm = pm_sleep_ptr(&pl061_dev_pm_ops),
|
||||
},
|
||||
.id_table = pl061_ids,
|
||||
.probe = pl061_probe,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,111 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Layerscape GPIO QIXIS FPGA driver
|
||||
*
|
||||
* Copyright 2025 NXP
|
||||
*/
|
||||
|
||||
#include <linux/device.h>
|
||||
#include <linux/gpio/driver.h>
|
||||
#include <linux/gpio/regmap.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/regmap.h>
|
||||
|
||||
struct qixis_cpld_gpio_config {
|
||||
u64 output_lines;
|
||||
};
|
||||
|
||||
static const struct qixis_cpld_gpio_config lx2160ardb_sfp_cfg = {
|
||||
.output_lines = BIT(0),
|
||||
};
|
||||
|
||||
static const struct qixis_cpld_gpio_config ls1046aqds_stat_pres2_cfg = {
|
||||
.output_lines = 0x0,
|
||||
};
|
||||
|
||||
static const struct regmap_config regmap_config_8r_8v = {
|
||||
.reg_bits = 8,
|
||||
.val_bits = 8,
|
||||
};
|
||||
|
||||
static int qixis_cpld_gpio_probe(struct platform_device *pdev)
|
||||
{
|
||||
DECLARE_BITMAP(fixed_direction_output, 8);
|
||||
const struct qixis_cpld_gpio_config *cfg;
|
||||
struct gpio_regmap_config config = {0};
|
||||
struct regmap *regmap;
|
||||
void __iomem *reg;
|
||||
u32 base;
|
||||
int ret;
|
||||
|
||||
if (!pdev->dev.parent)
|
||||
return -ENODEV;
|
||||
|
||||
cfg = device_get_match_data(&pdev->dev);
|
||||
|
||||
ret = device_property_read_u32(&pdev->dev, "reg", &base);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
regmap = dev_get_regmap(pdev->dev.parent, NULL);
|
||||
if (!regmap) {
|
||||
/* In case there is no regmap configured by the parent device,
|
||||
* create our own from the MMIO space.
|
||||
*/
|
||||
reg = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(reg))
|
||||
return PTR_ERR(reg);
|
||||
|
||||
regmap = devm_regmap_init_mmio(&pdev->dev, reg, ®map_config_8r_8v);
|
||||
if (!regmap)
|
||||
return -ENODEV;
|
||||
|
||||
/* In this case, the offset of our register is 0 inside the
|
||||
* regmap area that we just created.
|
||||
*/
|
||||
base = 0;
|
||||
}
|
||||
config.reg_dat_base = GPIO_REGMAP_ADDR(base);
|
||||
config.reg_set_base = GPIO_REGMAP_ADDR(base);
|
||||
|
||||
config.drvdata = (void *)cfg;
|
||||
config.regmap = regmap;
|
||||
config.parent = &pdev->dev;
|
||||
config.ngpio_per_reg = 8;
|
||||
config.ngpio = 8;
|
||||
|
||||
bitmap_from_u64(fixed_direction_output, cfg->output_lines);
|
||||
config.fixed_direction_output = fixed_direction_output;
|
||||
|
||||
return PTR_ERR_OR_ZERO(devm_gpio_regmap_register(&pdev->dev, &config));
|
||||
}
|
||||
|
||||
static const struct of_device_id qixis_cpld_gpio_of_match[] = {
|
||||
{
|
||||
.compatible = "fsl,lx2160ardb-fpga-gpio-sfp",
|
||||
.data = &lx2160ardb_sfp_cfg,
|
||||
},
|
||||
{
|
||||
.compatible = "fsl,ls1046aqds-fpga-gpio-stat-pres2",
|
||||
.data = &ls1046aqds_stat_pres2_cfg,
|
||||
},
|
||||
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, qixis_cpld_gpio_of_match);
|
||||
|
||||
static struct platform_driver qixis_cpld_gpio_driver = {
|
||||
.probe = qixis_cpld_gpio_probe,
|
||||
.driver = {
|
||||
.name = "gpio-qixis-cpld",
|
||||
.of_match_table = qixis_cpld_gpio_of_match,
|
||||
},
|
||||
};
|
||||
module_platform_driver(qixis_cpld_gpio_driver);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Ioana Ciornei <ioana.ciornei@nxp.com>");
|
||||
MODULE_DESCRIPTION("Layerscape GPIO QIXIS FPGA driver");
|
||||
|
|
@ -82,7 +82,11 @@ static int gpio_regmap_get(struct gpio_chip *chip, unsigned int offset)
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = regmap_read(gpio->regmap, reg, &val);
|
||||
/* ensure we don't spoil any register cache with pin input values */
|
||||
if (gpio->reg_dat_base == gpio->reg_set_base)
|
||||
ret = regmap_read_bypassed(gpio->regmap, reg, &val);
|
||||
else
|
||||
ret = regmap_read(gpio->regmap, reg, &val);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
|
@ -94,7 +98,7 @@ static int gpio_regmap_set(struct gpio_chip *chip, unsigned int offset,
|
|||
{
|
||||
struct gpio_regmap *gpio = gpiochip_get_data(chip);
|
||||
unsigned int base = gpio_regmap_addr(gpio->reg_set_base);
|
||||
unsigned int reg, mask;
|
||||
unsigned int reg, mask, mask_val;
|
||||
int ret;
|
||||
|
||||
ret = gpio->reg_mask_xlate(gpio, base, offset, ®, &mask);
|
||||
|
|
@ -102,9 +106,15 @@ static int gpio_regmap_set(struct gpio_chip *chip, unsigned int offset,
|
|||
return ret;
|
||||
|
||||
if (val)
|
||||
ret = regmap_update_bits(gpio->regmap, reg, mask, mask);
|
||||
mask_val = mask;
|
||||
else
|
||||
ret = regmap_update_bits(gpio->regmap, reg, mask, 0);
|
||||
mask_val = 0;
|
||||
|
||||
/* ignore input values which shadow the old output value */
|
||||
if (gpio->reg_dat_base == gpio->reg_set_base)
|
||||
ret = regmap_write_bits(gpio->regmap, reg, mask, mask_val);
|
||||
else
|
||||
ret = regmap_update_bits(gpio->regmap, reg, mask, mask_val);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -322,6 +322,7 @@ MODULE_DEVICE_TABLE(auxiliary, gpio_shared_proxy_id_table);
|
|||
static struct auxiliary_driver gpio_shared_proxy_driver = {
|
||||
.driver = {
|
||||
.name = "gpio-shared-proxy",
|
||||
.suppress_bind_attrs = true,
|
||||
},
|
||||
.probe = gpio_shared_proxy_probe,
|
||||
.id_table = gpio_shared_proxy_id_table,
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (c) 2016-2022 NVIDIA Corporation
|
||||
* Copyright (c) 2016-2025 NVIDIA Corporation
|
||||
*
|
||||
* Author: Thierry Reding <treding@nvidia.com>
|
||||
* Dipen Patel <dpatel@nvidia.com>
|
||||
|
|
@ -69,6 +69,30 @@
|
|||
|
||||
#define TEGRA186_GPIO_INTERRUPT_STATUS(x) (0x100 + (x) * 4)
|
||||
|
||||
/* Tegra410 GPIOs implemented by the COMPUTE GPIO controller */
|
||||
#define TEGRA410_COMPUTE_GPIO_PORT_A 0
|
||||
#define TEGRA410_COMPUTE_GPIO_PORT_B 1
|
||||
#define TEGRA410_COMPUTE_GPIO_PORT_C 2
|
||||
#define TEGRA410_COMPUTE_GPIO_PORT_D 3
|
||||
#define TEGRA410_COMPUTE_GPIO_PORT_E 4
|
||||
|
||||
/* Tegra410 GPIOs implemented by the SYSTEM GPIO controller */
|
||||
#define TEGRA410_SYSTEM_GPIO_PORT_A 0
|
||||
#define TEGRA410_SYSTEM_GPIO_PORT_B 1
|
||||
#define TEGRA410_SYSTEM_GPIO_PORT_C 2
|
||||
#define TEGRA410_SYSTEM_GPIO_PORT_D 3
|
||||
#define TEGRA410_SYSTEM_GPIO_PORT_E 4
|
||||
#define TEGRA410_SYSTEM_GPIO_PORT_I 5
|
||||
#define TEGRA410_SYSTEM_GPIO_PORT_J 6
|
||||
#define TEGRA410_SYSTEM_GPIO_PORT_K 7
|
||||
#define TEGRA410_SYSTEM_GPIO_PORT_L 8
|
||||
#define TEGRA410_SYSTEM_GPIO_PORT_M 9
|
||||
#define TEGRA410_SYSTEM_GPIO_PORT_N 10
|
||||
#define TEGRA410_SYSTEM_GPIO_PORT_P 11
|
||||
#define TEGRA410_SYSTEM_GPIO_PORT_Q 12
|
||||
#define TEGRA410_SYSTEM_GPIO_PORT_R 13
|
||||
#define TEGRA410_SYSTEM_GPIO_PORT_V 14
|
||||
|
||||
struct tegra_gpio_port {
|
||||
const char *name;
|
||||
unsigned int bank;
|
||||
|
|
@ -85,6 +109,7 @@ struct tegra_gpio_soc {
|
|||
const struct tegra_gpio_port *ports;
|
||||
unsigned int num_ports;
|
||||
const char *name;
|
||||
const char *prefix;
|
||||
unsigned int instance;
|
||||
|
||||
unsigned int num_irqs_per_bank;
|
||||
|
|
@ -916,8 +941,12 @@ static int tegra186_gpio_probe(struct platform_device *pdev)
|
|||
char *name;
|
||||
|
||||
for (j = 0; j < port->pins; j++) {
|
||||
name = devm_kasprintf(gpio->gpio.parent, GFP_KERNEL,
|
||||
"P%s.%02x", port->name, j);
|
||||
if (gpio->soc->prefix)
|
||||
name = devm_kasprintf(gpio->gpio.parent, GFP_KERNEL, "%s-P%s.%02x",
|
||||
gpio->soc->prefix, port->name, j);
|
||||
else
|
||||
name = devm_kasprintf(gpio->gpio.parent, GFP_KERNEL, "P%s.%02x",
|
||||
port->name, j);
|
||||
if (!name)
|
||||
return -ENOMEM;
|
||||
|
||||
|
|
@ -1002,14 +1031,17 @@ static int tegra186_gpio_probe(struct platform_device *pdev)
|
|||
return devm_gpiochip_add_data(&pdev->dev, &gpio->gpio, gpio);
|
||||
}
|
||||
|
||||
#define TEGRA186_MAIN_GPIO_PORT(_name, _bank, _port, _pins) \
|
||||
[TEGRA186_MAIN_GPIO_PORT_##_name] = { \
|
||||
.name = #_name, \
|
||||
.bank = _bank, \
|
||||
.port = _port, \
|
||||
.pins = _pins, \
|
||||
#define TEGRA_GPIO_PORT(_prefix, _name, _bank, _port, _pins) \
|
||||
[_prefix##_GPIO_PORT_##_name] = { \
|
||||
.name = #_name, \
|
||||
.bank = _bank, \
|
||||
.port = _port, \
|
||||
.pins = _pins, \
|
||||
}
|
||||
|
||||
#define TEGRA186_MAIN_GPIO_PORT(_name, _bank, _port, _pins) \
|
||||
TEGRA_GPIO_PORT(TEGRA186_MAIN, _name, _bank, _port, _pins)
|
||||
|
||||
static const struct tegra_gpio_port tegra186_main_ports[] = {
|
||||
TEGRA186_MAIN_GPIO_PORT( A, 2, 0, 7),
|
||||
TEGRA186_MAIN_GPIO_PORT( B, 3, 0, 7),
|
||||
|
|
@ -1045,13 +1077,8 @@ static const struct tegra_gpio_soc tegra186_main_soc = {
|
|||
.has_vm_support = false,
|
||||
};
|
||||
|
||||
#define TEGRA186_AON_GPIO_PORT(_name, _bank, _port, _pins) \
|
||||
[TEGRA186_AON_GPIO_PORT_##_name] = { \
|
||||
.name = #_name, \
|
||||
.bank = _bank, \
|
||||
.port = _port, \
|
||||
.pins = _pins, \
|
||||
}
|
||||
#define TEGRA186_AON_GPIO_PORT(_name, _bank, _port, _pins) \
|
||||
TEGRA_GPIO_PORT(TEGRA186_AON, _name, _bank, _port, _pins)
|
||||
|
||||
static const struct tegra_gpio_port tegra186_aon_ports[] = {
|
||||
TEGRA186_AON_GPIO_PORT( S, 0, 1, 5),
|
||||
|
|
@ -1073,13 +1100,8 @@ static const struct tegra_gpio_soc tegra186_aon_soc = {
|
|||
.has_vm_support = false,
|
||||
};
|
||||
|
||||
#define TEGRA194_MAIN_GPIO_PORT(_name, _bank, _port, _pins) \
|
||||
[TEGRA194_MAIN_GPIO_PORT_##_name] = { \
|
||||
.name = #_name, \
|
||||
.bank = _bank, \
|
||||
.port = _port, \
|
||||
.pins = _pins, \
|
||||
}
|
||||
#define TEGRA194_MAIN_GPIO_PORT(_name, _bank, _port, _pins) \
|
||||
TEGRA_GPIO_PORT(TEGRA194_MAIN, _name, _bank, _port, _pins)
|
||||
|
||||
static const struct tegra_gpio_port tegra194_main_ports[] = {
|
||||
TEGRA194_MAIN_GPIO_PORT( A, 1, 2, 8),
|
||||
|
|
@ -1129,13 +1151,8 @@ static const struct tegra_gpio_soc tegra194_main_soc = {
|
|||
.has_vm_support = true,
|
||||
};
|
||||
|
||||
#define TEGRA194_AON_GPIO_PORT(_name, _bank, _port, _pins) \
|
||||
[TEGRA194_AON_GPIO_PORT_##_name] = { \
|
||||
.name = #_name, \
|
||||
.bank = _bank, \
|
||||
.port = _port, \
|
||||
.pins = _pins, \
|
||||
}
|
||||
#define TEGRA194_AON_GPIO_PORT(_name, _bank, _port, _pins) \
|
||||
TEGRA_GPIO_PORT(TEGRA194_AON, _name, _bank, _port, _pins)
|
||||
|
||||
static const struct tegra_gpio_port tegra194_aon_ports[] = {
|
||||
TEGRA194_AON_GPIO_PORT(AA, 0, 3, 8),
|
||||
|
|
@ -1155,13 +1172,8 @@ static const struct tegra_gpio_soc tegra194_aon_soc = {
|
|||
.has_vm_support = false,
|
||||
};
|
||||
|
||||
#define TEGRA234_MAIN_GPIO_PORT(_name, _bank, _port, _pins) \
|
||||
[TEGRA234_MAIN_GPIO_PORT_##_name] = { \
|
||||
.name = #_name, \
|
||||
.bank = _bank, \
|
||||
.port = _port, \
|
||||
.pins = _pins, \
|
||||
}
|
||||
#define TEGRA234_MAIN_GPIO_PORT(_name, _bank, _port, _pins) \
|
||||
TEGRA_GPIO_PORT(TEGRA234_MAIN, _name, _bank, _port, _pins)
|
||||
|
||||
static const struct tegra_gpio_port tegra234_main_ports[] = {
|
||||
TEGRA234_MAIN_GPIO_PORT( A, 0, 0, 8),
|
||||
|
|
@ -1200,13 +1212,8 @@ static const struct tegra_gpio_soc tegra234_main_soc = {
|
|||
.has_vm_support = true,
|
||||
};
|
||||
|
||||
#define TEGRA234_AON_GPIO_PORT(_name, _bank, _port, _pins) \
|
||||
[TEGRA234_AON_GPIO_PORT_##_name] = { \
|
||||
.name = #_name, \
|
||||
.bank = _bank, \
|
||||
.port = _port, \
|
||||
.pins = _pins, \
|
||||
}
|
||||
#define TEGRA234_AON_GPIO_PORT(_name, _bank, _port, _pins) \
|
||||
TEGRA_GPIO_PORT(TEGRA234_AON, _name, _bank, _port, _pins)
|
||||
|
||||
static const struct tegra_gpio_port tegra234_aon_ports[] = {
|
||||
TEGRA234_AON_GPIO_PORT(AA, 0, 4, 8),
|
||||
|
|
@ -1227,13 +1234,8 @@ static const struct tegra_gpio_soc tegra234_aon_soc = {
|
|||
.has_vm_support = false,
|
||||
};
|
||||
|
||||
#define TEGRA241_MAIN_GPIO_PORT(_name, _bank, _port, _pins) \
|
||||
[TEGRA241_MAIN_GPIO_PORT_##_name] = { \
|
||||
.name = #_name, \
|
||||
.bank = _bank, \
|
||||
.port = _port, \
|
||||
.pins = _pins, \
|
||||
}
|
||||
#define TEGRA241_MAIN_GPIO_PORT(_name, _bank, _port, _pins) \
|
||||
TEGRA_GPIO_PORT(TEGRA241_MAIN, _name, _bank, _port, _pins)
|
||||
|
||||
static const struct tegra_gpio_port tegra241_main_ports[] = {
|
||||
TEGRA241_MAIN_GPIO_PORT(A, 0, 0, 8),
|
||||
|
|
@ -1258,13 +1260,8 @@ static const struct tegra_gpio_soc tegra241_main_soc = {
|
|||
.has_vm_support = false,
|
||||
};
|
||||
|
||||
#define TEGRA241_AON_GPIO_PORT(_name, _bank, _port, _pins) \
|
||||
[TEGRA241_AON_GPIO_PORT_##_name] = { \
|
||||
.name = #_name, \
|
||||
.bank = _bank, \
|
||||
.port = _port, \
|
||||
.pins = _pins, \
|
||||
}
|
||||
#define TEGRA241_AON_GPIO_PORT(_name, _bank, _port, _pins) \
|
||||
TEGRA_GPIO_PORT(TEGRA241_AON, _name, _bank, _port, _pins)
|
||||
|
||||
static const struct tegra_gpio_port tegra241_aon_ports[] = {
|
||||
TEGRA241_AON_GPIO_PORT(AA, 0, 0, 8),
|
||||
|
|
@ -1280,13 +1277,8 @@ static const struct tegra_gpio_soc tegra241_aon_soc = {
|
|||
.has_vm_support = false,
|
||||
};
|
||||
|
||||
#define TEGRA256_MAIN_GPIO_PORT(_name, _bank, _port, _pins) \
|
||||
[TEGRA256_MAIN_GPIO_PORT_##_name] = { \
|
||||
.name = #_name, \
|
||||
.bank = _bank, \
|
||||
.port = _port, \
|
||||
.pins = _pins, \
|
||||
}
|
||||
#define TEGRA256_MAIN_GPIO_PORT(_name, _bank, _port, _pins) \
|
||||
TEGRA_GPIO_PORT(TEGRA256_MAIN, _name, _bank, _port, _pins)
|
||||
|
||||
static const struct tegra_gpio_port tegra256_main_ports[] = {
|
||||
TEGRA256_MAIN_GPIO_PORT(A, 0, 0, 8),
|
||||
|
|
@ -1304,6 +1296,56 @@ static const struct tegra_gpio_soc tegra256_main_soc = {
|
|||
.has_vm_support = true,
|
||||
};
|
||||
|
||||
#define TEGRA410_COMPUTE_GPIO_PORT(_name, _bank, _port, _pins) \
|
||||
TEGRA_GPIO_PORT(TEGRA410_COMPUTE, _name, _bank, _port, _pins)
|
||||
|
||||
static const struct tegra_gpio_port tegra410_compute_ports[] = {
|
||||
TEGRA410_COMPUTE_GPIO_PORT(A, 0, 0, 3),
|
||||
TEGRA410_COMPUTE_GPIO_PORT(B, 1, 0, 8),
|
||||
TEGRA410_COMPUTE_GPIO_PORT(C, 1, 1, 3),
|
||||
TEGRA410_COMPUTE_GPIO_PORT(D, 2, 0, 8),
|
||||
TEGRA410_COMPUTE_GPIO_PORT(E, 2, 1, 8),
|
||||
};
|
||||
|
||||
static const struct tegra_gpio_soc tegra410_compute_soc = {
|
||||
.num_ports = ARRAY_SIZE(tegra410_compute_ports),
|
||||
.ports = tegra410_compute_ports,
|
||||
.name = "tegra410-gpio-compute",
|
||||
.prefix = "COMPUTE",
|
||||
.num_irqs_per_bank = 8,
|
||||
.instance = 0,
|
||||
};
|
||||
|
||||
#define TEGRA410_SYSTEM_GPIO_PORT(_name, _bank, _port, _pins) \
|
||||
TEGRA_GPIO_PORT(TEGRA410_SYSTEM, _name, _bank, _port, _pins)
|
||||
|
||||
static const struct tegra_gpio_port tegra410_system_ports[] = {
|
||||
TEGRA410_SYSTEM_GPIO_PORT(A, 0, 0, 7),
|
||||
TEGRA410_SYSTEM_GPIO_PORT(B, 0, 1, 8),
|
||||
TEGRA410_SYSTEM_GPIO_PORT(C, 0, 2, 8),
|
||||
TEGRA410_SYSTEM_GPIO_PORT(D, 0, 3, 8),
|
||||
TEGRA410_SYSTEM_GPIO_PORT(E, 0, 4, 6),
|
||||
TEGRA410_SYSTEM_GPIO_PORT(I, 1, 0, 8),
|
||||
TEGRA410_SYSTEM_GPIO_PORT(J, 1, 1, 7),
|
||||
TEGRA410_SYSTEM_GPIO_PORT(K, 1, 2, 7),
|
||||
TEGRA410_SYSTEM_GPIO_PORT(L, 1, 3, 7),
|
||||
TEGRA410_SYSTEM_GPIO_PORT(M, 2, 0, 7),
|
||||
TEGRA410_SYSTEM_GPIO_PORT(N, 2, 1, 6),
|
||||
TEGRA410_SYSTEM_GPIO_PORT(P, 2, 2, 8),
|
||||
TEGRA410_SYSTEM_GPIO_PORT(Q, 2, 3, 3),
|
||||
TEGRA410_SYSTEM_GPIO_PORT(R, 2, 4, 2),
|
||||
TEGRA410_SYSTEM_GPIO_PORT(V, 1, 4, 2),
|
||||
};
|
||||
|
||||
static const struct tegra_gpio_soc tegra410_system_soc = {
|
||||
.num_ports = ARRAY_SIZE(tegra410_system_ports),
|
||||
.ports = tegra410_system_ports,
|
||||
.name = "tegra410-gpio-system",
|
||||
.prefix = "SYSTEM",
|
||||
.num_irqs_per_bank = 8,
|
||||
.instance = 0,
|
||||
};
|
||||
|
||||
static const struct of_device_id tegra186_gpio_of_match[] = {
|
||||
{
|
||||
.compatible = "nvidia,tegra186-gpio",
|
||||
|
|
@ -1339,6 +1381,8 @@ static const struct acpi_device_id tegra186_gpio_acpi_match[] = {
|
|||
{ .id = "NVDA0408", .driver_data = (kernel_ulong_t)&tegra194_aon_soc },
|
||||
{ .id = "NVDA0508", .driver_data = (kernel_ulong_t)&tegra241_main_soc },
|
||||
{ .id = "NVDA0608", .driver_data = (kernel_ulong_t)&tegra241_aon_soc },
|
||||
{ .id = "NVDA0708", .driver_data = (kernel_ulong_t)&tegra410_compute_soc },
|
||||
{ .id = "NVDA0808", .driver_data = (kernel_ulong_t)&tegra410_system_soc },
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(acpi, tegra186_gpio_acpi_match);
|
||||
|
|
|
|||
|
|
@ -279,19 +279,18 @@ static void tqmx86_gpio_irq_handler(struct irq_desc *desc)
|
|||
}
|
||||
|
||||
/* Minimal runtime PM is needed by the IRQ subsystem */
|
||||
static int __maybe_unused tqmx86_gpio_runtime_suspend(struct device *dev)
|
||||
static int tqmx86_gpio_runtime_suspend(struct device *dev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __maybe_unused tqmx86_gpio_runtime_resume(struct device *dev)
|
||||
static int tqmx86_gpio_runtime_resume(struct device *dev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dev_pm_ops tqmx86_gpio_dev_pm_ops = {
|
||||
SET_RUNTIME_PM_OPS(tqmx86_gpio_runtime_suspend,
|
||||
tqmx86_gpio_runtime_resume, NULL)
|
||||
RUNTIME_PM_OPS(tqmx86_gpio_runtime_suspend, tqmx86_gpio_runtime_resume, NULL)
|
||||
};
|
||||
|
||||
static void tqmx86_init_irq_valid_mask(struct gpio_chip *chip,
|
||||
|
|
@ -425,7 +424,7 @@ static int tqmx86_gpio_probe(struct platform_device *pdev)
|
|||
static struct platform_driver tqmx86_gpio_driver = {
|
||||
.driver = {
|
||||
.name = "tqmx86-gpio",
|
||||
.pm = &tqmx86_gpio_dev_pm_ops,
|
||||
.pm = pm_ptr(&tqmx86_gpio_dev_pm_ops),
|
||||
},
|
||||
.probe = tqmx86_gpio_probe,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -426,7 +426,7 @@ static void uniphier_gpio_remove(struct platform_device *pdev)
|
|||
irq_domain_remove(priv->domain);
|
||||
}
|
||||
|
||||
static int __maybe_unused uniphier_gpio_suspend(struct device *dev)
|
||||
static int uniphier_gpio_suspend(struct device *dev)
|
||||
{
|
||||
struct uniphier_gpio_priv *priv = dev_get_drvdata(dev);
|
||||
unsigned int nbanks = uniphier_gpio_get_nbanks(priv->chip.ngpio);
|
||||
|
|
@ -448,7 +448,7 @@ static int __maybe_unused uniphier_gpio_suspend(struct device *dev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int __maybe_unused uniphier_gpio_resume(struct device *dev)
|
||||
static int uniphier_gpio_resume(struct device *dev)
|
||||
{
|
||||
struct uniphier_gpio_priv *priv = dev_get_drvdata(dev);
|
||||
unsigned int nbanks = uniphier_gpio_get_nbanks(priv->chip.ngpio);
|
||||
|
|
@ -473,8 +473,7 @@ static int __maybe_unused uniphier_gpio_resume(struct device *dev)
|
|||
}
|
||||
|
||||
static const struct dev_pm_ops uniphier_gpio_pm_ops = {
|
||||
SET_LATE_SYSTEM_SLEEP_PM_OPS(uniphier_gpio_suspend,
|
||||
uniphier_gpio_resume)
|
||||
LATE_SYSTEM_SLEEP_PM_OPS(uniphier_gpio_suspend, uniphier_gpio_resume)
|
||||
};
|
||||
|
||||
static const struct of_device_id uniphier_gpio_match[] = {
|
||||
|
|
@ -489,7 +488,7 @@ static struct platform_driver uniphier_gpio_driver = {
|
|||
.driver = {
|
||||
.name = "uniphier-gpio",
|
||||
.of_match_table = uniphier_gpio_match,
|
||||
.pm = &uniphier_gpio_pm_ops,
|
||||
.pm = pm_sleep_ptr(&uniphier_gpio_pm_ops),
|
||||
},
|
||||
};
|
||||
module_platform_driver(uniphier_gpio_driver);
|
||||
|
|
|
|||
|
|
@ -500,9 +500,7 @@ static int gpio_virtuser_value_set(void *data, u64 val)
|
|||
if (val > 1)
|
||||
return -EINVAL;
|
||||
|
||||
gpiod_set_value_cansleep(ld->ad.desc, (int)val);
|
||||
|
||||
return 0;
|
||||
return gpiod_set_value_cansleep(ld->ad.desc, (int)val);
|
||||
}
|
||||
|
||||
DEFINE_DEBUGFS_ATTRIBUTE(gpio_virtuser_value_fops,
|
||||
|
|
@ -543,7 +541,7 @@ static void gpio_virtuser_set_value_atomic(struct irq_work *work)
|
|||
struct gpio_virtuser_irq_work_context *ctx =
|
||||
to_gpio_virtuser_irq_work_context(work);
|
||||
|
||||
gpiod_set_value(ctx->desc, ctx->val);
|
||||
ctx->ret = gpiod_set_value(ctx->desc, ctx->val);
|
||||
complete(&ctx->work_completion);
|
||||
}
|
||||
|
||||
|
|
@ -562,7 +560,7 @@ static int gpio_virtuser_value_atomic_set(void *data, u64 val)
|
|||
|
||||
gpio_virtuser_irq_work_queue_sync(&ctx);
|
||||
|
||||
return 0;
|
||||
return ctx.ret;
|
||||
}
|
||||
|
||||
DEFINE_DEBUGFS_ATTRIBUTE(gpio_virtuser_value_atomic_fops,
|
||||
|
|
|
|||
|
|
@ -130,7 +130,7 @@ static int xgene_gpio_dir_out(struct gpio_chip *gc,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static __maybe_unused int xgene_gpio_suspend(struct device *dev)
|
||||
static int xgene_gpio_suspend(struct device *dev)
|
||||
{
|
||||
struct xgene_gpio *gpio = dev_get_drvdata(dev);
|
||||
unsigned long bank_offset;
|
||||
|
|
@ -143,7 +143,7 @@ static __maybe_unused int xgene_gpio_suspend(struct device *dev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static __maybe_unused int xgene_gpio_resume(struct device *dev)
|
||||
static int xgene_gpio_resume(struct device *dev)
|
||||
{
|
||||
struct xgene_gpio *gpio = dev_get_drvdata(dev);
|
||||
unsigned long bank_offset;
|
||||
|
|
@ -156,7 +156,7 @@ static __maybe_unused int xgene_gpio_resume(struct device *dev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(xgene_gpio_pm, xgene_gpio_suspend, xgene_gpio_resume);
|
||||
static DEFINE_SIMPLE_DEV_PM_OPS(xgene_gpio_pm, xgene_gpio_suspend, xgene_gpio_resume);
|
||||
|
||||
static int xgene_gpio_probe(struct platform_device *pdev)
|
||||
{
|
||||
|
|
@ -204,7 +204,7 @@ static struct platform_driver xgene_gpio_driver = {
|
|||
.name = "xgene-gpio",
|
||||
.of_match_table = xgene_gpio_of_match,
|
||||
.acpi_match_table = ACPI_PTR(xgene_gpio_acpi_match),
|
||||
.pm = &xgene_gpio_pm,
|
||||
.pm = pm_sleep_ptr(&xgene_gpio_pm),
|
||||
},
|
||||
.probe = xgene_gpio_probe,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -286,7 +286,7 @@ static void xgpio_free(struct gpio_chip *chip, unsigned int offset)
|
|||
pm_runtime_put(chip->parent);
|
||||
}
|
||||
|
||||
static int __maybe_unused xgpio_suspend(struct device *dev)
|
||||
static int xgpio_suspend(struct device *dev)
|
||||
{
|
||||
struct xgpio_instance *gpio = dev_get_drvdata(dev);
|
||||
struct irq_data *data = irq_get_irq_data(gpio->irq);
|
||||
|
|
@ -327,7 +327,7 @@ static void xgpio_irq_ack(struct irq_data *irq_data)
|
|||
{
|
||||
}
|
||||
|
||||
static int __maybe_unused xgpio_resume(struct device *dev)
|
||||
static int xgpio_resume(struct device *dev)
|
||||
{
|
||||
struct xgpio_instance *gpio = dev_get_drvdata(dev);
|
||||
struct irq_data *data = irq_get_irq_data(gpio->irq);
|
||||
|
|
@ -343,7 +343,7 @@ static int __maybe_unused xgpio_resume(struct device *dev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int __maybe_unused xgpio_runtime_suspend(struct device *dev)
|
||||
static int xgpio_runtime_suspend(struct device *dev)
|
||||
{
|
||||
struct xgpio_instance *gpio = dev_get_drvdata(dev);
|
||||
|
||||
|
|
@ -352,7 +352,7 @@ static int __maybe_unused xgpio_runtime_suspend(struct device *dev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int __maybe_unused xgpio_runtime_resume(struct device *dev)
|
||||
static int xgpio_runtime_resume(struct device *dev)
|
||||
{
|
||||
struct xgpio_instance *gpio = dev_get_drvdata(dev);
|
||||
|
||||
|
|
@ -360,9 +360,8 @@ static int __maybe_unused xgpio_runtime_resume(struct device *dev)
|
|||
}
|
||||
|
||||
static const struct dev_pm_ops xgpio_dev_pm_ops = {
|
||||
SET_SYSTEM_SLEEP_PM_OPS(xgpio_suspend, xgpio_resume)
|
||||
SET_RUNTIME_PM_OPS(xgpio_runtime_suspend,
|
||||
xgpio_runtime_resume, NULL)
|
||||
SYSTEM_SLEEP_PM_OPS(xgpio_suspend, xgpio_resume)
|
||||
RUNTIME_PM_OPS(xgpio_runtime_suspend, xgpio_runtime_resume, NULL)
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -682,7 +681,7 @@ static struct platform_driver xgpio_plat_driver = {
|
|||
.driver = {
|
||||
.name = "gpio-xilinx",
|
||||
.of_match_table = xgpio_of_match,
|
||||
.pm = &xgpio_dev_pm_ops,
|
||||
.pm = pm_ptr(&xgpio_dev_pm_ops),
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -735,7 +735,7 @@ static void zynq_gpio_restore_context(struct zynq_gpio *gpio)
|
|||
}
|
||||
}
|
||||
|
||||
static int __maybe_unused zynq_gpio_suspend(struct device *dev)
|
||||
static int zynq_gpio_suspend(struct device *dev)
|
||||
{
|
||||
struct zynq_gpio *gpio = dev_get_drvdata(dev);
|
||||
struct irq_data *data = irq_get_irq_data(gpio->irq);
|
||||
|
|
@ -756,7 +756,7 @@ static int __maybe_unused zynq_gpio_suspend(struct device *dev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int __maybe_unused zynq_gpio_resume(struct device *dev)
|
||||
static int zynq_gpio_resume(struct device *dev)
|
||||
{
|
||||
struct zynq_gpio *gpio = dev_get_drvdata(dev);
|
||||
struct irq_data *data = irq_get_irq_data(gpio->irq);
|
||||
|
|
@ -779,7 +779,7 @@ static int __maybe_unused zynq_gpio_resume(struct device *dev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int __maybe_unused zynq_gpio_runtime_suspend(struct device *dev)
|
||||
static int zynq_gpio_runtime_suspend(struct device *dev)
|
||||
{
|
||||
struct zynq_gpio *gpio = dev_get_drvdata(dev);
|
||||
|
||||
|
|
@ -788,7 +788,7 @@ static int __maybe_unused zynq_gpio_runtime_suspend(struct device *dev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int __maybe_unused zynq_gpio_runtime_resume(struct device *dev)
|
||||
static int zynq_gpio_runtime_resume(struct device *dev)
|
||||
{
|
||||
struct zynq_gpio *gpio = dev_get_drvdata(dev);
|
||||
|
||||
|
|
@ -814,9 +814,8 @@ static void zynq_gpio_free(struct gpio_chip *chip, unsigned int offset)
|
|||
}
|
||||
|
||||
static const struct dev_pm_ops zynq_gpio_dev_pm_ops = {
|
||||
SET_SYSTEM_SLEEP_PM_OPS(zynq_gpio_suspend, zynq_gpio_resume)
|
||||
SET_RUNTIME_PM_OPS(zynq_gpio_runtime_suspend,
|
||||
zynq_gpio_runtime_resume, NULL)
|
||||
SYSTEM_SLEEP_PM_OPS(zynq_gpio_suspend, zynq_gpio_resume)
|
||||
RUNTIME_PM_OPS(zynq_gpio_runtime_suspend, zynq_gpio_runtime_resume, NULL)
|
||||
};
|
||||
|
||||
static const struct zynq_platform_data versal_gpio_def = {
|
||||
|
|
@ -1022,7 +1021,7 @@ static void zynq_gpio_remove(struct platform_device *pdev)
|
|||
static struct platform_driver zynq_gpio_driver = {
|
||||
.driver = {
|
||||
.name = DRIVER_NAME,
|
||||
.pm = &zynq_gpio_dev_pm_ops,
|
||||
.pm = pm_ptr(&zynq_gpio_dev_pm_ops),
|
||||
.of_match_table = zynq_gpio_of_match,
|
||||
},
|
||||
.probe = zynq_gpio_probe,
|
||||
|
|
|
|||
|
|
@ -1099,7 +1099,7 @@ acpi_gpio_adr_space_handler(u32 function, acpi_physical_address address,
|
|||
return AE_BAD_PARAMETER;
|
||||
}
|
||||
|
||||
length = min_t(u16, agpio->pin_table_length, pin_index + bits);
|
||||
length = min(agpio->pin_table_length, pin_index + bits);
|
||||
for (i = pin_index; i < length; ++i) {
|
||||
unsigned int pin = agpio->pin_table[i];
|
||||
struct acpi_gpio_connection *conn;
|
||||
|
|
|
|||
|
|
@ -652,7 +652,7 @@ static enum hte_return process_hw_ts_thread(void *p)
|
|||
}
|
||||
le.line_seqno = line->line_seqno;
|
||||
le.seqno = (lr->num_lines == 1) ? le.line_seqno : line->req_seqno;
|
||||
le.offset = gpio_chip_hwgpio(line->desc);
|
||||
le.offset = gpiod_hwgpio(line->desc);
|
||||
|
||||
linereq_put_event(lr, &le);
|
||||
|
||||
|
|
@ -676,7 +676,7 @@ static enum hte_return process_hw_ts(struct hte_ts_data *ts, void *p)
|
|||
if (READ_ONCE(line->sw_debounced)) {
|
||||
line->total_discard_seq++;
|
||||
line->last_seqno = ts->seq;
|
||||
mod_delayed_work(system_wq, &line->work,
|
||||
mod_delayed_work(system_percpu_wq, &line->work,
|
||||
usecs_to_jiffies(READ_ONCE(line->desc->debounce_period_us)));
|
||||
} else {
|
||||
if (unlikely(ts->seq < line->line_seqno))
|
||||
|
|
@ -769,7 +769,7 @@ static irqreturn_t edge_irq_thread(int irq, void *p)
|
|||
line->line_seqno++;
|
||||
le.line_seqno = line->line_seqno;
|
||||
le.seqno = (lr->num_lines == 1) ? le.line_seqno : line->req_seqno;
|
||||
le.offset = gpio_chip_hwgpio(line->desc);
|
||||
le.offset = gpiod_hwgpio(line->desc);
|
||||
|
||||
linereq_put_event(lr, &le);
|
||||
|
||||
|
|
@ -817,7 +817,7 @@ static irqreturn_t debounce_irq_handler(int irq, void *p)
|
|||
{
|
||||
struct line *line = p;
|
||||
|
||||
mod_delayed_work(system_wq, &line->work,
|
||||
mod_delayed_work(system_percpu_wq, &line->work,
|
||||
usecs_to_jiffies(READ_ONCE(line->desc->debounce_period_us)));
|
||||
|
||||
return IRQ_HANDLED;
|
||||
|
|
@ -867,7 +867,7 @@ static void debounce_work_func(struct work_struct *work)
|
|||
|
||||
lr = line->req;
|
||||
le.timestamp_ns = line_event_timestamp(line);
|
||||
le.offset = gpio_chip_hwgpio(line->desc);
|
||||
le.offset = gpiod_hwgpio(line->desc);
|
||||
#ifdef CONFIG_HTE
|
||||
if (edflags & GPIO_V2_LINE_FLAG_EVENT_CLOCK_HTE) {
|
||||
/* discard events except the last one */
|
||||
|
|
@ -1567,7 +1567,7 @@ static void linereq_show_fdinfo(struct seq_file *out, struct file *file)
|
|||
|
||||
for (i = 0; i < lr->num_lines; i++)
|
||||
seq_printf(out, "gpio-line:\t%d\n",
|
||||
gpio_chip_hwgpio(lr->lines[i].desc));
|
||||
gpiod_hwgpio(lr->lines[i].desc));
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
@ -2220,7 +2220,7 @@ static void gpio_desc_to_lineinfo(struct gpio_desc *desc,
|
|||
return;
|
||||
|
||||
memset(info, 0, sizeof(*info));
|
||||
info->offset = gpio_chip_hwgpio(desc);
|
||||
info->offset = gpiod_hwgpio(desc);
|
||||
|
||||
if (desc->name)
|
||||
strscpy(info->name, desc->name, sizeof(info->name));
|
||||
|
|
@ -2526,7 +2526,7 @@ static int lineinfo_changed_notify(struct notifier_block *nb,
|
|||
struct gpio_desc *desc = data;
|
||||
struct file *fp;
|
||||
|
||||
if (!test_bit(gpio_chip_hwgpio(desc), cdev->watched_lines))
|
||||
if (!test_bit(gpiod_hwgpio(desc), cdev->watched_lines))
|
||||
return NOTIFY_DONE;
|
||||
|
||||
/* Keep the file descriptor alive for the duration of the notification. */
|
||||
|
|
@ -2804,7 +2804,7 @@ int gpiolib_cdev_register(struct gpio_device *gdev, dev_t devt)
|
|||
if (!gc)
|
||||
return -ENODEV;
|
||||
|
||||
chip_dbg(gc, "added GPIO chardev (%d:%d)\n", MAJOR(devt), gdev->id);
|
||||
gpiochip_dbg(gc, "added GPIO chardev (%d:%d)\n", MAJOR(devt), gdev->id);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,30 +34,20 @@ EXPORT_SYMBOL_GPL(gpio_free);
|
|||
*/
|
||||
int gpio_request_one(unsigned gpio, unsigned long flags, const char *label)
|
||||
{
|
||||
struct gpio_desc *desc;
|
||||
int err;
|
||||
|
||||
/* Compatibility: assume unavailable "valid" GPIOs will appear later */
|
||||
desc = gpio_to_desc(gpio);
|
||||
if (!desc)
|
||||
return -EPROBE_DEFER;
|
||||
|
||||
err = gpiod_request(desc, label);
|
||||
err = gpio_request(gpio, label);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (flags & GPIOF_IN)
|
||||
err = gpiod_direction_input(desc);
|
||||
err = gpio_direction_input(gpio);
|
||||
else
|
||||
err = gpiod_direction_output_raw(desc, !!(flags & GPIOF_OUT_INIT_HIGH));
|
||||
err = gpio_direction_output(gpio, !!(flags & GPIOF_OUT_INIT_HIGH));
|
||||
|
||||
if (err)
|
||||
goto free_gpio;
|
||||
gpio_free(gpio);
|
||||
|
||||
return 0;
|
||||
|
||||
free_gpio:
|
||||
gpiod_free(desc);
|
||||
return err;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(gpio_request_one);
|
||||
|
|
@ -78,11 +68,9 @@ int gpio_request(unsigned gpio, const char *label)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(gpio_request);
|
||||
|
||||
static void devm_gpio_release(struct device *dev, void *res)
|
||||
static void devm_gpio_release(void *gpio)
|
||||
{
|
||||
unsigned *gpio = res;
|
||||
|
||||
gpio_free(*gpio);
|
||||
gpio_free((unsigned)(unsigned long)gpio);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -100,22 +88,22 @@ static void devm_gpio_release(struct device *dev, void *res)
|
|||
int devm_gpio_request_one(struct device *dev, unsigned gpio,
|
||||
unsigned long flags, const char *label)
|
||||
{
|
||||
unsigned *dr;
|
||||
int rc;
|
||||
|
||||
dr = devres_alloc(devm_gpio_release, sizeof(unsigned), GFP_KERNEL);
|
||||
if (!dr)
|
||||
return -ENOMEM;
|
||||
rc = gpio_request(gpio, label);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
if (flags & GPIOF_IN)
|
||||
rc = gpio_direction_input(gpio);
|
||||
else
|
||||
rc = gpio_direction_output(gpio, !!(flags & GPIOF_OUT_INIT_HIGH));
|
||||
|
||||
rc = gpio_request_one(gpio, flags, label);
|
||||
if (rc) {
|
||||
devres_free(dr);
|
||||
gpio_free(gpio);
|
||||
return rc;
|
||||
}
|
||||
|
||||
*dr = gpio;
|
||||
devres_add(dev, dr);
|
||||
|
||||
return 0;
|
||||
return devm_add_action_or_reset(dev, devm_gpio_release, (void *)(unsigned long)gpio);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(devm_gpio_request_one);
|
||||
|
|
|
|||
|
|
@ -1031,85 +1031,6 @@ static int of_gpio_threecell_xlate(struct gpio_chip *gc,
|
|||
return gpiospec->args[1];
|
||||
}
|
||||
|
||||
#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
|
||||
* @mm_gc: pointer to the of_mm_gpio_chip allocated structure
|
||||
* @data: driver data to store in the struct gpio_chip
|
||||
*
|
||||
* To use this function you should allocate and fill mm_gc with:
|
||||
*
|
||||
* 1) In the gpio_chip structure:
|
||||
* - all the callbacks
|
||||
* - of_gpio_n_cells
|
||||
* - of_xlate callback (optional)
|
||||
*
|
||||
* 3) In the of_mm_gpio_chip structure:
|
||||
* - save_regs callback (optional)
|
||||
*
|
||||
* If succeeded, this function will map bank's memory and will
|
||||
* do all necessary work for you. Then you'll able to use .regs
|
||||
* to manage GPIOs from the callbacks.
|
||||
*
|
||||
* Returns:
|
||||
* 0 on success, or negative errno on failure.
|
||||
*/
|
||||
int of_mm_gpiochip_add_data(struct device_node *np,
|
||||
struct of_mm_gpio_chip *mm_gc,
|
||||
void *data)
|
||||
{
|
||||
int ret = -ENOMEM;
|
||||
struct gpio_chip *gc = &mm_gc->gc;
|
||||
|
||||
gc->label = kasprintf(GFP_KERNEL, "%pOF", np);
|
||||
if (!gc->label)
|
||||
goto err0;
|
||||
|
||||
mm_gc->regs = of_iomap(np, 0);
|
||||
if (!mm_gc->regs)
|
||||
goto err1;
|
||||
|
||||
gc->base = -1;
|
||||
|
||||
if (mm_gc->save_regs)
|
||||
mm_gc->save_regs(mm_gc);
|
||||
|
||||
fwnode_handle_put(mm_gc->gc.fwnode);
|
||||
mm_gc->gc.fwnode = fwnode_handle_get(of_fwnode_handle(np));
|
||||
|
||||
ret = gpiochip_add_data(gc, data);
|
||||
if (ret)
|
||||
goto err2;
|
||||
|
||||
return 0;
|
||||
err2:
|
||||
of_node_put(np);
|
||||
iounmap(mm_gc->regs);
|
||||
err1:
|
||||
kfree(gc->label);
|
||||
err0:
|
||||
pr_err("%pOF: GPIO chip registration failed with status %d\n", np, ret);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(of_mm_gpiochip_add_data);
|
||||
|
||||
/**
|
||||
* of_mm_gpiochip_remove - Remove memory mapped GPIO chip (bank)
|
||||
* @mm_gc: pointer to the of_mm_gpio_chip allocated structure
|
||||
*/
|
||||
void of_mm_gpiochip_remove(struct of_mm_gpio_chip *mm_gc)
|
||||
{
|
||||
struct gpio_chip *gc = &mm_gc->gc;
|
||||
|
||||
gpiochip_remove(gc);
|
||||
iounmap(mm_gc->regs);
|
||||
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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -49,6 +49,7 @@ struct gpio_shared_entry {
|
|||
unsigned int offset;
|
||||
/* Index in the property value array. */
|
||||
size_t index;
|
||||
struct mutex lock;
|
||||
struct gpio_shared_desc *shared_desc;
|
||||
struct kref ref;
|
||||
struct list_head refs;
|
||||
|
|
@ -58,6 +59,7 @@ static LIST_HEAD(gpio_shared_list);
|
|||
static DEFINE_MUTEX(gpio_shared_lock);
|
||||
static DEFINE_IDA(gpio_shared_ida);
|
||||
|
||||
#if IS_ENABLED(CONFIG_OF)
|
||||
static struct gpio_shared_entry *
|
||||
gpio_shared_find_entry(struct fwnode_handle *controller_node,
|
||||
unsigned int offset)
|
||||
|
|
@ -72,7 +74,26 @@ gpio_shared_find_entry(struct fwnode_handle *controller_node,
|
|||
return NULL;
|
||||
}
|
||||
|
||||
#if IS_ENABLED(CONFIG_OF)
|
||||
/* Handle all special nodes that we should ignore. */
|
||||
static bool gpio_shared_of_node_ignore(struct device_node *node)
|
||||
{
|
||||
/*
|
||||
* __symbols__ is a special, internal node and should not be considered
|
||||
* when scanning for shared GPIOs.
|
||||
*/
|
||||
if (of_node_name_eq(node, "__symbols__"))
|
||||
return true;
|
||||
|
||||
/*
|
||||
* GPIO hogs have a "gpios" property which is not a phandle and can't
|
||||
* possibly refer to a shared GPIO.
|
||||
*/
|
||||
if (of_property_present(node, "gpio-hog"))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static int gpio_shared_of_traverse(struct device_node *curr)
|
||||
{
|
||||
struct gpio_shared_entry *entry;
|
||||
|
|
@ -84,6 +105,9 @@ static int gpio_shared_of_traverse(struct device_node *curr)
|
|||
const char *suffix;
|
||||
int ret, count, i;
|
||||
|
||||
if (gpio_shared_of_node_ignore(curr))
|
||||
return 0;
|
||||
|
||||
for_each_property_of_node(curr, prop) {
|
||||
/*
|
||||
* The standard name for a GPIO property is "foo-gpios"
|
||||
|
|
@ -147,6 +171,7 @@ static int gpio_shared_of_traverse(struct device_node *curr)
|
|||
entry->offset = offset;
|
||||
entry->index = count;
|
||||
INIT_LIST_HEAD(&entry->refs);
|
||||
mutex_init(&entry->lock);
|
||||
|
||||
list_add_tail(&entry->list, &gpio_shared_list);
|
||||
}
|
||||
|
|
@ -205,7 +230,10 @@ static int gpio_shared_of_traverse(struct device_node *curr)
|
|||
|
||||
static int gpio_shared_of_scan(void)
|
||||
{
|
||||
return gpio_shared_of_traverse(of_root);
|
||||
if (of_root)
|
||||
return gpio_shared_of_traverse(of_root);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
static int gpio_shared_of_scan(void)
|
||||
|
|
@ -220,6 +248,7 @@ static void gpio_shared_adev_release(struct device *dev)
|
|||
}
|
||||
|
||||
static int gpio_shared_make_adev(struct gpio_device *gdev,
|
||||
struct gpio_shared_entry *entry,
|
||||
struct gpio_shared_ref *ref)
|
||||
{
|
||||
struct auxiliary_device *adev = &ref->adev;
|
||||
|
|
@ -232,6 +261,7 @@ static int gpio_shared_make_adev(struct gpio_device *gdev,
|
|||
adev->id = ref->dev_id;
|
||||
adev->name = "proxy";
|
||||
adev->dev.parent = gdev->dev.parent;
|
||||
adev->dev.platform_data = entry;
|
||||
adev->dev.release = gpio_shared_adev_release;
|
||||
|
||||
ret = auxiliary_device_init(adev);
|
||||
|
|
@ -250,6 +280,84 @@ static int gpio_shared_make_adev(struct gpio_device *gdev,
|
|||
return 0;
|
||||
}
|
||||
|
||||
#if IS_ENABLED(CONFIG_RESET_GPIO)
|
||||
/*
|
||||
* Special case: reset-gpio is an auxiliary device that's created dynamically
|
||||
* and put in between the GPIO controller and consumers of shared GPIOs
|
||||
* referred to by the "reset-gpios" property.
|
||||
*
|
||||
* If the supposed consumer of a shared GPIO didn't match any of the mappings
|
||||
* we created when scanning the firmware nodes, it's still possible that it's
|
||||
* the reset-gpio device which didn't exist at the time of the scan.
|
||||
*
|
||||
* This function verifies it an return true if it's the case.
|
||||
*/
|
||||
static bool gpio_shared_dev_is_reset_gpio(struct device *consumer,
|
||||
struct gpio_shared_entry *entry,
|
||||
struct gpio_shared_ref *ref)
|
||||
{
|
||||
struct fwnode_handle *reset_fwnode = dev_fwnode(consumer);
|
||||
struct fwnode_reference_args ref_args, aux_args;
|
||||
struct device *parent = consumer->parent;
|
||||
bool match;
|
||||
int ret;
|
||||
|
||||
/* The reset-gpio device must have a parent AND a firmware node. */
|
||||
if (!parent || !reset_fwnode)
|
||||
return false;
|
||||
|
||||
/*
|
||||
* FIXME: use device_is_compatible() once the reset-gpio drivers gains
|
||||
* a compatible string which it currently does not have.
|
||||
*/
|
||||
if (!strstarts(dev_name(consumer), "reset.gpio."))
|
||||
return false;
|
||||
|
||||
/*
|
||||
* Parent of the reset-gpio auxiliary device is the GPIO chip whose
|
||||
* fwnode we stored in the entry structure.
|
||||
*/
|
||||
if (!device_match_fwnode(parent, entry->fwnode))
|
||||
return false;
|
||||
|
||||
/*
|
||||
* The device associated with the shared reference's firmware node is
|
||||
* the consumer of the reset control exposed by the reset-gpio device.
|
||||
* It must have a "reset-gpios" property that's referencing the entry's
|
||||
* firmware node.
|
||||
*
|
||||
* The reference args must agree between the real consumer and the
|
||||
* auxiliary reset-gpio device.
|
||||
*/
|
||||
ret = fwnode_property_get_reference_args(ref->fwnode, "reset-gpios",
|
||||
NULL, 2, 0, &ref_args);
|
||||
if (ret)
|
||||
return false;
|
||||
|
||||
ret = fwnode_property_get_reference_args(reset_fwnode, "reset-gpios",
|
||||
NULL, 2, 0, &aux_args);
|
||||
if (ret) {
|
||||
fwnode_handle_put(ref_args.fwnode);
|
||||
return false;
|
||||
}
|
||||
|
||||
match = ((ref_args.fwnode == entry->fwnode) &&
|
||||
(aux_args.fwnode == entry->fwnode) &&
|
||||
(ref_args.args[0] == aux_args.args[0]));
|
||||
|
||||
fwnode_handle_put(ref_args.fwnode);
|
||||
fwnode_handle_put(aux_args.fwnode);
|
||||
return match;
|
||||
}
|
||||
#else
|
||||
static bool gpio_shared_dev_is_reset_gpio(struct device *consumer,
|
||||
struct gpio_shared_entry *entry,
|
||||
struct gpio_shared_ref *ref)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
#endif /* CONFIG_RESET_GPIO */
|
||||
|
||||
int gpio_shared_add_proxy_lookup(struct device *consumer, unsigned long lflags)
|
||||
{
|
||||
const char *dev_id = dev_name(consumer);
|
||||
|
|
@ -265,7 +373,8 @@ int gpio_shared_add_proxy_lookup(struct device *consumer, unsigned long lflags)
|
|||
|
||||
list_for_each_entry(entry, &gpio_shared_list, list) {
|
||||
list_for_each_entry(ref, &entry->refs, list) {
|
||||
if (!device_match_fwnode(consumer, ref->fwnode))
|
||||
if (!device_match_fwnode(consumer, ref->fwnode) &&
|
||||
!gpio_shared_dev_is_reset_gpio(consumer, entry, ref))
|
||||
continue;
|
||||
|
||||
/* We've already done that on a previous request. */
|
||||
|
|
@ -356,7 +465,7 @@ int gpio_device_setup_shared(struct gpio_device *gdev)
|
|||
pr_debug("Setting up a shared GPIO entry for %s\n",
|
||||
fwnode_get_name(ref->fwnode));
|
||||
|
||||
ret = gpio_shared_make_adev(gdev, ref);
|
||||
ret = gpio_shared_make_adev(gdev, entry, ref);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -390,10 +499,11 @@ static void gpio_shared_release(struct kref *kref)
|
|||
{
|
||||
struct gpio_shared_entry *entry =
|
||||
container_of(kref, struct gpio_shared_entry, ref);
|
||||
struct gpio_shared_desc *shared_desc = entry->shared_desc;
|
||||
struct gpio_shared_desc *shared_desc;
|
||||
|
||||
guard(mutex)(&gpio_shared_lock);
|
||||
guard(mutex)(&entry->lock);
|
||||
|
||||
shared_desc = entry->shared_desc;
|
||||
gpio_device_put(shared_desc->desc->gdev);
|
||||
if (shared_desc->can_sleep)
|
||||
mutex_destroy(&shared_desc->mutex);
|
||||
|
|
@ -416,6 +526,8 @@ gpiod_shared_desc_create(struct gpio_shared_entry *entry)
|
|||
struct gpio_shared_desc *shared_desc;
|
||||
struct gpio_device *gdev;
|
||||
|
||||
lockdep_assert_held(&entry->lock);
|
||||
|
||||
shared_desc = kzalloc(sizeof(*shared_desc), GFP_KERNEL);
|
||||
if (!shared_desc)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
|
@ -436,57 +548,42 @@ gpiod_shared_desc_create(struct gpio_shared_entry *entry)
|
|||
return shared_desc;
|
||||
}
|
||||
|
||||
static struct gpio_shared_entry *gpiod_shared_find(struct auxiliary_device *adev)
|
||||
struct gpio_shared_desc *devm_gpiod_shared_get(struct device *dev)
|
||||
{
|
||||
struct gpio_shared_desc *shared_desc;
|
||||
struct gpio_shared_entry *entry;
|
||||
struct gpio_shared_ref *ref;
|
||||
int ret;
|
||||
|
||||
guard(mutex)(&gpio_shared_lock);
|
||||
lockdep_assert_not_held(&gpio_shared_lock);
|
||||
|
||||
list_for_each_entry(entry, &gpio_shared_list, list) {
|
||||
list_for_each_entry(ref, &entry->refs, list) {
|
||||
if (adev != &ref->adev)
|
||||
continue;
|
||||
|
||||
if (entry->shared_desc) {
|
||||
kref_get(&entry->ref);
|
||||
return entry;
|
||||
}
|
||||
entry = dev_get_platdata(dev);
|
||||
if (WARN_ON(!entry))
|
||||
/* Programmer bug */
|
||||
return ERR_PTR(-ENOENT);
|
||||
|
||||
scoped_guard(mutex, &entry->lock) {
|
||||
if (entry->shared_desc) {
|
||||
kref_get(&entry->ref);
|
||||
shared_desc = entry->shared_desc;
|
||||
} else {
|
||||
shared_desc = gpiod_shared_desc_create(entry);
|
||||
if (IS_ERR(shared_desc))
|
||||
return ERR_CAST(shared_desc);
|
||||
|
||||
kref_init(&entry->ref);
|
||||
entry->shared_desc = shared_desc;
|
||||
|
||||
pr_debug("Device %s acquired a reference to the shared GPIO %u owned by %s\n",
|
||||
dev_name(&adev->dev), gpio_chip_hwgpio(shared_desc->desc),
|
||||
gpio_device_get_label(shared_desc->desc->gdev));
|
||||
|
||||
|
||||
return entry;
|
||||
}
|
||||
|
||||
pr_debug("Device %s acquired a reference to the shared GPIO %u owned by %s\n",
|
||||
dev_name(dev), gpiod_hwgpio(shared_desc->desc),
|
||||
gpio_device_get_label(shared_desc->desc->gdev));
|
||||
}
|
||||
|
||||
return ERR_PTR(-ENOENT);
|
||||
}
|
||||
|
||||
struct gpio_shared_desc *devm_gpiod_shared_get(struct device *dev)
|
||||
{
|
||||
struct gpio_shared_entry *entry;
|
||||
int ret;
|
||||
|
||||
entry = gpiod_shared_find(to_auxiliary_dev(dev));
|
||||
if (IS_ERR(entry))
|
||||
return ERR_CAST(entry);
|
||||
|
||||
ret = devm_add_action_or_reset(dev, gpiod_shared_put, entry);
|
||||
if (ret)
|
||||
return ERR_PTR(ret);
|
||||
|
||||
return entry->shared_desc;
|
||||
return shared_desc;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(devm_gpiod_shared_get);
|
||||
|
||||
|
|
@ -502,6 +599,7 @@ static void gpio_shared_drop_ref(struct gpio_shared_ref *ref)
|
|||
static void gpio_shared_drop_entry(struct gpio_shared_entry *entry)
|
||||
{
|
||||
list_del(&entry->list);
|
||||
mutex_destroy(&entry->lock);
|
||||
fwnode_handle_put(entry->fwnode);
|
||||
kfree(entry);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ static struct gpio_device *swnode_get_gpio_device(struct fwnode_handle *fwnode)
|
|||
|
||||
gdev_node = to_software_node(fwnode);
|
||||
if (!gdev_node || !gdev_node->name)
|
||||
return ERR_PTR(-EINVAL);
|
||||
goto fwnode_lookup;
|
||||
|
||||
/*
|
||||
* Check for a special node that identifies undefined GPIOs, this is
|
||||
|
|
@ -41,6 +41,7 @@ static struct gpio_device *swnode_get_gpio_device(struct fwnode_handle *fwnode)
|
|||
!strcmp(gdev_node->name, GPIOLIB_SWNODE_UNDEFINED_NAME))
|
||||
return ERR_PTR(-ENOENT);
|
||||
|
||||
fwnode_lookup:
|
||||
gdev = gpio_device_find_by_fwnode(fwnode);
|
||||
return gdev ?: ERR_PTR(-EPROBE_DEFER);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -244,7 +244,7 @@ static int gpio_sysfs_request_irq(struct gpiod_data *data, unsigned char flags)
|
|||
* Remove this redundant call (along with the corresponding unlock)
|
||||
* when those drivers have been fixed.
|
||||
*/
|
||||
ret = gpiochip_lock_as_irq(guard.gc, gpio_chip_hwgpio(desc));
|
||||
ret = gpiochip_lock_as_irq(guard.gc, gpiod_hwgpio(desc));
|
||||
if (ret < 0)
|
||||
goto err_clr_bits;
|
||||
|
||||
|
|
@ -258,7 +258,7 @@ static int gpio_sysfs_request_irq(struct gpiod_data *data, unsigned char flags)
|
|||
return 0;
|
||||
|
||||
err_unlock:
|
||||
gpiochip_unlock_as_irq(guard.gc, gpio_chip_hwgpio(desc));
|
||||
gpiochip_unlock_as_irq(guard.gc, gpiod_hwgpio(desc));
|
||||
err_clr_bits:
|
||||
clear_bit(GPIOD_FLAG_EDGE_RISING, &desc->flags);
|
||||
clear_bit(GPIOD_FLAG_EDGE_FALLING, &desc->flags);
|
||||
|
|
@ -280,7 +280,7 @@ static void gpio_sysfs_free_irq(struct gpiod_data *data)
|
|||
|
||||
data->irq_flags = 0;
|
||||
free_irq(data->irq, data);
|
||||
gpiochip_unlock_as_irq(guard.gc, gpio_chip_hwgpio(desc));
|
||||
gpiochip_unlock_as_irq(guard.gc, gpiod_hwgpio(desc));
|
||||
clear_bit(GPIOD_FLAG_EDGE_RISING, &desc->flags);
|
||||
clear_bit(GPIOD_FLAG_EDGE_FALLING, &desc->flags);
|
||||
}
|
||||
|
|
@ -478,10 +478,10 @@ static int export_gpio_desc(struct gpio_desc *desc)
|
|||
if (!guard.gc)
|
||||
return -ENODEV;
|
||||
|
||||
offset = gpio_chip_hwgpio(desc);
|
||||
offset = gpiod_hwgpio(desc);
|
||||
if (!gpiochip_line_is_valid(guard.gc, offset)) {
|
||||
pr_debug_ratelimited("%s: GPIO %d masked\n", __func__,
|
||||
gpio_chip_hwgpio(desc));
|
||||
gpiod_hwgpio(desc));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
|
@ -823,7 +823,7 @@ int gpiod_export(struct gpio_desc *desc, bool direction_may_change)
|
|||
}
|
||||
|
||||
desc_data->chip_attr_group.name = kasprintf(GFP_KERNEL, "gpio%u",
|
||||
gpio_chip_hwgpio(desc));
|
||||
gpiod_hwgpio(desc));
|
||||
if (!desc_data->chip_attr_group.name) {
|
||||
status = -ENOMEM;
|
||||
goto err_put_dirent;
|
||||
|
|
@ -843,7 +843,7 @@ int gpiod_export(struct gpio_desc *desc, bool direction_may_change)
|
|||
if (status)
|
||||
goto err_free_name;
|
||||
|
||||
path = kasprintf(GFP_KERNEL, "gpio%u/value", gpio_chip_hwgpio(desc));
|
||||
path = kasprintf(GFP_KERNEL, "gpio%u/value", gpiod_hwgpio(desc));
|
||||
if (!path) {
|
||||
status = -ENOMEM;
|
||||
goto err_remove_groups;
|
||||
|
|
@ -1091,7 +1091,7 @@ static int gpiofind_sysfs_register(struct gpio_chip *gc, const void *data)
|
|||
|
||||
ret = gpiochip_sysfs_register(gdev);
|
||||
if (ret)
|
||||
chip_err(gc, "failed to register the sysfs entry: %d\n", ret);
|
||||
gpiochip_err(gc, "failed to register the sysfs entry: %d\n", ret);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -236,6 +236,19 @@ int desc_to_gpio(const struct gpio_desc *desc)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(desc_to_gpio);
|
||||
|
||||
/**
|
||||
* gpiod_hwgpio - Return the GPIO number of the passed descriptor relative to
|
||||
* its chip.
|
||||
* @desc: GPIO descriptor
|
||||
*
|
||||
* Returns:
|
||||
* Hardware offset of the GPIO represented by the descriptor.
|
||||
*/
|
||||
int gpiod_hwgpio(const struct gpio_desc *desc)
|
||||
{
|
||||
return desc - &desc->gdev->descs[0];
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(gpiod_hwgpio);
|
||||
|
||||
/**
|
||||
* gpiod_to_chip - Return the GPIO chip to which a GPIO descriptor belongs
|
||||
|
|
@ -444,7 +457,7 @@ int gpiod_get_direction(struct gpio_desc *desc)
|
|||
if (!guard.gc)
|
||||
return -ENODEV;
|
||||
|
||||
offset = gpio_chip_hwgpio(desc);
|
||||
offset = gpiod_hwgpio(desc);
|
||||
flags = READ_ONCE(desc->flags);
|
||||
|
||||
/*
|
||||
|
|
@ -922,8 +935,8 @@ static void gpiochip_machine_hog(struct gpio_chip *gc, struct gpiod_hog *hog)
|
|||
|
||||
desc = gpiochip_get_desc(gc, hog->chip_hwnum);
|
||||
if (IS_ERR(desc)) {
|
||||
chip_err(gc, "%s: unable to get GPIO desc: %ld\n", __func__,
|
||||
PTR_ERR(desc));
|
||||
gpiochip_err(gc, "%s: unable to get GPIO desc: %ld\n",
|
||||
__func__, PTR_ERR(desc));
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -1125,7 +1138,7 @@ int gpiochip_add_data_with_key(struct gpio_chip *gc, void *data,
|
|||
|
||||
ret = gpiodev_add_to_list_unlocked(gdev);
|
||||
if (ret) {
|
||||
chip_err(gc, "GPIO integer space overlap, cannot add chip\n");
|
||||
gpiochip_err(gc, "GPIO integer space overlap, cannot add chip\n");
|
||||
goto err_free_label;
|
||||
}
|
||||
}
|
||||
|
|
@ -1537,8 +1550,7 @@ static void gpiochip_set_hierarchical_irqchip(struct gpio_chip *gc,
|
|||
&parent_hwirq,
|
||||
&parent_type);
|
||||
if (ret) {
|
||||
chip_err(gc, "skip set-up on hwirq %d\n",
|
||||
i);
|
||||
gpiochip_err(gc, "skip set-up on hwirq %d\n", i);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
@ -1551,15 +1563,14 @@ static void gpiochip_set_hierarchical_irqchip(struct gpio_chip *gc,
|
|||
ret = irq_domain_alloc_irqs(gc->irq.domain, 1,
|
||||
NUMA_NO_NODE, &fwspec);
|
||||
if (ret < 0) {
|
||||
chip_err(gc,
|
||||
"can not allocate irq for GPIO line %d parent hwirq %d in hierarchy domain: %d\n",
|
||||
i, parent_hwirq,
|
||||
ret);
|
||||
gpiochip_err(gc,
|
||||
"can not allocate irq for GPIO line %d parent hwirq %d in hierarchy domain: %d\n",
|
||||
i, parent_hwirq, ret);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
chip_err(gc, "%s unknown fwnode type proceed anyway\n", __func__);
|
||||
gpiochip_err(gc, "%s unknown fwnode type proceed anyway\n", __func__);
|
||||
|
||||
return;
|
||||
}
|
||||
|
|
@ -1611,15 +1622,15 @@ 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);
|
||||
gpiochip_dbg(gc, "allocate IRQ %d, hwirq %lu\n", irq, hwirq);
|
||||
|
||||
ret = girq->child_to_parent_hwirq(gc, hwirq, type,
|
||||
&parent_hwirq, &parent_type);
|
||||
if (ret) {
|
||||
chip_err(gc, "can't look up hwirq %lu\n", hwirq);
|
||||
gpiochip_err(gc, "can't look up hwirq %lu\n", hwirq);
|
||||
return ret;
|
||||
}
|
||||
chip_dbg(gc, "found parent hwirq %u\n", parent_hwirq);
|
||||
gpiochip_dbg(gc, "found parent hwirq %u\n", parent_hwirq);
|
||||
|
||||
/*
|
||||
* We set handle_bad_irq because the .set_type() should
|
||||
|
|
@ -1640,8 +1651,8 @@ static int gpiochip_hierarchy_irq_domain_alloc(struct irq_domain *d,
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
chip_dbg(gc, "alloc_irqs_parent for %d parent hwirq %d\n",
|
||||
irq, parent_hwirq);
|
||||
gpiochip_dbg(gc, "alloc_irqs_parent for %d parent hwirq %d\n",
|
||||
irq, parent_hwirq);
|
||||
irq_set_lockdep_class(irq, gc->irq.lock_key, gc->irq.request_key);
|
||||
ret = irq_domain_alloc_irqs_parent(d, irq, 1, &gpio_parent_fwspec);
|
||||
/*
|
||||
|
|
@ -1651,9 +1662,9 @@ static int gpiochip_hierarchy_irq_domain_alloc(struct irq_domain *d,
|
|||
if (irq_domain_is_msi(d->parent) && (ret == -EEXIST))
|
||||
ret = 0;
|
||||
if (ret)
|
||||
chip_err(gc,
|
||||
"failed to allocate parent hwirq %d for hwirq %lu\n",
|
||||
parent_hwirq, hwirq);
|
||||
gpiochip_err(gc,
|
||||
"failed to allocate parent hwirq %d for hwirq %lu\n",
|
||||
parent_hwirq, hwirq);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -1729,7 +1740,7 @@ static struct irq_domain *gpiochip_hierarchy_create_domain(struct gpio_chip *gc)
|
|||
|
||||
if (!gc->irq.child_to_parent_hwirq ||
|
||||
!gc->irq.fwnode) {
|
||||
chip_err(gc, "missing irqdomain vital data\n");
|
||||
gpiochip_err(gc, "missing irqdomain vital data\n");
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
|
|
@ -2002,7 +2013,7 @@ static void gpiochip_set_irq_hooks(struct gpio_chip *gc)
|
|||
if (irqchip->flags & IRQCHIP_IMMUTABLE)
|
||||
return;
|
||||
|
||||
chip_warn(gc, "not an immutable chip, please consider fixing it!\n");
|
||||
gpiochip_warn(gc, "not an immutable chip, please consider fixing it!\n");
|
||||
|
||||
if (!irqchip->irq_request_resources &&
|
||||
!irqchip->irq_release_resources) {
|
||||
|
|
@ -2018,8 +2029,8 @@ static void gpiochip_set_irq_hooks(struct gpio_chip *gc)
|
|||
* ...and if so, give a gentle warning that this is bad
|
||||
* practice.
|
||||
*/
|
||||
chip_info(gc,
|
||||
"detected irqchip that is shared with multiple gpiochips: please fix the driver.\n");
|
||||
gpiochip_info(gc,
|
||||
"detected irqchip that is shared with multiple gpiochips: please fix the driver.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -2048,7 +2059,8 @@ static int gpiochip_irqchip_add_allocated_domain(struct gpio_chip *gc,
|
|||
return -EINVAL;
|
||||
|
||||
if (gc->to_irq)
|
||||
chip_warn(gc, "to_irq is redefined in %s and you shouldn't rely on it\n", __func__);
|
||||
gpiochip_warn(gc, "to_irq is redefined in %s and you shouldn't rely on it\n",
|
||||
__func__);
|
||||
|
||||
gc->to_irq = gpiochip_to_irq;
|
||||
gc->irq.domain = domain;
|
||||
|
|
@ -2089,7 +2101,7 @@ static int gpiochip_add_irqchip(struct gpio_chip *gc,
|
|||
return 0;
|
||||
|
||||
if (gc->irq.parent_handler && gc->can_sleep) {
|
||||
chip_err(gc, "you cannot have chained interrupts on a chip that may sleep\n");
|
||||
gpiochip_err(gc, "you cannot have chained interrupts on a chip that may sleep\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
|
@ -2325,10 +2337,8 @@ int gpiochip_add_pingroup_range(struct gpio_chip *gc,
|
|||
int ret;
|
||||
|
||||
pin_range = kzalloc(sizeof(*pin_range), GFP_KERNEL);
|
||||
if (!pin_range) {
|
||||
chip_err(gc, "failed to allocate pin ranges\n");
|
||||
if (!pin_range)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* Use local offset as range ID */
|
||||
pin_range->range.id = gpio_offset;
|
||||
|
|
@ -2347,7 +2357,7 @@ int gpiochip_add_pingroup_range(struct gpio_chip *gc,
|
|||
|
||||
pinctrl_add_gpio_range(pctldev, &pin_range->range);
|
||||
|
||||
chip_dbg(gc, "created GPIO range %d->%d ==> %s PINGRP %s\n",
|
||||
gpiochip_dbg(gc, "created GPIO range %d->%d ==> %s PINGRP %s\n",
|
||||
gpio_offset, gpio_offset + pin_range->range.npins - 1,
|
||||
pinctrl_dev_get_devname(pctldev), pin_group);
|
||||
|
||||
|
|
@ -2388,10 +2398,8 @@ int gpiochip_add_pin_range_with_pins(struct gpio_chip *gc,
|
|||
int ret;
|
||||
|
||||
pin_range = kzalloc(sizeof(*pin_range), GFP_KERNEL);
|
||||
if (!pin_range) {
|
||||
chip_err(gc, "failed to allocate pin ranges\n");
|
||||
if (!pin_range)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* Use local offset as range ID */
|
||||
pin_range->range.id = gpio_offset;
|
||||
|
|
@ -2405,19 +2413,18 @@ int gpiochip_add_pin_range_with_pins(struct gpio_chip *gc,
|
|||
&pin_range->range);
|
||||
if (IS_ERR(pin_range->pctldev)) {
|
||||
ret = PTR_ERR(pin_range->pctldev);
|
||||
chip_err(gc, "could not create pin range\n");
|
||||
gpiochip_err(gc, "could not create pin range\n");
|
||||
kfree(pin_range);
|
||||
return ret;
|
||||
}
|
||||
if (pin_range->range.pins)
|
||||
chip_dbg(gc, "created GPIO range %d->%d ==> %s %d sparse PIN range { %d, ... }",
|
||||
gpio_offset, gpio_offset + npins - 1,
|
||||
pinctl_name, npins, pins[0]);
|
||||
gpiochip_dbg(gc, "created GPIO range %d->%d ==> %s %d sparse PIN range { %d, ... }",
|
||||
gpio_offset, gpio_offset + npins - 1,
|
||||
pinctl_name, npins, pins[0]);
|
||||
else
|
||||
chip_dbg(gc, "created GPIO range %d->%d ==> %s PIN %d->%d\n",
|
||||
gpio_offset, gpio_offset + npins - 1,
|
||||
pinctl_name,
|
||||
pin_offset, pin_offset + npins - 1);
|
||||
gpiochip_dbg(gc, "created GPIO range %d->%d ==> %s PIN %d->%d\n",
|
||||
gpio_offset, gpio_offset + npins - 1, pinctl_name,
|
||||
pin_offset, pin_offset + npins - 1);
|
||||
|
||||
list_add_tail(&pin_range->node, &gdev->pin_ranges);
|
||||
|
||||
|
|
@ -2461,7 +2468,7 @@ static int gpiod_request_commit(struct gpio_desc *desc, const char *label)
|
|||
if (test_and_set_bit(GPIOD_FLAG_REQUESTED, &desc->flags))
|
||||
return -EBUSY;
|
||||
|
||||
offset = gpio_chip_hwgpio(desc);
|
||||
offset = gpiod_hwgpio(desc);
|
||||
if (!gpiochip_line_is_valid(guard.gc, offset))
|
||||
return -EINVAL;
|
||||
|
||||
|
|
@ -2523,7 +2530,7 @@ static void gpiod_free_commit(struct gpio_desc *desc)
|
|||
|
||||
if (guard.gc && test_bit(GPIOD_FLAG_REQUESTED, &flags)) {
|
||||
if (guard.gc->free)
|
||||
guard.gc->free(guard.gc, gpio_chip_hwgpio(desc));
|
||||
guard.gc->free(guard.gc, gpiod_hwgpio(desc));
|
||||
|
||||
clear_bit(GPIOD_FLAG_ACTIVE_LOW, &flags);
|
||||
clear_bit(GPIOD_FLAG_REQUESTED, &flags);
|
||||
|
|
@ -2627,7 +2634,7 @@ struct gpio_desc *gpiochip_request_own_desc(struct gpio_chip *gc,
|
|||
int ret;
|
||||
|
||||
if (IS_ERR(desc)) {
|
||||
chip_err(gc, "failed to get GPIO %s descriptor\n", name);
|
||||
gpiochip_err(gc, "failed to get GPIO %s descriptor\n", name);
|
||||
return desc;
|
||||
}
|
||||
|
||||
|
|
@ -2638,7 +2645,7 @@ struct gpio_desc *gpiochip_request_own_desc(struct gpio_chip *gc,
|
|||
ret = gpiod_configure_flags(desc, label, lflags, dflags);
|
||||
if (ret) {
|
||||
gpiod_free_commit(desc);
|
||||
chip_err(gc, "setup of own GPIO %s failed\n", name);
|
||||
gpiochip_err(gc, "setup of own GPIO %s failed\n", name);
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
|
|
@ -2683,7 +2690,7 @@ int gpio_do_set_config(struct gpio_desc *desc, unsigned long config)
|
|||
if (!guard.gc->set_config)
|
||||
return -ENOTSUPP;
|
||||
|
||||
ret = guard.gc->set_config(guard.gc, gpio_chip_hwgpio(desc), config);
|
||||
ret = guard.gc->set_config(guard.gc, gpiod_hwgpio(desc), config);
|
||||
if (ret > 0)
|
||||
ret = -EBADE;
|
||||
|
||||
|
|
@ -2714,7 +2721,7 @@ static int gpio_set_config_with_argument_optional(struct gpio_desc *desc,
|
|||
u32 argument)
|
||||
{
|
||||
struct device *dev = &desc->gdev->dev;
|
||||
int gpio = gpio_chip_hwgpio(desc);
|
||||
int gpio = gpiod_hwgpio(desc);
|
||||
int ret;
|
||||
|
||||
ret = gpio_set_config_with_argument(desc, mode, argument);
|
||||
|
|
@ -2877,9 +2884,9 @@ int gpiod_direction_input_nonotify(struct gpio_desc *desc)
|
|||
*/
|
||||
if (guard.gc->direction_input) {
|
||||
ret = gpiochip_direction_input(guard.gc,
|
||||
gpio_chip_hwgpio(desc));
|
||||
gpiod_hwgpio(desc));
|
||||
} else if (guard.gc->get_direction) {
|
||||
dir = gpiochip_get_direction(guard.gc, gpio_chip_hwgpio(desc));
|
||||
dir = gpiochip_get_direction(guard.gc, gpiod_hwgpio(desc));
|
||||
if (dir < 0)
|
||||
return dir;
|
||||
|
||||
|
|
@ -2938,12 +2945,12 @@ static int gpiod_direction_output_raw_commit(struct gpio_desc *desc, int value)
|
|||
|
||||
if (guard.gc->direction_output) {
|
||||
ret = gpiochip_direction_output(guard.gc,
|
||||
gpio_chip_hwgpio(desc), val);
|
||||
gpiod_hwgpio(desc), val);
|
||||
} else {
|
||||
/* Check that we are in output mode if we can */
|
||||
if (guard.gc->get_direction) {
|
||||
dir = gpiochip_get_direction(guard.gc,
|
||||
gpio_chip_hwgpio(desc));
|
||||
gpiod_hwgpio(desc));
|
||||
if (dir < 0)
|
||||
return dir;
|
||||
|
||||
|
|
@ -2958,7 +2965,7 @@ static int gpiod_direction_output_raw_commit(struct gpio_desc *desc, int value)
|
|||
* If we can't actively set the direction, we are some
|
||||
* output-only chip, so just drive the output as desired.
|
||||
*/
|
||||
ret = gpiochip_set(guard.gc, gpio_chip_hwgpio(desc), val);
|
||||
ret = gpiochip_set(guard.gc, gpiod_hwgpio(desc), val);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -3109,7 +3116,7 @@ int gpiod_enable_hw_timestamp_ns(struct gpio_desc *desc, unsigned long flags)
|
|||
}
|
||||
|
||||
ret = guard.gc->en_hw_timestamp(guard.gc,
|
||||
gpio_chip_hwgpio(desc), flags);
|
||||
gpiod_hwgpio(desc), flags);
|
||||
if (ret)
|
||||
gpiod_warn(desc, "%s: hw ts request failed\n", __func__);
|
||||
|
||||
|
|
@ -3141,7 +3148,7 @@ int gpiod_disable_hw_timestamp_ns(struct gpio_desc *desc, unsigned long flags)
|
|||
return -ENOTSUPP;
|
||||
}
|
||||
|
||||
ret = guard.gc->dis_hw_timestamp(guard.gc, gpio_chip_hwgpio(desc),
|
||||
ret = guard.gc->dis_hw_timestamp(guard.gc, gpiod_hwgpio(desc),
|
||||
flags);
|
||||
if (ret)
|
||||
gpiod_warn(desc, "%s: hw ts release failed\n", __func__);
|
||||
|
|
@ -3272,7 +3279,7 @@ static int gpiochip_get(struct gpio_chip *gc, unsigned int offset)
|
|||
|
||||
static int gpio_chip_get_value(struct gpio_chip *gc, const struct gpio_desc *desc)
|
||||
{
|
||||
return gc->get ? gpiochip_get(gc, gpio_chip_hwgpio(desc)) : -EIO;
|
||||
return gc->get ? gpiochip_get(gc, gpiod_hwgpio(desc)) : -EIO;
|
||||
}
|
||||
|
||||
/* I/O calls are only valid after configuration completed; the relevant
|
||||
|
|
@ -3432,7 +3439,7 @@ int gpiod_get_array_value_complex(bool raw, bool can_sleep,
|
|||
first = i;
|
||||
do {
|
||||
const struct gpio_desc *desc = desc_array[i];
|
||||
int hwgpio = gpio_chip_hwgpio(desc);
|
||||
int hwgpio = gpiod_hwgpio(desc);
|
||||
|
||||
__set_bit(hwgpio, mask);
|
||||
i++;
|
||||
|
|
@ -3454,7 +3461,7 @@ int gpiod_get_array_value_complex(bool raw, bool can_sleep,
|
|||
|
||||
for (j = first; j < i; ) {
|
||||
const struct gpio_desc *desc = desc_array[j];
|
||||
int hwgpio = gpio_chip_hwgpio(desc);
|
||||
int hwgpio = gpiod_hwgpio(desc);
|
||||
int value = test_bit(hwgpio, bits);
|
||||
|
||||
if (!raw && test_bit(GPIOD_FLAG_ACTIVE_LOW, &desc->flags))
|
||||
|
|
@ -3591,7 +3598,7 @@ EXPORT_SYMBOL_GPL(gpiod_get_array_value);
|
|||
*/
|
||||
static int gpio_set_open_drain_value_commit(struct gpio_desc *desc, bool value)
|
||||
{
|
||||
int ret = 0, offset = gpio_chip_hwgpio(desc);
|
||||
int ret = 0, offset = gpiod_hwgpio(desc);
|
||||
|
||||
CLASS(gpio_chip_guard, guard)(desc);
|
||||
if (!guard.gc)
|
||||
|
|
@ -3620,7 +3627,7 @@ static int gpio_set_open_drain_value_commit(struct gpio_desc *desc, bool value)
|
|||
*/
|
||||
static int gpio_set_open_source_value_commit(struct gpio_desc *desc, bool value)
|
||||
{
|
||||
int ret = 0, offset = gpio_chip_hwgpio(desc);
|
||||
int ret = 0, offset = gpiod_hwgpio(desc);
|
||||
|
||||
CLASS(gpio_chip_guard, guard)(desc);
|
||||
if (!guard.gc)
|
||||
|
|
@ -3652,7 +3659,7 @@ static int gpiod_set_raw_value_commit(struct gpio_desc *desc, bool value)
|
|||
return -ENODEV;
|
||||
|
||||
trace_gpio_value(desc_to_gpio(desc), 0, value);
|
||||
return gpiochip_set(guard.gc, gpio_chip_hwgpio(desc), value);
|
||||
return gpiochip_set(guard.gc, gpiod_hwgpio(desc), value);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -3775,7 +3782,7 @@ int gpiod_set_array_value_complex(bool raw, bool can_sleep,
|
|||
|
||||
do {
|
||||
struct gpio_desc *desc = desc_array[i];
|
||||
int hwgpio = gpio_chip_hwgpio(desc);
|
||||
int hwgpio = gpiod_hwgpio(desc);
|
||||
int value = test_bit(i, value_bitmap);
|
||||
|
||||
if (unlikely(!test_bit(GPIOD_FLAG_IS_OUT, &desc->flags)))
|
||||
|
|
@ -4035,7 +4042,7 @@ int gpiod_to_irq(const struct gpio_desc *desc)
|
|||
if (!gc)
|
||||
return -ENODEV;
|
||||
|
||||
offset = gpio_chip_hwgpio(desc);
|
||||
offset = gpiod_hwgpio(desc);
|
||||
if (gc->to_irq) {
|
||||
ret = gc->to_irq(gc, offset);
|
||||
if (ret)
|
||||
|
|
@ -4085,8 +4092,8 @@ int gpiochip_lock_as_irq(struct gpio_chip *gc, unsigned int offset)
|
|||
int dir = gpiod_get_direction(desc);
|
||||
|
||||
if (dir < 0) {
|
||||
chip_err(gc, "%s: cannot get GPIO direction\n",
|
||||
__func__);
|
||||
gpiochip_err(gc, "%s: cannot get GPIO direction\n",
|
||||
__func__);
|
||||
return dir;
|
||||
}
|
||||
}
|
||||
|
|
@ -4094,9 +4101,9 @@ int gpiochip_lock_as_irq(struct gpio_chip *gc, unsigned int offset)
|
|||
/* To be valid for IRQ the line needs to be input or open drain */
|
||||
if (test_bit(GPIOD_FLAG_IS_OUT, &desc->flags) &&
|
||||
!test_bit(GPIOD_FLAG_OPEN_DRAIN, &desc->flags)) {
|
||||
chip_err(gc,
|
||||
"%s: tried to flag a GPIO set as output for IRQ\n",
|
||||
__func__);
|
||||
gpiochip_err(gc,
|
||||
"%s: tried to flag a GPIO set as output for IRQ\n",
|
||||
__func__);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
|
|
@ -4173,7 +4180,7 @@ int gpiochip_reqres_irq(struct gpio_chip *gc, unsigned int offset)
|
|||
|
||||
ret = gpiochip_lock_as_irq(gc, offset);
|
||||
if (ret) {
|
||||
chip_err(gc, "unable to lock HW IRQ %u for IRQ\n", offset);
|
||||
gpiochip_err(gc, "unable to lock HW IRQ %u for IRQ\n", offset);
|
||||
module_put(gc->gpiodev->owner);
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -5015,7 +5022,7 @@ int gpiod_hog(struct gpio_desc *desc, const char *name,
|
|||
if (test_and_set_bit(GPIOD_FLAG_IS_HOGGED, &desc->flags))
|
||||
return 0;
|
||||
|
||||
hwnum = gpio_chip_hwgpio(desc);
|
||||
hwnum = gpiod_hwgpio(desc);
|
||||
|
||||
local_desc = gpiochip_request_own_desc(guard.gc, hwnum, name,
|
||||
lflags, dflags);
|
||||
|
|
@ -5096,7 +5103,7 @@ struct gpio_descs *__must_check gpiod_get_array(struct device *dev,
|
|||
* If pin hardware number of array member 0 is also 0, select
|
||||
* its chip as a candidate for fast bitmap processing path.
|
||||
*/
|
||||
if (descs->ndescs == 0 && gpio_chip_hwgpio(desc) == 0) {
|
||||
if (descs->ndescs == 0 && gpiod_hwgpio(desc) == 0) {
|
||||
struct gpio_descs *array;
|
||||
|
||||
bitmap_size = BITS_TO_LONGS(gdev->ngpio > count ?
|
||||
|
|
@ -5141,7 +5148,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 (gpio_chip_hwgpio(desc) != descs->ndescs) {
|
||||
else if (gpiod_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
|
||||
|
|
|
|||
|
|
@ -275,49 +275,30 @@ int gpiochip_get_ngpios(struct gpio_chip *gc, struct device *dev);
|
|||
struct gpio_desc *gpiochip_get_desc(struct gpio_chip *gc, unsigned int hwnum);
|
||||
const char *gpiod_get_label(struct gpio_desc *desc);
|
||||
|
||||
/*
|
||||
* Return the GPIO number of the passed descriptor relative to its chip
|
||||
*/
|
||||
static inline int gpio_chip_hwgpio(const struct gpio_desc *desc)
|
||||
{
|
||||
return desc - &desc->gdev->descs[0];
|
||||
}
|
||||
|
||||
/* With descriptor prefix */
|
||||
|
||||
#define gpiod_err(desc, fmt, ...) \
|
||||
#define __gpiod_pr(level, desc, fmt, ...) \
|
||||
do { \
|
||||
scoped_guard(srcu, &desc->gdev->desc_srcu) { \
|
||||
pr_err("gpio-%d (%s): " fmt, desc_to_gpio(desc), \
|
||||
gpiod_get_label(desc) ? : "?", ##__VA_ARGS__); \
|
||||
pr_##level("gpio-%d (%s): " fmt, desc_to_gpio(desc), \
|
||||
gpiod_get_label(desc) ?: "?", ##__VA_ARGS__); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define gpiod_warn(desc, fmt, ...) \
|
||||
do { \
|
||||
scoped_guard(srcu, &desc->gdev->desc_srcu) { \
|
||||
pr_warn("gpio-%d (%s): " fmt, desc_to_gpio(desc), \
|
||||
gpiod_get_label(desc) ? : "?", ##__VA_ARGS__); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define gpiod_dbg(desc, fmt, ...) \
|
||||
do { \
|
||||
scoped_guard(srcu, &desc->gdev->desc_srcu) { \
|
||||
pr_debug("gpio-%d (%s): " fmt, desc_to_gpio(desc), \
|
||||
gpiod_get_label(desc) ? : "?", ##__VA_ARGS__); \
|
||||
} \
|
||||
} while (0)
|
||||
#define gpiod_err(desc, fmt, ...) __gpiod_pr(err, desc, fmt, ##__VA_ARGS__)
|
||||
#define gpiod_warn(desc, fmt, ...) __gpiod_pr(warn, desc, fmt, ##__VA_ARGS__)
|
||||
#define gpiod_dbg(desc, fmt, ...) __gpiod_pr(debug, desc, fmt, ##__VA_ARGS__)
|
||||
|
||||
/* With chip prefix */
|
||||
|
||||
#define chip_err(gc, fmt, ...) \
|
||||
dev_err(&gc->gpiodev->dev, "(%s): " fmt, gc->label, ##__VA_ARGS__)
|
||||
#define chip_warn(gc, fmt, ...) \
|
||||
dev_warn(&gc->gpiodev->dev, "(%s): " fmt, gc->label, ##__VA_ARGS__)
|
||||
#define chip_info(gc, fmt, ...) \
|
||||
dev_info(&gc->gpiodev->dev, "(%s): " fmt, gc->label, ##__VA_ARGS__)
|
||||
#define chip_dbg(gc, fmt, ...) \
|
||||
dev_dbg(&gc->gpiodev->dev, "(%s): " fmt, gc->label, ##__VA_ARGS__)
|
||||
#define __gpiochip_pr(level, gc, fmt, ...) \
|
||||
do { \
|
||||
dev_##level(&gc->gpiodev->dev, "(%s): " fmt, gc->label, ##__VA_ARGS__); \
|
||||
} while (0)
|
||||
|
||||
#define gpiochip_err(gc, fmt, ...) __gpiochip_pr(err, gc, fmt, ##__VA_ARGS__)
|
||||
#define gpiochip_warn(gc, fmt, ...) __gpiochip_pr(warn, gc, fmt, ##__VA_ARGS__)
|
||||
#define gpiochip_info(gc, fmt, ...) __gpiochip_pr(info, gc, fmt, ##__VA_ARGS__)
|
||||
#define gpiochip_dbg(gc, fmt, ...) __gpiochip_pr(dbg, gc, fmt, ##__VA_ARGS__)
|
||||
|
||||
#endif /* GPIOLIB_H */
|
||||
|
|
|
|||
|
|
@ -41,6 +41,19 @@ config INTEL_VBTN
|
|||
To compile this driver as a module, choose M here: the module will
|
||||
be called intel_vbtn.
|
||||
|
||||
config INTEL_EHL_PSE_IO
|
||||
tristate "Intel Elkhart Lake PSE I/O driver"
|
||||
depends on PCI
|
||||
select AUXILIARY_BUS
|
||||
help
|
||||
Select this option to enable Intel Elkhart Lake PSE GPIO and Timed
|
||||
I/O support. This driver enumerates the PCI parent device and
|
||||
creates auxiliary child devices for these capabilities. The actual
|
||||
functionalities are provided by their respective auxiliary drivers.
|
||||
|
||||
To compile this driver as a module, choose M here: the module will
|
||||
be called intel_ehl_pse_io.
|
||||
|
||||
config INTEL_INT0002_VGPIO
|
||||
tristate "Intel ACPI INT0002 Virtual GPIO driver"
|
||||
depends on GPIOLIB && ACPI && PM_SLEEP
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ intel-target-$(CONFIG_INTEL_HID_EVENT) += hid.o
|
|||
intel-target-$(CONFIG_INTEL_VBTN) += vbtn.o
|
||||
|
||||
# Intel miscellaneous drivers
|
||||
intel-target-$(CONFIG_INTEL_EHL_PSE_IO) += ehl_pse_io.o
|
||||
intel-target-$(CONFIG_INTEL_INT0002_VGPIO) += int0002_vgpio.o
|
||||
intel-target-$(CONFIG_INTEL_ISHTP_ECLITE) += ishtp_eclite.o
|
||||
intel-target-$(CONFIG_INTEL_OAKTRAIL) += oaktrail.o
|
||||
|
|
|
|||
|
|
@ -77,7 +77,7 @@ static const struct software_node max17047_node = {
|
|||
* software node.
|
||||
*/
|
||||
static struct software_node_ref_args fusb302_mux_refs[] = {
|
||||
{ .node = NULL },
|
||||
SOFTWARE_NODE_REFERENCE(NULL),
|
||||
};
|
||||
|
||||
static const struct property_entry fusb302_properties[] = {
|
||||
|
|
@ -190,11 +190,6 @@ static void cht_int33fe_remove_nodes(struct cht_int33fe_data *data)
|
|||
{
|
||||
software_node_unregister_node_group(node_group);
|
||||
|
||||
if (fusb302_mux_refs[0].node) {
|
||||
fwnode_handle_put(software_node_fwnode(fusb302_mux_refs[0].node));
|
||||
fusb302_mux_refs[0].node = NULL;
|
||||
}
|
||||
|
||||
if (data->dp) {
|
||||
data->dp->secondary = NULL;
|
||||
fwnode_handle_put(data->dp);
|
||||
|
|
@ -202,7 +197,15 @@ static void cht_int33fe_remove_nodes(struct cht_int33fe_data *data)
|
|||
}
|
||||
}
|
||||
|
||||
static int cht_int33fe_add_nodes(struct cht_int33fe_data *data)
|
||||
static void cht_int33fe_put_swnode(void *data)
|
||||
{
|
||||
struct fwnode_handle *fwnode = data;
|
||||
|
||||
fwnode_handle_put(fwnode);
|
||||
fusb302_mux_refs[0] = SOFTWARE_NODE_REFERENCE(NULL);
|
||||
}
|
||||
|
||||
static int cht_int33fe_add_nodes(struct device *dev, struct cht_int33fe_data *data)
|
||||
{
|
||||
const struct software_node *mux_ref_node;
|
||||
int ret;
|
||||
|
|
@ -212,17 +215,25 @@ static int cht_int33fe_add_nodes(struct cht_int33fe_data *data)
|
|||
* until the mux driver has created software node for the mux device.
|
||||
* It means we depend on the mux driver. This function will return
|
||||
* -EPROBE_DEFER until the mux device is registered.
|
||||
*
|
||||
* FIXME: the relevant software node exists in intel-xhci-usb-role-switch
|
||||
* and - if exported - could be used to set up a static reference.
|
||||
*/
|
||||
mux_ref_node = software_node_find_by_name(NULL, "intel-xhci-usb-sw");
|
||||
if (!mux_ref_node)
|
||||
return -EPROBE_DEFER;
|
||||
|
||||
ret = devm_add_action_or_reset(dev, cht_int33fe_put_swnode,
|
||||
software_node_fwnode(mux_ref_node));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* Update node used in "usb-role-switch" property. Note that we
|
||||
* rely on software_node_register_node_group() to use the original
|
||||
* instance of properties instead of copying them.
|
||||
*/
|
||||
fusb302_mux_refs[0].node = mux_ref_node;
|
||||
fusb302_mux_refs[0] = SOFTWARE_NODE_REFERENCE(mux_ref_node);
|
||||
|
||||
ret = software_node_register_node_group(node_group);
|
||||
if (ret)
|
||||
|
|
@ -345,7 +356,7 @@ static int cht_int33fe_typec_probe(struct platform_device *pdev)
|
|||
return fusb302_irq;
|
||||
}
|
||||
|
||||
ret = cht_int33fe_add_nodes(data);
|
||||
ret = cht_int33fe_add_nodes(dev, data);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,86 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Intel Elkhart Lake Programmable Service Engine (PSE) I/O
|
||||
*
|
||||
* Copyright (c) 2025 Intel Corporation.
|
||||
*
|
||||
* Author: Raag Jadav <raag.jadav@intel.com>
|
||||
*/
|
||||
|
||||
#include <linux/auxiliary_bus.h>
|
||||
#include <linux/device/devres.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/gfp_types.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/sizes.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#include <linux/ehl_pse_io_aux.h>
|
||||
|
||||
#define EHL_PSE_IO_DEV_SIZE SZ_4K
|
||||
|
||||
static int ehl_pse_io_dev_create(struct pci_dev *pci, const char *name, int idx)
|
||||
{
|
||||
struct device *dev = &pci->dev;
|
||||
struct auxiliary_device *adev;
|
||||
struct ehl_pse_io_data *data;
|
||||
resource_size_t start, offset;
|
||||
u32 id;
|
||||
|
||||
data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
|
||||
id = (pci_domain_nr(pci->bus) << 16) | pci_dev_id(pci);
|
||||
start = pci_resource_start(pci, 0);
|
||||
offset = EHL_PSE_IO_DEV_SIZE * idx;
|
||||
|
||||
data->mem = DEFINE_RES_MEM(start + offset, EHL_PSE_IO_DEV_SIZE);
|
||||
data->irq = pci_irq_vector(pci, idx);
|
||||
|
||||
adev = __devm_auxiliary_device_create(dev, EHL_PSE_IO_NAME, name, data, id);
|
||||
|
||||
return adev ? 0 : -ENODEV;
|
||||
}
|
||||
|
||||
static int ehl_pse_io_probe(struct pci_dev *pci, const struct pci_device_id *id)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = pcim_enable_device(pci);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
pci_set_master(pci);
|
||||
|
||||
ret = pci_alloc_irq_vectors(pci, 2, 2, PCI_IRQ_MSI);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = ehl_pse_io_dev_create(pci, EHL_PSE_GPIO_NAME, 0);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return ehl_pse_io_dev_create(pci, EHL_PSE_TIO_NAME, 1);
|
||||
}
|
||||
|
||||
static const struct pci_device_id ehl_pse_io_ids[] = {
|
||||
{ PCI_VDEVICE(INTEL, 0x4b88) },
|
||||
{ PCI_VDEVICE(INTEL, 0x4b89) },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(pci, ehl_pse_io_ids);
|
||||
|
||||
static struct pci_driver ehl_pse_io_driver = {
|
||||
.name = EHL_PSE_IO_NAME,
|
||||
.id_table = ehl_pse_io_ids,
|
||||
.probe = ehl_pse_io_probe,
|
||||
};
|
||||
module_pci_driver(ehl_pse_io_driver);
|
||||
|
||||
MODULE_AUTHOR("Raag Jadav <raag.jadav@intel.com>");
|
||||
MODULE_DESCRIPTION("Intel Elkhart Lake PSE I/O driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
|
@ -89,6 +89,7 @@ config RESET_EYEQ
|
|||
config RESET_GPIO
|
||||
tristate "GPIO reset controller"
|
||||
depends on GPIOLIB
|
||||
select AUXILIARY_BUS
|
||||
help
|
||||
This enables a generic reset controller for resets attached via
|
||||
GPIOs. Typically for OF platforms this driver expects "reset-gpios"
|
||||
|
|
|
|||
|
|
@ -4,20 +4,22 @@
|
|||
*
|
||||
* Copyright 2013 Philipp Zabel, Pengutronix
|
||||
*/
|
||||
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/atomic.h>
|
||||
#include <linux/auxiliary_bus.h>
|
||||
#include <linux/cleanup.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/kref.h>
|
||||
#include <linux/gpio/driver.h>
|
||||
#include <linux/gpio/machine.h>
|
||||
#include <linux/gpio/property.h>
|
||||
#include <linux/idr.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/kref.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/reset.h>
|
||||
#include <linux/reset-controller.h>
|
||||
#include <linux/slab.h>
|
||||
|
|
@ -76,10 +78,12 @@ struct reset_control_array {
|
|||
/**
|
||||
* struct reset_gpio_lookup - lookup key for ad-hoc created reset-gpio devices
|
||||
* @of_args: phandle to the reset controller with all the args like GPIO number
|
||||
* @swnode: Software node containing the reference to the GPIO provider
|
||||
* @list: list entry for the reset_gpio_lookup_list
|
||||
*/
|
||||
struct reset_gpio_lookup {
|
||||
struct of_phandle_args of_args;
|
||||
struct fwnode_handle *swnode;
|
||||
struct list_head list;
|
||||
};
|
||||
|
||||
|
|
@ -848,56 +852,45 @@ static void __reset_control_put_internal(struct reset_control *rstc)
|
|||
kref_put(&rstc->refcnt, __reset_control_release);
|
||||
}
|
||||
|
||||
static int __reset_add_reset_gpio_lookup(int id, struct device_node *np,
|
||||
unsigned int gpio,
|
||||
unsigned int of_flags)
|
||||
static void reset_gpio_aux_device_release(struct device *dev)
|
||||
{
|
||||
const struct fwnode_handle *fwnode = of_fwnode_handle(np);
|
||||
unsigned int lookup_flags;
|
||||
const char *label_tmp;
|
||||
struct auxiliary_device *adev = to_auxiliary_dev(dev);
|
||||
|
||||
/*
|
||||
* Later we map GPIO flags between OF and Linux, however not all
|
||||
* constants from include/dt-bindings/gpio/gpio.h and
|
||||
* include/linux/gpio/machine.h match each other.
|
||||
*/
|
||||
if (of_flags > GPIO_ACTIVE_LOW) {
|
||||
pr_err("reset-gpio code does not support GPIO flags %u for GPIO %u\n",
|
||||
of_flags, gpio);
|
||||
return -EINVAL;
|
||||
kfree(adev);
|
||||
}
|
||||
|
||||
static int reset_add_gpio_aux_device(struct device *parent,
|
||||
struct fwnode_handle *swnode,
|
||||
int id, void *pdata)
|
||||
{
|
||||
struct auxiliary_device *adev;
|
||||
int ret;
|
||||
|
||||
adev = kzalloc(sizeof(*adev), GFP_KERNEL);
|
||||
if (!adev)
|
||||
return -ENOMEM;
|
||||
|
||||
adev->id = id;
|
||||
adev->name = "gpio";
|
||||
adev->dev.parent = parent;
|
||||
adev->dev.platform_data = pdata;
|
||||
adev->dev.release = reset_gpio_aux_device_release;
|
||||
device_set_node(&adev->dev, swnode);
|
||||
|
||||
ret = auxiliary_device_init(adev);
|
||||
if (ret) {
|
||||
kfree(adev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
struct gpio_device *gdev __free(gpio_device_put) = gpio_device_find_by_fwnode(fwnode);
|
||||
if (!gdev)
|
||||
return -EPROBE_DEFER;
|
||||
ret = __auxiliary_device_add(adev, "reset");
|
||||
if (ret) {
|
||||
auxiliary_device_uninit(adev);
|
||||
kfree(adev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
label_tmp = gpio_device_get_label(gdev);
|
||||
if (!label_tmp)
|
||||
return -EINVAL;
|
||||
|
||||
char *label __free(kfree) = kstrdup(label_tmp, GFP_KERNEL);
|
||||
if (!label)
|
||||
return -ENOMEM;
|
||||
|
||||
/* Size: one lookup entry plus sentinel */
|
||||
struct gpiod_lookup_table *lookup __free(kfree) = kzalloc(struct_size(lookup, table, 2),
|
||||
GFP_KERNEL);
|
||||
if (!lookup)
|
||||
return -ENOMEM;
|
||||
|
||||
lookup->dev_id = kasprintf(GFP_KERNEL, "reset-gpio.%d", id);
|
||||
if (!lookup->dev_id)
|
||||
return -ENOMEM;
|
||||
|
||||
lookup_flags = GPIO_PERSISTENT;
|
||||
lookup_flags |= of_flags & GPIO_ACTIVE_LOW;
|
||||
lookup->table[0] = GPIO_LOOKUP(no_free_ptr(label), gpio, "reset",
|
||||
lookup_flags);
|
||||
|
||||
/* Not freed on success, because it is persisent subsystem data. */
|
||||
gpiod_add_lookup_table(no_free_ptr(lookup));
|
||||
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -905,8 +898,10 @@ static int __reset_add_reset_gpio_lookup(int id, struct device_node *np,
|
|||
*/
|
||||
static int __reset_add_reset_gpio_device(const struct of_phandle_args *args)
|
||||
{
|
||||
struct property_entry properties[2] = { };
|
||||
unsigned int offset, of_flags, lflags;
|
||||
struct reset_gpio_lookup *rgpio_dev;
|
||||
struct platform_device *pdev;
|
||||
struct device *parent;
|
||||
int id, ret;
|
||||
|
||||
/*
|
||||
|
|
@ -925,6 +920,28 @@ static int __reset_add_reset_gpio_device(const struct of_phandle_args *args)
|
|||
*/
|
||||
lockdep_assert_not_held(&reset_list_mutex);
|
||||
|
||||
offset = args->args[0];
|
||||
of_flags = args->args[1];
|
||||
|
||||
/*
|
||||
* Later we map GPIO flags between OF and Linux, however not all
|
||||
* constants from include/dt-bindings/gpio/gpio.h and
|
||||
* include/linux/gpio/machine.h match each other.
|
||||
*
|
||||
* FIXME: Find a better way of translating OF flags to GPIO lookup
|
||||
* flags.
|
||||
*/
|
||||
if (of_flags > GPIO_ACTIVE_LOW) {
|
||||
pr_err("reset-gpio code does not support GPIO flags %u for GPIO %u\n",
|
||||
of_flags, offset);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
struct gpio_device *gdev __free(gpio_device_put) =
|
||||
gpio_device_find_by_fwnode(of_fwnode_handle(args->np));
|
||||
if (!gdev)
|
||||
return -EPROBE_DEFER;
|
||||
|
||||
guard(mutex)(&reset_gpio_lookup_mutex);
|
||||
|
||||
list_for_each_entry(rgpio_dev, &reset_gpio_lookup_list, list) {
|
||||
|
|
@ -934,6 +951,10 @@ static int __reset_add_reset_gpio_device(const struct of_phandle_args *args)
|
|||
}
|
||||
}
|
||||
|
||||
lflags = GPIO_PERSISTENT | (of_flags & GPIO_ACTIVE_LOW);
|
||||
parent = gpio_device_to_device(gdev);
|
||||
properties[0] = PROPERTY_ENTRY_GPIO("reset-gpios", parent->fwnode, offset, lflags);
|
||||
|
||||
id = ida_alloc(&reset_gpio_ida, GFP_KERNEL);
|
||||
if (id < 0)
|
||||
return id;
|
||||
|
|
@ -945,11 +966,6 @@ static int __reset_add_reset_gpio_device(const struct of_phandle_args *args)
|
|||
goto err_ida_free;
|
||||
}
|
||||
|
||||
ret = __reset_add_reset_gpio_lookup(id, args->np, args->args[0],
|
||||
args->args[1]);
|
||||
if (ret < 0)
|
||||
goto err_kfree;
|
||||
|
||||
rgpio_dev->of_args = *args;
|
||||
/*
|
||||
* We keep the device_node reference, but of_args.np is put at the end
|
||||
|
|
@ -957,20 +973,26 @@ static int __reset_add_reset_gpio_device(const struct of_phandle_args *args)
|
|||
* Hold reference as long as rgpio_dev memory is valid.
|
||||
*/
|
||||
of_node_get(rgpio_dev->of_args.np);
|
||||
pdev = platform_device_register_data(NULL, "reset-gpio", id,
|
||||
&rgpio_dev->of_args,
|
||||
sizeof(rgpio_dev->of_args));
|
||||
ret = PTR_ERR_OR_ZERO(pdev);
|
||||
|
||||
rgpio_dev->swnode = fwnode_create_software_node(properties, NULL);
|
||||
if (IS_ERR(rgpio_dev->swnode)) {
|
||||
ret = PTR_ERR(rgpio_dev->swnode);
|
||||
goto err_put_of_node;
|
||||
}
|
||||
|
||||
ret = reset_add_gpio_aux_device(parent, rgpio_dev->swnode, id,
|
||||
&rgpio_dev->of_args);
|
||||
if (ret)
|
||||
goto err_put;
|
||||
goto err_del_swnode;
|
||||
|
||||
list_add(&rgpio_dev->list, &reset_gpio_lookup_list);
|
||||
|
||||
return 0;
|
||||
|
||||
err_put:
|
||||
err_del_swnode:
|
||||
fwnode_remove_software_node(rgpio_dev->swnode);
|
||||
err_put_of_node:
|
||||
of_node_put(rgpio_dev->of_args.np);
|
||||
err_kfree:
|
||||
kfree(rgpio_dev);
|
||||
err_ida_free:
|
||||
ida_free(&reset_gpio_ida, id);
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
#include <linux/auxiliary_bus.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/reset-controller.h>
|
||||
|
||||
struct reset_gpio_priv {
|
||||
|
|
@ -61,9 +61,10 @@ static void reset_gpio_of_node_put(void *data)
|
|||
of_node_put(data);
|
||||
}
|
||||
|
||||
static int reset_gpio_probe(struct platform_device *pdev)
|
||||
static int reset_gpio_probe(struct auxiliary_device *adev,
|
||||
const struct auxiliary_device_id *id)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct device *dev = &adev->dev;
|
||||
struct of_phandle_args *platdata = dev_get_platdata(dev);
|
||||
struct reset_gpio_priv *priv;
|
||||
int ret;
|
||||
|
|
@ -75,7 +76,7 @@ static int reset_gpio_probe(struct platform_device *pdev)
|
|||
if (!priv)
|
||||
return -ENOMEM;
|
||||
|
||||
platform_set_drvdata(pdev, &priv->rc);
|
||||
auxiliary_set_drvdata(adev, &priv->rc);
|
||||
|
||||
priv->reset = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH);
|
||||
if (IS_ERR(priv->reset))
|
||||
|
|
@ -99,20 +100,20 @@ static int reset_gpio_probe(struct platform_device *pdev)
|
|||
return devm_reset_controller_register(dev, &priv->rc);
|
||||
}
|
||||
|
||||
static const struct platform_device_id reset_gpio_ids[] = {
|
||||
{ .name = "reset-gpio", },
|
||||
static const struct auxiliary_device_id reset_gpio_ids[] = {
|
||||
{ .name = "reset.gpio" },
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(platform, reset_gpio_ids);
|
||||
MODULE_DEVICE_TABLE(auxiliary, reset_gpio_ids);
|
||||
|
||||
static struct platform_driver reset_gpio_driver = {
|
||||
static struct auxiliary_driver reset_gpio_driver = {
|
||||
.probe = reset_gpio_probe,
|
||||
.id_table = reset_gpio_ids,
|
||||
.driver = {
|
||||
.name = "reset-gpio",
|
||||
},
|
||||
};
|
||||
module_platform_driver(reset_gpio_driver);
|
||||
module_auxiliary_driver(reset_gpio_driver);
|
||||
|
||||
MODULE_AUTHOR("Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>");
|
||||
MODULE_DESCRIPTION("Generic GPIO reset driver");
|
||||
|
|
|
|||
|
|
@ -52,20 +52,6 @@ static struct spi_board_info amp_info_template = {
|
|||
.mode = SPI_MODE_0,
|
||||
};
|
||||
|
||||
static const struct software_node cs42l43_gpiochip_swnode = {
|
||||
.name = "cs42l43-pinctrl",
|
||||
};
|
||||
|
||||
static const struct software_node_ref_args cs42l43_cs_refs[] = {
|
||||
SOFTWARE_NODE_REFERENCE(&cs42l43_gpiochip_swnode, 0, GPIO_ACTIVE_LOW),
|
||||
SOFTWARE_NODE_REFERENCE(&swnode_gpio_undefined),
|
||||
};
|
||||
|
||||
static const struct property_entry cs42l43_cs_props[] = {
|
||||
PROPERTY_ENTRY_REF_ARRAY("cs-gpios", cs42l43_cs_refs),
|
||||
{}
|
||||
};
|
||||
|
||||
static int cs42l43_spi_tx(struct regmap *regmap, const u8 *buf, unsigned int len)
|
||||
{
|
||||
const u8 *end = buf + len;
|
||||
|
|
@ -324,11 +310,6 @@ static void cs42l43_release_of_node(void *data)
|
|||
fwnode_handle_put(data);
|
||||
}
|
||||
|
||||
static void cs42l43_release_sw_node(void *data)
|
||||
{
|
||||
software_node_unregister(&cs42l43_gpiochip_swnode);
|
||||
}
|
||||
|
||||
static int cs42l43_spi_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct cs42l43 *cs42l43 = dev_get_drvdata(pdev->dev.parent);
|
||||
|
|
@ -391,6 +372,15 @@ static int cs42l43_spi_probe(struct platform_device *pdev)
|
|||
fwnode_property_read_u32(xu_fwnode, "01fa-sidecar-instances", &nsidecars);
|
||||
|
||||
if (nsidecars) {
|
||||
struct software_node_ref_args args[] = {
|
||||
SOFTWARE_NODE_REFERENCE(fwnode, 0, GPIO_ACTIVE_LOW),
|
||||
SOFTWARE_NODE_REFERENCE(&swnode_gpio_undefined),
|
||||
};
|
||||
struct property_entry props[] = {
|
||||
PROPERTY_ENTRY_REF_ARRAY("cs-gpios", args),
|
||||
{ }
|
||||
};
|
||||
|
||||
ret = fwnode_property_read_u32(xu_fwnode, "01fa-spk-id-val", &spkid);
|
||||
if (!ret) {
|
||||
dev_dbg(priv->dev, "01fa-spk-id-val = %d\n", spkid);
|
||||
|
|
@ -403,17 +393,7 @@ static int cs42l43_spi_probe(struct platform_device *pdev)
|
|||
"Failed to get spk-id-gpios\n");
|
||||
}
|
||||
|
||||
ret = software_node_register(&cs42l43_gpiochip_swnode);
|
||||
if (ret)
|
||||
return dev_err_probe(priv->dev, ret,
|
||||
"Failed to register gpio swnode\n");
|
||||
|
||||
ret = devm_add_action_or_reset(priv->dev, cs42l43_release_sw_node, NULL);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = device_create_managed_software_node(&priv->ctlr->dev,
|
||||
cs42l43_cs_props, NULL);
|
||||
ret = device_create_managed_software_node(&priv->ctlr->dev, props, NULL);
|
||||
if (ret)
|
||||
return dev_err_probe(priv->dev, ret, "Failed to add swnode\n");
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,24 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Intel Elkhart Lake PSE I/O Auxiliary Device
|
||||
*
|
||||
* Copyright (c) 2025 Intel Corporation.
|
||||
*
|
||||
* Author: Raag Jadav <raag.jadav@intel.com>
|
||||
*/
|
||||
|
||||
#ifndef _EHL_PSE_IO_AUX_H_
|
||||
#define _EHL_PSE_IO_AUX_H_
|
||||
|
||||
#include <linux/ioport.h>
|
||||
|
||||
#define EHL_PSE_IO_NAME "ehl_pse_io"
|
||||
#define EHL_PSE_GPIO_NAME "gpio"
|
||||
#define EHL_PSE_TIO_NAME "pps_tio"
|
||||
|
||||
struct ehl_pse_io_data {
|
||||
struct resource mem;
|
||||
int irq;
|
||||
};
|
||||
|
||||
#endif /* _EHL_PSE_IO_AUX_H_ */
|
||||
|
|
@ -173,6 +173,8 @@ bool gpiod_is_shared(const struct gpio_desc *desc);
|
|||
struct gpio_desc *gpio_to_desc(unsigned gpio);
|
||||
int desc_to_gpio(const struct gpio_desc *desc);
|
||||
|
||||
int gpiod_hwgpio(const struct gpio_desc *desc);
|
||||
|
||||
struct gpio_desc *fwnode_gpiod_get_index(struct fwnode_handle *fwnode,
|
||||
const char *con_id, int index,
|
||||
enum gpiod_flags flags,
|
||||
|
|
|
|||
|
|
@ -1,36 +0,0 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
/*
|
||||
* OF helpers for the old of_mm_gpio_chip, used on ppc32 and nios2,
|
||||
* do not use in new code.
|
||||
*
|
||||
* Copyright (c) 2007-2008 MontaVista Software, Inc.
|
||||
*
|
||||
* Author: Anton Vorontsov <avorontsov@ru.mvista.com>
|
||||
*/
|
||||
|
||||
#ifndef __LINUX_GPIO_LEGACY_OF_MM_GPIO_CHIP_H
|
||||
#define __LINUX_GPIO_LEGACY_OF_MM_GPIO_CHIP_H
|
||||
|
||||
#include <linux/gpio/driver.h>
|
||||
#include <linux/of.h>
|
||||
|
||||
/*
|
||||
* OF GPIO chip for memory mapped banks
|
||||
*/
|
||||
struct of_mm_gpio_chip {
|
||||
struct gpio_chip gc;
|
||||
void (*save_regs)(struct of_mm_gpio_chip *mm_gc);
|
||||
void __iomem *regs;
|
||||
};
|
||||
|
||||
static inline struct of_mm_gpio_chip *to_of_mm_gpio_chip(struct gpio_chip *gc)
|
||||
{
|
||||
return container_of(gc, struct of_mm_gpio_chip, gc);
|
||||
}
|
||||
|
||||
extern int of_mm_gpiochip_add_data(struct device_node *np,
|
||||
struct of_mm_gpio_chip *mm_gc,
|
||||
void *data);
|
||||
extern void of_mm_gpiochip_remove(struct of_mm_gpio_chip *mm_gc);
|
||||
|
||||
#endif /* __LINUX_GPIO_LEGACY_OF_MM_GPIO_CHIP_H */
|
||||
|
|
@ -50,8 +50,8 @@ struct regmap;
|
|||
* @regmap_irq_chip: (Optional) Pointer on an regmap_irq_chip structure. If
|
||||
* set, a regmap-irq device will be created and the IRQ
|
||||
* domain will be set accordingly.
|
||||
* @regmap_irq_line (Optional) The IRQ the device uses to signal interrupts.
|
||||
* @regmap_irq_flags (Optional) The IRQF_ flags to use for the interrupt.
|
||||
* @regmap_irq_line: (Optional) The IRQ the device uses to signal interrupts.
|
||||
* @regmap_irq_flags: (Optional) The IRQF_ flags to use for the interrupt.
|
||||
*
|
||||
* The ->reg_mask_xlate translates a given base address and GPIO offset to
|
||||
* register and mask pair. The base address is one of the given register
|
||||
|
|
|
|||
|
|
@ -355,19 +355,26 @@ struct software_node;
|
|||
|
||||
/**
|
||||
* struct software_node_ref_args - Reference property with additional arguments
|
||||
* @node: Reference to a software node
|
||||
* @swnode: Reference to a software node
|
||||
* @fwnode: Alternative reference to a firmware node handle
|
||||
* @nargs: Number of elements in @args array
|
||||
* @args: Integer arguments
|
||||
*/
|
||||
struct software_node_ref_args {
|
||||
const struct software_node *node;
|
||||
const struct software_node *swnode;
|
||||
struct fwnode_handle *fwnode;
|
||||
unsigned int nargs;
|
||||
u64 args[NR_FWNODE_REFERENCE_ARGS];
|
||||
};
|
||||
|
||||
#define SOFTWARE_NODE_REFERENCE(_ref_, ...) \
|
||||
(const struct software_node_ref_args) { \
|
||||
.node = _ref_, \
|
||||
.swnode = _Generic(_ref_, \
|
||||
const struct software_node *: _ref_, \
|
||||
default: NULL), \
|
||||
.fwnode = _Generic(_ref_, \
|
||||
struct fwnode_handle *: _ref_, \
|
||||
default: NULL), \
|
||||
.nargs = COUNT_ARGS(__VA_ARGS__), \
|
||||
.args = { __VA_ARGS__ }, \
|
||||
}
|
||||
|
|
|
|||
|
|
@ -564,13 +564,14 @@ static inline bool strstarts(const char *str, const char *prefix)
|
|||
|
||||
/**
|
||||
* strends - Check if a string ends with another string.
|
||||
* @str - NULL-terminated string to check against @suffix
|
||||
* @suffix - NULL-terminated string defining the suffix to look for in @str
|
||||
* @str: NULL-terminated string to check against @suffix
|
||||
* @suffix: NULL-terminated string defining the suffix to look for in @str
|
||||
*
|
||||
* Returns:
|
||||
* True if @str ends with @suffix. False in all other cases.
|
||||
*/
|
||||
static inline bool strends(const char *str, const char *suffix)
|
||||
static inline bool __attribute__((nonnull(1, 2)))
|
||||
strends(const char *str, const char *suffix)
|
||||
{
|
||||
unsigned int str_len = strlen(str), suffix_len = strlen(suffix);
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue