summaryrefslogtreecommitdiff
path: root/docs/zephyr
diff options
context:
space:
mode:
authorAndrew McRae <amcrae@google.com>2022-01-31 17:26:14 +1100
committerCommit Bot <commit-bot@chromium.org>2022-02-04 23:53:25 +0000
commitab6886d640027e98149d3716fc237d493559b1ff (patch)
tree5287f2dcf900a817739cb8e0419138f44a7ac799 /docs/zephyr
parent18bdd2b936a9f5d56634d0156338cdad792373d9 (diff)
downloadchrome-ec-ab6886d640027e98149d3716fc237d493559b1ff.tar.gz
zephyr_gpio: Update docs about GPIOs
Update the Zephyr GPIO docs BUG=none TEST=none BRANCH=none Signed-off-by: Andrew McRae <amcrae@google.com> Change-Id: I3c2e439cf0224db803c16675e2ec877f1baf7dcf Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/3426246 Reviewed-by: Keith Short <keithshort@chromium.org>
Diffstat (limited to 'docs/zephyr')
-rw-r--r--docs/zephyr/zephyr_gpio.md267
1 files changed, 218 insertions, 49 deletions
diff --git a/docs/zephyr/zephyr_gpio.md b/docs/zephyr/zephyr_gpio.md
index 320086a70b..82b54790fe 100644
--- a/docs/zephyr/zephyr_gpio.md
+++ b/docs/zephyr/zephyr_gpio.md
@@ -18,80 +18,207 @@ Kconfig Option | Default | Documentation
## Devicetree Nodes
-Configure the GPIO module by declaring all GPIOs in the devicetree node with
+Configure the GPIO module by declaring all GPIOs as child nodes in
+the devicetree node with
`compatible` property `named-gpios`. The GPIO module automatically initializes
all GPIOs from this node (unless the `no-auto-init` property is present).
Legacy C source code accesses GPIOs using the specified
`enum-name` property as an enum name of the GPIO.
+Zephyr based code uses the node label, an alias, or other node reference
+to identify the GPIO.
Named GPIO properties:
Property | Description | Settings
:------- | :---------- | :-------
-`#gpio-cells` | Specifier cell count, always `<0>`, required if the node label is used in a `-gpios` property. | `<0>`
-`gpios` | GPIO phandle, identifies the port (X), pin number (Y) and flags. | `<&gpioX Y flags>`
+`gpios` | GPIO `phandle-array`, identifies the port (X), pin number (Y) and flags. | `<&gpioX Y flags>`
`enum-name` | An optional name used to define an enum to refer to the GPIO in legacy code. | `GPIO_<NAME>`
`no-auto-init` | If present, the GPIO **will not** be initialized at start-up. | boolean, default false
-The use of `no-auto-init` allows GPIOs to be skipped at start-up initialization time,
-and selectively enabled by code at some later time.
+The use of `no-auto-init` allows GPIOs to be skipped at start-up
+initialization time, and selectively enabled by code at some later time.
The file [gpio-enum-name.yaml] defines the list of valid `enum-name` values.
In the GPIO declaration use the lowercase net name from the schematic as the
-*node name*, and the same net name prefixed with `gpio_` as *node label*. For example:
+*node name*, and the same net name prefixed with `gpio_` as *node label*.
+For example:
```
named-gpios {
compatible = "named-gpios";
...
gpio_en_pp5000_fan: en_pp5000_fan {
- #gpio-cells = <0>;
gpios = <&gpio6 1 GPIO_OUT_LOW>;
enum-name = "GPIO_EN_PP5000_FAN";
};
+ gpio_power_on_odl: power_on {
+ gpios = <&gpio4 4 GPIO_INPUT_PULL_UP>;
+ };
+};
...
-}
+aliases {
+ gpio-power = &gpio_power_on_odl;
+};
```
The `flags` cell of the `gpios` property defines the GPIO signal properties,
valid options are listed in [dt-bindings/gpio_defines.h], which is normally
-included from the main project DTS file.
+included from the main board DTS file.
For platform specific features, other flags may be available in the Zephyr
[dt-bindings/gpio/gpio.h] file, such as `GPIO_VOLTAGE_1P8`.
### Legacy enum-name usage
-Only GPIOs that require referencing from legacy common code should have an `enum-name` property.
-The legacy API (e.g `gpio_get_level(enum gpio_signal)`) requires a known name for the enum, which
-is set using the `enum-name` property.
+Only GPIOs that require referencing from legacy common code should have
+an `enum-name` property.
+The legacy API (e.g `gpio_get_level(enum gpio_signal)`) requires a known
+name for the enum, which is set using the `enum-name` property.
+
+Do *not* use `enum gpio_signal` or the enum signal names in any Zephyr
+based code - instead, use the standard Zephyr GPIO API.
### Zephyr GPIO API usage
GPIOs references that are not in legacy common code should use the
[standard Zephyr API](https://docs.zephyrproject.org/latest/reference/peripherals/gpio.html)
-to access the GPIOs.
-To facilitate this, all GPIOs in `named-gpios` will have prebuilt `struct gpio_dt_spec` blocks
+to access the GPIO.
+
+GPIOs are referenced in the `named-gpios` child nodes using the
+node label (if one exists), an alias to a node label, or
+indirectly as a node reference via as a `phandle` in another node.
+
+To facilitate this, all GPIO child nodes in `named-gpios`
+have preinitialised `const struct gpio_dt_spec *` pointers
created that may be used directly in the Zephyr GPIO API calls.
-These blocks are accessed via a macro (`GPIO_DT_LABEL`) using the node label on the GPIO.
-The legacy enum can also be used to retrieve the `gpio_dt_spec` for an GPIO via the
-function `gpio_get_dt_spec` (though this is a runtime lookup). E.g:
+These pointers are accessible via the following macros:
+
+Macro | Argument | Description
+:------- | :---------- | :-------
+`GPIO_DT_FROM_NODELABEL` | nodelabel | Uses a node label to reference the GPIO node.
+`GPIO_DT_FROM_NODE` | node | Uses a node id (referenced as a `phandle` in another node).
+`GPIO_DT_FROM_ALIAS` | alias | Uses an alias to a label on the GPIO node.
+
+The legacy enum can also be used to retrieve the `gpio_dt_spec` for
+a GPIO via the function `gpio_get_dt_spec()` (though this is a
+runtime lookup). E.g:
+
+```
+ fan_status = gpio_pin_get_dt(GPIO_DT_FROM_NODELABEL(gpio_en_pp5000_fan));
+ power_status = gpio_pin_get_dt(GPIO_DT_FROM_ALIAS(gpio_power));
+...
+ /*
+ * Legacy code gave us an enum gpio_signal, get a Zephyr reference
+ * for that GPIO.
+ */
+ const struct gpio_dt_spec *my_gpio = gpio_get_dt_spec(my_signal);
+ my_status = gpio_pin_get_dt(my_gpio);
+```
+
+The `GPIO_DT_FROM_NODE` macro is used when a `named-gpio` is referenced
+from another node via a `phandle` property.
+
+```
+ gpio-interrupts {
+ compatible = "cros-ec,gpio-interrupts";
+
+ int_power_button: power_button {
+ irq-pin = <&gpio_gsc_ec_pwr_btn_odl>;
+ ...
+ };
+...
+ /*
+ * Get the GPIO associated with interrupt.
+ */
+ const struct gpio_dt_spec *pwr_btn =
+ GPIO_DT_FROM_NODE(DT_PHANDLE(DT_NODELABEL(int_power_button), irq_pin));
+ pwr_on = gpio_pin_get_dt(pwr_btn);
+
+```
+
+When referencing a named-gpio child node from another DTS node,
+it is important not to use `gpio` or `gpios` as the trailing suffix
+of the name property. Any referencing property with a name
+ending in `gpio` or `gpios` is
+[treated specially in devicetree](https://docs.zephyrproject.org/latest/guides/dts/bindings.html#specifier-cell-names-cells),
+and assumes the target node is a GPIO node (i.e a node
+with cell specifiers of `pin` and `flags`).
+
+The goal is to migrate away from using the legacy API
+(using the Zephyr API instead), and deprecate the use of the `enum-name`
+property to generate the GPIO signal enum.
+
+### Run-time configuration of GPIOs
+
+It is common to have different hardware configurations supported
+within the same EC image by using `FW_CONFIG` configuration bits
+to selectively choose or enable/disable hardware options.
+Previously, GPIOs were aliased via a #define in `gpio_map.h` to a common
+GPIO in `named-gpios`, allowing different names to be used for the same GPIO.
+At run-time the GPIO would be configured according to the usage required.
+
+However this scheme relies on the use of the legacy
+`enum gpio_signal` to identify the GPIO.
+Given that code is being migrated to the Zephyr API, it is preferred that
+a separate `named-gpio` node be allocated to each use of the GPIO in question,
+and use the `no-auto-init` property to allow the initialisation only
+when code requires it.
+
+So if a board had 2 GPIOs with different use depending on a board type, the
+configuration would appear:
+
+```
+ gpio_hdmi_enable: hdmi_enable{
+ gpios = <&gpio0 2 0>;
+ no-auto-init;
+ };
+ gpio_udb_c1_int: udb_c1_int {
+ gpios = <&gpio0 2 GPIO_PULL_UP>;
+ no-auto-init;
+ };
+```
+
+The board config handling may have:
+
+```
+...
+ if (board_type() == 1) {
+ gpio_pin_configure_dt(GPIO_DT_FROM_NODELABEL(gpio_hdmi_enable), GPIO_OUTPUT);
+ } else {
+ gpio_pin_configure_dt(GPIO_DT_FROM_NODELABEL(gpio_usb_c1_int), GPIO_INPUT);
+ }
+```
+
+Alternatively, a DTS alias may be used:
```
- fan_status = gpio_pin_get_dt(GPIO_DT_LABEL(gpio_en_pp5000_fan));
+ gpio_alt_pin: alt_pin {
+ gpios = <&gpio0 2 GPIO_PULL_UP>;
+ no-auto-init;
+ };
...
- /*
- * Legacy code gave us an enum gpio_signal, get a Zephyr reference
- * for that GPIO.
- */
- const struct gpio_dt_spec *my_gpio = gpio_get_dt_spec(my_signal);
- my_status = gpio_pin_get_dt(my_gpio);
+aliases {
+ gpio-usb-c1-int = &gpio_alt_pin;
+ gpio-hdmi-enable = &gpio_alt_pin;
+};
+...
+ if (board_type() == 1) {
+ /* Use as output to enable the HDMI port */
+ gpio_pin_configure_dt(GPIO_DT_FROM_ALIAS(gpio_hdmi_enable), GPIO_OUTPUT);
+ } else {
+ /* Use as type C port 1 interrupt */
+ gpio_pin_configure_dt(GPIO_DT_FROM_ALIAS(gpio_usb_c1_int), GPIO_INPUT);
+ /* enable interrupt */
+ ...
+ }
+
```
-The goal is to migrate away from using the legacy API to use the Zephyr API, and
-eventually deprecate the use of the `enum-name` property to generate the GPIO signal enum.
+Note that the alias names have a dash instead of an underscore
+(because the alias name is a *property*, not a node name), but the
+name is converted to lower case with underscores for code access.
### Unused GPIOs
@@ -101,12 +228,12 @@ specific code initializes all the unused GPIOs for optimum power consumption.
For example on the Volteer reference board:
```
-unused-pins {
+ unused-pins {
compatible = "unused-gpios";
unused-gpios =
- <&gpio3 4 0>, /* Unused, default platform initialization. */
- ...
- <&gpiob 6 GPIO_OUTPUT_LOW>; /* Explicit initialization flags. */
+ <&gpio3 4 0>, /* Unused, default platform initialization. */
+ ...
+ <&gpiob 6 GPIO_OUTPUT_LOW>; /* Explicit initialization flags. */
};
```
@@ -145,14 +272,14 @@ named-gpios {
## GPIO Interrupts
-GPIO interrupts are specified in a device tree node with a `compatible` property
-of `cros-ec,gpio-interrupts`.
+GPIO interrupts are specified in a device tree node with
+a `compatible` property of `cros-ec,gpio-interrupts`.
Child nodes of this single node contain the following properties:
Property | Description | Settings
:------- | :---------- | :-------
-`irq-gpio` | A reference via a node label to the GPIO that is associated with this interrupt. | `<&gpio_lable>`
+`irq-pin` | A reference via a node label to the named-gpio that is associated with this interrupt. | `<&gpio_label>`
`flags` | The GPIO [interrupt flags](https://docs.zephyrproject.org/latest/reference/peripherals/gpio.html) that define how the interrupt is generated. | `GPIO_INT_<flags>`
`handler` | The C name of the interrupt handler that handles the interrupt. | C function name.
@@ -163,7 +290,7 @@ gpio-interrupts {
compatible = "cros-ec,gpio-interrupts";
...
int_power_button: power_button {
- irq-gpio = <&gpio_ec_pwr_btn_l>;
+ irq-pin = <&gpio_ec_pwr_btn_l>;
flags = <GPIO_INT_EDGE_BOTH>;
handler = "power_button_interrupt";
};
@@ -172,8 +299,8 @@ gpio-interrupts {
```
There must only be one named node containing all of the device tree interrupt
-configuration, but of course overlays may be used to add child nodes or modify the
-single node.
+configuration, but of course overlays may be used to add child nodes or
+modify the single node.
The C handler takes one argument, the `enum signal` of the GPIO, such as:
@@ -185,16 +312,42 @@ void power_button_interrupt(enum gpio_signal signal)
}
```
-This matches the function signature of the existing legacy interrupt handlers, so no
-shims are required.
+This matches the function signature of the existing legacy interrupt
+handlers, so no shims are required.
-Before any interrupt can be received, it must be enabled. Legacy code uses
-the functions `gpio_enable_interrupt(enum signal)` and
-`gpio_disable_interrupt(enum signal)` functions.
+Interrupt handlers in Zephyr based code may need to compare
+the `signal` against known GPIOs, if (for instance) there is a
+common handler for events from multiple GPIOs.
+Rather than using the predefined enums (which require that the GPIO
+has an `enum-name` property), the macro `GPIO_SIGNAL(node_id)` may be
+used to uniquely identify the signal regardless of whether
+an `enum-name` property is on the GPIO e.g:
+
+```
+void button_input(enum gpio_signal signal)
+{
+ switch(signal) {
+ case GPIO_SIGNAL(DT_NODELABEL(gpio_volume_up)):
+ ...
+ break;
+ case GPIO_SIGNAL(DT_NODELABEL(gpio_volume_down)):
+ ...
+ break;
+ case GPIO_SIGNAL(DT_NODELABEL(gpio_power_button)):
+ ...
+ break;
+ }
+}
+```
+
+Before any interrupt can be received, it must be enabled.
+Legacy code uses the functions `gpio_enable_interrupt(enum signal)` and
+`gpio_disable_interrupt(enum signal)` functions. Do not use these in
+any Zephyr based code.
Whilst it is possible to use the Zephyr GPIO interrupt API directly,
for convenience (until the deprecation of the legacy GPIO enum signal names)
-interrupts can be identified via a macro and the label on the interrupt child nodes,
+interrupts can be identified via a macro and the label on the interrupt nodes,
and these can be used to enable or disable the interrupts:
```
@@ -203,6 +356,23 @@ and these can be used to enable or disable the interrupts:
This avoid having to create boiler-plate callbacks as part of the interrupt setup.
+For nodes that require a reference to an GPIO interrupt (such as sensor
+configuration node etc.), the node can be referenced directly
+using `GPIO_INT_FROM_NODE` e.g:
+
+```
+[DTS]
+ sensor-irqs = <
+ &int_imu
+ &int_accel
+ >;
+[code]
+
+#define ENABLE_SENSOR_INTS(i, id) \
+ gpio_enable_dt_interrupt(GPIO_INT_FROM_NODE(DT_PHANDLE_BY_IDX(id, sensor_irqs, i)))
+
+```
+
## Threads
GPIO support does not enable any threads.
@@ -211,7 +381,8 @@ GPIO support does not enable any threads.
### Shell Commands
-The EC application defines two different shell commands to read and change the state of a GPIO:
+The EC application defines two different shell commands to read and
+change the state of a GPIO:
Command | Description | Usage
:------ | :---------- | :----
@@ -245,7 +416,6 @@ named-gpios {
compatible = "named-gpios";
...
gpio_ec_entering_rw: ec_entering_rw {
- #gpio-cells = <0>;
gpios = <&gpioe 3 GPIO_OUT_LOW>;
enum-name = "GPIO_ENTERING_RW";
};
@@ -264,10 +434,9 @@ property `GPIO_ENTERING_RW`.
Use the `node label` to reference the GPIO in other devicetree nodes:
```
-cbi_eeprom: eeprom@50 {
- compatible = "atmel,at24";
- reg = <0x50>;
- wp-gpios = <&gpio_ec_wp_l>;
+my_node: my-node {
+ compatible = "cros-ec,my-feature"
+ signal-pin = <&gpio_ec_entering_rw>;
};
```
@@ -284,6 +453,6 @@ project.
[dt-bindings/gpio/gpio.h]: https://github.com/zephyrproject-rtos/zephyr/blob/main/include/dt-bindings/gpio/gpio.h
[dt-bindings/gpio_defines.h]: ../../zephyr/include/dt-bindings/gpio_defines.h
[include/drivers/gpio.h]: https://docs.zephyrproject.org/latest/reference/peripherals/gpio.html?highlight=gpio_int_disable#api-reference
-[gpio_map.h]: ../../zephyr/projects/trogdor/lazor/include/gpio_map.h
[gpio.dts]: ../../zephyr/projects/volteer/volteer/gpio.dts
+[interrupts.dts]: ../../zephyr/projects/volteer/volteer/interrupts.dts
[BUILD.py]: ../../zephyr/projects/volteer/volteer/BUILD.py