요약·해설과 원문, 전문 번역을 서로 분리했습니다. API 이름, symbol, source path는 원문 표기를 사용합니다.
1. 요약·해설
원문의 핵심 논리와 kernel programming 관점의 보충 설명입니다. 아래의 전문 번역과는 별도로 작성했습니다.
2. 영어 원문 전체
번역 기준이 된 Linux v6.18.37 원문입니다. 줄 번호는 이 버전의 파일 좌표입니다.
원문 전체 펼치기
.. SPDX-License-Identifier: GPL-2.0
======================================
_DSD Device Properties Related to GPIO
======================================
With the release of ACPI 5.1, the _DSD configuration object finally
allows names to be given to GPIOs (and other things as well) returned
by _CRS. Previously we were only able to use an integer index to find
the corresponding GPIO, which is pretty error prone (it depends on
the _CRS output ordering, for example).
With _DSD we can now query GPIOs using a name instead of an integer
index, like the ASL example below shows::
// Bluetooth device with reset and shutdown GPIOs
Device (BTH)
{
Name (_HID, ...)
Name (_CRS, ResourceTemplate ()
{
GpioIo (Exclusive, PullUp, 0, 0, IoRestrictionOutputOnly,
"\\_SB.GPO0", 0, ResourceConsumer) { 15 }
GpioIo (Exclusive, PullUp, 0, 0, IoRestrictionOutputOnly,
"\\_SB.GPO0", 0, ResourceConsumer) { 27, 31 }
})
Name (_DSD, Package ()
{
ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
Package ()
{
Package () { "reset-gpios", Package () { ^BTH, 1, 1, 0 } },
Package () { "shutdown-gpios", Package () { ^BTH, 0, 0, 0 } },
}
})
}
The format of the supported GPIO property is::
Package () { "name", Package () { ref, index, pin, active_low }}
ref
The device that has _CRS containing GpioIo()/GpioInt() resources,
typically this is the device itself (BTH in our case).
index
Index of the GpioIo()/GpioInt() resource in _CRS starting from zero.
pin
Pin in the GpioIo()/GpioInt() resource. Typically this is zero.
active_low
If 1, the GPIO is marked as active-low.
Since ACPI GpioIo() resource does not have a field saying whether it is
active-low or active-high, the "active_low" argument can be used here.
Setting it to 1 marks the GPIO as active-low.
Note, active_low in _DSD does not make sense for GpioInt() resource and
must be 0. GpioInt() resource has its own means of defining it.
In our Bluetooth example the "reset-gpios" refers to the second GpioIo()
resource, second pin in that resource with the GPIO number of 31.
The GpioIo() resource unfortunately doesn't explicitly provide an initial
state of the output pin which driver should use during its initialization.
Linux tries to use common sense here and derives the state from the bias
and polarity settings. The table below shows the expectations:
+-------------+-------------+-----------------------------------------------+
| Pull Bias | Polarity | Requested... |
+=============+=============+===============================================+
| Implicit |
+-------------+-------------+-----------------------------------------------+
| **Default** | x | AS IS (assumed firmware configured it for us) |
+-------------+-------------+-----------------------------------------------+
| Explicit |
+-------------+-------------+-----------------------------------------------+
| **None** | x | AS IS (assumed firmware configured it for us) |
| | | with no Pull Bias |
+-------------+-------------+-----------------------------------------------+
| **Up** | x (no _DSD) | |
| +-------------+ as high, assuming non-active |
| | Low | |
| +-------------+-----------------------------------------------+
| | High | as high, assuming active |
+-------------+-------------+-----------------------------------------------+
| **Down** | x (no _DSD) | |
| +-------------+ as low, assuming non-active |
| | High | |
| +-------------+-----------------------------------------------+
| | Low | as low, assuming active |
+-------------+-------------+-----------------------------------------------+
That said, for our above example, since the bias setting is explicit and
_DSD is present, both GPIOs will be treated as active with a high
polarity and Linux will configure the pins in this state until a driver
reprograms them differently.
It is possible to leave holes in the array of GPIOs. This is useful in
cases like with SPI host controllers where some chip selects may be
implemented as GPIOs and some as native signals. For example a SPI host
controller can have chip selects 0 and 2 implemented as GPIOs and 1 as
native::
Package () {
"cs-gpios",
Package () {
^GPIO, 19, 0, 0, // chip select 0: GPIO
0, // chip select 1: native signal
^GPIO, 20, 0, 0, // chip select 2: GPIO
}
}
Note, that historically ACPI has no means of the GPIO polarity and thus
the SPISerialBus() resource defines it on the per-chip basis. In order
to avoid a chain of negations, the GPIO polarity is considered being
Active High. Even for the cases when _DSD() is involved (see the example
above) the GPIO CS polarity must be defined Active High to avoid ambiguity.
Other supported properties
==========================
Following Device Tree compatible device properties are also supported by
_DSD device properties for GPIO controllers:
- gpio-hog
- output-high
- output-low
- input
- line-name
Example::
Name (_DSD, Package () {
// _DSD Hierarchical Properties Extension UUID
ToUUID("dbb8e3e6-5886-4ba6-8795-1319f52a966b"),
Package () {
Package () { "hog-gpio8", "G8PU" }
}
})
Name (G8PU, Package () {
ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
Package () {
Package () { "gpio-hog", 1 },
Package () { "gpios", Package () { 8, 0 } },
Package () { "output-high", 1 },
Package () { "line-name", "gpio8-pullup" },
}
})
- gpio-line-names
The ``gpio-line-names`` declaration is a list of strings ("names"), which
describes each line/pin of a GPIO controller/expander. This list, contained in
a package, must be inserted inside the GPIO controller declaration of an ACPI
table (typically inside the DSDT). The ``gpio-line-names`` list must respect the
following rules (see also the examples):
- the first name in the list corresponds with the first line/pin of the GPIO
controller/expander
- the names inside the list must be consecutive (no "holes" are permitted)
- the list can be incomplete and can end before the last GPIO line: in
other words, it is not mandatory to fill all the GPIO lines
- empty names are allowed (two quotation marks ``""`` correspond to an empty
name)
- names inside one GPIO controller/expander must be unique
Example of a GPIO controller of 16 lines, with an incomplete list with two
empty names::
Package () {
"gpio-line-names",
Package () {
"pin_0",
"pin_1",
"",
"",
"pin_3",
"pin_4_push_button",
}
}
At runtime, the above declaration produces the following result (using the
"libgpiod" tools)::
root@debian:~# gpioinfo gpiochip4
gpiochip4 - 16 lines:
line 0: "pin_0" unused input active-high
line 1: "pin_1" unused input active-high
line 2: unnamed unused input active-high
line 3: unnamed unused input active-high
line 4: "pin_3" unused input active-high
line 5: "pin_4_push_button" unused input active-high
line 6: unnamed unused input active-high
line 7 unnamed unused input active-high
line 8: unnamed unused input active-high
line 9: unnamed unused input active-high
line 10: unnamed unused input active-high
line 11: unnamed unused input active-high
line 12: unnamed unused input active-high
line 13: unnamed unused input active-high
line 14: unnamed unused input active-high
line 15: unnamed unused input active-high
root@debian:~# gpiofind pin_4_push_button
gpiochip4 5
root@debian:~#
Another example::
Package () {
"gpio-line-names",
Package () {
"SPI0_CS_N", "EXP2_INT", "MUX6_IO", "UART0_RXD",
"MUX7_IO", "LVL_C_A1", "MUX0_IO", "SPI1_MISO",
}
}
See Documentation/devicetree/bindings/gpio/gpio.txt for more information
about these properties.
ACPI GPIO Mappings Provided by Drivers
======================================
There are systems in which the ACPI tables do not contain _DSD but provide _CRS
with GpioIo()/GpioInt() resources and device drivers still need to work with
them.
In those cases ACPI device identification objects, _HID, _CID, _CLS, _SUB, _HRV,
available to the driver can be used to identify the device and that is supposed
to be sufficient to determine the meaning and purpose of all of the GPIO lines
listed by the GpioIo()/GpioInt() resources returned by _CRS. In other words,
the driver is supposed to know what to use from the GpioIo()/GpioInt() resources
for once it has identified the device. Having done that, it can simply assign names
to the GPIO lines it is going to use and provide the GPIO subsystem with a
mapping between those names and the ACPI GPIO resources corresponding to them.
To do that, the driver needs to define a mapping table as a NULL-terminated
array of struct acpi_gpio_mapping objects that each contains a name, a pointer
to an array of line data (struct acpi_gpio_params) objects and the size of that
array. Each struct acpi_gpio_params object consists of three fields,
crs_entry_index, line_index, active_low, representing the index of the target
GpioIo()/GpioInt() resource in _CRS starting from zero, the index of the target
line in that resource starting from zero, and the active-low flag for that line,
respectively, in analogy with the _DSD GPIO property format specified above.
For the example Bluetooth device discussed previously the data structures in
question would look like this::
static const struct acpi_gpio_params reset_gpio = { 1, 1, false };
static const struct acpi_gpio_params shutdown_gpio = { 0, 0, false };
static const struct acpi_gpio_mapping bluetooth_acpi_gpios[] = {
{ "reset-gpios", &reset_gpio, 1 },
{ "shutdown-gpios", &shutdown_gpio, 1 },
{ }
};
Next, the mapping table needs to be passed as the second argument to
acpi_dev_add_driver_gpios() or its managed analogue that will
register it with the ACPI device object pointed to by its first
argument. That should be done in the driver's .probe() routine.
On removal, the driver should unregister its GPIO mapping table by
calling acpi_dev_remove_driver_gpios() on the ACPI device object where that
table was previously registered.
Using the _CRS fallback
=======================
If a device does not have _DSD or the driver does not create ACPI GPIO
mapping, the Linux GPIO framework refuses to return any GPIOs. This is
because the driver does not know what it actually gets. For example, if we
have a device like below::
Device (BTH)
{
Name (_HID, ...)
Name (_CRS, ResourceTemplate () {
GpioIo (Exclusive, PullNone, 0, 0, IoRestrictionNone,
"\\_SB.GPO0", 0, ResourceConsumer) { 15 }
GpioIo (Exclusive, PullNone, 0, 0, IoRestrictionNone,
"\\_SB.GPO0", 0, ResourceConsumer) { 27 }
})
}
The driver might expect to get the right GPIO when it does::
desc = gpiod_get(dev, "reset", GPIOD_OUT_LOW);
if (IS_ERR(desc))
...error handling...
but since there is no way to know the mapping between "reset" and
the GpioIo() in _CRS the desc will hold ERR_PTR(-ENOENT).
The driver author can solve this by passing the mapping explicitly
(this is the recommended way and it's documented in the above chapter).
The ACPI GPIO mapping tables should not contaminate drivers that are not
knowing about which exact device they are servicing on. It implies that
the ACPI GPIO mapping tables are hardly linked to an ACPI ID and certain
objects, as listed in the above chapter, of the device in question.
Getting GPIO descriptor
=======================
There are two main approaches to get GPIO resource from ACPI::
desc = gpiod_get(dev, connection_id, flags);
desc = gpiod_get_index(dev, connection_id, index, flags);
We may consider two different cases here, i.e. when connection ID is
provided and otherwise.
Case 1::
desc = gpiod_get(dev, "non-null-connection-id", flags);
desc = gpiod_get_index(dev, "non-null-connection-id", index, flags);
Case 1 assumes that corresponding ACPI device description must have
defined device properties and will prevent from getting any GPIO resources
otherwise.
Case 2::
desc = gpiod_get(dev, NULL, flags);
desc = gpiod_get_index(dev, NULL, index, flags);
Case 2 explicitly tells GPIO core to look for resources in _CRS.
Be aware that gpiod_get_index() in cases 1 and 2, assuming that there
are two versions of ACPI device description provided and no mapping is
present in the driver, will return different resources. That's why a
certain driver has to handle them carefully as explained in the previous
chapter.
3. 한국어 전문 번역
영어 원문의 문단 순서와 의미를 유지한 전체 번역입니다. 코드, 함수명, symbol과 URL은 원문 표기를 유지합니다.
_DSD GPIO 이름과 property 형식
1-60ACPI 5.1의 `_DSD` configuration object는 `_CRS`가 반환하는 GPIO를 비롯한 resource에 이름을 붙일 수 있게 했다. 이전에는 대응 GPIO를 integer index로만 찾아야 했고, 이 방식은 `_CRS` output 순서에 의존하므로 오류가 나기 쉬웠다.
이제 driver는 정수 index 대신 `_DSD`의 이름으로 GPIO를 질의할 수 있다. Bluetooth device BTH 예제에는 reset과 shutdown GPIO가 있고, `_CRS`는 controller `\_SB.GPO0`의 두 `GpioIo()` resource를 반환한다.
첫 `GpioIo()` resource는 output-only pin 15 하나를 포함한다. 두 번째 `GpioIo()` resource는 pin 27과 31을 포함한다. 둘 다 `Exclusive`, `PullUp`, `IoRestrictionOutputOnly`, `ResourceConsumer`로 기술되어 있다.
Device Properties UUID `daffd814-6eba-4d8c-8a91-bc9bbf4aa301` 아래에서 `reset-gpios`는 `{ ^BTH, 1, 1, 0 }`, `shutdown-gpios`는 `{ ^BTH, 0, 0, 0 }`으로 정의된다.
Resource index와 내부 pin index를 분리해서 봐야 최종 GPIO number를 정확히 찾을 수 있다.
Property 값은 참조 device, resource index, resource 내부 pin index, active-low flag 순서다.
지원 형식은 `Package () { "name", Package () { ref, index, pin, active_low } }`다. `ref`는 `GpioIo()` 또는 `GpioInt()` resource가 있는 device이고, 보통 현재 device 자신이다. `index`와 `pin`은 모두 0부터 시작한다.
ACPI `GpioIo()` resource에는 active-low인지 active-high인지 나타내는 필드가 없으므로 `_DSD`의 `active_low` argument가 이를 보완한다. 값을 1로 설정하면 GPIO를 active-low로 표시한다.
반면 `GpioInt()`에는 polarity를 정의하는 자체 수단이 있다. 따라서 `GpioInt()`를 참조하는 `_DSD` GPIO property에서 `active_low`는 의미가 없으며 반드시 0이어야 한다.
reset-gpios 같은 이름이 controller pin으로 해석되는 과정이다.
.. SPDX-License-Identifier: GPL-2.0
======================================
_DSD Device Properties Related to GPIO
======================================
With the release of ACPI 5.1, the _DSD configuration object finally
allows names to be given to GPIOs (and other things as well) returned
by _CRS. Previously we were only able to use an integer index to find
the corresponding GPIO, which is pretty error prone (it depends on
the _CRS output ordering, for example).
With _DSD we can now query GPIOs using a name instead of an integer
index, like the ASL example below shows::
// Bluetooth device with reset and shutdown GPIOs
Device (BTH)
{
Name (_HID, ...)
Name (_CRS, ResourceTemplate ()
{
GpioIo (Exclusive, PullUp, 0, 0, IoRestrictionOutputOnly,
"\\_SB.GPO0", 0, ResourceConsumer) { 15 }
GpioIo (Exclusive, PullUp, 0, 0, IoRestrictionOutputOnly,
"\\_SB.GPO0", 0, ResourceConsumer) { 27, 31 }
})
Name (_DSD, Package ()
{
ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
Package ()
{
Package () { "reset-gpios", Package () { ^BTH, 1, 1, 0 } },
Package () { "shutdown-gpios", Package () { ^BTH, 0, 0, 0 } },
}
})
}
The format of the supported GPIO property is::
Package () { "name", Package () { ref, index, pin, active_low }}
ref
The device that has _CRS containing GpioIo()/GpioInt() resources,
typically this is the device itself (BTH in our case).
index
Index of the GpioIo()/GpioInt() resource in _CRS starting from zero.
pin
Pin in the GpioIo()/GpioInt() resource. Typically this is zero.
active_low
If 1, the GPIO is marked as active-low.
Since ACPI GpioIo() resource does not have a field saying whether it is
active-low or active-high, the "active_low" argument can be used here.
Setting it to 1 marks the GPIO as active-low.
Note, active_low in _DSD does not make sense for GpioInt() resource and
must be 0. GpioInt() resource has its own means of defining it.
Bluetooth mapping과 초기 출력 상태
61-120Bluetooth 예제에서 `reset-gpios`는 두 번째 `GpioIo()` resource의 두 번째 pin을 가리킨다. 즉 `{ ^BTH, 1, 1, 0 }`의 resource index 1과 pin index 1을 따라가면 GPIO number 31이다. `shutdown-gpios`는 resource index 0의 pin index 0이므로 GPIO 15다.
_DSD tuple을 _CRS 배열에 적용한 결과다.
`GpioIo()` resource에는 driver가 초기화 중 사용해야 할 output pin의 초기 state가 명시적으로 들어 있지 않다. Linux는 pull bias와 polarity 설정을 조합해 합리적인 초기 state를 유도한다.
원문의 기대값 표를 bias, polarity와 Linux 요청 상태로 재구성했다.
Implicit `Default` bias는 polarity와 관계없이 현재 상태를 그대로 두며 firmware가 대신 설정했다고 가정한다. Explicit `None`도 pull bias만 없앤 채 현재 상태를 유지한다.
Explicit `Up`은 pin을 high로 요청한다. `_DSD`가 없어 polarity를 알 수 없거나 active-low이면 high를 non-active로 간주하고, active-high이면 high를 active로 간주한다. Explicit `Down`은 반대로 pin을 low로 요청하며, polarity 미지정 또는 active-high이면 non-active, active-low이면 active로 본다.
BTH 예제는 explicit `PullUp`이며 `_DSD`가 존재하고 두 property의 `active_low`가 0이다. 따라서 두 GPIO는 high polarity에서 active로 취급되고, driver가 다르게 재program할 때까지 Linux가 pin을 high active state로 설정한다.
GPIO 배열에는 빈 slot을 둘 수 있다. SPI host controller에서 일부 chip select는 GPIO로, 다른 chip select는 native signal로 구현되는 경우가 대표적이다.
예제 `cs-gpios`는 chip select 0을 `^GPIO`의 GPIO 19, chip select 1을 숫자 `0`으로 표시한 native signal, chip select 2를 GPIO 20에 대응시킨다. 빈 slot은 뒤의 index가 당겨지지 않도록 보존한다.
GPIO와 native chip select가 섞여 있어도 logical chip-select index는 유지된다.
역사적으로 ACPI에는 GPIO polarity를 나타낼 수단이 없었고 `SPISerialBus()` resource가 chip별 polarity를 정의했다. 연속적인 polarity 부정을 피하려고 GPIO chip-select property의 polarity는 Active High로 간주한다. `_DSD()`를 사용하는 경우에도 모호성을 없애려면 GPIO CS polarity를 Active High로 정의해야 한다.
In our Bluetooth example the "reset-gpios" refers to the second GpioIo()
resource, second pin in that resource with the GPIO number of 31.
The GpioIo() resource unfortunately doesn't explicitly provide an initial
state of the output pin which driver should use during its initialization.
Linux tries to use common sense here and derives the state from the bias
and polarity settings. The table below shows the expectations:
+-------------+-------------+-----------------------------------------------+
| Pull Bias | Polarity | Requested... |
+=============+=============+===============================================+
| Implicit |
+-------------+-------------+-----------------------------------------------+
| **Default** | x | AS IS (assumed firmware configured it for us) |
+-------------+-------------+-----------------------------------------------+
| Explicit |
+-------------+-------------+-----------------------------------------------+
| **None** | x | AS IS (assumed firmware configured it for us) |
| | | with no Pull Bias |
+-------------+-------------+-----------------------------------------------+
| **Up** | x (no _DSD) | |
| +-------------+ as high, assuming non-active |
| | Low | |
| +-------------+-----------------------------------------------+
| | High | as high, assuming active |
+-------------+-------------+-----------------------------------------------+
| **Down** | x (no _DSD) | |
| +-------------+ as low, assuming non-active |
| | High | |
| +-------------+-----------------------------------------------+
| | Low | as low, assuming active |
+-------------+-------------+-----------------------------------------------+
That said, for our above example, since the bias setting is explicit and
_DSD is present, both GPIOs will be treated as active with a high
polarity and Linux will configure the pins in this state until a driver
reprograms them differently.
It is possible to leave holes in the array of GPIOs. This is useful in
cases like with SPI host controllers where some chip selects may be
implemented as GPIOs and some as native signals. For example a SPI host
controller can have chip selects 0 and 2 implemented as GPIOs and 1 as
native::
Package () {
"cs-gpios",
Package () {
^GPIO, 19, 0, 0, // chip select 0: GPIO
0, // chip select 1: native signal
^GPIO, 20, 0, 0, // chip select 2: GPIO
}
}
Note, that historically ACPI has no means of the GPIO polarity and thus
the SPISerialBus() resource defines it on the per-chip basis. In order
to avoid a chain of negations, the GPIO polarity is considered being
Active High. Even for the cases when _DSD() is involved (see the example
above) the GPIO CS polarity must be defined Active High to avoid ambiguity.
GPIO hog와 gpio-line-names 규칙
121-168ACPI GPIO controller의 `_DSD`는 Device Tree와 호환되는 `gpio-hog`, `output-high`, `output-low`, `input`, `line-name` property를 지원한다.
예제는 `_DSD` Hierarchical Properties Extension UUID `dbb8e3e6-5886-4ba6-8795-1319f52a966b`를 사용해 `hog-gpio8` child name을 `G8PU` package에 연결한다.
`G8PU`는 Device Properties UUID `daffd814-6eba-4d8c-8a91-bc9bbf4aa301` 아래에 `gpio-hog=1`, `gpios={ 8, 0 }`, `output-high=1`, `line-name="gpio8-pullup"`을 제공한다. 결과적으로 GPIO 8을 output-high hog로 예약하고 사람이 읽을 line name을 붙인다.
Controller의 hierarchical entry가 data-only child package의 실제 hog 설정으로 이어진다.
예제의 GPIO 8 pull-up hog 설정을 항목별로 정리했다.
`gpio-line-names`는 GPIO controller 또는 expander의 각 line/pin을 설명하는 문자열 목록이다. 이 package는 보통 DSDT 안의 GPIO controller 선언 내부에 넣는다.
목록의 첫 이름은 controller의 첫 line에 대응한다. 항목은 중간 index를 생략하지 않고 연속되어야 한다. 다만 목록 자체는 마지막 GPIO 전에 끝나도 되므로 모든 line을 채울 의무는 없다.
빈 이름 `""`은 허용된다. 빈 문자열도 해당 index를 차지하므로 뒤의 이름 위치를 보존하는 데 사용한다. 같은 GPIO controller 또는 expander 안에서 비어 있지 않은 line name은 서로 고유해야 한다.
배열 위치와 이름의 유효성을 결정하는 다섯 규칙이다.
Other supported properties
==========================
Following Device Tree compatible device properties are also supported by
_DSD device properties for GPIO controllers:
- gpio-hog
- output-high
- output-low
- input
- line-name
Example::
Name (_DSD, Package () {
// _DSD Hierarchical Properties Extension UUID
ToUUID("dbb8e3e6-5886-4ba6-8795-1319f52a966b"),
Package () {
Package () { "hog-gpio8", "G8PU" }
}
})
Name (G8PU, Package () {
ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
Package () {
Package () { "gpio-hog", 1 },
Package () { "gpios", Package () { 8, 0 } },
Package () { "output-high", 1 },
Package () { "line-name", "gpio8-pullup" },
}
})
- gpio-line-names
The ``gpio-line-names`` declaration is a list of strings ("names"), which
describes each line/pin of a GPIO controller/expander. This list, contained in
a package, must be inserted inside the GPIO controller declaration of an ACPI
table (typically inside the DSDT). The ``gpio-line-names`` list must respect the
following rules (see also the examples):
- the first name in the list corresponds with the first line/pin of the GPIO
controller/expander
- the names inside the list must be consecutive (no "holes" are permitted)
- the list can be incomplete and can end before the last GPIO line: in
other words, it is not mandatory to fill all the GPIO lines
- empty names are allowed (two quotation marks ``""`` correspond to an empty
name)
- names inside one GPIO controller/expander must be unique
gpio-line-names와 libgpiod 결과
169-22216-line GPIO controller 예제는 이름 여섯 개만 제공하는 불완전 목록이며 그중 두 항목은 빈 문자열이다. 배열 위치는 line 0부터 순서대로 `pin_0`, `pin_1`, 빈 이름, 빈 이름, `pin_3`, `pin_4_push_button`에 대응한다.
이름 문자열의 숫자는 GPIO index를 결정하지 않는다. 실제 index는 package 안의 위치로 결정되므로 `pin_3` 문자열은 다섯 번째 항목인 line 4, `pin_4_push_button`은 여섯 번째 항목인 line 5에 나타난다. 원문의 이 배치를 임의로 고치면 firmware ABI가 달라진다.
Package 위치와 runtime line을 그대로 대응시켰다.
Runtime에서 `gpioinfo gpiochip4`를 실행하면 gpiochip4가 16 line을 가진 것으로 표시된다. Line 0과 1은 각각 `pin_0`, `pin_1`, line 2와 3은 `unnamed`, line 4는 `pin_3`, line 5는 `pin_4_push_button`으로 보인다. 목록이 끝난 line 6부터 15도 `unnamed`다.
예제 출력에서 line은 모두 unused input active-high 상태다. `gpiofind pin_4_push_button`은 이름을 검색해 `gpiochip4 5`를 반환하므로 해당 이름이 line 5에 배치되었음을 확인할 수 있다.
Firmware package가 libgpiod 도구에서 보이는 이름으로 변환되는 과정이다.
두 번째 예제는 line 0부터 7까지 `SPI0_CS_N`, `EXP2_INT`, `MUX6_IO`, `UART0_RXD`, `MUX7_IO`, `LVL_C_A1`, `MUX0_IO`, `SPI1_MISO`를 연속해서 지정한다.
8개 이름이 package 순서대로 GPIO line 0부터 7에 대응한다.
이 property들에 관한 추가 정보는 원문이 가리키는 `Documentation/devicetree/bindings/gpio/gpio.txt`를 참조한다.
Example of a GPIO controller of 16 lines, with an incomplete list with two
empty names::
Package () {
"gpio-line-names",
Package () {
"pin_0",
"pin_1",
"",
"",
"pin_3",
"pin_4_push_button",
}
}
At runtime, the above declaration produces the following result (using the
"libgpiod" tools)::
root@debian:~# gpioinfo gpiochip4
gpiochip4 - 16 lines:
line 0: "pin_0" unused input active-high
line 1: "pin_1" unused input active-high
line 2: unnamed unused input active-high
line 3: unnamed unused input active-high
line 4: "pin_3" unused input active-high
line 5: "pin_4_push_button" unused input active-high
line 6: unnamed unused input active-high
line 7 unnamed unused input active-high
line 8: unnamed unused input active-high
line 9: unnamed unused input active-high
line 10: unnamed unused input active-high
line 11: unnamed unused input active-high
line 12: unnamed unused input active-high
line 13: unnamed unused input active-high
line 14: unnamed unused input active-high
line 15: unnamed unused input active-high
root@debian:~# gpiofind pin_4_push_button
gpiochip4 5
root@debian:~#
Another example::
Package () {
"gpio-line-names",
Package () {
"SPI0_CS_N", "EXP2_INT", "MUX6_IO", "UART0_RXD",
"MUX7_IO", "LVL_C_A1", "MUX0_IO", "SPI1_MISO",
}
}
See Documentation/devicetree/bindings/gpio/gpio.txt for more information
about these properties.
Driver가 제공하는 ACPI GPIO mapping
223-267일부 system의 ACPI table에는 `_DSD`가 없지만 `_CRS`에는 `GpioIo()` 또는 `GpioInt()` resource가 있다. 이런 system에서도 device driver가 GPIO를 사용해야 할 수 있다.
Driver가 볼 수 있는 `_HID`, `_CID`, `_CLS`, `_SUB`, `_HRV` 같은 ACPI device identification object로 device를 확실히 식별할 수 있다면, 그 정보만으로 `_CRS`가 나열한 모든 GPIO line의 의미와 목적을 결정할 수 있어야 한다.
즉 driver는 식별한 특정 device에서 어느 `GpioIo()` 또는 `GpioInt()` line을 써야 하는지 알고 있어야 한다. 그런 경우 사용할 line에 이름을 부여하고, 그 이름과 ACPI GPIO resource 사이의 mapping을 GPIO subsystem에 제공할 수 있다.
Firmware _DSD가 없을 때 특정 device 지식으로 이름을 복원하는 경로다.
Mapping table은 `struct acpi_gpio_mapping` object의 NULL-terminated 배열이다. 각 entry는 이름, line data 배열인 `struct acpi_gpio_params` pointer, 그리고 그 배열 크기를 담는다.
각 `struct acpi_gpio_params`는 `crs_entry_index`, `line_index`, `active_low` 세 필드로 이루어진다. 각각 `_CRS`에서 0부터 세는 대상 GPIO resource index, resource 안에서 0부터 세는 line index, 해당 line의 active-low flag다. 구조는 앞서 설명한 `_DSD` GPIO property 형식과 대응한다.
Driver mapping도 _DSD tuple과 같은 세 좌표를 사용한다.
앞의 Bluetooth device는 `reset_gpio = { 1, 1, false }`, `shutdown_gpio = { 0, 0, false }`로 표현된다. `bluetooth_acpi_gpios[]`는 `reset-gpios`를 `reset_gpio`, `shutdown-gpios`를 `shutdown_gpio`에 각각 크기 1로 연결하고 빈 `{ }` entry로 종료한다.
Firmware _DSD 예제와 동일한 reset·shutdown 좌표를 C 구조체로 표현한다.
Driver의 `.probe()` routine에서 mapping table을 `acpi_dev_add_driver_gpios()`의 두 번째 인자로 전달한다. 첫 인자는 mapping을 등록할 ACPI device object다. Managed analogue를 사용할 수도 있다.
Device 제거 시에는 mapping을 등록했던 같은 ACPI device object에 `acpi_dev_remove_driver_gpios()`를 호출해 table을 해제해야 한다.
ACPI GPIO Mappings Provided by Drivers
======================================
There are systems in which the ACPI tables do not contain _DSD but provide _CRS
with GpioIo()/GpioInt() resources and device drivers still need to work with
them.
In those cases ACPI device identification objects, _HID, _CID, _CLS, _SUB, _HRV,
available to the driver can be used to identify the device and that is supposed
to be sufficient to determine the meaning and purpose of all of the GPIO lines
listed by the GpioIo()/GpioInt() resources returned by _CRS. In other words,
the driver is supposed to know what to use from the GpioIo()/GpioInt() resources
for once it has identified the device. Having done that, it can simply assign names
to the GPIO lines it is going to use and provide the GPIO subsystem with a
mapping between those names and the ACPI GPIO resources corresponding to them.
To do that, the driver needs to define a mapping table as a NULL-terminated
array of struct acpi_gpio_mapping objects that each contains a name, a pointer
to an array of line data (struct acpi_gpio_params) objects and the size of that
array. Each struct acpi_gpio_params object consists of three fields,
crs_entry_index, line_index, active_low, representing the index of the target
GpioIo()/GpioInt() resource in _CRS starting from zero, the index of the target
line in that resource starting from zero, and the active-low flag for that line,
respectively, in analogy with the _DSD GPIO property format specified above.
For the example Bluetooth device discussed previously the data structures in
question would look like this::
static const struct acpi_gpio_params reset_gpio = { 1, 1, false };
static const struct acpi_gpio_params shutdown_gpio = { 0, 0, false };
static const struct acpi_gpio_mapping bluetooth_acpi_gpios[] = {
{ "reset-gpios", &reset_gpio, 1 },
{ "shutdown-gpios", &shutdown_gpio, 1 },
{ }
};
Next, the mapping table needs to be passed as the second argument to
acpi_dev_add_driver_gpios() or its managed analogue that will
register it with the ACPI device object pointed to by its first
argument. That should be done in the driver's .probe() routine.
On removal, the driver should unregister its GPIO mapping table by
calling acpi_dev_remove_driver_gpios() on the ACPI device object where that
table was previously registered.
_CRS fallback과 명시적 mapping
268-304Device에 `_DSD`가 없고 driver도 ACPI GPIO mapping을 만들지 않으면 Linux GPIO framework는 GPIO 반환을 거부한다. Driver가 실제로 어떤 GPIO를 받는지 알 수 없기 때문이다.
예제 BTH device의 `_CRS`는 controller `\_SB.GPO0`에 GPIO 15와 27을 각각 별도 `GpioIo()` resource로 제공하지만, 이 두 line 중 어느 것이 reset인지 설명하는 `_DSD`는 없다.
이 상태에서 driver가 `gpiod_get(dev, "reset", GPIOD_OUT_LOW)`을 호출해도 `"reset"`과 `_CRS`의 어느 `GpioIo()`가 대응하는지 알 방법이 없다. 따라서 `desc`에는 `ERR_PTR(-ENOENT)`가 들어간다.
Resource가 존재해도 의미 mapping이 없으면 connection ID 요청은 실패한다.
권장 해결책은 앞 절에서 설명한 mapping을 driver가 명시적으로 제공하는 것이다. 이렇게 해야 resource 순서와 connection name의 관계를 review 가능한 코드로 고정할 수 있다.
ACPI GPIO mapping table은 자신이 정확히 어떤 device를 지원하는지 모르는 generic driver를 오염시켜서는 안 된다. Mapping은 특정 ACPI ID와 앞서 나열한 identification object에 단단히 결합되어야 하며, 확인되지 않은 다른 model에 재사용하면 안 된다.
Connection ID를 안전하게 쓰기 위한 조건을 구분한다.
Using the _CRS fallback
=======================
If a device does not have _DSD or the driver does not create ACPI GPIO
mapping, the Linux GPIO framework refuses to return any GPIOs. This is
because the driver does not know what it actually gets. For example, if we
have a device like below::
Device (BTH)
{
Name (_HID, ...)
Name (_CRS, ResourceTemplate () {
GpioIo (Exclusive, PullNone, 0, 0, IoRestrictionNone,
"\\_SB.GPO0", 0, ResourceConsumer) { 15 }
GpioIo (Exclusive, PullNone, 0, 0, IoRestrictionNone,
"\\_SB.GPO0", 0, ResourceConsumer) { 27 }
})
}
The driver might expect to get the right GPIO when it does::
desc = gpiod_get(dev, "reset", GPIOD_OUT_LOW);
if (IS_ERR(desc))
...error handling...
but since there is no way to know the mapping between "reset" and
the GpioIo() in _CRS the desc will hold ERR_PTR(-ENOENT).
The driver author can solve this by passing the mapping explicitly
(this is the recommended way and it's documented in the above chapter).
The ACPI GPIO mapping tables should not contaminate drivers that are not
knowing about which exact device they are servicing on. It implies that
the ACPI GPIO mapping tables are hardly linked to an ACPI ID and certain
objects, as listed in the above chapter, of the device in question.
GPIO descriptor 획득 API
305-336ACPI에서 GPIO resource를 얻는 주요 API는 `gpiod_get(dev, connection_id, flags)`와 `gpiod_get_index(dev, connection_id, index, flags)` 두 가지다. 차이는 동일 connection의 여러 descriptor 중 index를 지정하는지 여부다.
해석은 connection ID가 non-NULL인지 `NULL`인지에 따라 크게 두 경우로 나뉜다.
Case 1에서 `gpiod_get(dev, "non-null-connection-id", flags)` 또는 `gpiod_get_index(dev, "non-null-connection-id", index, flags)`를 호출하면 대응 ACPI device description에 device property가 정의되어 있어야 한다. Property가 없으면 GPIO resource를 얻지 못하도록 막는다.
Case 2에서 `gpiod_get(dev, NULL, flags)` 또는 `gpiod_get_index(dev, NULL, index, flags)`를 호출하면 GPIO core에 `_CRS` resource를 직접 찾으라고 명시한다.
Non-NULL ID는 property mapping을 요구하고 NULL은 _CRS fallback을 명시한다.
이름, index와 firmware description 형태에 따라 API를 고르는 순서다.
Driver mapping이 없고 ACPI device description의 두 version이 하나는 property mapping을 제공하고 다른 하나는 `_CRS` 순서만 제공한다고 가정하면, Case 1과 Case 2의 `gpiod_get_index()`는 서로 다른 resource를 반환할 수 있다. 따라서 특정 driver는 앞 절의 규칙에 따라 두 firmware 형태를 신중히 처리해야 한다.
안전한 구현은 non-NULL connection ID에는 명시적 mapping을 요구하고, `NULL` fallback은 대상 device의 `_CRS` 순서를 driver가 확실히 알고 있을 때만 사용하는 것이다.
Getting GPIO descriptor
=======================
There are two main approaches to get GPIO resource from ACPI::
desc = gpiod_get(dev, connection_id, flags);
desc = gpiod_get_index(dev, connection_id, index, flags);
We may consider two different cases here, i.e. when connection ID is
provided and otherwise.
Case 1::
desc = gpiod_get(dev, "non-null-connection-id", flags);
desc = gpiod_get_index(dev, "non-null-connection-id", index, flags);
Case 1 assumes that corresponding ACPI device description must have
defined device properties and will prevent from getting any GPIO resources
otherwise.
Case 2::
desc = gpiod_get(dev, NULL, flags);
desc = gpiod_get_index(dev, NULL, index, flags);
Case 2 explicitly tells GPIO core to look for resources in _CRS.
Be aware that gpiod_get_index() in cases 1 and 2, assuming that there
are two versions of ACPI device description provided and no mapping is
present in the driver, will return different resources. That's why a
certain driver has to handle them carefully as explained in the previous
chapter.
요약·해설
gpio-properties.rst:1-336ACPI `_DSD` GPIO property는 `ref, index, pin, active_low` tuple로 `_CRS`의 `GpioIo()` 또는 `GpioInt()` resource에 이름을 붙인다. Resource index와 resource 내부 pin index는 모두 0부터 시작하며 `GpioInt()`의 active_low 값은 반드시 0이다.
Linux는 `GpioIo()`의 초기 output state를 pull bias와 polarity에서 유도한다. GPIO 배열에는 native signal을 나타내는 빈 slot을 둘 수 있지만, SPI chip-select polarity는 중복 부정을 피하도록 Active High로 표현해야 한다.
GPIO controller는 hog와 `gpio-line-names`를 제공할 수 있다. Line name 배열은 line 0부터 연속하며 빈 이름은 허용되고 전체 line보다 짧아도 되지만, 같은 controller 안의 이름은 고유해야 한다.
Firmware에 `_DSD`가 없으면 특정 ACPI ID를 아는 driver가 `struct acpi_gpio_mapping`을 등록할 수 있다. 이름 mapping 없이 non-NULL connection ID를 요청하면 `ERR_PTR(-ENOENT)`가 반환되며, `NULL` ID는 `_CRS` 직접 검색을 명시한다.
Firmware와 driver 양쪽에서 GPIO 의미를 보존하는 점검 절차다.