gpio updates for v6.9

Serialization rework:
 - use SRCU to serialize access to the global GPIO device list, to GPIO device
   structs themselves and to GPIO descriptors
 - make the GPIO subsystem resilient to the GPIO providers being unbound while
   the API calls are in progress
 - don't dereference the SRCU-protected chip pointer if the information we need
   can be obtained from the GPIO device structure
 - move some of the information contained in struct gpio_chip to struct
   gpio_device to further reduce the need to dereference the former
 - pass the GPIO device struct instead of the GPIO chip to sysfs callback to,
   again, reduce the need for accessing the latter
 - get GPIO descriptors from the GPIO device, not from the chip for the same
   reason
 - allow for mostly lockless operation of the GPIO driver API: assure
   consistency with SRCU and atomic operations
 - remove the global GPIO spinlock
 - remove the character device RW semaphore
 
 Core GPIOLIB:
 - constify pointers in GPIO API where applicable
 - unify the GPIO counting APIs for ACPI and OF
 - provide a macro for iterating over all GPIOs, not only the ones that are
   requested
 - remove leftover typedefs
 - pass the consumer device to GPIO core in devm_fwnode_gpiod_get_index() for
   improved logging
 - constify the GPIO bus type
 - don't warn about removing GPIO chips with descriptors still held by users as
   we can now handle this situation gracefully
 - remove unused logging helpers
 - unexport functions that are only used internally in the GPIO subsystem
 - set the device type (assign the relevant struct device_type) for GPIO devices
 
 New drivers:
 - add the ChromeOS EC GPIO driver
 
 Driver improvements:
 - allow building gpio-vf610 with COMPILE_TEST as well as disabling it in
   menuconfig (before it was always built for i.MX cofigs)
 - count the number of EICs using the device properties instead of hard-coding
   it in gpio-eic-sprd
 - improve the device naming, extend the debugfs output and add lockdep asserts
   to gpio-sim
 
 DT bindings:
 - document the 'label' property for gpio-pca9570
 - convert aspeed,ast2400-gpio bindings to DT schema
 - disallow unevaluated properties for gpio-mvebu
 - document a new model in renesas,rcar-gpio
 
 Documentation:
 - improve the character device kerneldocs in user-space headers
 - add proper documentation for the character device uAPI (both v1 and v2)
 - move the sysfs and gpio-mockup docs into the "obsolete" section
 - improve naming consistency for GPIO terms
 - clarify the line values description for sysfs
 - minor docs improvements
 - improve the driver API contract for setting GPIO direction
 - mark unsafe APIs as deprecated in kerneldocs and suggest replacements
 
 Other:
 - remove an obsolete test from selftests
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCgAdFiEEFp3rbAvDxGAT0sefEacuoBRx13IFAmXu1ecACgkQEacuoBRx
 13JR7w//R3TswZ1uC9qkRjat9eA2KZUaI2QChlS7V/yXVcDHynuTlO/ZQmnnMdYL
 ch7T2cjPcW0OCt0UhcjamUmYtWaxe1e5GU3E42EosWUsojEzgGs0iNKe0R4SHYzv
 whlkFqO8+8IctYhiMpAU1PzP9N4YBqypwgCrTqHIrYuhz3MbPQxtCMkr7g0LTo8u
 Z3K0D3Y0LuwISWNYYhA20Bwemn1fEHXJ9f3pTeNaGh2dGZek9k9xd0zWcCxwhaYD
 CBTBiZXf57TUTJ2u+JG+au1ghEmmvBPlMpza+fazypbcvsiQxdGvv5QH1bTwyt4B
 woGq+biLLvlwfJ8BT7+09uni7gUyNL3wWkixlx/8Slkyti4xWqgZQ3WnhwN8yS4Y
 DbkTtzH/PIsjr1dZw6rnGoXi80lBEaok7LeI0QhybopTXQI+CnIbE/RBhzly8Mf8
 1cAVFjrF2gPuaTuheakRBw4LOhegf4a485fadJVEUeEpeF7/p9rDQWAbgohYUnCE
 gHPwkTOJuOZp+BlsTOyspnqxWnDVMtCnmi+q1o7JvEgXqAtzU7+1gz/wDpfsHgHQ
 oze6V2JvD2R3JkHmdqcIzq5yNwk1rOguOY3saNiwSk95JY+A8vhAe/gVykklKDXX
 oX/DPwlVd/0OR+0HCQ3r0pXK8BSRQ9qm/nUZNnLB+Rts9K1peIU=
 =LX+L
 -----END PGP SIGNATURE-----

Merge tag 'gpio-updates-for-v6.9-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/brgl/linux

Pull gpio updates from Bartosz Golaszewski:
 "The biggest feature is the locking overhaul. Up until now the
  synchronization in the GPIO subsystem was broken. There was a single
  spinlock "protecting" multiple data structures but doing it wrong (as
  evidenced by several places where it would be released when a sleeping
  function was called and then reacquired without checking the protected
  state).

  We tried to use an RW semaphore before but the main issue with GPIO is
  that we have drivers implementing the interfaces in both sleeping and
  non-sleeping ways as well as user-facing interfaces that can be called
  both from process as well as atomic contexts. Both ends converge in
  the same code paths that can use neither spinlocks nor mutexes. The
  only reasonable way out is to use SRCU and go mostly lockless. To that
  end: we add several SRCU structs in relevant places and use them to
  assure consistency between API calls together with atomic reads and
  writes of GPIO descriptor flags where it makes sense.

  This code has spent several weeks in next and has received several
  fixes in the first week or two after which it stabilized nicely. The
  GPIO subsystem is now resilient to providers being suddenly unbound.
  We managed to also remove the existing character device RW semaphore
  and the obsolete global spinlock.

  Other than the locking rework we have one new driver (for Chromebook
  EC), much appreciated documentation improvements from Kent and the
  regular driver improvements, DT-bindings updates and GPIOLIB core
  tweaks.

  Serialization rework:
   - use SRCU to serialize access to the global GPIO device list, to
     GPIO device structs themselves and to GPIO descriptors
   - make the GPIO subsystem resilient to the GPIO providers being
     unbound while the API calls are in progress
   - don't dereference the SRCU-protected chip pointer if the
     information we need can be obtained from the GPIO device structure
   - move some of the information contained in struct gpio_chip to
     struct gpio_device to further reduce the need to dereference the
     former
   - pass the GPIO device struct instead of the GPIO chip to sysfs
     callback to, again, reduce the need for accessing the latter
   - get GPIO descriptors from the GPIO device, not from the chip for
     the same reason
   - allow for mostly lockless operation of the GPIO driver API: assure
     consistency with SRCU and atomic operations
   - remove the global GPIO spinlock
   - remove the character device RW semaphore

  Core GPIOLIB:
   - constify pointers in GPIO API where applicable
   - unify the GPIO counting APIs for ACPI and OF
   - provide a macro for iterating over all GPIOs, not only the ones
     that are requested
   - remove leftover typedefs
   - pass the consumer device to GPIO core in
     devm_fwnode_gpiod_get_index() for improved logging
   - constify the GPIO bus type
   - don't warn about removing GPIO chips with descriptors still held by
     users as we can now handle this situation gracefully
   - remove unused logging helpers
   - unexport functions that are only used internally in the GPIO
     subsystem
   - set the device type (assign the relevant struct device_type) for
     GPIO devices

  New drivers:
   - add the ChromeOS EC GPIO driver

  Driver improvements:
   - allow building gpio-vf610 with COMPILE_TEST as well as disabling it
     in menuconfig (before it was always built for i.MX cofigs)
   - count the number of EICs using the device properties instead of
     hard-coding it in gpio-eic-sprd
   - improve the device naming, extend the debugfs output and add
     lockdep asserts to gpio-sim

  DT bindings:
   - document the 'label' property for gpio-pca9570
   - convert aspeed,ast2400-gpio bindings to DT schema
   - disallow unevaluated properties for gpio-mvebu
   - document a new model in renesas,rcar-gpio

  Documentation:
   - improve the character device kerneldocs in user-space headers
   - add proper documentation for the character device uAPI (both v1 and v2)
   - move the sysfs and gpio-mockup docs into the "obsolete" section
   - improve naming consistency for GPIO terms
   - clarify the line values description for sysfs
   - minor docs improvements
   - improve the driver API contract for setting GPIO direction
   - mark unsafe APIs as deprecated in kerneldocs and suggest
     replacements

  Other:
   - remove an obsolete test from selftests"

* tag 'gpio-updates-for-v6.9-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/brgl/linux: (79 commits)
  gpio: sysfs: repair export returning -EPERM on 1st attempt
  selftest: gpio: remove obsolete gpio-mockup test
  gpiolib: Deduplicate cleanup for-loop in gpiochip_add_data_with_key()
  dt-bindings: gpio: aspeed,ast2400-gpio: Convert to DT schema
  gpio: acpi: Make acpi_gpio_count() take firmware node as a parameter
  gpio: of: Make of_gpio_get_count() take firmware node as a parameter
  gpiolib: Pass consumer device through to core in devm_fwnode_gpiod_get_index()
  gpio: sim: use for_each_hwgpio()
  gpio: provide for_each_hwgpio()
  gpio: don't warn about removing GPIO chips with active users anymore
  gpio: sim: delimit the fwnode name with a ":" when generating labels
  gpio: sim: add lockdep asserts
  gpio: Add ChromeOS EC GPIO driver
  gpio: constify of_phandle_args in of_find_gpio_device_by_xlate()
  gpio: fix memory leak in gpiod_request_commit()
  gpio: constify opaque pointer "data" in gpio_device_find()
  gpio: cdev: fix a NULL-pointer dereference with DEBUG enabled
  gpio: uapi: clarify default_values being logical
  gpio: sysfs: fix inverted pointer logic
  gpio: don't let lockdep complain about inherently dangerous RCU usage
  ...
This commit is contained in:
Linus Torvalds 2024-03-13 11:14:55 -07:00
commit 69afef4af4
56 changed files with 2995 additions and 773 deletions

View File

@ -28,5 +28,5 @@ Description:
/label ... (r/o) descriptive, not necessarily unique
/ngpio ... (r/o) number of GPIOs; numbered N to N + (ngpio - 1)
This ABI is deprecated and will be removed after 2020. It is
replaced with the GPIO character device.
This ABI is obsoleted by Documentation/ABI/testing/gpio-cdev and will be
removed after 2020.

View File

@ -6,8 +6,9 @@ Description:
The character device files /dev/gpiochip* are the interface
between GPIO chips and userspace.
The ioctl(2)-based ABI is defined and documented in
[include/uapi]<linux/gpio.h>.
The ioctl(2)-based ABI is defined in
[include/uapi]<linux/gpio.h> and documented in
Documentation/userspace-api/gpio/chardev.rst.
The following file operations are supported:
@ -17,8 +18,8 @@ Description:
ioctl(2)
Initiate various actions.
See the inline documentation in [include/uapi]<linux/gpio.h>
for descriptions of all ioctls.
See Documentation/userspace-api/gpio/chardev.rst
for a description of all ioctls.
close(2)
Stops and free up the I/O contexts that was associated

View File

@ -3,6 +3,14 @@
GPIO Testing Driver
===================
.. note::
This module has been obsoleted by the more flexible gpio-sim.rst.
New developments should use that API and existing developments are
encouraged to migrate as soon as possible.
This module will continue to be maintained but no new features will be
added.
The GPIO Testing Driver (gpio-mockup) provides a way to create simulated GPIO
chips for testing purposes. The lines exposed by these chips can be accessed
using the standard GPIO character device interface as well as manipulated

View File

@ -1,16 +1,16 @@
.. SPDX-License-Identifier: GPL-2.0
====
gpio
GPIO
====
.. toctree::
:maxdepth: 1
Character Device Userspace API <../../userspace-api/gpio/chardev>
gpio-aggregator
sysfs
gpio-mockup
gpio-sim
Obsolete APIs <obsolete>
.. only:: subproject and html

View File

@ -0,0 +1,13 @@
.. SPDX-License-Identifier: GPL-2.0
==================
Obsolete GPIO APIs
==================
.. toctree::
:maxdepth: 1
Character Device Userspace API (v1) <../../userspace-api/gpio/chardev_v1>
Sysfs Interface <../../userspace-api/gpio/sysfs>
Mockup Testing Module <gpio-mockup>

View File

@ -0,0 +1,148 @@
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/gpio/aspeed,ast2400-gpio.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Aspeed GPIO controller
maintainers:
- Andrew Jeffery <andrew@codeconstruct.com.au>
properties:
compatible:
enum:
- aspeed,ast2400-gpio
- aspeed,ast2500-gpio
- aspeed,ast2600-gpio
reg:
maxItems: 1
clocks:
maxItems: 1
description: The clock to use for debounce timings
gpio-controller: true
gpio-line-names:
minItems: 36
maxItems: 232
gpio-ranges: true
"#gpio-cells":
const: 2
interrupts:
maxItems: 1
interrupt-controller: true
"#interrupt-cells":
const: 2
ngpios:
minimum: 36
maximum: 232
required:
- compatible
- reg
- interrupts
- interrupt-controller
- "#interrupt-cells"
- gpio-controller
- "#gpio-cells"
allOf:
- if:
properties:
compatible:
contains:
const: aspeed,ast2400-gpio
then:
properties:
gpio-line-names:
minItems: 220
maxItems: 220
ngpios:
const: 220
- if:
properties:
compatible:
contains:
const: aspeed,ast2500-gpio
then:
properties:
gpio-line-names:
minItems: 232
maxItems: 232
ngpios:
const: 232
- if:
properties:
compatible:
contains:
const: aspeed,ast2600-gpio
then:
properties:
gpio-line-names:
minItems: 36
maxItems: 208
ngpios:
enum: [ 36, 208 ]
required:
- ngpios
additionalProperties: false
examples:
- |
gpio@1e780000 {
compatible = "aspeed,ast2400-gpio";
reg = <0x1e780000 0x1000>;
interrupts = <20>;
interrupt-controller;
#interrupt-cells = <2>;
gpio-controller;
#gpio-cells = <2>;
};
- |
gpio: gpio@1e780000 {
compatible = "aspeed,ast2500-gpio";
reg = <0x1e780000 0x200>;
interrupts = <20>;
interrupt-controller;
#interrupt-cells = <2>;
gpio-controller;
#gpio-cells = <2>;
gpio-ranges = <&pinctrl 0 0 232>;
};
- |
#include <dt-bindings/clock/ast2600-clock.h>
#include <dt-bindings/interrupt-controller/arm-gic.h>
#include <dt-bindings/interrupt-controller/irq.h>
gpio0: gpio@1e780000 {
compatible = "aspeed,ast2600-gpio";
reg = <0x1e780000 0x400>;
clocks = <&syscon ASPEED_CLK_APB2>;
interrupts = <GIC_SPI 40 IRQ_TYPE_LEVEL_HIGH>;
interrupt-controller;
#interrupt-cells = <2>;
#gpio-cells = <2>;
gpio-controller;
gpio-ranges = <&pinctrl 0 0 208>;
ngpios = <208>;
};
gpio1: gpio@1e780800 {
compatible = "aspeed,ast2600-gpio";
reg = <0x1e780800 0x800>;
clocks = <&syscon ASPEED_CLK_APB1>;
interrupts = <GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>;
interrupt-controller;
#interrupt-cells = <2>;
gpio-controller;
#gpio-cells = <2>;
gpio-ranges = <&pinctrl 0 208 36>;
ngpios = <36>;
};

View File

@ -1,39 +0,0 @@
Aspeed GPIO controller Device Tree Bindings
-------------------------------------------
Required properties:
- compatible : Either "aspeed,ast2400-gpio", "aspeed,ast2500-gpio",
or "aspeed,ast2600-gpio".
- #gpio-cells : Should be two
- First cell is the GPIO line number
- Second cell is used to specify optional
parameters (unused)
- reg : Address and length of the register set for the device
- gpio-controller : Marks the device node as a GPIO controller.
- interrupts : Interrupt specifier (see interrupt bindings for
details)
- interrupt-controller : Mark the GPIO controller as an interrupt-controller
Optional properties:
- clocks : A phandle to the clock to use for debounce timings
- ngpios : Number of GPIOs controlled by this controller. Should be set
when there are multiple GPIO controllers on a SoC (ast2600).
The gpio and interrupt properties are further described in their respective
bindings documentation:
- Documentation/devicetree/bindings/gpio/gpio.txt
- Documentation/devicetree/bindings/interrupt-controller/interrupts.txt
Example:
gpio@1e780000 {
#gpio-cells = <2>;
compatible = "aspeed,ast2400-gpio";
gpio-controller;
interrupts = <20>;
reg = <0x1e780000 0x1000>;
interrupt-controller;
};

View File

@ -115,7 +115,7 @@ allOf:
required:
- reg
unevaluatedProperties: true
unevaluatedProperties: false
examples:
- |

View File

@ -28,6 +28,9 @@ properties:
minItems: 4
maxItems: 8
label:
description: A descriptive name for this device.
required:
- compatible
- reg

View File

@ -53,6 +53,7 @@ properties:
- renesas,gpio-r8a779a0 # R-Car V3U
- renesas,gpio-r8a779f0 # R-Car S4-8
- renesas,gpio-r8a779g0 # R-Car V4H
- renesas,gpio-r8a779h0 # R-Car V4M
- const: renesas,rcar-gen4-gpio # R-Car Gen4
reg:

View File

@ -222,9 +222,9 @@ Use the following calls to access GPIOs from an atomic context::
int gpiod_get_value(const struct gpio_desc *desc);
void gpiod_set_value(struct gpio_desc *desc, int value);
The values are boolean, zero for low, nonzero for high. When reading the value
of an output pin, the value returned should be what's seen on the pin. That
won't always match the specified output value, because of issues including
The values are boolean, zero for inactive, nonzero for active. When reading the
value of an output pin, the value returned should be what's seen on the pin.
That won't always match the specified output value, because of issues including
open-drain signaling and output latencies.
The get/set calls do not return errors because "invalid GPIO" should have been
@ -277,11 +277,11 @@ switch their output to a high impedance value. The consumer should not need to
care. (For details read about open drain in driver.rst.)
With this, all the gpiod_set_(array)_value_xxx() functions interpret the
parameter "value" as "asserted" ("1") or "de-asserted" ("0"). The physical line
parameter "value" as "active" ("1") or "inactive" ("0"). The physical line
level will be driven accordingly.
As an example, if the active low property for a dedicated GPIO is set, and the
gpiod_set_(array)_value_xxx() passes "asserted" ("1"), the physical line level
gpiod_set_(array)_value_xxx() passes "active" ("1"), the physical line level
will be driven low.
To summarize::

View File

@ -0,0 +1,116 @@
.. SPDX-License-Identifier: GPL-2.0
===================================
GPIO Character Device Userspace API
===================================
This is latest version (v2) of the character device API, as defined in
``include/uapi/linux/gpio.h.``
First added in 5.10.
.. note::
Do NOT abuse userspace APIs to control hardware that has proper kernel
drivers. There may already be a driver for your use case, and an existing
kernel driver is sure to provide a superior solution to bitbashing
from userspace.
Read Documentation/driver-api/gpio/drivers-on-gpio.rst to avoid reinventing
kernel wheels in userspace.
Similarly, for multi-function lines there may be other subsystems, such as
Documentation/spi/index.rst, Documentation/i2c/index.rst,
Documentation/driver-api/pwm.rst, Documentation/w1/index.rst etc, that
provide suitable drivers and APIs for your hardware.
Basic examples using the character device API can be found in ``tools/gpio/*``.
The API is based around two major objects, the :ref:`gpio-v2-chip` and the
:ref:`gpio-v2-line-request`.
.. _gpio-v2-chip:
Chip
====
The Chip represents a single GPIO chip and is exposed to userspace using device
files of the form ``/dev/gpiochipX``.
Each chip supports a number of GPIO lines,
:c:type:`chip.lines<gpiochip_info>`. Lines on the chip are identified by an
``offset`` in the range from 0 to ``chip.lines - 1``, i.e. `[0,chip.lines)`.
Lines are requested from the chip using gpio-v2-get-line-ioctl.rst
and the resulting line request is used to access the GPIO chip's lines or
monitor the lines for edge events.
Within this documentation, the file descriptor returned by calling `open()`
on the GPIO device file is referred to as ``chip_fd``.
Operations
----------
The following operations may be performed on the chip:
.. toctree::
:titlesonly:
Get Line <gpio-v2-get-line-ioctl>
Get Chip Info <gpio-get-chipinfo-ioctl>
Get Line Info <gpio-v2-get-lineinfo-ioctl>
Watch Line Info <gpio-v2-get-lineinfo-watch-ioctl>
Unwatch Line Info <gpio-get-lineinfo-unwatch-ioctl>
Read Line Info Changed Events <gpio-v2-lineinfo-changed-read>
.. _gpio-v2-line-request:
Line Request
============
Line requests are created by gpio-v2-get-line-ioctl.rst and provide
access to a set of requested lines. The line request is exposed to userspace
via the anonymous file descriptor returned in
:c:type:`request.fd<gpio_v2_line_request>` by gpio-v2-get-line-ioctl.rst.
Within this documentation, the line request file descriptor is referred to
as ``req_fd``.
Operations
----------
The following operations may be performed on the line request:
.. toctree::
:titlesonly:
Get Line Values <gpio-v2-line-get-values-ioctl>
Set Line Values <gpio-v2-line-set-values-ioctl>
Read Line Edge Events <gpio-v2-line-event-read>
Reconfigure Lines <gpio-v2-line-set-config-ioctl>
Types
=====
This section contains the structs and enums that are referenced by the API v2,
as defined in ``include/uapi/linux/gpio.h``.
.. kernel-doc:: include/uapi/linux/gpio.h
:identifiers:
gpio_v2_line_attr_id
gpio_v2_line_attribute
gpio_v2_line_changed_type
gpio_v2_line_config
gpio_v2_line_config_attribute
gpio_v2_line_event
gpio_v2_line_event_id
gpio_v2_line_flag
gpio_v2_line_info
gpio_v2_line_info_changed
gpio_v2_line_request
gpio_v2_line_values
gpiochip_info
.. toctree::
:hidden:
error-codes

View File

@ -0,0 +1,131 @@
.. SPDX-License-Identifier: GPL-2.0
========================================
GPIO Character Device Userspace API (v1)
========================================
.. warning::
This API is obsoleted by chardev.rst (v2).
New developments should use the v2 API, and existing developments are
encouraged to migrate as soon as possible, as this API will be removed
in the future. The v2 API is a functional superset of the v1 API so any
v1 call can be directly translated to a v2 equivalent.
This interface will continue to be maintained for the migration period,
but new features will only be added to the new API.
First added in 4.8.
The API is based around three major objects, the :ref:`gpio-v1-chip`, the
:ref:`gpio-v1-line-handle`, and the :ref:`gpio-v1-line-event`.
Where "line event" is used in this document it refers to the request that can
monitor a line for edge events, not the edge events themselves.
.. _gpio-v1-chip:
Chip
====
The Chip represents a single GPIO chip and is exposed to userspace using device
files of the form ``/dev/gpiochipX``.
Each chip supports a number of GPIO lines,
:c:type:`chip.lines<gpiochip_info>`. Lines on the chip are identified by an
``offset`` in the range from 0 to ``chip.lines - 1``, i.e. `[0,chip.lines)`.
Lines are requested from the chip using either gpio-get-linehandle-ioctl.rst
and the resulting line handle is used to access the GPIO chip's lines, or
gpio-get-lineevent-ioctl.rst and the resulting line event is used to monitor
a GPIO line for edge events.
Within this documentation, the file descriptor returned by calling `open()`
on the GPIO device file is referred to as ``chip_fd``.
Operations
----------
The following operations may be performed on the chip:
.. toctree::
:titlesonly:
Get Line Handle <gpio-get-linehandle-ioctl>
Get Line Event <gpio-get-lineevent-ioctl>
Get Chip Info <gpio-get-chipinfo-ioctl>
Get Line Info <gpio-get-lineinfo-ioctl>
Watch Line Info <gpio-get-lineinfo-watch-ioctl>
Unwatch Line Info <gpio-get-lineinfo-unwatch-ioctl>
Read Line Info Changed Events <gpio-lineinfo-changed-read>
.. _gpio-v1-line-handle:
Line Handle
===========
Line handles are created by gpio-get-linehandle-ioctl.rst and provide
access to a set of requested lines. The line handle is exposed to userspace
via the anonymous file descriptor returned in
:c:type:`request.fd<gpiohandle_request>` by gpio-get-linehandle-ioctl.rst.
Within this documentation, the line handle file descriptor is referred to
as ``handle_fd``.
Operations
----------
The following operations may be performed on the line handle:
.. toctree::
:titlesonly:
Get Line Values <gpio-handle-get-line-values-ioctl>
Set Line Values <gpio-handle-set-line-values-ioctl>
Reconfigure Lines <gpio-handle-set-config-ioctl>
.. _gpio-v1-line-event:
Line Event
==========
Line events are created by gpio-get-lineevent-ioctl.rst and provide
access to a requested line. The line event is exposed to userspace
via the anonymous file descriptor returned in
:c:type:`request.fd<gpioevent_request>` by gpio-get-lineevent-ioctl.rst.
Within this documentation, the line event file descriptor is referred to
as ``event_fd``.
Operations
----------
The following operations may be performed on the line event:
.. toctree::
:titlesonly:
Get Line Value <gpio-handle-get-line-values-ioctl>
Read Line Edge Events <gpio-lineevent-data-read>
Types
=====
This section contains the structs that are referenced by the ABI v1.
The :c:type:`struct gpiochip_info<gpiochip_info>` is common to ABI v1 and v2.
.. kernel-doc:: include/uapi/linux/gpio.h
:identifiers:
gpioevent_data
gpioevent_request
gpiohandle_config
gpiohandle_data
gpiohandle_request
gpioline_info
gpioline_info_changed
.. toctree::
:hidden:
error-codes

View File

@ -0,0 +1,79 @@
.. SPDX-License-Identifier: GPL-2.0
.. _gpio_errors:
*******************
GPIO Error Codes
*******************
.. _gpio-errors:
.. tabularcolumns:: |p{2.5cm}|p{15.0cm}|
.. flat-table:: Common GPIO error codes
:header-rows: 0
:stub-columns: 0
:widths: 1 16
- - ``EAGAIN`` (aka ``EWOULDBLOCK``)
- The device was opened in non-blocking mode and a read can't
be performed as there is no data available.
- - ``EBADF``
- The file descriptor is not valid.
- - ``EBUSY``
- The ioctl can't be handled because the device is busy. Typically
returned when an ioctl attempts something that would require the
usage of a resource that was already allocated. The ioctl must not
be retried without performing another action to fix the problem
first.
- - ``EFAULT``
- There was a failure while copying data from/to userspace, probably
caused by an invalid pointer reference.
- - ``EINVAL``
- One or more of the ioctl parameters are invalid or out of the
allowed range. This is a widely used error code.
- - ``ENODEV``
- Device not found or was removed.
- - ``ENOMEM``
- There's not enough memory to handle the desired operation.
- - ``EPERM``
- Permission denied. Typically returned in response to an attempt
to perform an action incompatible with the current line
configuration.
- - ``EIO``
- I/O error. Typically returned when there are problems communicating
with a hardware device or requesting features that hardware does not
support. This could indicate broken or flaky hardware.
It's a 'Something is wrong, I give up!' type of error.
- - ``ENXIO``
- Typically returned when a feature requiring interrupt support was
requested, but the line does not support interrupts.
.. note::
#. This list is not exhaustive; ioctls may return other error codes.
Since errors may have side effects such as a driver reset,
applications should abort on unexpected errors, or otherwise
assume that the device is in a bad state.
#. Request-specific error codes are listed in the individual
requests descriptions.

View File

@ -0,0 +1,41 @@
.. SPDX-License-Identifier: GPL-2.0
.. _GPIO_GET_CHIPINFO_IOCTL:
***********************
GPIO_GET_CHIPINFO_IOCTL
***********************
Name
====
GPIO_GET_CHIPINFO_IOCTL - Get the publicly available information for a chip.
Synopsis
========
.. c:macro:: GPIO_GET_CHIPINFO_IOCTL
``int ioctl(int chip_fd, GPIO_GET_CHIPINFO_IOCTL, struct gpiochip_info *info)``
Arguments
=========
``chip_fd``
The file descriptor of the GPIO character device returned by `open()`.
``info``
The :c:type:`chip_info<gpiochip_info>` to be populated.
Description
===========
Gets the publicly available information for a particular GPIO chip.
Return Value
============
On success 0 and ``info`` is populated with the chip info.
On error -1 and the ``errno`` variable is set appropriately.
Common error codes are described in error-codes.rst.

View File

@ -0,0 +1,84 @@
.. SPDX-License-Identifier: GPL-2.0
.. _GPIO_GET_LINEEVENT_IOCTL:
************************
GPIO_GET_LINEEVENT_IOCTL
************************
.. warning::
This ioctl is part of chardev_v1.rst and is obsoleted by
gpio-v2-get-line-ioctl.rst.
Name
====
GPIO_GET_LINEEVENT_IOCTL - Request a line with edge detection from the kernel.
Synopsis
========
.. c:macro:: GPIO_GET_LINEEVENT_IOCTL
``int ioctl(int chip_fd, GPIO_GET_LINEEVENT_IOCTL, struct gpioevent_request *request)``
Arguments
=========
``chip_fd``
The file descriptor of the GPIO character device returned by `open()`.
``request``
The :c:type:`event_request<gpioevent_request>` specifying the line
to request and its configuration.
Description
===========
Request a line with edge detection from the kernel.
On success, the requesting process is granted exclusive access to the line
value and may receive events when edges are detected on the line, as
described in gpio-lineevent-data-read.rst.
The state of a line is guaranteed to remain as requested until the returned
file descriptor is closed. Once the file descriptor is closed, the state of
the line becomes uncontrolled from the userspace perspective, and may revert
to its default state.
Requesting a line already in use is an error (**EBUSY**).
Requesting edge detection on a line that does not support interrupts is an
error (**ENXIO**).
As with the :ref:`line handle<gpio-get-linehandle-config-support>`, the
bias configuration is best effort.
Closing the ``chip_fd`` has no effect on existing line events.
Configuration Rules
-------------------
The following configuration rules apply:
The line event is requested as an input, so no flags specific to output lines,
``GPIOHANDLE_REQUEST_OUTPUT``, ``GPIOHANDLE_REQUEST_OPEN_DRAIN``, or
``GPIOHANDLE_REQUEST_OPEN_SOURCE``, may be set.
Only one bias flag, ``GPIOHANDLE_REQUEST_BIAS_xxx``, may be set.
If no bias flags are set then the bias configuration is not changed.
The edge flags, ``GPIOEVENT_REQUEST_RISING_EDGE`` and
``GPIOEVENT_REQUEST_FALLING_EDGE``, may be combined to detect both rising
and falling edges.
Requesting an invalid configuration is an error (**EINVAL**).
Return Value
============
On success 0 and the :c:type:`request.fd<gpioevent_request>` contains the file
descriptor for the request.
On error -1 and the ``errno`` variable is set appropriately.
Common error codes are described in error-codes.rst.

View File

@ -0,0 +1,125 @@
.. SPDX-License-Identifier: GPL-2.0
.. _GPIO_GET_LINEHANDLE_IOCTL:
*************************
GPIO_GET_LINEHANDLE_IOCTL
*************************
.. warning::
This ioctl is part of chardev_v1.rst and is obsoleted by
gpio-v2-get-line-ioctl.rst.
Name
====
GPIO_GET_LINEHANDLE_IOCTL - Request a line or lines from the kernel.
Synopsis
========
.. c:macro:: GPIO_GET_LINEHANDLE_IOCTL
``int ioctl(int chip_fd, GPIO_GET_LINEHANDLE_IOCTL, struct gpiohandle_request *request)``
Arguments
=========
``chip_fd``
The file descriptor of the GPIO character device returned by `open()`.
``request``
The :c:type:`handle_request<gpiohandle_request>` specifying the lines to
request and their configuration.
Description
===========
Request a line or lines from the kernel.
While multiple lines may be requested, the same configuration applies to all
lines in the request.
On success, the requesting process is granted exclusive access to the line
value and write access to the line configuration.
The state of a line, including the value of output lines, is guaranteed to
remain as requested until the returned file descriptor is closed. Once the
file descriptor is closed, the state of the line becomes uncontrolled from
the userspace perspective, and may revert to its default state.
Requesting a line already in use is an error (**EBUSY**).
Closing the ``chip_fd`` has no effect on existing line handles.
.. _gpio-get-linehandle-config-rules:
Configuration Rules
-------------------
The following configuration rules apply:
The direction flags, ``GPIOHANDLE_REQUEST_INPUT`` and
``GPIOHANDLE_REQUEST_OUTPUT``, cannot be combined. If neither are set then the
only other flag that may be set is ``GPIOHANDLE_REQUEST_ACTIVE_LOW`` and the
line is requested "as-is" to allow reading of the line value without altering
the electrical configuration.
The drive flags, ``GPIOHANDLE_REQUEST_OPEN_xxx``, require the
``GPIOHANDLE_REQUEST_OUTPUT`` to be set.
Only one drive flag may be set.
If none are set then the line is assumed push-pull.
Only one bias flag, ``GPIOHANDLE_REQUEST_BIAS_xxx``, may be set, and
it requires a direction flag to also be set.
If no bias flags are set then the bias configuration is not changed.
Requesting an invalid configuration is an error (**EINVAL**).
.. _gpio-get-linehandle-config-support:
Configuration Support
---------------------
Where the requested configuration is not directly supported by the underlying
hardware and driver, the kernel applies one of these approaches:
- reject the request
- emulate the feature in software
- treat the feature as best effort
The approach applied depends on whether the feature can reasonably be emulated
in software, and the impact on the hardware and userspace if the feature is not
supported.
The approach applied for each feature is as follows:
============== ===========
Feature Approach
============== ===========
Bias best effort
Direction reject
Drive emulate
============== ===========
Bias is treated as best effort to allow userspace to apply the same
configuration for platforms that support internal bias as those that require
external bias.
Worst case the line floats rather than being biased as expected.
Drive is emulated by switching the line to an input when the line should not
be driven.
In all cases, the configuration reported by gpio-get-lineinfo-ioctl.rst
is the requested configuration, not the resulting hardware configuration.
Userspace cannot determine if a feature is supported in hardware, is
emulated, or is best effort.
Return Value
============
On success 0 and the :c:type:`request.fd<gpiohandle_request>` contains the
file descriptor for the request.
On error -1 and the ``errno`` variable is set appropriately.
Common error codes are described in error-codes.rst.

View File

@ -0,0 +1,54 @@
.. SPDX-License-Identifier: GPL-2.0
.. _GPIO_GET_LINEINFO_IOCTL:
***********************
GPIO_GET_LINEINFO_IOCTL
***********************
.. warning::
This ioctl is part of chardev_v1.rst and is obsoleted by
gpio-v2-get-lineinfo-ioctl.rst.
Name
====
GPIO_GET_LINEINFO_IOCTL - Get the publicly available information for a line.
Synopsis
========
.. c:macro:: GPIO_GET_LINEINFO_IOCTL
``int ioctl(int chip_fd, GPIO_GET_LINEINFO_IOCTL, struct gpioline_info *info)``
Arguments
=========
``chip_fd``
The file descriptor of the GPIO character device returned by `open()`.
``info``
The :c:type:`line_info<gpioline_info>` to be populated, with the
``offset`` field set to indicate the line to be collected.
Description
===========
Get the publicly available information for a line.
This information is available independent of whether the line is in use.
.. note::
The line info does not include the line value.
The line must be requested using gpio-get-linehandle-ioctl.rst or
gpio-get-lineevent-ioctl.rst to access its value.
Return Value
============
On success 0 and ``info`` is populated with the chip info.
On error -1 and the ``errno`` variable is set appropriately.
Common error codes are described in error-codes.rst.

View File

@ -0,0 +1,49 @@
.. SPDX-License-Identifier: GPL-2.0
.. _GPIO_GET_LINEINFO_UNWATCH_IOCTL:
*******************************
GPIO_GET_LINEINFO_UNWATCH_IOCTL
*******************************
Name
====
GPIO_GET_LINEINFO_UNWATCH_IOCTL - Disable watching a line for changes to its
requested state and configuration information.
Synopsis
========
.. c:macro:: GPIO_GET_LINEINFO_UNWATCH_IOCTL
``int ioctl(int chip_fd, GPIO_GET_LINEINFO_UNWATCH_IOCTL, u32 *offset)``
Arguments
=========
``chip_fd``
The file descriptor of the GPIO character device returned by `open()`.
``offset``
The offset of the line to no longer watch.
Description
===========
Remove the line from the list of lines being watched on this ``chip_fd``.
This is the reverse of gpio-v2-get-lineinfo-watch-ioctl.rst (v2) and
gpio-get-lineinfo-watch-ioctl.rst (v1).
Unwatching a line that is not watched is an error (**EBUSY**).
First added in 5.7.
Return Value
============
On success 0.
On error -1 and the ``errno`` variable is set appropriately.
Common error codes are described in error-codes.rst.

View File

@ -0,0 +1,74 @@
.. SPDX-License-Identifier: GPL-2.0
.. _GPIO_GET_LINEINFO_WATCH_IOCTL:
*****************************
GPIO_GET_LINEINFO_WATCH_IOCTL
*****************************
.. warning::
This ioctl is part of chardev_v1.rst and is obsoleted by
gpio-v2-get-lineinfo-watch-ioctl.rst.
Name
====
GPIO_GET_LINEINFO_WATCH_IOCTL - Enable watching a line for changes to its
request state and configuration information.
Synopsis
========
.. c:macro:: GPIO_GET_LINEINFO_WATCH_IOCTL
``int ioctl(int chip_fd, GPIO_GET_LINEINFO_WATCH_IOCTL, struct gpioline_info *info)``
Arguments
=========
``chip_fd``
The file descriptor of the GPIO character device returned by `open()`.
``info``
The :c:type:`line_info<gpioline_info>` struct to be populated, with
the ``offset`` set to indicate the line to watch
Description
===========
Enable watching a line for changes to its request state and configuration
information. Changes to line info include a line being requested, released
or reconfigured.
.. note::
Watching line info is not generally required, and would typically only be
used by a system monitoring component.
The line info does NOT include the line value.
The line must be requested using gpio-get-linehandle-ioctl.rst or
gpio-get-lineevent-ioctl.rst to access its value, and the line event can
monitor a line for events using gpio-lineevent-data-read.rst.
By default all lines are unwatched when the GPIO chip is opened.
Multiple lines may be watched simultaneously by adding a watch for each.
Once a watch is set, any changes to line info will generate events which can be
read from the ``chip_fd`` as described in
gpio-lineinfo-changed-read.rst.
Adding a watch to a line that is already watched is an error (**EBUSY**).
Watches are specific to the ``chip_fd`` and are independent of watches
on the same GPIO chip opened with a separate call to `open()`.
First added in 5.7.
Return Value
============
On success 0 and ``info`` is populated with the current line info.
On error -1 and the ``errno`` variable is set appropriately.
Common error codes are described in error-codes.rst.

View File

@ -0,0 +1,56 @@
.. SPDX-License-Identifier: GPL-2.0
.. _GPIOHANDLE_GET_LINE_VALUES_IOCTL:
********************************
GPIOHANDLE_GET_LINE_VALUES_IOCTL
********************************
.. warning::
This ioctl is part of chardev_v1.rst and is obsoleted by
gpio-v2-line-get-values-ioctl.rst.
Name
====
GPIOHANDLE_GET_LINE_VALUES_IOCTL - Get the values of all requested lines.
Synopsis
========
.. c:macro:: GPIOHANDLE_GET_LINE_VALUES_IOCTL
``int ioctl(int handle_fd, GPIOHANDLE_GET_LINE_VALUES_IOCTL, struct gpiohandle_data *values)``
Arguments
=========
``handle_fd``
The file descriptor of the GPIO character device, as returned in the
:c:type:`request.fd<gpiohandle_request>` by gpio-get-linehandle-ioctl.rst.
``values``
The :c:type:`line_values<gpiohandle_data>` to be populated.
Description
===========
Get the values of all requested lines.
The values of both input and output lines may be read.
For output lines, the value returned is driver and configuration dependent and
may be either the output buffer (the last requested value set) or the input
buffer (the actual level of the line), and depending on the hardware and
configuration these may differ.
This ioctl can also be used to read the line value for line events,
substituting the ``event_fd`` for the ``handle_fd``. As there is only
one line requested in that case, only the one value is returned in ``values``.
Return Value
============
On success 0 and ``values`` populated with the values read.
On error -1 and the ``errno`` variable is set appropriately.
Common error codes are described in error-codes.rst.

View File

@ -0,0 +1,63 @@
.. SPDX-License-Identifier: GPL-2.0
.. _GPIOHANDLE_SET_CONFIG_IOCTL:
***************************
GPIOHANDLE_SET_CONFIG_IOCTL
***************************
.. warning::
This ioctl is part of chardev_v1.rst and is obsoleted by
gpio-v2-line-set-config-ioctl.rst.
Name
====
GPIOHANDLE_SET_CONFIG_IOCTL - Update the configuration of previously requested lines.
Synopsis
========
.. c:macro:: GPIOHANDLE_SET_CONFIG_IOCTL
``int ioctl(int handle_fd, GPIOHANDLE_SET_CONFIG_IOCTL, struct gpiohandle_config *config)``
Arguments
=========
``handle_fd``
The file descriptor of the GPIO character device, as returned in the
:c:type:`request.fd<gpiohandle_request>` by gpio-get-linehandle-ioctl.rst.
``config``
The new :c:type:`configuration<gpiohandle_config>` to apply to the
requested lines.
Description
===========
Update the configuration of previously requested lines, without releasing the
line or introducing potential glitches.
The configuration applies to all requested lines.
The same :ref:`gpio-get-linehandle-config-rules` and
:ref:`gpio-get-linehandle-config-support` that apply when requesting the
lines also apply when updating the line configuration.
The motivating use case for this command is changing direction of
bi-directional lines between input and output, but it may be used more
generally to move lines seamlessly from one configuration state to another.
To only change the value of output lines, use
gpio-handle-set-line-values-ioctl.rst.
First added in 5.5.
Return Value
============
On success 0.
On error -1 and the ``errno`` variable is set appropriately.
Common error codes are described in error-codes.rst.

View File

@ -0,0 +1,48 @@
.. SPDX-License-Identifier: GPL-2.0
.. _GPIO_HANDLE_SET_LINE_VALUES_IOCTL:
*********************************
GPIO_HANDLE_SET_LINE_VALUES_IOCTL
*********************************
.. warning::
This ioctl is part of chardev_v1.rst and is obsoleted by
gpio-v2-line-set-values-ioctl.rst.
Name
====
GPIO_HANDLE_SET_LINE_VALUES_IOCTL - Set the values of all requested output lines.
Synopsis
========
.. c:macro:: GPIO_HANDLE_SET_LINE_VALUES_IOCTL
``int ioctl(int handle_fd, GPIO_HANDLE_SET_LINE_VALUES_IOCTL, struct gpiohandle_data *values)``
Arguments
=========
``handle_fd``
The file descriptor of the GPIO character device, as returned in the
:c:type:`request.fd<gpiohandle_request>` by gpio-get-linehandle-ioctl.rst.
``values``
The :c:type:`line_values<gpiohandle_data>` to set.
Description
===========
Set the values of all requested output lines.
Only the values of output lines may be set.
Attempting to set the value of input lines is an error (**EPERM**).
Return Value
============
On success 0.
On error -1 and the ``errno`` variable is set appropriately.
Common error codes are described in error-codes.rst.

View File

@ -0,0 +1,84 @@
.. SPDX-License-Identifier: GPL-2.0
.. _GPIO_LINEEVENT_DATA_READ:
************************
GPIO_LINEEVENT_DATA_READ
************************
.. warning::
This ioctl is part of chardev_v1.rst and is obsoleted by
gpio-v2-line-event-read.rst.
Name
====
GPIO_LINEEVENT_DATA_READ - Read edge detection events from a line event.
Synopsis
========
``int read(int event_fd, void *buf, size_t count)``
Arguments
=========
``event_fd``
The file descriptor of the GPIO character device, as returned in the
:c:type:`request.fd<gpioevent_request>` by gpio-get-lineevent-ioctl.rst.
``buf``
The buffer to contain the :c:type:`events<gpioevent_data>`.
``count``
The number of bytes available in ``buf``, which must be at
least the size of a :c:type:`gpioevent_data`.
Description
===========
Read edge detection events for a line from a line event.
Edge detection must be enabled for the input line using either
``GPIOEVENT_REQUEST_RISING_EDGE`` or ``GPIOEVENT_REQUEST_FALLING_EDGE``, or
both. Edge events are then generated whenever edge interrupts are detected on
the input line.
The kernel captures and timestamps edge events as close as possible to their
occurrence and stores them in a buffer from where they can be read by
userspace at its convenience using `read()`.
The source of the clock for :c:type:`event.timestamp<gpioevent_data>` is
``CLOCK_MONOTONIC``, except for kernels earlier than Linux 5.7 when it was
``CLOCK_REALTIME``. There is no indication in the :c:type:`gpioevent_data`
as to which clock source is used, it must be determined from either the kernel
version or sanity checks on the timestamp itself.
Events read from the buffer are always in the same order that they were
detected by the kernel.
The size of the kernel event buffer is fixed at 16 events.
The buffer may overflow if bursts of events occur quicker than they are read
by userspace. If an overflow occurs then the most recent event is discarded.
Overflow cannot be detected from userspace.
To minimize the number of calls required to copy events from the kernel to
userspace, `read()` supports copying multiple events. The number of events
copied is the lower of the number available in the kernel buffer and the
number that will fit in the userspace buffer (``buf``).
The `read()` will block if no event is available and the ``event_fd`` has not
been set **O_NONBLOCK**.
The presence of an event can be tested for by checking that the ``event_fd`` is
readable using `poll()` or an equivalent.
Return Value
============
On success the number of bytes read, which will be a multiple of the size of
a :c:type:`gpio_lineevent_data` event.
On error -1 and the ``errno`` variable is set appropriately.
Common error codes are described in error-codes.rst.

View File

@ -0,0 +1,87 @@
.. SPDX-License-Identifier: GPL-2.0
.. _GPIO_LINEINFO_CHANGED_READ:
**************************
GPIO_LINEINFO_CHANGED_READ
**************************
.. warning::
This ioctl is part of chardev_v1.rst and is obsoleted by
gpio-v2-lineinfo-changed-read.rst.
Name
====
GPIO_LINEINFO_CHANGED_READ - Read line info change events for watched lines
from the chip.
Synopsis
========
``int read(int chip_fd, void *buf, size_t count)``
Arguments
=========
``chip_fd``
The file descriptor of the GPIO character device returned by `open()`.
``buf``
The buffer to contain the :c:type:`events<gpioline_info_changed>`.
``count``
The number of bytes available in ``buf``, which must be at least the size
of a :c:type:`gpioline_info_changed` event.
Description
===========
Read line info change events for watched lines from the chip.
.. note::
Monitoring line info changes is not generally required, and would typically
only be performed by a system monitoring component.
These events relate to changes in a line's request state or configuration,
not its value. Use gpio-lineevent-data-read.rst to receive events when a
line changes value.
A line must be watched using gpio-get-lineinfo-watch-ioctl.rst to generate
info changed events. Subsequently, a request, release, or reconfiguration
of the line will generate an info changed event.
The kernel timestamps events when they occur and stores them in a buffer
from where they can be read by userspace at its convenience using `read()`.
The size of the kernel event buffer is fixed at 32 events per ``chip_fd``.
The buffer may overflow if bursts of events occur quicker than they are read
by userspace. If an overflow occurs then the most recent event is discarded.
Overflow cannot be detected from userspace.
Events read from the buffer are always in the same order that they were
detected by the kernel, including when multiple lines are being monitored by
the one ``chip_fd``.
To minimize the number of calls required to copy events from the kernel to
userspace, `read()` supports copying multiple events. The number of events
copied is the lower of the number available in the kernel buffer and the
number that will fit in the userspace buffer (``buf``).
A `read()` will block if no event is available and the ``chip_fd`` has not
been set **O_NONBLOCK**.
The presence of an event can be tested for by checking that the ``chip_fd`` is
readable using `poll()` or an equivalent.
First added in 5.7.
Return Value
============
On success the number of bytes read, which will be a multiple of the size of
a :c:type:`gpioline_info_changed` event.
On error -1 and the ``errno`` variable is set appropriately.
Common error codes are described in error-codes.rst.

View File

@ -0,0 +1,152 @@
.. SPDX-License-Identifier: GPL-2.0
.. _GPIO_V2_GET_LINE_IOCTL:
**********************
GPIO_V2_GET_LINE_IOCTL
**********************
Name
====
GPIO_V2_GET_LINE_IOCTL - Request a line or lines from the kernel.
Synopsis
========
.. c:macro:: GPIO_V2_GET_LINE_IOCTL
``int ioctl(int chip_fd, GPIO_V2_GET_LINE_IOCTL, struct gpio_v2_line_request *request)``
Arguments
=========
``chip_fd``
The file descriptor of the GPIO character device returned by `open()`.
``request``
The :c:type:`line_request<gpio_v2_line_request>` specifying the lines
to request and their configuration.
Description
===========
On success, the requesting process is granted exclusive access to the line
value, write access to the line configuration, and may receive events when
edges are detected on the line, all of which are described in more detail in
:ref:`gpio-v2-line-request`.
A number of lines may be requested in the one line request, and request
operations are performed on the requested lines by the kernel as atomically
as possible. e.g. gpio-v2-line-get-values-ioctl.rst will read all the
requested lines at once.
The state of a line, including the value of output lines, is guaranteed to
remain as requested until the returned file descriptor is closed. Once the
file descriptor is closed, the state of the line becomes uncontrolled from
the userspace perspective, and may revert to its default state.
Requesting a line already in use is an error (**EBUSY**).
Closing the ``chip_fd`` has no effect on existing line requests.
.. _gpio-v2-get-line-config-rules:
Configuration Rules
-------------------
For any given requested line, the following configuration rules apply:
The direction flags, ``GPIO_V2_LINE_FLAG_INPUT`` and
``GPIO_V2_LINE_FLAG_OUTPUT``, cannot be combined. If neither are set then
the only other flag that may be set is ``GPIO_V2_LINE_FLAG_ACTIVE_LOW``
and the line is requested "as-is" to allow reading of the line value
without altering the electrical configuration.
The drive flags, ``GPIO_V2_LINE_FLAG_OPEN_xxx``, require the
``GPIO_V2_LINE_FLAG_OUTPUT`` to be set.
Only one drive flag may be set.
If none are set then the line is assumed push-pull.
Only one bias flag, ``GPIO_V2_LINE_FLAG_BIAS_xxx``, may be set, and it
requires a direction flag to also be set.
If no bias flags are set then the bias configuration is not changed.
The edge flags, ``GPIO_V2_LINE_FLAG_EDGE_xxx``, require
``GPIO_V2_LINE_FLAG_INPUT`` to be set and may be combined to detect both rising
and falling edges. Requesting edge detection from a line that does not support
it is an error (**ENXIO**).
Only one event clock flag, ``GPIO_V2_LINE_FLAG_EVENT_CLOCK_xxx``, may be set.
If none are set then the event clock defaults to ``CLOCK_MONOTONIC``.
The ``GPIO_V2_LINE_FLAG_EVENT_CLOCK_HTE`` flag requires supporting hardware
and a kernel with ``CONFIG_HTE`` set. Requesting HTE from a device that
doesn't support it is an error (**EOPNOTSUP**).
The :c:type:`debounce_period_us<gpio_v2_line_attribute>` attribute may only
be applied to lines with ``GPIO_V2_LINE_FLAG_INPUT`` set. When set, debounce
applies to both the values returned by gpio-v2-line-get-values-ioctl.rst and
the edges returned by gpio-v2-line-event-read.rst. If not
supported directly by hardware, debouncing is emulated in software by the
kernel. Requesting debounce on a line that supports neither debounce in
hardware nor interrupts, as required for software emulation, is an error
(**ENXIO**).
Requesting an invalid configuration is an error (**EINVAL**).
.. _gpio-v2-get-line-config-support:
Configuration Support
---------------------
Where the requested configuration is not directly supported by the underlying
hardware and driver, the kernel applies one of these approaches:
- reject the request
- emulate the feature in software
- treat the feature as best effort
The approach applied depends on whether the feature can reasonably be emulated
in software, and the impact on the hardware and userspace if the feature is not
supported.
The approach applied for each feature is as follows:
============== ===========
Feature Approach
============== ===========
Bias best effort
Debounce emulate
Direction reject
Drive emulate
Edge Detection reject
============== ===========
Bias is treated as best effort to allow userspace to apply the same
configuration for platforms that support internal bias as those that require
external bias.
Worst case the line floats rather than being biased as expected.
Debounce is emulated by applying a filter to hardware interrupts on the line.
An edge event is generated after an edge is detected and the line remains
stable for the debounce period.
The event timestamp corresponds to the end of the debounce period.
Drive is emulated by switching the line to an input when the line should not
be actively driven.
Edge detection requires interrupt support, and is rejected if that is not
supported. Emulation by polling can still be performed from userspace.
In all cases, the configuration reported by gpio-v2-get-lineinfo-ioctl.rst
is the requested configuration, not the resulting hardware configuration.
Userspace cannot determine if a feature is supported in hardware, is
emulated, or is best effort.
Return Value
============
On success 0 and the :c:type:`request.fd<gpio_v2_line_request>` contains the
file descriptor for the request.
On error -1 and the ``errno`` variable is set appropriately.
Common error codes are described in error-codes.rst.

View File

@ -0,0 +1,50 @@
.. SPDX-License-Identifier: GPL-2.0
.. _GPIO_V2_GET_LINEINFO_IOCTL:
**************************
GPIO_V2_GET_LINEINFO_IOCTL
**************************
Name
====
GPIO_V2_GET_LINEINFO_IOCTL - Get the publicly available information for a line.
Synopsis
========
.. c:macro:: GPIO_V2_GET_LINEINFO_IOCTL
``int ioctl(int chip_fd, GPIO_V2_GET_LINEINFO_IOCTL, struct gpio_v2_line_info *info)``
Arguments
=========
``chip_fd``
The file descriptor of the GPIO character device returned by `open()`.
``info``
The :c:type:`line_info<gpio_v2_line_info>` to be populated, with the
``offset`` field set to indicate the line to be collected.
Description
===========
Get the publicly available information for a line.
This information is available independent of whether the line is in use.
.. note::
The line info does not include the line value.
The line must be requested using gpio-v2-get-line-ioctl.rst to access its
value.
Return Value
============
On success 0 and ``info`` is populated with the chip info.
On error -1 and the ``errno`` variable is set appropriately.
Common error codes are described in error-codes.rst.

View File

@ -0,0 +1,67 @@
.. SPDX-License-Identifier: GPL-2.0
.. _GPIO_V2_GET_LINEINFO_WATCH_IOCTL:
********************************
GPIO_V2_GET_LINEINFO_WATCH_IOCTL
********************************
Name
====
GPIO_V2_GET_LINEINFO_WATCH_IOCTL - Enable watching a line for changes to its
request state and configuration information.
Synopsis
========
.. c:macro:: GPIO_V2_GET_LINEINFO_WATCH_IOCTL
``int ioctl(int chip_fd, GPIO_V2_GET_LINEINFO_WATCH_IOCTL, struct gpio_v2_line_info *info)``
Arguments
=========
``chip_fd``
The file descriptor of the GPIO character device returned by `open()`.
``info``
The :c:type:`line_info<gpio_v2_line_info>` struct to be populated, with
the ``offset`` set to indicate the line to watch
Description
===========
Enable watching a line for changes to its request state and configuration
information. Changes to line info include a line being requested, released
or reconfigured.
.. note::
Watching line info is not generally required, and would typically only be
used by a system monitoring component.
The line info does NOT include the line value.
The line must be requested using gpio-v2-get-line-ioctl.rst to access
its value, and the line request can monitor a line for events using
gpio-v2-line-event-read.rst.
By default all lines are unwatched when the GPIO chip is opened.
Multiple lines may be watched simultaneously by adding a watch for each.
Once a watch is set, any changes to line info will generate events which can be
read from the ``chip_fd`` as described in
gpio-v2-lineinfo-changed-read.rst.
Adding a watch to a line that is already watched is an error (**EBUSY**).
Watches are specific to the ``chip_fd`` and are independent of watches
on the same GPIO chip opened with a separate call to `open()`.
Return Value
============
On success 0 and ``info`` is populated with the current line info.
On error -1 and the ``errno`` variable is set appropriately.
Common error codes are described in error-codes.rst.

View File

@ -0,0 +1,83 @@
.. SPDX-License-Identifier: GPL-2.0
.. _GPIO_V2_LINE_EVENT_READ:
***********************
GPIO_V2_LINE_EVENT_READ
***********************
Name
====
GPIO_V2_LINE_EVENT_READ - Read edge detection events for lines from a request.
Synopsis
========
``int read(int req_fd, void *buf, size_t count)``
Arguments
=========
``req_fd``
The file descriptor of the GPIO character device, as returned in the
:c:type:`request.fd<gpio_v2_line_request>` by gpio-v2-get-line-ioctl.rst.
``buf``
The buffer to contain the :c:type:`events<gpio_v2_line_event>`.
``count``
The number of bytes available in ``buf``, which must be at
least the size of a :c:type:`gpio_v2_line_event`.
Description
===========
Read edge detection events for lines from a request.
Edge detection must be enabled for the input line using either
``GPIO_V2_LINE_FLAG_EDGE_RISING`` or ``GPIO_V2_LINE_FLAG_EDGE_FALLING``, or
both. Edge events are then generated whenever edge interrupts are detected on
the input line.
The kernel captures and timestamps edge events as close as possible to their
occurrence and stores them in a buffer from where they can be read by
userspace at its convenience using `read()`.
Events read from the buffer are always in the same order that they were
detected by the kernel, including when multiple lines are being monitored by
the one request.
The size of the kernel event buffer is fixed at the time of line request
creation, and can be influenced by the
:c:type:`request.event_buffer_size<gpio_v2_line_request>`.
The default size is 16 times the number of lines requested.
The buffer may overflow if bursts of events occur quicker than they are read
by userspace. If an overflow occurs then the oldest buffered event is
discarded. Overflow can be detected from userspace by monitoring the event
sequence numbers.
To minimize the number of calls required to copy events from the kernel to
userspace, `read()` supports copying multiple events. The number of events
copied is the lower of the number available in the kernel buffer and the
number that will fit in the userspace buffer (``buf``).
Changing the edge detection flags using gpio-v2-line-set-config-ioctl.rst
does not remove or modify the events already contained in the kernel event
buffer.
The `read()` will block if no event is available and the ``req_fd`` has not
been set **O_NONBLOCK**.
The presence of an event can be tested for by checking that the ``req_fd`` is
readable using `poll()` or an equivalent.
Return Value
============
On success the number of bytes read, which will be a multiple of the size of a
:c:type:`gpio_v2_line_event` event.
On error -1 and the ``errno`` variable is set appropriately.
Common error codes are described in error-codes.rst.

View File

@ -0,0 +1,51 @@
.. SPDX-License-Identifier: GPL-2.0
.. _GPIO_V2_LINE_GET_VALUES_IOCTL:
*****************************
GPIO_V2_LINE_GET_VALUES_IOCTL
*****************************
Name
====
GPIO_V2_LINE_GET_VALUES_IOCTL - Get the values of requested lines.
Synopsis
========
.. c:macro:: GPIO_V2_LINE_GET_VALUES_IOCTL
``int ioctl(int req_fd, GPIO_V2_LINE_GET_VALUES_IOCTL, struct gpio_v2_line_values *values)``
Arguments
=========
``req_fd``
The file descriptor of the GPIO character device, as returned in the
:c:type:`request.fd<gpio_v2_line_request>` by gpio-v2-get-line-ioctl.rst.
``values``
The :c:type:`line_values<gpio_v2_line_values>` to get with the ``mask`` set
to indicate the subset of requested lines to get.
Description
===========
Get the values of requested lines.
The values of both input and output lines may be read.
For output lines, the value returned is driver and configuration dependent and
may be either the output buffer (the last requested value set) or the input
buffer (the actual level of the line), and depending on the hardware and
configuration these may differ.
Return Value
============
On success 0 and the corresponding :c:type:`values.bits<gpio_v2_line_values>`
contain the value read.
On error -1 and the ``errno`` variable is set appropriately.
Common error codes are described in error-codes.rst.

View File

@ -0,0 +1,58 @@
.. SPDX-License-Identifier: GPL-2.0
.. _GPIO_V2_LINE_SET_CONFIG_IOCTL:
*****************************
GPIO_V2_LINE_SET_CONFIG_IOCTL
*****************************
Name
====
GPIO_V2_LINE_SET_CONFIG_IOCTL - Update the configuration of previously requested lines.
Synopsis
========
.. c:macro:: GPIO_V2_LINE_SET_CONFIG_IOCTL
``int ioctl(int req_fd, GPIO_V2_LINE_SET_CONFIG_IOCTL, struct gpio_v2_line_config *config)``
Arguments
=========
``req_fd``
The file descriptor of the GPIO character device, as returned in the
:c:type:`request.fd<gpio_v2_line_request>` by gpio-v2-get-line-ioctl.rst.
``config``
The new :c:type:`configuration<gpio_v2_line_config>` to apply to the
requested lines.
Description
===========
Update the configuration of previously requested lines, without releasing the
line or introducing potential glitches.
The new configuration must specify the configuration of all requested lines.
The same :ref:`gpio-v2-get-line-config-rules` and
:ref:`gpio-v2-get-line-config-support` that apply when requesting the lines
also apply when updating the line configuration.
The motivating use case for this command is changing direction of
bi-directional lines between input and output, but it may also be used to
dynamically control edge detection, or more generally move lines seamlessly
from one configuration state to another.
To only change the value of output lines, use
gpio-v2-line-set-values-ioctl.rst.
Return Value
============
On success 0.
On error -1 and the ``errno`` variable is set appropriately.
Common error codes are described in error-codes.rst.

View File

@ -0,0 +1,47 @@
.. SPDX-License-Identifier: GPL-2.0
.. _GPIO_V2_LINE_SET_VALUES_IOCTL:
*****************************
GPIO_V2_LINE_SET_VALUES_IOCTL
*****************************
Name
====
GPIO_V2_LINE_SET_VALUES_IOCTL - Set the values of requested output lines.
Synopsis
========
.. c:macro:: GPIO_V2_LINE_SET_VALUES_IOCTL
``int ioctl(int req_fd, GPIO_V2_LINE_SET_VALUES_IOCTL, struct gpio_v2_line_values *values)``
Arguments
=========
``req_fd``
The file descriptor of the GPIO character device, as returned in the
:c:type:`request.fd<gpio_v2_line_request>` by gpio-v2-get-line-ioctl.rst.
``values``
The :c:type:`line_values<gpio_v2_line_values>` to set with the ``mask`` set
to indicate the subset of requested lines to set and ``bits`` set to
indicate the new value.
Description
===========
Set the values of requested output lines.
Only the values of output lines may be set.
Attempting to set the value of an input line is an error (**EPERM**).
Return Value
============
On success 0.
On error -1 and the ``errno`` variable is set appropriately.
Common error codes are described in error-codes.rst.

View File

@ -0,0 +1,81 @@
.. SPDX-License-Identifier: GPL-2.0
.. _GPIO_V2_LINEINFO_CHANGED_READ:
*****************************
GPIO_V2_LINEINFO_CHANGED_READ
*****************************
Name
====
GPIO_V2_LINEINFO_CHANGED_READ - Read line info changed events for watched
lines from the chip.
Synopsis
========
``int read(int chip_fd, void *buf, size_t count)``
Arguments
=========
``chip_fd``
The file descriptor of the GPIO character device returned by `open()`.
``buf``
The buffer to contain the :c:type:`events<gpio_v2_line_info_changed>`.
``count``
The number of bytes available in ``buf``, which must be at least the size
of a :c:type:`gpio_v2_line_info_changed` event.
Description
===========
Read line info changed events for watched lines from the chip.
.. note::
Monitoring line info changes is not generally required, and would typically
only be performed by a system monitoring component.
These events relate to changes in a line's request state or configuration,
not its value. Use gpio-v2-line-event-read.rst to receive events when a
line changes value.
A line must be watched using gpio-v2-get-lineinfo-watch-ioctl.rst to generate
info changed events. Subsequently, a request, release, or reconfiguration
of the line will generate an info changed event.
The kernel timestamps events when they occur and stores them in a buffer
from where they can be read by userspace at its convenience using `read()`.
The size of the kernel event buffer is fixed at 32 events per ``chip_fd``.
The buffer may overflow if bursts of events occur quicker than they are read
by userspace. If an overflow occurs then the most recent event is discarded.
Overflow cannot be detected from userspace.
Events read from the buffer are always in the same order that they were
detected by the kernel, including when multiple lines are being monitored by
the one ``chip_fd``.
To minimize the number of calls required to copy events from the kernel to
userspace, `read()` supports copying multiple events. The number of events
copied is the lower of the number available in the kernel buffer and the
number that will fit in the userspace buffer (``buf``).
A `read()` will block if no event is available and the ``chip_fd`` has not
been set **O_NONBLOCK**.
The presence of an event can be tested for by checking that the ``chip_fd`` is
readable using `poll()` or an equivalent.
Return Value
============
On success the number of bytes read, which will be a multiple of the size
of a :c:type:`gpio_v2_line_info_changed` event.
On error -1 and the ``errno`` variable is set appropriately.
Common error codes are described in error-codes.rst.

View File

@ -0,0 +1,18 @@
.. SPDX-License-Identifier: GPL-2.0
====
GPIO
====
.. toctree::
:maxdepth: 1
Character Device Userspace API <chardev>
Obsolete Userspace APIs <obsolete>
.. only:: subproject and html
Indices
=======
* :ref:`genindex`

View File

@ -0,0 +1,11 @@
.. SPDX-License-Identifier: GPL-2.0
============================
Obsolete GPIO Userspace APIs
============================
.. toctree::
:maxdepth: 1
Character Device Userspace API (v1) <chardev_v1>
Sysfs Interface <sysfs>

View File

@ -2,18 +2,18 @@ GPIO Sysfs Interface for Userspace
==================================
.. warning::
This API is obsoleted by the chardev.rst and the ABI documentation has
been moved to Documentation/ABI/obsolete/sysfs-gpio.
THIS ABI IS DEPRECATED, THE ABI DOCUMENTATION HAS BEEN MOVED TO
Documentation/ABI/obsolete/sysfs-gpio AND NEW USERSPACE CONSUMERS
ARE SUPPOSED TO USE THE CHARACTER DEVICE ABI. THIS OLD SYSFS ABI WILL
NOT BE DEVELOPED (NO NEW FEATURES), IT WILL JUST BE MAINTAINED.
New developments should use the chardev.rst, and existing developments are
encouraged to migrate as soon as possible, as this API will be removed
in the future.
Refer to the examples in tools/gpio/* for an introduction to the new
character device ABI. Also see the userspace header in
include/uapi/linux/gpio.h
This interface will continue to be maintained for the migration period,
but new features will only be added to the new API.
The deprecated sysfs ABI
------------------------
The obsolete sysfs ABI
----------------------
Platforms which use the "gpiolib" implementors framework may choose to
configure a sysfs user interface to GPIOs. This is different from the
debugfs interface, since it provides control over GPIO direction and
@ -33,9 +33,12 @@ userspace GPIO can be used to determine system configuration data that
standard kernels won't know about. And for some tasks, simple userspace
GPIO drivers could be all that the system really needs.
DO NOT ABUSE SYSFS TO CONTROL HARDWARE THAT HAS PROPER KERNEL DRIVERS.
PLEASE READ THE DOCUMENT AT Documentation/driver-api/gpio/drivers-on-gpio.rst
TO AVOID REINVENTING KERNEL WHEELS IN USERSPACE. I MEAN IT. REALLY.
.. note::
Do NOT abuse sysfs to control hardware that has proper kernel drivers.
Please read Documentation/driver-api/gpio/drivers-on-gpio.rst
to avoid reinventing kernel wheels in userspace.
I MEAN IT. REALLY.
Paths in Sysfs
--------------
@ -84,9 +87,9 @@ and have the following read/write attributes:
allow userspace to reconfigure this GPIO's direction.
"value" ...
reads as either 0 (low) or 1 (high). If the GPIO
reads as either 0 (inactive) or 1 (active). If the GPIO
is configured as an output, this value may be written;
any nonzero value is treated as high.
any nonzero value is treated as active.
If the pin can be configured as interrupt-generating interrupt
and if it has been configured to generate interrupts (see the

View File

@ -42,6 +42,7 @@ Devices and I/O
accelerators/ocxl
dma-buf-alloc-exchange
gpio/index
iommu
iommufd
media/index

View File

@ -9190,6 +9190,7 @@ S: Maintained
T: git git://git.kernel.org/pub/scm/linux/kernel/git/brgl/linux.git
F: Documentation/ABI/obsolete/sysfs-gpio
F: Documentation/ABI/testing/gpio-cdev
F: Documentation/userspace-api/gpio/
F: drivers/gpio/gpiolib-cdev.c
F: include/uapi/linux/gpio.h
F: tools/gpio/

View File

@ -711,8 +711,9 @@ config GPIO_UNIPHIER
Say yes here to support UniPhier GPIOs.
config GPIO_VF610
def_bool y
depends on ARCH_MXC
bool "VF610 GPIO support"
default y if SOC_VF610
depends on ARCH_MXC || COMPILE_TEST
select GPIOLIB_IRQCHIP
help
Say yes here to support i.MX or Vybrid vf610 GPIOs.
@ -1240,6 +1241,16 @@ config GPIO_BD9571MWV
This driver can also be built as a module. If so, the module
will be called gpio-bd9571mwv.
config GPIO_CROS_EC
tristate "ChromeOS EC GPIO support"
depends on CROS_EC
help
GPIO driver for the ChromeOS Embedded Controller (EC). GPIOs
cannot be set unless the system is unlocked.
This driver can also be built as a module. If so, the module
will be called gpio-cros-ec.
config GPIO_CRYSTAL_COVE
tristate "GPIO support for Crystal Cove PMIC"
depends on (X86 || COMPILE_TEST) && INTEL_SOC_PMIC

View File

@ -46,6 +46,7 @@ obj-$(CONFIG_GPIO_BT8XX) += gpio-bt8xx.o
obj-$(CONFIG_GPIO_CADENCE) += gpio-cadence.o
obj-$(CONFIG_GPIO_CLPS711X) += gpio-clps711x.o
obj-$(CONFIG_GPIO_SNPS_CREG) += gpio-creg-snps.o
obj-$(CONFIG_GPIO_CROS_EC) += gpio-cros-ec.o
obj-$(CONFIG_GPIO_CRYSTAL_COVE) += gpio-crystalcove.o
obj-$(CONFIG_GPIO_CS5535) += gpio-cs5535.o
obj-$(CONFIG_GPIO_DA9052) += gpio-da9052.o

209
drivers/gpio/gpio-cros-ec.c Normal file
View File

@ -0,0 +1,209 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright 2024 Google LLC
*
* This driver provides the ability to control GPIOs on the Chrome OS EC.
* There isn't any direction control, and setting values on GPIOs is only
* possible when the system is unlocked.
*/
#include <linux/bitops.h>
#include <linux/device.h>
#include <linux/errno.h>
#include <linux/gpio/driver.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/platform_data/cros_ec_commands.h>
#include <linux/platform_data/cros_ec_proto.h>
#include <linux/platform_device.h>
#include <linux/property.h>
#include <linux/slab.h>
/* Prefix all names to avoid collisions with EC <-> AP nets */
static const char cros_ec_gpio_prefix[] = "EC:";
/* Setting gpios is only supported when the system is unlocked */
static void cros_ec_gpio_set(struct gpio_chip *gc, unsigned int gpio, int val)
{
const char *name = gc->names[gpio] + strlen(cros_ec_gpio_prefix);
struct cros_ec_device *cros_ec = gpiochip_get_data(gc);
struct ec_params_gpio_set params = {
.val = val,
};
int ret;
ssize_t copied;
copied = strscpy(params.name, name, sizeof(params.name));
if (copied < 0)
return;
ret = cros_ec_cmd(cros_ec, 0, EC_CMD_GPIO_SET, &params,
sizeof(params), NULL, 0);
if (ret < 0)
dev_err(gc->parent, "error setting gpio%d (%s) on EC: %d\n", gpio, name, ret);
}
static int cros_ec_gpio_get(struct gpio_chip *gc, unsigned int gpio)
{
const char *name = gc->names[gpio] + strlen(cros_ec_gpio_prefix);
struct cros_ec_device *cros_ec = gpiochip_get_data(gc);
struct ec_params_gpio_get params;
struct ec_response_gpio_get response;
int ret;
ssize_t copied;
copied = strscpy(params.name, name, sizeof(params.name));
if (copied < 0)
return -EINVAL;
ret = cros_ec_cmd(cros_ec, 0, EC_CMD_GPIO_GET, &params,
sizeof(params), &response, sizeof(response));
if (ret < 0) {
dev_err(gc->parent, "error getting gpio%d (%s) on EC: %d\n", gpio, name, ret);
return ret;
}
return response.val;
}
#define CROS_EC_GPIO_INPUT BIT(8)
#define CROS_EC_GPIO_OUTPUT BIT(9)
static int cros_ec_gpio_get_direction(struct gpio_chip *gc, unsigned int gpio)
{
const char *name = gc->names[gpio] + strlen(cros_ec_gpio_prefix);
struct cros_ec_device *cros_ec = gpiochip_get_data(gc);
struct ec_params_gpio_get_v1 params = {
.subcmd = EC_GPIO_GET_INFO,
.get_info.index = gpio,
};
struct ec_response_gpio_get_v1 response;
int ret;
ret = cros_ec_cmd(cros_ec, 1, EC_CMD_GPIO_GET, &params,
sizeof(params), &response, sizeof(response));
if (ret < 0) {
dev_err(gc->parent, "error getting direction of gpio%d (%s) on EC: %d\n", gpio, name, ret);
return ret;
}
if (response.get_info.flags & CROS_EC_GPIO_INPUT)
return GPIO_LINE_DIRECTION_IN;
if (response.get_info.flags & CROS_EC_GPIO_OUTPUT)
return GPIO_LINE_DIRECTION_OUT;
return -EINVAL;
}
/* Query EC for all gpio line names */
static int cros_ec_gpio_init_names(struct cros_ec_device *cros_ec, struct gpio_chip *gc)
{
struct ec_params_gpio_get_v1 params = {
.subcmd = EC_GPIO_GET_INFO,
};
struct ec_response_gpio_get_v1 response;
int ret, i;
/* EC may not NUL terminate */
size_t name_len = strlen(cros_ec_gpio_prefix) + sizeof(response.get_info.name) + 1;
ssize_t copied;
const char **names;
char *str;
names = devm_kcalloc(gc->parent, gc->ngpio, sizeof(*names), GFP_KERNEL);
if (!names)
return -ENOMEM;
gc->names = names;
str = devm_kcalloc(gc->parent, gc->ngpio, name_len, GFP_KERNEL);
if (!str)
return -ENOMEM;
/* Get gpio line names one at a time */
for (i = 0; i < gc->ngpio; i++) {
params.get_info.index = i;
ret = cros_ec_cmd(cros_ec, 1, EC_CMD_GPIO_GET, &params,
sizeof(params), &response, sizeof(response));
if (ret < 0) {
dev_err_probe(gc->parent, ret, "error getting gpio%d info\n", i);
return ret;
}
names[i] = str;
copied = scnprintf(str, name_len, "%s%s", cros_ec_gpio_prefix,
response.get_info.name);
if (copied < 0)
return copied;
str += copied + 1;
}
return 0;
}
/* Query EC for number of gpios */
static int cros_ec_gpio_ngpios(struct cros_ec_device *cros_ec)
{
struct ec_params_gpio_get_v1 params = {
.subcmd = EC_GPIO_GET_COUNT,
};
struct ec_response_gpio_get_v1 response;
int ret;
ret = cros_ec_cmd(cros_ec, 1, EC_CMD_GPIO_GET, &params,
sizeof(params), &response, sizeof(response));
if (ret < 0)
return ret;
return response.get_count.val;
}
static int cros_ec_gpio_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct device *parent = dev->parent;
struct cros_ec_dev *ec_dev = dev_get_drvdata(parent);
struct cros_ec_device *cros_ec = ec_dev->ec_dev;
struct gpio_chip *gc;
int ngpios;
int ret;
/* Use the fwnode from the protocol device, e.g. cros-ec-spi */
device_set_node(dev, dev_fwnode(cros_ec->dev));
ngpios = cros_ec_gpio_ngpios(cros_ec);
if (ngpios < 0) {
dev_err_probe(dev, ngpios, "error getting gpio count\n");
return ngpios;
}
gc = devm_kzalloc(dev, sizeof(*gc), GFP_KERNEL);
if (!gc)
return -ENOMEM;
gc->ngpio = ngpios;
gc->parent = dev;
ret = cros_ec_gpio_init_names(cros_ec, gc);
if (ret)
return ret;
gc->can_sleep = true;
gc->label = dev_name(dev);
gc->base = -1;
gc->set = cros_ec_gpio_set;
gc->get = cros_ec_gpio_get;
gc->get_direction = cros_ec_gpio_get_direction;
return devm_gpiochip_add_data(dev, gc, cros_ec);
}
static struct platform_driver cros_ec_gpio_driver = {
.probe = cros_ec_gpio_probe,
.driver = {
.name = "cros-ec-gpio",
},
};
module_platform_driver(cros_ec_gpio_driver);
MODULE_DESCRIPTION("ChromeOS EC GPIO Driver");
MODULE_LICENSE("GPL");

View File

@ -108,7 +108,6 @@ static struct sprd_eic *to_sprd_eic(struct notifier_block *nb)
struct sprd_eic_variant_data {
enum sprd_eic_type type;
u32 num_eics;
};
static const char *sprd_eic_label_name[SPRD_EIC_MAX] = {
@ -118,22 +117,18 @@ static const char *sprd_eic_label_name[SPRD_EIC_MAX] = {
static const struct sprd_eic_variant_data sc9860_eic_dbnc_data = {
.type = SPRD_EIC_DEBOUNCE,
.num_eics = 8,
};
static const struct sprd_eic_variant_data sc9860_eic_latch_data = {
.type = SPRD_EIC_LATCH,
.num_eics = 8,
};
static const struct sprd_eic_variant_data sc9860_eic_async_data = {
.type = SPRD_EIC_ASYNC,
.num_eics = 8,
};
static const struct sprd_eic_variant_data sc9860_eic_sync_data = {
.type = SPRD_EIC_SYNC,
.num_eics = 8,
};
static inline void __iomem *sprd_eic_offset_base(struct sprd_eic *sprd_eic,
@ -619,6 +614,7 @@ static int sprd_eic_probe(struct platform_device *pdev)
struct gpio_irq_chip *irq;
struct sprd_eic *sprd_eic;
struct resource *res;
u16 num_banks = 0;
int ret, i;
pdata = of_device_get_match_data(dev);
@ -652,10 +648,12 @@ static int sprd_eic_probe(struct platform_device *pdev)
sprd_eic->base[i] = devm_ioremap_resource(dev, res);
if (IS_ERR(sprd_eic->base[i]))
return PTR_ERR(sprd_eic->base[i]);
num_banks++;
}
sprd_eic->chip.label = sprd_eic_label_name[sprd_eic->type];
sprd_eic->chip.ngpio = pdata->num_eics;
sprd_eic->chip.ngpio = num_banks * SPRD_EIC_PER_BANK_NR;
sprd_eic->chip.base = -1;
sprd_eic->chip.parent = dev;
sprd_eic->chip.direction_input = sprd_eic_direction_input;

View File

@ -22,6 +22,7 @@
#include <linux/irq_sim.h>
#include <linux/kernel.h>
#include <linux/list.h>
#include <linux/lockdep.h>
#include <linux/minmax.h>
#include <linux/mod_devicetable.h>
#include <linux/module.h>
@ -234,10 +235,10 @@ static void gpio_sim_dbg_show(struct seq_file *seq, struct gpio_chip *gc)
guard(mutex)(&chip->lock);
for_each_requested_gpio(gc, i, label)
for_each_hwgpio(gc, i, label)
seq_printf(seq, " gpio-%-3d (%s) %s,%s\n",
gc->base + i,
label,
label ?: "<unused>",
test_bit(i, chip->direction_map) ? "input" :
test_bit(i, chip->value_map) ? "output-high" :
"output-low",
@ -420,7 +421,7 @@ static int gpio_sim_add_bank(struct fwnode_handle *swnode, struct device *dev)
ret = fwnode_property_read_string(swnode, "gpio-sim,label", &label);
if (ret) {
label = devm_kasprintf(dev, GFP_KERNEL, "%s-%pfwP",
label = devm_kasprintf(dev, GFP_KERNEL, "%s:%pfwP",
dev_name(dev), swnode);
if (!label)
return -ENOMEM;
@ -697,8 +698,10 @@ static struct gpio_sim_device *gpio_sim_hog_get_device(struct gpio_sim_hog *hog)
return gpio_sim_line_get_device(line);
}
static bool gpio_sim_device_is_live_unlocked(struct gpio_sim_device *dev)
static bool gpio_sim_device_is_live(struct gpio_sim_device *dev)
{
lockdep_assert_held(&dev->lock);
return !!dev->pdev;
}
@ -737,7 +740,7 @@ gpio_sim_device_config_live_show(struct config_item *item, char *page)
bool live;
scoped_guard(mutex, &dev->lock)
live = gpio_sim_device_is_live_unlocked(dev);
live = gpio_sim_device_is_live(dev);
return sprintf(page, "%c\n", live ? '1' : '0');
}
@ -833,7 +836,7 @@ static int gpio_sim_add_hogs(struct gpio_sim_device *dev)
GFP_KERNEL);
else
hog->chip_label = kasprintf(GFP_KERNEL,
"gpio-sim.%u-%pfwP",
"gpio-sim.%u:%pfwP",
dev->id,
bank->swnode);
if (!hog->chip_label) {
@ -926,7 +929,7 @@ static bool gpio_sim_bank_labels_non_unique(struct gpio_sim_device *dev)
return false;
}
static int gpio_sim_device_activate_unlocked(struct gpio_sim_device *dev)
static int gpio_sim_device_activate(struct gpio_sim_device *dev)
{
struct platform_device_info pdevinfo;
struct fwnode_handle *swnode;
@ -934,6 +937,8 @@ static int gpio_sim_device_activate_unlocked(struct gpio_sim_device *dev)
struct gpio_sim_bank *bank;
int ret;
lockdep_assert_held(&dev->lock);
if (list_empty(&dev->bank_list))
return -ENODATA;
@ -998,10 +1003,12 @@ static int gpio_sim_device_activate_unlocked(struct gpio_sim_device *dev)
return 0;
}
static void gpio_sim_device_deactivate_unlocked(struct gpio_sim_device *dev)
static void gpio_sim_device_deactivate(struct gpio_sim_device *dev)
{
struct fwnode_handle *swnode;
lockdep_assert_held(&dev->lock);
swnode = dev_fwnode(&dev->pdev->dev);
platform_device_unregister(dev->pdev);
gpio_sim_remove_hogs(dev);
@ -1023,12 +1030,12 @@ gpio_sim_device_config_live_store(struct config_item *item,
guard(mutex)(&dev->lock);
if (live == gpio_sim_device_is_live_unlocked(dev))
if (live == gpio_sim_device_is_live(dev))
ret = -EPERM;
else if (live)
ret = gpio_sim_device_activate_unlocked(dev);
ret = gpio_sim_device_activate(dev);
else
gpio_sim_device_deactivate_unlocked(dev);
gpio_sim_device_deactivate(dev);
return ret ?: count;
}
@ -1069,7 +1076,7 @@ static ssize_t gpio_sim_bank_config_chip_name_show(struct config_item *item,
guard(mutex)(&dev->lock);
if (gpio_sim_device_is_live_unlocked(dev))
if (gpio_sim_device_is_live(dev))
return device_for_each_child(&dev->pdev->dev, &ctx,
gpio_sim_emit_chip_name);
@ -1098,7 +1105,7 @@ static ssize_t gpio_sim_bank_config_label_store(struct config_item *item,
guard(mutex)(&dev->lock);
if (gpio_sim_device_is_live_unlocked(dev))
if (gpio_sim_device_is_live(dev))
return -EBUSY;
trimmed = gpio_sim_strdup_trimmed(page, count);
@ -1142,7 +1149,7 @@ gpio_sim_bank_config_num_lines_store(struct config_item *item,
guard(mutex)(&dev->lock);
if (gpio_sim_device_is_live_unlocked(dev))
if (gpio_sim_device_is_live(dev))
return -EBUSY;
bank->num_lines = num_lines;
@ -1179,7 +1186,7 @@ static ssize_t gpio_sim_line_config_name_store(struct config_item *item,
guard(mutex)(&dev->lock);
if (gpio_sim_device_is_live_unlocked(dev))
if (gpio_sim_device_is_live(dev))
return -EBUSY;
trimmed = gpio_sim_strdup_trimmed(page, count);
@ -1219,7 +1226,7 @@ static ssize_t gpio_sim_hog_config_name_store(struct config_item *item,
guard(mutex)(&dev->lock);
if (gpio_sim_device_is_live_unlocked(dev))
if (gpio_sim_device_is_live(dev))
return -EBUSY;
trimmed = gpio_sim_strdup_trimmed(page, count);
@ -1274,7 +1281,7 @@ gpio_sim_hog_config_direction_store(struct config_item *item,
guard(mutex)(&dev->lock);
if (gpio_sim_device_is_live_unlocked(dev))
if (gpio_sim_device_is_live(dev))
return -EBUSY;
if (sysfs_streq(page, "input"))
@ -1392,7 +1399,7 @@ gpio_sim_bank_config_make_line_group(struct config_group *group,
guard(mutex)(&dev->lock);
if (gpio_sim_device_is_live_unlocked(dev))
if (gpio_sim_device_is_live(dev))
return ERR_PTR(-EBUSY);
line = kzalloc(sizeof(*line), GFP_KERNEL);
@ -1445,7 +1452,7 @@ gpio_sim_device_config_make_bank_group(struct config_group *group,
guard(mutex)(&dev->lock);
if (gpio_sim_device_is_live_unlocked(dev))
if (gpio_sim_device_is_live(dev))
return ERR_PTR(-EBUSY);
bank = kzalloc(sizeof(*bank), GFP_KERNEL);
@ -1467,8 +1474,8 @@ static void gpio_sim_device_config_group_release(struct config_item *item)
struct gpio_sim_device *dev = to_gpio_sim_device(item);
scoped_guard(mutex, &dev->lock) {
if (gpio_sim_device_is_live_unlocked(dev))
gpio_sim_device_deactivate_unlocked(dev);
if (gpio_sim_device_is_live(dev))
gpio_sim_device_deactivate(dev);
}
mutex_destroy(&dev->lock);

View File

@ -126,7 +126,7 @@ static DEFINE_MUTEX(acpi_gpio_deferred_req_irqs_lock);
static LIST_HEAD(acpi_gpio_deferred_req_irqs_list);
static bool acpi_gpio_deferred_req_irqs_done;
static int acpi_gpiochip_find(struct gpio_chip *gc, void *data)
static int acpi_gpiochip_find(struct gpio_chip *gc, const void *data)
{
return device_match_acpi_handle(&gc->gpiodev->dev, data);
}
@ -1402,17 +1402,17 @@ static int acpi_find_gpio_count(struct acpi_resource *ares, void *data)
}
/**
* acpi_gpio_count - count the GPIOs associated with a device / function
* @dev: GPIO consumer, can be %NULL for system-global GPIOs
* acpi_gpio_count - count the GPIOs associated with a firmware node / function
* @fwnode: firmware node of the GPIO consumer
* @con_id: function within the GPIO consumer
*
* Return:
* The number of GPIOs associated with a device / function or %-ENOENT,
* The number of GPIOs associated with a firmware node / function or %-ENOENT,
* if no GPIO has been assigned to the requested function.
*/
int acpi_gpio_count(struct device *dev, const char *con_id)
int acpi_gpio_count(const struct fwnode_handle *fwnode, const char *con_id)
{
struct acpi_device *adev = ACPI_COMPANION(dev);
struct acpi_device *adev = to_acpi_device_node(fwnode);
const union acpi_object *obj;
const struct acpi_gpio_mapping *gm;
int count = -ENOENT;
@ -1429,8 +1429,7 @@ int acpi_gpio_count(struct device *dev, const char *con_id)
snprintf(propname, sizeof(propname), "%s",
gpio_suffixes[i]);
ret = acpi_dev_get_property(adev, propname, ACPI_TYPE_ANY,
&obj);
ret = acpi_dev_get_property(adev, propname, ACPI_TYPE_ANY, &obj);
if (ret == 0) {
if (obj->type == ACPI_TYPE_LOCAL_REFERENCE)
count = 1;

View File

@ -33,7 +33,7 @@ struct gpio_desc *acpi_find_gpio(struct fwnode_handle *fwnode,
enum gpiod_flags *dflags,
unsigned long *lookupflags);
int acpi_gpio_count(struct device *dev, const char *con_id);
int acpi_gpio_count(const struct fwnode_handle *fwnode, const char *con_id);
#else
static inline void acpi_gpiochip_add(struct gpio_chip *chip) { }
static inline void acpi_gpiochip_remove(struct gpio_chip *chip) { }
@ -51,7 +51,8 @@ acpi_find_gpio(struct fwnode_handle *fwnode, const char *con_id,
{
return ERR_PTR(-ENOENT);
}
static inline int acpi_gpio_count(struct device *dev, const char *con_id)
static inline int acpi_gpio_count(const struct fwnode_handle *fwnode,
const char *con_id)
{
return -ENODEV;
}

View File

@ -24,7 +24,6 @@
#include <linux/pinctrl/consumer.h>
#include <linux/poll.h>
#include <linux/rbtree.h>
#include <linux/rwsem.h>
#include <linux/seq_file.h>
#include <linux/spinlock.h>
#include <linux/timekeeping.h>
@ -61,11 +60,6 @@ static_assert(IS_ALIGNED(sizeof(struct gpio_v2_line_values), 8));
* interface to gpiolib GPIOs via ioctl()s.
*/
typedef __poll_t (*poll_fn)(struct file *, struct poll_table_struct *);
typedef long (*ioctl_fn)(struct file *, unsigned int, unsigned long);
typedef ssize_t (*read_fn)(struct file *, char __user *,
size_t count, loff_t *);
/*
* GPIO line handle management
*/
@ -210,9 +204,9 @@ static long linehandle_ioctl(struct file *file, unsigned int cmd,
unsigned int i;
int ret;
guard(rwsem_read)(&lh->gdev->sem);
guard(srcu)(&lh->gdev->srcu);
if (!lh->gdev->chip)
if (!rcu_access_pointer(lh->gdev->chip))
return -ENODEV;
switch (cmd) {
@ -337,7 +331,7 @@ static int linehandle_create(struct gpio_device *gdev, void __user *ip)
/* Request each GPIO */
for (i = 0; i < handlereq.lines; i++) {
u32 offset = handlereq.lineoffsets[i];
struct gpio_desc *desc = gpiochip_get_desc(gdev->chip, offset);
struct gpio_desc *desc = gpio_device_get_desc(gdev, offset);
if (IS_ERR(desc)) {
ret = PTR_ERR(desc);
@ -1525,9 +1519,9 @@ static long linereq_ioctl(struct file *file, unsigned int cmd,
struct linereq *lr = file->private_data;
void __user *ip = (void __user *)arg;
guard(rwsem_read)(&lr->gdev->sem);
guard(srcu)(&lr->gdev->srcu);
if (!lr->gdev->chip)
if (!rcu_access_pointer(lr->gdev->chip))
return -ENODEV;
switch (cmd) {
@ -1556,9 +1550,9 @@ static __poll_t linereq_poll(struct file *file,
struct linereq *lr = file->private_data;
__poll_t events = 0;
guard(rwsem_read)(&lr->gdev->sem);
guard(srcu)(&lr->gdev->srcu);
if (!lr->gdev->chip)
if (!rcu_access_pointer(lr->gdev->chip))
return EPOLLHUP | EPOLLERR;
poll_wait(file, &lr->wait, wait);
@ -1578,9 +1572,9 @@ static ssize_t linereq_read(struct file *file, char __user *buf,
ssize_t bytes_read = 0;
int ret;
guard(rwsem_read)(&lr->gdev->sem);
guard(srcu)(&lr->gdev->srcu);
if (!lr->gdev->chip)
if (!rcu_access_pointer(lr->gdev->chip))
return -ENODEV;
if (count < sizeof(le))
@ -1744,7 +1738,7 @@ static int linereq_create(struct gpio_device *gdev, void __user *ip)
/* Request each GPIO */
for (i = 0; i < ulr.num_lines; i++) {
u32 offset = ulr.offsets[i];
struct gpio_desc *desc = gpiochip_get_desc(gdev->chip, offset);
struct gpio_desc *desc = gpio_device_get_desc(gdev, offset);
if (IS_ERR(desc)) {
ret = PTR_ERR(desc);
@ -1879,9 +1873,9 @@ static __poll_t lineevent_poll(struct file *file,
struct lineevent_state *le = file->private_data;
__poll_t events = 0;
guard(rwsem_read)(&le->gdev->sem);
guard(srcu)(&le->gdev->srcu);
if (!le->gdev->chip)
if (!rcu_access_pointer(le->gdev->chip))
return EPOLLHUP | EPOLLERR;
poll_wait(file, &le->wait, wait);
@ -1917,9 +1911,9 @@ static ssize_t lineevent_read(struct file *file, char __user *buf,
ssize_t ge_size;
int ret;
guard(rwsem_read)(&le->gdev->sem);
guard(srcu)(&le->gdev->srcu);
if (!le->gdev->chip)
if (!rcu_access_pointer(le->gdev->chip))
return -ENODEV;
/*
@ -2000,9 +1994,9 @@ static long lineevent_ioctl(struct file *file, unsigned int cmd,
void __user *ip = (void __user *)arg;
struct gpiohandle_data ghd;
guard(rwsem_read)(&le->gdev->sem);
guard(srcu)(&le->gdev->srcu);
if (!le->gdev->chip)
if (!rcu_access_pointer(le->gdev->chip))
return -ENODEV;
/*
@ -2128,7 +2122,7 @@ static int lineevent_create(struct gpio_device *gdev, void __user *ip)
lflags = eventreq.handleflags;
eflags = eventreq.eventflags;
desc = gpiochip_get_desc(gdev->chip, offset);
desc = gpio_device_get_desc(gdev, offset);
if (IS_ERR(desc))
return PTR_ERR(desc);
@ -2300,21 +2294,26 @@ static void gpio_v2_line_info_changed_to_v1(
static void gpio_desc_to_lineinfo(struct gpio_desc *desc,
struct gpio_v2_line_info *info)
{
struct gpio_chip *gc = desc->gdev->chip;
unsigned long dflags;
const char *label;
CLASS(gpio_chip_guard, guard)(desc);
if (!guard.gc)
return;
memset(info, 0, sizeof(*info));
info->offset = gpio_chip_hwgpio(desc);
scoped_guard(spinlock_irqsave, &gpio_lock) {
if (desc->name)
strscpy(info->name, desc->name, sizeof(info->name));
if (desc->name)
strscpy(info->name, desc->name, sizeof(info->name));
if (desc->label)
strscpy(info->consumer, desc->label,
dflags = READ_ONCE(desc->flags);
scoped_guard(srcu, &desc->srcu) {
label = gpiod_get_label(desc);
if (label && test_bit(FLAG_REQUESTED, &dflags))
strscpy(info->consumer, label,
sizeof(info->consumer));
dflags = READ_ONCE(desc->flags);
}
/*
@ -2334,8 +2333,8 @@ static void gpio_desc_to_lineinfo(struct gpio_desc *desc,
test_bit(FLAG_USED_AS_IRQ, &dflags) ||
test_bit(FLAG_EXPORT, &dflags) ||
test_bit(FLAG_SYSFS, &dflags) ||
!gpiochip_line_is_valid(gc, info->offset) ||
!pinctrl_gpio_can_use_line(gc, info->offset))
!gpiochip_line_is_valid(guard.gc, info->offset) ||
!pinctrl_gpio_can_use_line(guard.gc, info->offset))
info->flags |= GPIO_V2_LINE_FLAG_USED;
if (test_bit(FLAG_IS_OUT, &dflags))
@ -2422,7 +2421,7 @@ static int lineinfo_get_v1(struct gpio_chardev_data *cdev, void __user *ip,
return -EFAULT;
/* this doubles as a range check on line_offset */
desc = gpiochip_get_desc(cdev->gdev->chip, lineinfo.line_offset);
desc = gpio_device_get_desc(cdev->gdev, lineinfo.line_offset);
if (IS_ERR(desc))
return PTR_ERR(desc);
@ -2459,7 +2458,7 @@ static int lineinfo_get(struct gpio_chardev_data *cdev, void __user *ip,
if (memchr_inv(lineinfo.padding, 0, sizeof(lineinfo.padding)))
return -EINVAL;
desc = gpiochip_get_desc(cdev->gdev->chip, lineinfo.offset);
desc = gpio_device_get_desc(cdev->gdev, lineinfo.offset);
if (IS_ERR(desc))
return PTR_ERR(desc);
@ -2508,10 +2507,10 @@ static long gpio_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
struct gpio_device *gdev = cdev->gdev;
void __user *ip = (void __user *)arg;
guard(rwsem_read)(&gdev->sem);
guard(srcu)(&gdev->srcu);
/* We fail any subsequent ioctl():s when the chip is gone */
if (!gdev->chip)
if (!rcu_access_pointer(gdev->chip))
return -ENODEV;
/* Fill in the struct and pass to userspace */
@ -2594,9 +2593,9 @@ static __poll_t lineinfo_watch_poll(struct file *file,
struct gpio_chardev_data *cdev = file->private_data;
__poll_t events = 0;
guard(rwsem_read)(&cdev->gdev->sem);
guard(srcu)(&cdev->gdev->srcu);
if (!cdev->gdev->chip)
if (!rcu_access_pointer(cdev->gdev->chip))
return EPOLLHUP | EPOLLERR;
poll_wait(file, &cdev->wait, pollt);
@ -2617,9 +2616,9 @@ static ssize_t lineinfo_watch_read(struct file *file, char __user *buf,
int ret;
size_t event_size;
guard(rwsem_read)(&cdev->gdev->sem);
guard(srcu)(&cdev->gdev->srcu);
if (!cdev->gdev->chip)
if (!rcu_access_pointer(cdev->gdev->chip))
return -ENODEV;
#ifndef CONFIG_GPIO_CDEV_V1
@ -2694,17 +2693,17 @@ static int gpio_chrdev_open(struct inode *inode, struct file *file)
struct gpio_chardev_data *cdev;
int ret = -ENOMEM;
guard(rwsem_read)(&gdev->sem);
guard(srcu)(&gdev->srcu);
/* Fail on open if the backing gpiochip is gone */
if (!gdev->chip)
if (!rcu_access_pointer(gdev->chip))
return -ENODEV;
cdev = kzalloc(sizeof(*cdev), GFP_KERNEL);
if (!cdev)
return -ENODEV;
cdev->watched_lines = bitmap_zalloc(gdev->chip->ngpio, GFP_KERNEL);
cdev->watched_lines = bitmap_zalloc(gdev->ngpio, GFP_KERNEL);
if (!cdev->watched_lines)
goto out_free_cdev;
@ -2784,6 +2783,7 @@ static const struct file_operations gpio_fileops = {
int gpiolib_cdev_register(struct gpio_device *gdev, dev_t devt)
{
struct gpio_chip *gc;
int ret;
cdev_init(&gdev->chrdev, &gpio_fileops);
@ -2794,8 +2794,12 @@ int gpiolib_cdev_register(struct gpio_device *gdev, dev_t devt)
if (ret)
return ret;
chip_dbg(gdev->chip, "added GPIO chardev (%d:%d)\n",
MAJOR(devt), gdev->id);
guard(srcu)(&gdev->srcu);
gc = srcu_dereference(gdev->chip, &gdev->srcu);
if (!gc)
return -ENODEV;
chip_dbg(gc, "added GPIO chardev (%d:%d)\n", MAJOR(devt), gdev->id);
return 0;
}

View File

@ -158,7 +158,7 @@ struct gpio_desc *devm_fwnode_gpiod_get_index(struct device *dev,
if (!dr)
return ERR_PTR(-ENOMEM);
desc = fwnode_gpiod_get_index(fwnode, con_id, index, flags, label);
desc = gpiod_find_and_request(dev, fwnode, con_id, index, flags, label, false);
if (IS_ERR(desc)) {
devres_free(dr);
return desc;

View File

@ -6,6 +6,9 @@
#include "gpiolib.h"
/*
* **DEPRECATED** This function is deprecated and must not be used in new code.
*/
void gpio_free(unsigned gpio)
{
gpiod_free(gpio_to_desc(gpio));
@ -17,6 +20,8 @@ EXPORT_SYMBOL_GPL(gpio_free);
* @gpio: the GPIO number
* @flags: GPIO configuration as specified by GPIOF_*
* @label: a literal description string of this GPIO
*
* **DEPRECATED** This function is deprecated and must not be used in new code.
*/
int gpio_request_one(unsigned gpio, unsigned long flags, const char *label)
{
@ -53,6 +58,9 @@ int gpio_request_one(unsigned gpio, unsigned long flags, const char *label)
}
EXPORT_SYMBOL_GPL(gpio_request_one);
/*
* **DEPRECATED** This function is deprecated and must not be used in new code.
*/
int gpio_request(unsigned gpio, const char *label)
{
struct gpio_desc *desc = gpio_to_desc(gpio);
@ -69,6 +77,8 @@ EXPORT_SYMBOL_GPL(gpio_request);
* gpio_request_array - request multiple GPIOs in a single call
* @array: array of the 'struct gpio'
* @num: how many GPIOs in the array
*
* **DEPRECATED** This function is deprecated and must not be used in new code.
*/
int gpio_request_array(const struct gpio *array, size_t num)
{
@ -92,6 +102,8 @@ EXPORT_SYMBOL_GPL(gpio_request_array);
* gpio_free_array - release multiple GPIOs in a single call
* @array: array of the 'struct gpio'
* @num: how many GPIOs in the array
*
* **DEPRECATED** This function is deprecated and must not be used in new code.
*/
void gpio_free_array(const struct gpio *array, size_t num)
{

View File

@ -68,7 +68,7 @@ static int of_gpio_named_count(const struct device_node *np,
/**
* of_gpio_spi_cs_get_count() - special GPIO counting for SPI
* @dev: Consuming device
* @np: Consuming device node
* @con_id: Function within the GPIO consumer
*
* Some elder GPIO controllers need special quirks. Currently we handle
@ -78,10 +78,9 @@ static int of_gpio_named_count(const struct device_node *np,
* the counting of "cs-gpios" to count "gpios" transparent to the
* driver.
*/
static int of_gpio_spi_cs_get_count(struct device *dev, const char *con_id)
static int of_gpio_spi_cs_get_count(const struct device_node *np,
const char *con_id)
{
struct device_node *np = dev->of_node;
if (!IS_ENABLED(CONFIG_SPI_MASTER))
return 0;
if (!con_id || strcmp(con_id, "cs"))
@ -93,13 +92,14 @@ static int of_gpio_spi_cs_get_count(struct device *dev, const char *con_id)
return of_gpio_named_count(np, "gpios");
}
int of_gpio_get_count(struct device *dev, const char *con_id)
int of_gpio_count(const struct fwnode_handle *fwnode, const char *con_id)
{
const struct device_node *np = to_of_node(fwnode);
int ret;
char propname[32];
unsigned int i;
ret = of_gpio_spi_cs_get_count(dev, con_id);
ret = of_gpio_spi_cs_get_count(np, con_id);
if (ret > 0)
return ret;
@ -111,16 +111,17 @@ int of_gpio_get_count(struct device *dev, const char *con_id)
snprintf(propname, sizeof(propname), "%s",
gpio_suffixes[i]);
ret = of_gpio_named_count(dev->of_node, propname);
ret = of_gpio_named_count(np, propname);
if (ret > 0)
break;
}
return ret ? ret : -ENOENT;
}
static int of_gpiochip_match_node_and_xlate(struct gpio_chip *chip, void *data)
static int of_gpiochip_match_node_and_xlate(struct gpio_chip *chip,
const void *data)
{
struct of_phandle_args *gpiospec = data;
const struct of_phandle_args *gpiospec = data;
return device_match_of_node(&chip->gpiodev->dev, gpiospec->np) &&
chip->of_xlate &&
@ -128,7 +129,7 @@ static int of_gpiochip_match_node_and_xlate(struct gpio_chip *chip, void *data)
}
static struct gpio_device *
of_find_gpio_device_by_xlate(struct of_phandle_args *gpiospec)
of_find_gpio_device_by_xlate(const struct of_phandle_args *gpiospec)
{
return gpio_device_find(gpiospec, of_gpiochip_match_node_and_xlate);
}
@ -414,6 +415,8 @@ out:
* @propname: Name of property containing gpio specifier(s)
* @index: index of the GPIO
*
* **DEPRECATED** This function is deprecated and must not be used in new code.
*
* Returns GPIO number to use with Linux generic GPIO API, or one of the errno
* value on the error condition.
*/
@ -798,7 +801,7 @@ static int of_gpiochip_add_hog(struct gpio_chip *chip, struct device_node *hog)
return ret;
#ifdef CONFIG_OF_DYNAMIC
desc->hog = hog;
WRITE_ONCE(desc->hog, hog);
#endif
}
@ -846,11 +849,11 @@ static void of_gpiochip_remove_hog(struct gpio_chip *chip,
struct gpio_desc *desc;
for_each_gpio_desc_with_flag(chip, desc, FLAG_IS_HOGGED)
if (desc->hog == hog)
if (READ_ONCE(desc->hog) == hog)
gpiochip_free_own_desc(desc);
}
static int of_gpiochip_match_node(struct gpio_chip *chip, void *data)
static int of_gpiochip_match_node(struct gpio_chip *chip, const void *data)
{
return device_match_of_node(&chip->gpiodev->dev, data);
}

View File

@ -9,6 +9,7 @@
#include <linux/notifier.h>
struct device;
struct fwnode_handle;
struct gpio_chip;
struct gpio_desc;
@ -21,7 +22,7 @@ struct gpio_desc *of_find_gpio(struct device_node *np,
unsigned long *lookupflags);
int of_gpiochip_add(struct gpio_chip *gc);
void of_gpiochip_remove(struct gpio_chip *gc);
int of_gpio_get_count(struct device *dev, const char *con_id);
int of_gpio_count(const struct fwnode_handle *fwnode, const char *con_id);
#else
static inline struct gpio_desc *of_find_gpio(struct device_node *np,
const char *con_id,
@ -32,7 +33,8 @@ static inline struct gpio_desc *of_find_gpio(struct device_node *np,
}
static inline int of_gpiochip_add(struct gpio_chip *gc) { return 0; }
static inline void of_gpiochip_remove(struct gpio_chip *gc) { }
static inline int of_gpio_get_count(struct device *dev, const char *con_id)
static inline int of_gpio_count(const struct fwnode_handle *fwnode,
const char *con_id)
{
return 0;
}

View File

@ -1,6 +1,7 @@
// SPDX-License-Identifier: GPL-2.0
#include <linux/bitops.h>
#include <linux/cleanup.h>
#include <linux/device.h>
#include <linux/idr.h>
#include <linux/init.h>
@ -13,6 +14,7 @@
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/string.h>
#include <linux/srcu.h>
#include <linux/sysfs.h>
#include <linux/types.h>
@ -170,6 +172,10 @@ static int gpio_sysfs_request_irq(struct device *dev, unsigned char flags)
unsigned long irq_flags;
int ret;
CLASS(gpio_chip_guard, guard)(desc);
if (!guard.gc)
return -ENODEV;
data->irq = gpiod_to_irq(desc);
if (data->irq < 0)
return -EIO;
@ -194,7 +200,7 @@ static int gpio_sysfs_request_irq(struct device *dev, unsigned char flags)
* Remove this redundant call (along with the corresponding
* unlock) when those drivers have been fixed.
*/
ret = gpiochip_lock_as_irq(desc->gdev->chip, gpio_chip_hwgpio(desc));
ret = gpiochip_lock_as_irq(guard.gc, gpio_chip_hwgpio(desc));
if (ret < 0)
goto err_put_kn;
@ -208,7 +214,7 @@ static int gpio_sysfs_request_irq(struct device *dev, unsigned char flags)
return 0;
err_unlock:
gpiochip_unlock_as_irq(desc->gdev->chip, gpio_chip_hwgpio(desc));
gpiochip_unlock_as_irq(guard.gc, gpio_chip_hwgpio(desc));
err_put_kn:
sysfs_put(data->value_kn);
@ -224,9 +230,13 @@ static void gpio_sysfs_free_irq(struct device *dev)
struct gpiod_data *data = dev_get_drvdata(dev);
struct gpio_desc *desc = data->desc;
CLASS(gpio_chip_guard, guard)(desc);
if (!guard.gc)
return;
data->irq_flags = 0;
free_irq(data->irq, data);
gpiochip_unlock_as_irq(desc->gdev->chip, gpio_chip_hwgpio(desc));
gpiochip_unlock_as_irq(guard.gc, gpio_chip_hwgpio(desc));
sysfs_put(data->value_kn);
}
@ -400,27 +410,27 @@ static const struct attribute_group *gpio_groups[] = {
static ssize_t base_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
const struct gpio_chip *chip = dev_get_drvdata(dev);
const struct gpio_device *gdev = dev_get_drvdata(dev);
return sysfs_emit(buf, "%d\n", chip->base);
return sysfs_emit(buf, "%d\n", gdev->base);
}
static DEVICE_ATTR_RO(base);
static ssize_t label_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
const struct gpio_chip *chip = dev_get_drvdata(dev);
const struct gpio_device *gdev = dev_get_drvdata(dev);
return sysfs_emit(buf, "%s\n", chip->label ?: "");
return sysfs_emit(buf, "%s\n", gdev->label);
}
static DEVICE_ATTR_RO(label);
static ssize_t ngpio_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
const struct gpio_chip *chip = dev_get_drvdata(dev);
const struct gpio_device *gdev = dev_get_drvdata(dev);
return sysfs_emit(buf, "%u\n", chip->ngpio);
return sysfs_emit(buf, "%u\n", gdev->ngpio);
}
static DEVICE_ATTR_RO(ngpio);
@ -443,13 +453,12 @@ static ssize_t export_store(const struct class *class,
const char *buf, size_t len)
{
struct gpio_desc *desc;
struct gpio_chip *gc;
int status, offset;
long gpio;
status = kstrtol(buf, 0, &gpio);
if (status < 0)
goto done;
if (status)
return status;
desc = gpio_to_desc(gpio);
/* reject invalid GPIOs */
@ -457,9 +466,13 @@ static ssize_t export_store(const struct class *class,
pr_warn("%s: invalid GPIO %ld\n", __func__, gpio);
return -EINVAL;
}
gc = desc->gdev->chip;
CLASS(gpio_chip_guard, guard)(desc);
if (!guard.gc)
return -ENODEV;
offset = gpio_chip_hwgpio(desc);
if (!gpiochip_line_is_valid(gc, offset)) {
if (!gpiochip_line_is_valid(guard.gc, offset)) {
pr_warn("%s: GPIO %ld masked\n", __func__, gpio);
return -EINVAL;
}
@ -562,8 +575,6 @@ int gpiod_export(struct gpio_desc *desc, bool direction_may_change)
const char *ioname = NULL;
struct gpio_device *gdev;
struct gpiod_data *data;
struct gpio_chip *chip;
unsigned long flags;
struct device *dev;
int status, offset;
@ -578,29 +589,28 @@ int gpiod_export(struct gpio_desc *desc, bool direction_may_change)
return -EINVAL;
}
CLASS(gpio_chip_guard, guard)(desc);
if (!guard.gc)
return -ENODEV;
if (test_and_set_bit(FLAG_EXPORT, &desc->flags))
return -EPERM;
gdev = desc->gdev;
chip = gdev->chip;
mutex_lock(&sysfs_lock);
/* check if chip is being removed */
if (!chip || !gdev->mockdev) {
if (!gdev->mockdev) {
status = -ENODEV;
goto err_unlock;
}
spin_lock_irqsave(&gpio_lock, flags);
if (!test_bit(FLAG_REQUESTED, &desc->flags) ||
test_bit(FLAG_EXPORT, &desc->flags)) {
spin_unlock_irqrestore(&gpio_lock, flags);
gpiod_dbg(desc, "%s: unavailable (requested=%d, exported=%d)\n",
__func__,
test_bit(FLAG_REQUESTED, &desc->flags),
test_bit(FLAG_EXPORT, &desc->flags));
if (!test_bit(FLAG_REQUESTED, &desc->flags)) {
gpiod_dbg(desc, "%s: unavailable (not requested)\n", __func__);
status = -EPERM;
goto err_unlock;
}
spin_unlock_irqrestore(&gpio_lock, flags);
data = kzalloc(sizeof(*data), GFP_KERNEL);
if (!data) {
@ -610,14 +620,14 @@ int gpiod_export(struct gpio_desc *desc, bool direction_may_change)
data->desc = desc;
mutex_init(&data->mutex);
if (chip->direction_input && chip->direction_output)
if (guard.gc->direction_input && guard.gc->direction_output)
data->direction_can_change = direction_may_change;
else
data->direction_can_change = false;
offset = gpio_chip_hwgpio(desc);
if (chip->names && chip->names[offset])
ioname = chip->names[offset];
if (guard.gc->names && guard.gc->names[offset])
ioname = guard.gc->names[offset];
dev = device_create_with_groups(&gpio_class, &gdev->dev,
MKDEV(0, 0), data, gpio_groups,
@ -628,7 +638,6 @@ int gpiod_export(struct gpio_desc *desc, bool direction_may_change)
goto err_free_data;
}
set_bit(FLAG_EXPORT, &desc->flags);
mutex_unlock(&sysfs_lock);
return 0;
@ -636,6 +645,7 @@ err_free_data:
kfree(data);
err_unlock:
mutex_unlock(&sysfs_lock);
clear_bit(FLAG_EXPORT, &desc->flags);
gpiod_dbg(desc, "%s: status %d\n", __func__, status);
return status;
}
@ -732,7 +742,7 @@ EXPORT_SYMBOL_GPL(gpiod_unexport);
int gpiochip_sysfs_register(struct gpio_device *gdev)
{
struct gpio_chip *chip = gdev->chip;
struct gpio_chip *chip;
struct device *parent;
struct device *dev;
@ -745,6 +755,12 @@ int gpiochip_sysfs_register(struct gpio_device *gdev)
if (!class_is_registered(&gpio_class))
return 0;
guard(srcu)(&gdev->srcu);
chip = srcu_dereference(gdev->chip, &gdev->srcu);
if (!chip)
return -ENODEV;
/*
* For sysfs backward compatibility we need to preserve this
* preferred parenting to the gpio_chip parent field, if set.
@ -755,7 +771,7 @@ int gpiochip_sysfs_register(struct gpio_device *gdev)
parent = &gdev->dev;
/* use chip->base for the ID; it's already known to be unique */
dev = device_create_with_groups(&gpio_class, parent, MKDEV(0, 0), chip,
dev = device_create_with_groups(&gpio_class, parent, MKDEV(0, 0), gdev,
gpiochip_groups, GPIOCHIP_NAME "%d",
chip->base);
if (IS_ERR(dev))
@ -771,18 +787,24 @@ int gpiochip_sysfs_register(struct gpio_device *gdev)
void gpiochip_sysfs_unregister(struct gpio_device *gdev)
{
struct gpio_desc *desc;
struct gpio_chip *chip = gdev->chip;
struct gpio_chip *chip;
if (!gdev->mockdev)
scoped_guard(mutex, &sysfs_lock) {
if (!gdev->mockdev)
return;
device_unregister(gdev->mockdev);
/* prevent further gpiod exports */
gdev->mockdev = NULL;
}
guard(srcu)(&gdev->srcu);
chip = srcu_dereference(gdev->chip, &gdev->srcu);
if (!chip)
return;
device_unregister(gdev->mockdev);
/* prevent further gpiod exports */
mutex_lock(&sysfs_lock);
gdev->mockdev = NULL;
mutex_unlock(&sysfs_lock);
/* unregister gpiod class devices owned by sysfs */
for_each_gpio_desc_with_flag(chip, desc, FLAG_SYSFS) {
gpiod_unexport(desc);
@ -790,11 +812,29 @@ void gpiochip_sysfs_unregister(struct gpio_device *gdev)
}
}
/*
* We're not really looking for a device - we just want to iterate over the
* list and call this callback for each GPIO device. This is why this function
* always returns 0.
*/
static int gpiofind_sysfs_register(struct gpio_chip *gc, const void *data)
{
struct gpio_device *gdev = gc->gpiodev;
int ret;
if (gdev->mockdev)
return 0;
ret = gpiochip_sysfs_register(gdev);
if (ret)
chip_err(gc, "failed to register the sysfs entry: %d\n", ret);
return 0;
}
static int __init gpiolib_sysfs_init(void)
{
int status;
unsigned long flags;
struct gpio_device *gdev;
int status;
status = class_register(&gpio_class);
if (status < 0)
@ -806,26 +846,8 @@ static int __init gpiolib_sysfs_init(void)
* We run before arch_initcall() so chip->dev nodes can have
* registered, and so arch_initcall() can always gpiod_export().
*/
spin_lock_irqsave(&gpio_lock, flags);
list_for_each_entry(gdev, &gpio_devices, list) {
if (gdev->mockdev)
continue;
(void)gpio_device_find(NULL, gpiofind_sysfs_register);
/*
* TODO we yield gpio_lock here because
* gpiochip_sysfs_register() acquires a mutex. This is unsafe
* and needs to be fixed.
*
* Also it would be nice to use gpio_device_find() here so we
* can keep gpio_chips local to gpiolib.c, but the yield of
* gpio_lock prevents us from doing this.
*/
spin_unlock_irqrestore(&gpio_lock, flags);
status = gpiochip_sysfs_register(gdev);
spin_lock_irqsave(&gpio_lock, flags);
}
spin_unlock_irqrestore(&gpio_lock, flags);
return status;
return 0;
}
postcore_initcall(gpiolib_sysfs_init);

File diff suppressed because it is too large Load Diff

View File

@ -16,7 +16,7 @@
#include <linux/gpio/driver.h>
#include <linux/module.h>
#include <linux/notifier.h>
#include <linux/rwsem.h>
#include <linux/srcu.h>
#define GPIOCHIP_NAME "gpiochip"
@ -33,6 +33,8 @@
* @descs: array of ngpio descriptors.
* @ngpio: the number of GPIO lines on this GPIO device, equal to the size
* of the @descs array.
* @can_sleep: indicate whether the GPIO chip driver's callbacks can sleep
* implying that they cannot be used from atomic context
* @base: GPIO base in the DEPRECATED global Linux GPIO numberspace, assigned
* at device creation time.
* @label: a descriptive name for the GPIO device, such as the part number
@ -43,9 +45,7 @@
* requested, released or reconfigured
* @device_notifier: used to notify character device wait queues about the GPIO
* device being unregistered
* @sem: protects the structure from a NULL-pointer dereference of @chip by
* user-space operations when the device gets unregistered during
* a hot-unplug event
* @srcu: protects the pointer to the underlying GPIO chip
* @pin_ranges: range of pins served by the GPIO driver
*
* This state container holds most of the runtime variable data
@ -59,16 +59,17 @@ struct gpio_device {
int id;
struct device *mockdev;
struct module *owner;
struct gpio_chip *chip;
struct gpio_chip __rcu *chip;
struct gpio_desc *descs;
int base;
u16 ngpio;
bool can_sleep;
const char *label;
void *data;
struct list_head list;
struct blocking_notifier_head line_state_notifier;
struct blocking_notifier_head device_notifier;
struct rw_semaphore sem;
struct srcu_struct srcu;
#ifdef CONFIG_PINCTRL
/*
@ -134,9 +135,6 @@ int gpiod_set_array_value_complex(bool raw, bool can_sleep,
int gpiod_set_transitory(struct gpio_desc *desc, bool transitory);
extern spinlock_t gpio_lock;
extern struct list_head gpio_devices;
void gpiod_line_state_notify(struct gpio_desc *desc, unsigned long action);
/**
@ -147,6 +145,7 @@ void gpiod_line_state_notify(struct gpio_desc *desc, unsigned long action);
* @label: Name of the consumer
* @name: Line name
* @hog: Pointer to the device node that hogs this line (if any)
* @srcu: SRCU struct protecting the label pointer.
*
* These are obtained using gpiod_get() and are preferable to the old
* integer-based handles.
@ -178,16 +177,38 @@ struct gpio_desc {
#define FLAG_EVENT_CLOCK_HTE 19 /* GPIO CDEV reports hardware timestamps in events */
/* Connection label */
const char *label;
const char __rcu *label;
/* Name of the GPIO */
const char *name;
#ifdef CONFIG_OF_DYNAMIC
struct device_node *hog;
#endif
struct srcu_struct srcu;
};
#define gpiod_not_found(desc) (IS_ERR(desc) && PTR_ERR(desc) == -ENOENT)
struct gpio_chip_guard {
struct gpio_device *gdev;
struct gpio_chip *gc;
int idx;
};
DEFINE_CLASS(gpio_chip_guard,
struct gpio_chip_guard,
srcu_read_unlock(&_T.gdev->srcu, _T.idx),
({
struct gpio_chip_guard _guard;
_guard.gdev = desc->gdev;
_guard.idx = srcu_read_lock(&_guard.gdev->srcu);
_guard.gc = srcu_dereference(_guard.gdev->chip,
&_guard.gdev->srcu);
_guard;
}),
struct gpio_desc *desc)
int gpiod_request(struct gpio_desc *desc, const char *label);
void gpiod_free(struct gpio_desc *desc);
@ -202,12 +223,21 @@ static inline int gpiod_request_user(struct gpio_desc *desc, const char *label)
return ret;
}
struct gpio_desc *gpiod_find_and_request(struct device *consumer,
struct fwnode_handle *fwnode,
const char *con_id,
unsigned int idx,
enum gpiod_flags flags,
const char *label,
bool platform_lookup_allowed);
int gpiod_configure_flags(struct gpio_desc *desc, const char *con_id,
unsigned long lflags, enum gpiod_flags dflags);
int gpio_set_debounce_timeout(struct gpio_desc *desc, unsigned int debounce);
int gpiod_hog(struct gpio_desc *desc, const char *name,
unsigned long lflags, enum gpiod_flags dflags);
int gpiochip_get_ngpios(struct gpio_chip *gc, struct device *dev);
const char *gpiod_get_label(struct gpio_desc *desc);
/*
* Return the GPIO number of the passed descriptor relative to its chip
@ -219,31 +249,32 @@ static inline int gpio_chip_hwgpio(const struct gpio_desc *desc)
/* With descriptor prefix */
#define gpiod_emerg(desc, fmt, ...) \
pr_emerg("gpio-%d (%s): " fmt, desc_to_gpio(desc), desc->label ? : "?",\
##__VA_ARGS__)
#define gpiod_crit(desc, fmt, ...) \
pr_crit("gpio-%d (%s): " fmt, desc_to_gpio(desc), desc->label ? : "?", \
##__VA_ARGS__)
#define gpiod_err(desc, fmt, ...) \
pr_err("gpio-%d (%s): " fmt, desc_to_gpio(desc), desc->label ? : "?", \
##__VA_ARGS__)
#define gpiod_warn(desc, fmt, ...) \
pr_warn("gpio-%d (%s): " fmt, desc_to_gpio(desc), desc->label ? : "?", \
##__VA_ARGS__)
#define gpiod_info(desc, fmt, ...) \
pr_info("gpio-%d (%s): " fmt, desc_to_gpio(desc), desc->label ? : "?", \
##__VA_ARGS__)
#define gpiod_dbg(desc, fmt, ...) \
pr_debug("gpio-%d (%s): " fmt, desc_to_gpio(desc), desc->label ? : "?",\
##__VA_ARGS__)
#define gpiod_err(desc, fmt, ...) \
do { \
scoped_guard(srcu, &desc->srcu) { \
pr_err("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->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->srcu) { \
pr_debug("gpio-%d (%s): " fmt, desc_to_gpio(desc), \
gpiod_get_label(desc) ? : "?", ##__VA_ARGS__); \
} \
} while (0)
/* With chip prefix */
#define chip_emerg(gc, fmt, ...) \
dev_emerg(&gc->gpiodev->dev, "(%s): " fmt, gc->label, ##__VA_ARGS__)
#define chip_crit(gc, fmt, ...) \
dev_crit(&gc->gpiodev->dev, "(%s): " fmt, gc->label, ##__VA_ARGS__)
#define chip_err(gc, fmt, ...) \
dev_err(&gc->gpiodev->dev, "(%s): " fmt, gc->label, ##__VA_ARGS__)
#define chip_warn(gc, fmt, ...) \

View File

@ -335,10 +335,12 @@ struct gpio_irq_chip {
* (same as GPIO_LINE_DIRECTION_OUT / GPIO_LINE_DIRECTION_IN),
* or negative error. It is recommended to always implement this
* function, even on input-only or output-only gpio chips.
* @direction_input: configures signal "offset" as input, or returns error
* This can be omitted on input-only or output-only gpio chips.
* @direction_output: configures signal "offset" as output, or returns error
* This can be omitted on input-only or output-only gpio chips.
* @direction_input: configures signal "offset" as input, returns 0 on success
* or a negative error number. This can be omitted on input-only or
* output-only gpio chips.
* @direction_output: configures signal "offset" as output, returns 0 on
* success or a negative error number. This can be omitted on input-only
* or output-only gpio chips.
* @get: returns value for signal "offset", 0=low, 1=high, or negative error
* @get_multiple: reads values for multiple signals defined by "mask" and
* stores them in "bits", returns 0 on success or negative error
@ -549,6 +551,21 @@ DEFINE_CLASS(_gpiochip_for_each_data,
}),
const char **label, int *i)
/**
* for_each_hwgpio - Iterates over all GPIOs for given chip.
* @_chip: Chip to iterate over.
* @_i: Loop counter.
* @_label: Place to store the address of the label if the GPIO is requested.
* Set to NULL for unused GPIOs.
*/
#define for_each_hwgpio(_chip, _i, _label) \
for (CLASS(_gpiochip_for_each_data, _data)(&_label, &_i); \
*_data.i < _chip->ngpio; \
(*_data.i)++, kfree(*(_data.label)), *_data.label = NULL) \
if (IS_ERR(*_data.label = \
gpiochip_dup_line_label(_chip, *_data.i))) {} \
else
/**
* for_each_requested_gpio_in_range - iterates over requested GPIOs in a given range
* @_chip: the chip to query
@ -626,8 +643,9 @@ int devm_gpiochip_add_data_with_key(struct device *dev, struct gpio_chip *gc,
void *data, struct lock_class_key *lock_key,
struct lock_class_key *request_key);
struct gpio_device *gpio_device_find(void *data,
int (*match)(struct gpio_chip *gc, void *data));
struct gpio_device *gpio_device_find(const void *data,
int (*match)(struct gpio_chip *gc,
const void *data));
struct gpio_device *gpio_device_find_by_label(const char *label);
struct gpio_device *gpio_device_find_by_fwnode(const struct fwnode_handle *fwnode);
@ -704,18 +722,6 @@ int bgpio_init(struct gpio_chip *gc, struct device *dev,
#define BGPIOF_NO_OUTPUT BIT(5) /* only input */
#define BGPIOF_NO_SET_ON_INPUT BIT(6)
int gpiochip_irq_map(struct irq_domain *d, unsigned int irq,
irq_hw_number_t hwirq);
void gpiochip_irq_unmap(struct irq_domain *d, unsigned int irq);
int gpiochip_irq_domain_activate(struct irq_domain *domain,
struct irq_data *data, bool reserve);
void gpiochip_irq_domain_deactivate(struct irq_domain *domain,
struct irq_data *data);
bool gpiochip_irqchip_irq_valid(const struct gpio_chip *gc,
unsigned int offset);
#ifdef CONFIG_GPIOLIB_IRQCHIP
int gpiochip_irqchip_add_domain(struct gpio_chip *gc,
struct irq_domain *domain);

View File

@ -67,7 +67,7 @@ struct gpiochip_info {
* @GPIO_V2_LINE_FLAG_BIAS_DISABLED: line has bias disabled
* @GPIO_V2_LINE_FLAG_EVENT_CLOCK_REALTIME: line events contain REALTIME timestamps
* @GPIO_V2_LINE_FLAG_EVENT_CLOCK_HTE: line events contain timestamps from
* hardware timestamp engine
* the hardware timestamping engine (HTE) subsystem
*/
enum gpio_v2_line_flag {
GPIO_V2_LINE_FLAG_USED = _BITULL(0),
@ -88,10 +88,10 @@ enum gpio_v2_line_flag {
/**
* struct gpio_v2_line_values - Values of GPIO lines
* @bits: a bitmap containing the value of the lines, set to 1 for active
* and 0 for inactive.
* and 0 for inactive
* @mask: a bitmap identifying the lines to get or set, with each bit
* number corresponding to the index into &struct
* gpio_v2_line_request.offsets.
* gpio_v2_line_request.offsets
*/
struct gpio_v2_line_values {
__aligned_u64 bits;
@ -123,7 +123,7 @@ enum gpio_v2_line_attr_id {
* @values: if id is %GPIO_V2_LINE_ATTR_ID_OUTPUT_VALUES, a bitmap
* containing the values to which the lines will be set, with each bit
* number corresponding to the index into &struct
* gpio_v2_line_request.offsets.
* gpio_v2_line_request.offsets
* @debounce_period_us: if id is %GPIO_V2_LINE_ATTR_ID_DEBOUNCE, the
* desired debounce period, in microseconds
*/
@ -143,7 +143,7 @@ struct gpio_v2_line_attribute {
* @attr: the configurable attribute
* @mask: a bitmap identifying the lines to which the attribute applies,
* with each bit number corresponding to the index into &struct
* gpio_v2_line_request.offsets.
* gpio_v2_line_request.offsets
*/
struct gpio_v2_line_config_attribute {
struct gpio_v2_line_attribute attr;
@ -178,7 +178,7 @@ struct gpio_v2_line_config {
* associated GPIO chip
* @consumer: a desired consumer label for the selected GPIO lines such as
* "my-bitbanged-relay"
* @config: requested configuration for the lines.
* @config: requested configuration for the lines
* @num_lines: number of lines requested in this request, i.e. the number
* of valid fields in the %GPIO_V2_LINES_MAX sized arrays, set to 1 to
* request a single line
@ -189,9 +189,8 @@ struct gpio_v2_line_config {
* buffer. If this field is zero then the buffer size defaults to a minimum
* of @num_lines * 16.
* @padding: reserved for future use and must be zero filled
* @fd: if successful this field will contain a valid anonymous file handle
* after a %GPIO_GET_LINE_IOCTL operation, zero or negative value means
* error
* @fd: after a successful %GPIO_V2_GET_LINE_IOCTL operation, contains
* a valid anonymous file descriptor representing the request
*/
struct gpio_v2_line_request {
__u32 offsets[GPIO_V2_LINES_MAX];
@ -217,7 +216,7 @@ struct gpio_v2_line_request {
* @num_attrs: the number of attributes in @attrs
* @flags: flags for this GPIO line, with values from &enum
* gpio_v2_line_flag, such as %GPIO_V2_LINE_FLAG_ACTIVE_LOW,
* %GPIO_V2_LINE_FLAG_OUTPUT etc, added together.
* %GPIO_V2_LINE_FLAG_OUTPUT etc, added together
* @attrs: the configuration attributes associated with the line
* @padding: reserved for future use
*/
@ -274,7 +273,7 @@ enum gpio_v2_line_event_id {
/**
* struct gpio_v2_line_event - The actual event being pushed to userspace
* @timestamp_ns: best estimate of time of event occurrence, in nanoseconds.
* @timestamp_ns: best estimate of time of event occurrence, in nanoseconds
* @id: event identifier with value from &enum gpio_v2_line_event_id
* @offset: the offset of the line that triggered the event
* @seqno: the sequence number for this event in the sequence of events for
@ -289,6 +288,10 @@ enum gpio_v2_line_event_id {
*
* If the %GPIO_V2_LINE_FLAG_EVENT_CLOCK_REALTIME flag is set then the
* @timestamp_ns is read from %CLOCK_REALTIME.
*
* If the %GPIO_V2_LINE_FLAG_EVENT_CLOCK_HTE flag is set then the
* @timestamp_ns is provided by the hardware timestamping engine (HTE)
* subsystem.
*/
struct gpio_v2_line_event {
__aligned_u64 timestamp_ns;
@ -330,7 +333,7 @@ struct gpio_v2_line_event {
* also be empty if the consumer doesn't set this up
*
* Note: This struct is part of ABI v1 and is deprecated.
* Use &struct gpio_v2_line_info instead.
* Use ABI v2 and &struct gpio_v2_line_info instead.
*/
struct gpioline_info {
__u32 line_offset;
@ -365,7 +368,7 @@ enum {
* at the end of the structure on 64-bit architectures.
*
* Note: This struct is part of ABI v1 and is deprecated.
* Use &struct gpio_v2_line_info_changed instead.
* Use ABI v2 and &struct gpio_v2_line_info_changed instead.
*/
struct gpioline_info_changed {
struct gpioline_info info;
@ -396,18 +399,17 @@ struct gpioline_info_changed {
* a batch of input or output lines, but they must all have the same
* characteristics, i.e. all inputs or all outputs, all active low etc
* @default_values: if the %GPIOHANDLE_REQUEST_OUTPUT is set for a requested
* line, this specifies the default output value, should be 0 (low) or
* 1 (high), anything else than 0 or 1 will be interpreted as 1 (high)
* line, this specifies the default output value, should be 0 (inactive) or
* 1 (active). Anything other than 0 or 1 will be interpreted as active.
* @consumer_label: a desired consumer label for the selected GPIO line(s)
* such as "my-bitbanged-relay"
* @lines: number of lines requested in this request, i.e. the number of
* valid fields in the above arrays, set to 1 to request a single line
* @fd: if successful this field will contain a valid anonymous file handle
* after a %GPIO_GET_LINEHANDLE_IOCTL operation, zero or negative value
* means error
* @fd: after a successful %GPIO_GET_LINEHANDLE_IOCTL operation, contains
* a valid anonymous file descriptor representing the request
*
* Note: This struct is part of ABI v1 and is deprecated.
* Use &struct gpio_v2_line_request instead.
* Use ABI v2 and &struct gpio_v2_line_request instead.
*/
struct gpiohandle_request {
__u32 lineoffsets[GPIOHANDLES_MAX];
@ -424,12 +426,12 @@ struct gpiohandle_request {
* %GPIOHANDLE_REQUEST_OUTPUT, %GPIOHANDLE_REQUEST_ACTIVE_LOW etc, added
* together
* @default_values: if the %GPIOHANDLE_REQUEST_OUTPUT is set in flags,
* this specifies the default output value, should be 0 (low) or
* 1 (high), anything else than 0 or 1 will be interpreted as 1 (high)
* this specifies the default output value, should be 0 (inactive) or
* 1 (active). Anything other than 0 or 1 will be interpreted as active.
* @padding: reserved for future use and should be zero filled
*
* Note: This struct is part of ABI v1 and is deprecated.
* Use &struct gpio_v2_line_config instead.
* Use ABI v2 and &struct gpio_v2_line_config instead.
*/
struct gpiohandle_config {
__u32 flags;
@ -441,10 +443,11 @@ struct gpiohandle_config {
* struct gpiohandle_data - Information of values on a GPIO handle
* @values: when getting the state of lines this contains the current
* state of a line, when setting the state of lines these should contain
* the desired target state
* the desired target state. States are 0 (inactive) or 1 (active).
* When setting, anything other than 0 or 1 will be interpreted as active.
*
* Note: This struct is part of ABI v1 and is deprecated.
* Use &struct gpio_v2_line_values instead.
* Use ABI v2 and &struct gpio_v2_line_values instead.
*/
struct gpiohandle_data {
__u8 values[GPIOHANDLES_MAX];
@ -465,12 +468,11 @@ struct gpiohandle_data {
* %GPIOEVENT_REQUEST_RISING_EDGE or %GPIOEVENT_REQUEST_FALLING_EDGE
* @consumer_label: a desired consumer label for the selected GPIO line(s)
* such as "my-listener"
* @fd: if successful this field will contain a valid anonymous file handle
* after a %GPIO_GET_LINEEVENT_IOCTL operation, zero or negative value
* means error
* @fd: after a successful %GPIO_GET_LINEEVENT_IOCTL operation, contains a
* valid anonymous file descriptor representing the request
*
* Note: This struct is part of ABI v1 and is deprecated.
* Use &struct gpio_v2_line_request instead.
* Use ABI v2 and &struct gpio_v2_line_request instead.
*/
struct gpioevent_request {
__u32 lineoffset;
@ -489,10 +491,11 @@ struct gpioevent_request {
/**
* struct gpioevent_data - The actual event being pushed to userspace
* @timestamp: best estimate of time of event occurrence, in nanoseconds
* @id: event identifier
* @id: event identifier, one of %GPIOEVENT_EVENT_RISING_EDGE or
* %GPIOEVENT_EVENT_FALLING_EDGE
*
* Note: This struct is part of ABI v1 and is deprecated.
* Use &struct gpio_v2_line_event instead.
* Use ABI v2 and &struct gpio_v2_line_event instead.
*/
struct gpioevent_data {
__u64 timestamp;

View File

@ -377,13 +377,10 @@ if [ "$full_test" ]; then
insmod_test "0,32,32,44,-1,22,-1,31" 32 12 22 31
fi
echo "2. Module load error tests"
echo "2.1 gpio overflow"
# Currently: The max number of gpio(1024) is defined in arm architecture.
insmod_test "-1,1024"
echo "2.1 no lines defined"
insmod_test "0,0"
if [ "$full_test" ]; then
echo "2.2 no lines defined"
insmod_test "0,0"
echo "2.3 ignore range overlap"
echo "2.2 ignore range overlap"
insmod_test "0,32,0,1" 32
insmod_test "0,32,1,5" 32
insmod_test "0,32,30,35" 32