aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--docs/docs/config/kscan.md66
-rw-r--r--docs/docs/config/power.md61
-rw-r--r--docs/docs/development/hardware-integration/includes/_gpio-key-direct.md14
-rw-r--r--docs/docs/development/hardware-integration/includes/_gpio-key-matrix.md14
-rw-r--r--docs/docs/development/hardware-integration/includes/_gpio-key-wakeup.md14
-rw-r--r--docs/docs/development/hardware-integration/includes/_sideband-direct.md37
-rw-r--r--docs/docs/development/hardware-integration/includes/_sideband-matrix.md66
-rw-r--r--docs/docs/development/hardware-integration/includes/_sideband-wakeup-direct.md28
-rw-r--r--docs/docs/development/hardware-integration/includes/_soft-off-behavior.md15
-rw-r--r--docs/docs/development/hardware-integration/includes/_soft-off-waker.md16
-rw-r--r--docs/docs/development/hardware-integration/soft-off-setup.mdx158
-rw-r--r--docs/docs/features/low-power-states.md81
-rw-r--r--docs/docs/features/soft-off.md275
-rw-r--r--docs/docs/keymaps/behaviors/soft-off.md4
-rw-r--r--docs/sidebars.js3
15 files changed, 531 insertions, 321 deletions
diff --git a/docs/docs/config/kscan.md b/docs/docs/config/kscan.md
index e3fa8969f4..f61812e461 100644
--- a/docs/docs/config/kscan.md
+++ b/docs/docs/config/kscan.md
@@ -71,15 +71,15 @@ Applies to: `compatible = "zmk,kscan-gpio-direct"`
Definition file: [zmk/app/module/dts/bindings/kscan/zmk,kscan-gpio-direct.yaml](https://github.com/zmkfirmware/zmk/blob/main/app/module/dts/bindings/kscan/zmk%2Ckscan-gpio-direct.yaml)
-| Property | Type | Description | Default |
-| ------------------------- | ---------- | ----------------------------------------------------------------------------------------------------------- | ------- |
-| `input-gpios` | GPIO array | Input GPIOs (one per key). Can be either direct GPIO pin or `gpio-key` references. | |
-| `debounce-press-ms` | int | Debounce time for key press in milliseconds. Use 0 for eager debouncing. | 5 |
-| `debounce-release-ms` | int | Debounce time for key release in milliseconds. | 5 |
-| `debounce-scan-period-ms` | int | Time between reads in milliseconds when any key is pressed. | 1 |
-| `poll-period-ms` | int | Time between reads in milliseconds when no key is pressed and `CONFIG_ZMK_KSCAN_DIRECT_POLLING` is enabled. | 10 |
-| `toggle-mode` | bool | Use toggle switch mode. | n |
-| `wakeup-source` | bool | Mark this kscan instance as able to wake the keyboard from deep sleep | n |
+| Property | Type | Description | Default |
+| ------------------------- | ---------- | ---------------------------------------------------------------------------------------------------------- | ------- |
+| `input-gpios` | GPIO array | Input GPIOs (one per key). Can be either direct GPIO pin or `gpio-key` references | |
+| `debounce-press-ms` | int | Debounce time for key press in milliseconds. Use 0 for eager debouncing | 5 |
+| `debounce-release-ms` | int | Debounce time for key release in milliseconds | 5 |
+| `debounce-scan-period-ms` | int | Time between reads in milliseconds when any key is pressed | 1 |
+| `poll-period-ms` | int | Time between reads in milliseconds when no key is pressed and `CONFIG_ZMK_KSCAN_DIRECT_POLLING` is enabled | 10 |
+| `toggle-mode` | bool | Use toggle switch mode | n |
+| `wakeup-source` | bool | Mark this kscan instance as able to wake the keyboard | n |
Assuming the switches connect each GPIO pin to the ground, the [GPIO flags](https://docs.zephyrproject.org/3.5.0/hardware/peripherals/gpio.html#api-reference) for the elements in `input-gpios` should be `(GPIO_ACTIVE_LOW | GPIO_PULL_UP)`:
@@ -133,16 +133,16 @@ Applies to: `compatible = "zmk,kscan-gpio-matrix"`
Definition file: [zmk/app/module/dts/bindings/kscan/zmk,kscan-gpio-matrix.yaml](https://github.com/zmkfirmware/zmk/blob/main/app/module/dts/bindings/kscan/zmk%2Ckscan-gpio-matrix.yaml)
-| Property | Type | Description | Default |
-| ------------------------- | ---------- | ----------------------------------------------------------------------------------------------------------- | ----------- |
-| `row-gpios` | GPIO array | Matrix row GPIOs in order, starting from the top row | |
-| `col-gpios` | GPIO array | Matrix column GPIOs in order, starting from the leftmost row | |
-| `debounce-press-ms` | int | Debounce time for key press in milliseconds. Use 0 for eager debouncing. | 5 |
-| `debounce-release-ms` | int | Debounce time for key release in milliseconds. | 5 |
-| `debounce-scan-period-ms` | int | Time between reads in milliseconds when any key is pressed. | 1 |
-| `diode-direction` | string | The direction of the matrix diodes | `"row2col"` |
-| `poll-period-ms` | int | Time between reads in milliseconds when no key is pressed and `CONFIG_ZMK_KSCAN_MATRIX_POLLING` is enabled. | 10 |
-| `wakeup-source` | bool | Mark this kscan instance as able to wake the keyboard from deep sleep | n |
+| Property | Type | Description | Default |
+| ------------------------- | ---------- | ---------------------------------------------------------------------------------------------------------- | ----------- |
+| `row-gpios` | GPIO array | Matrix row GPIOs in order, starting from the top row | |
+| `col-gpios` | GPIO array | Matrix column GPIOs in order, starting from the leftmost row | |
+| `debounce-press-ms` | int | Debounce time for key press in milliseconds. Use 0 for eager debouncing | 5 |
+| `debounce-release-ms` | int | Debounce time for key release in milliseconds | 5 |
+| `debounce-scan-period-ms` | int | Time between reads in milliseconds when any key is pressed | 1 |
+| `diode-direction` | string | The direction of the matrix diodes | `"row2col"` |
+| `poll-period-ms` | int | Time between reads in milliseconds when no key is pressed and `CONFIG_ZMK_KSCAN_MATRIX_POLLING` is enabled | 10 |
+| `wakeup-source` | bool | Mark this kscan instance as able to wake the keyboard | n |
The `diode-direction` property must be one of:
@@ -198,7 +198,7 @@ Definition file: [zmk/app/module/dts/bindings/kscan/zmk,kscan-gpio-charlieplex.y
| `debounce-release-ms` | int | Debounce time for key release in milliseconds. | 5 |
| `debounce-scan-period-ms` | int | Time between reads in milliseconds when any key is pressed. | 1 |
| `poll-period-ms` | int | Time between reads in milliseconds when no key is pressed and `interrupt-gpois` is not set. | 10 |
-| `wakeup-source` | bool | Mark this kscan instance as able to wake the keyboard from deep sleep | n |
+| `wakeup-source` | bool | Mark this kscan instance as able to wake the keyboard | n |
Define the transform with a [matrix transform](layout.md#matrix-transform). The row is always the driven pin, and the column always the receiving pin (input to the controller).
For example, in `RC(5,0)` power flows from the 6th pin in `gpios` to the 1st pin in `gpios`.
@@ -335,3 +335,29 @@ Definition file: [zmk/app/dts/bindings/zmk,kscan-mock.yaml](https://github.com/z
| `exit-after` | bool | Exit the program after running all events | false |
The `events` array should be defined using the macros from [app/module/include/dt-bindings/zmk/kscan_mock.h](https://github.com/zmkfirmware/zmk/blob/main/app/module/include/dt-bindings/zmk/kscan_mock.h).
+
+## Kscan Sideband Behavior Driver
+
+The Kscan sideband behaviors node can be used to assign behaviors to keys in a manner distinctly separate from the keymap. These assignments and definitions will not be affected by nor have any effect on the keymap.
+
+### Devicetree
+
+Applies to: `compatible = "zmk,kscan-sideband-behaviors"`
+
+Definition file: [zmk/app/dts/bindings/kscan/zmk,matrix-transform.yaml](https://github.com/zmkfirmware/zmk/blob/main/app/dts/bindings/kscan/zmk%2Ckscan-sideband-behaviors.yaml)
+
+| Property | Type | Description |
+| --------------- | ------- | --------------------------------------------------------- |
+| `kscan` | phandle | Phandle to a kscan containing keys to assign behaviors to |
+| `auto-enable` | bool | Enables the sideband instance on startup unconditionally |
+| `wakeup-source` | bool | Mark this kscan instance as able to wake the keyboard |
+
+If `auto-enable` is not set, then the sideband behavior will wait for an external activation source before being enabled, e.g. being assigned as the chosen `zmk,kscan`. The `kscan` can contain additional keys, which will be used by the keymap if this node is set as the chosen `zmk,kscan` and has an appropriate matrix transformation defined.
+
+Each child node should have the following properties:
+
+| Property | Type | Description | Default |
+| ---------- | ------------- | ------------------------------------------------------------------------------------- | ------- |
+| `row` | int | The row index of the key in the `kscan` to intercept and trigger a behavior for | 0 |
+| `column` | int | The column index of the key in the `kscan` to intercept and trigger a behavior for | |
+| `bindings` | phandle-array | The behavior that should be triggered when the matching row and column event triggers | |
diff --git a/docs/docs/config/power.md b/docs/docs/config/power.md
index 6e6a56e76b..df889ed33f 100644
--- a/docs/docs/config/power.md
+++ b/docs/docs/config/power.md
@@ -6,35 +6,20 @@ sidebar_label: Power Management
See [Configuration Overview](index.md) for instructions on how to
change these settings.
-## Idle/Sleep
+## Low Power States
-Configuration for entering low power modes when the keyboard is idle.
-
-In the idle state, peripherals such as displays and lighting are disabled, but the keyboard remains connected to Bluetooth so it can immediately respond when you press a key.
-
-In the deep sleep state, the keyboard additionally disconnects from Bluetooth and any external power output is disabled. This state uses very little power, but it may take a few seconds to reconnect after waking.
-
-### Kconfig
-
-Definition file: [zmk/app/Kconfig](https://github.com/zmkfirmware/zmk/blob/main/app/Kconfig)
-
-| Config | Type | Description | Default |
-| ------------------------------- | ---- | ----------------------------------------------------- | ------- |
-| `CONFIG_ZMK_IDLE_TIMEOUT` | int | Milliseconds of inactivity before entering idle state | 30000 |
-| `CONFIG_ZMK_SLEEP` | bool | Enable deep sleep support | n |
-| `CONFIG_ZMK_IDLE_SLEEP_TIMEOUT` | int | Milliseconds of inactivity before entering deep sleep | 900000 |
-
-## Soft Off
-
-The [soft off feature](../features/soft-off.md) allows turning the keyboard on/off from either dedicated hardware, or using the [`&soft_off` behavior](../keymaps/behaviors/soft-off.md) to turn off and a reset button to turn back on again.
+Configuration for entering [low power states](../features/low-power-states.md) when the keyboard is idle.
### Kconfig
Definition file: [zmk/app/Kconfig](https://github.com/zmkfirmware/zmk/blob/main/app/Kconfig)
-| Config | Type | Description | Default |
-| ------------------------ | ---- | ------------------------------------------------------------------- | ------- |
-| `CONFIG_ZMK_PM_SOFT_OFF` | bool | Enable soft off functionality from the keymap or dedicated hardware | n |
+| Config | Type | Description | Default |
+| ------------------------------- | ---- | ------------------------------------------------------------------- | ------- |
+| `CONFIG_ZMK_IDLE_TIMEOUT` | int | Milliseconds of inactivity before entering idle state | 30000 |
+| `CONFIG_ZMK_SLEEP` | bool | Enable deep sleep support | n |
+| `CONFIG_ZMK_IDLE_SLEEP_TIMEOUT` | int | Milliseconds of inactivity before entering deep sleep | 900000 |
+| `CONFIG_ZMK_PM_SOFT_OFF` | bool | Enable soft off functionality from the keymap or dedicated hardware | n |
## External Power Control
@@ -56,3 +41,33 @@ Applies to: `compatible = "zmk,ext-power-generic"`
| --------------- | ---------- | ------------------------------------------------------------- |
| `control-gpios` | GPIO array | List of GPIOs which should be active to enable external power |
| `init-delay-ms` | int | number of milliseconds to delay after initializing the driver |
+
+## GPIO Key Wakeup Trigger
+
+A device similar to a [kscan](./kscan.md) which will be enabled only when the keyboard is entering [soft off](../features/low-power-states.md#soft-off) state. This is used to configure a GPIO key to wake the keyboard from [soft off](../features/low-power-states.md#soft-off) once it is pressed.
+
+### Devicetree
+
+Applies to: `compatible = "zmk,gpio-key-wakeup-trigger"`
+
+Definition file: [zmk/app/dts/bindings/zmk,gpio-key-wakeup-trigger.yaml](https://github.com/zmkfirmware/zmk/blob/main/app/dts/bindings/zmk%2Cgpio-key-wakeup-trigger.yaml)
+
+| Property | Type | Description |
+| --------------- | ---------- | --------------------------------------------------------------------------------------------- |
+| `trigger` | phandle | Phandle to a GPIO key to be used to wake from soft off |
+| `wakeup-source` | bool | Mark this device as able to wake the keyboard |
+| `extra-gpios` | GPIO array | list of GPIO pins (including the appropriate flags) to set active before going into power off |
+
+The `wakeup-source` property should always be present for this node to be useful. The `extra-gpios` property should be used to ensure the GPIO pin will trigger properly to wake the keyboard. For example, for a `col2row` matrix kscan, these are the column pins relevant for soft off.
+
+## Soft Off Wakeup Sources
+
+Selects a list of devices to enable during [soft off](../features/low-power-states.md#soft-off), allowing those with `wakeup-source` as a property to wake the keyboard.
+
+### Devicetree
+
+Applies to: `compatible = "zmk,soft-off-wakeup-sources"`
+
+| Property | Type | Description |
+| ---------------- | ------------- | ------------------------------------------------------------------------------------------------- |
+| `wakeup-sources` | phandle array | List of devices to enable during the shutdown process to be sure they can later wake the keyboard |
diff --git a/docs/docs/development/hardware-integration/includes/_gpio-key-direct.md b/docs/docs/development/hardware-integration/includes/_gpio-key-direct.md
new file mode 100644
index 0000000000..2e36474488
--- /dev/null
+++ b/docs/docs/development/hardware-integration/includes/_gpio-key-direct.md
@@ -0,0 +1,14 @@
+Here is an example for a keyboard with a dedicated on/off push button that is a direct wire between the GPIO pin and ground:
+
+```dts
+/ {
+ keys {
+ compatible = "gpio-keys";
+ soft_off_gpio_key: soft_off_gpio_key {
+ gpios = <&gpio0 2 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>;
+ };
+ };
+};
+```
+
+In the above example the soft on/off would be triggered by pulling the specified pin low, typically by pressing a switch that has the other leg connected to ground.
diff --git a/docs/docs/development/hardware-integration/includes/_gpio-key-matrix.md b/docs/docs/development/hardware-integration/includes/_gpio-key-matrix.md
new file mode 100644
index 0000000000..d4fbe44c9e
--- /dev/null
+++ b/docs/docs/development/hardware-integration/includes/_gpio-key-matrix.md
@@ -0,0 +1,14 @@
+Here is an example for a keyboard with a GPIO pin that reads from the matrix:
+
+```dts
+/ {
+ keys {
+ compatible = "gpio-keys";
+ soft_off_gpio_key: soft_off_gpio_key {
+ gpios = <&gpio0 2 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>;
+ };
+ };
+};
+```
+
+Matrix inputs are triggered by pulling the specified pin high, typically by pressing some combination of switches which connects the matrix input to a matrix output.
diff --git a/docs/docs/development/hardware-integration/includes/_gpio-key-wakeup.md b/docs/docs/development/hardware-integration/includes/_gpio-key-wakeup.md
new file mode 100644
index 0000000000..7f8995b5bc
--- /dev/null
+++ b/docs/docs/development/hardware-integration/includes/_gpio-key-wakeup.md
@@ -0,0 +1,14 @@
+Here is an example for a keyboard with a GPIO pin reused from a matrix kscan:
+
+```dts
+/ {
+ keys {
+ compatible = "gpio-keys";
+ soft_off_gpio_key: soft_off_gpio_key {
+ gpios = <&gpio0 2 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>;
+ };
+ };
+};
+```
+
+The GPIO settings should match those in the kscan, so the above would be set to `(GPIO_ACTIVE_LOW | GPIO_PULL_UP)` for a direct kscan.
diff --git a/docs/docs/development/hardware-integration/includes/_sideband-direct.md b/docs/docs/development/hardware-integration/includes/_sideband-direct.md
new file mode 100644
index 0000000000..f59673fd04
--- /dev/null
+++ b/docs/docs/development/hardware-integration/includes/_sideband-direct.md
@@ -0,0 +1,37 @@
+### KScan sideband behavior
+
+The kscan sideband behavior driver will be used to trigger the [soft off behavior](../../../keymaps/behaviors/soft-off.md) "out of band" from the normal keymap processing. To do so, it will decorate/wrap an underlying kscan driver.
+
+With a simple direct pin setup, the [direct kscan](../../../config/kscan.md) driver can be used with a [GPIO key](#gpio-key), to make a small "side matrix":
+
+```dts
+/ {
+ wakeup_scan: wakeup_scan {
+ compatible = "zmk,kscan-gpio-direct";
+ input-keys = <&soft_off_gpio_key>;
+ wakeup-source;
+ };
+};
+```
+
+With that in place, the kscan sideband behavior will wrap the new driver:
+
+```dts
+/ {
+ side_band_behavior_triggers: side_band_behavior_triggers {
+ compatible = "zmk,kscan-sideband-behaviors";
+
+ kscan = <&wakeup_scan>;
+ auto-enable;
+ wakeup-source;
+
+ soft_off {
+ column = <0>;
+ row = <0>;
+ bindings = <&hw_soft_off>;
+ };
+ };
+};
+```
+
+As the kscan used only has a single key, both column and row are set to 0. The properties of the `kscan-sideband-behaviors` node can be found in the [appropriate configuration section](../../../config/kscan.md#kscan-sideband-behavior-driver).
diff --git a/docs/docs/development/hardware-integration/includes/_sideband-matrix.md b/docs/docs/development/hardware-integration/includes/_sideband-matrix.md
new file mode 100644
index 0000000000..2d7278018b
--- /dev/null
+++ b/docs/docs/development/hardware-integration/includes/_sideband-matrix.md
@@ -0,0 +1,66 @@
+### KScan sideband behavior
+
+The kscan sideband behavior driver will be used to trigger the [soft off behavior](../../../keymaps/behaviors/soft-off.md) "out of band" from the normal keymap processing. To do so, it will decorate/wrap an underlying kscan driver.
+
+For the matrix-integrated approach you will supplement the existing kscan matrix by adding the additional pin as another entry in
+the `row-gpios`/`col-gpios` for whichever pins are used to read the matrix state. This approach requires a matrix transform to be present. As an example, consider the following existing kscan matrix:
+
+```dts
+/ {
+ kscan: kscan {
+ compatible = "zmk,kscan-gpio-matrix";
+ diode-direction = "col2row";
+ wakeup-source;
+
+ col-gpios
+ = <&gpio0 12 GPIO_ACTIVE_HIGH>
+ , <&gpio1 9 GPIO_ACTIVE_HIGH>
+ ;
+ row-gpios
+ = <&gpio0 19 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>
+ , <&gpio0 4 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>
+ ;
+ };
+};
+```
+
+To supplement it with a soft off input, you would add another row value (without changing the matrix transform):
+
+```dts
+/ {
+ kscan: kscan {
+ compatible = "zmk,kscan-gpio-matrix";
+ diode-direction = "col2row";
+ wakeup-source;
+
+ col-gpios
+ = <&gpio0 12 GPIO_ACTIVE_HIGH>
+ , <&gpio1 9 GPIO_ACTIVE_HIGH>
+ ;
+ row-gpios
+ = <&gpio0 19 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>
+ , <&gpio0 4 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>
+ , <&gpio0 2 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>
+ ;
+ };
+};
+```
+
+With that in place, you would decorate the kscan driver:
+
+```dts
+/ {
+ side_band_behavior_triggers: side_band_behavior_triggers {
+ compatible = "zmk,kscan-sideband-behaviors";
+ wakeup-source;
+ kscan = <&kscan>;
+ soft_off {
+ column = <0>;
+ row = <2>;
+ bindings = <&hw_soft_off>;
+ };
+ };
+};
+```
+
+Critically, the `column` and `row` values would correspond to the location of the added entry. The properties of the `kscan-sideband-behaviors` node can be found in the [appropriate configuration section](../../../config/kscan.md#kscan-sideband-behavior-driver).
diff --git a/docs/docs/development/hardware-integration/includes/_sideband-wakeup-direct.md b/docs/docs/development/hardware-integration/includes/_sideband-wakeup-direct.md
new file mode 100644
index 0000000000..a3b8d565f4
--- /dev/null
+++ b/docs/docs/development/hardware-integration/includes/_sideband-wakeup-direct.md
@@ -0,0 +1,28 @@
+### KScan sideband behavior
+
+With a simple direct pin setup, the [direct kscan](../../../config/kscan.md) driver can be used with a [GPIO key](#gpio-key), to make a small "side matrix":
+
+```dts
+/ {
+ wakeup_scan: wakeup_scan {
+ compatible = "zmk,kscan-gpio-direct";
+ input-keys = <&soft_off_gpio_key>;
+ wakeup-source;
+ };
+};
+```
+
+The kscan sideband behavior needs to wrap the new driver to enable it:
+
+```dts
+/ {
+ side_band_behavior_triggers: side_band_behavior_triggers {
+ compatible = "zmk,kscan-sideband-behaviors";
+ kscan = <&wakeup_scan>;
+ auto-enable;
+ wakeup-source;
+ };
+};
+```
+
+The properties of the `kscan-sideband-behaviors` node can be found in the [appropriate configuration section](../../../config/kscan.md#kscan-sideband-behavior-driver).
diff --git a/docs/docs/development/hardware-integration/includes/_soft-off-behavior.md b/docs/docs/development/hardware-integration/includes/_soft-off-behavior.md
new file mode 100644
index 0000000000..b4377b902e
--- /dev/null
+++ b/docs/docs/development/hardware-integration/includes/_soft-off-behavior.md
@@ -0,0 +1,15 @@
+### Soft off behavior instance
+
+Behind the scenes, a hardware dedicated GPIO pin utilizes the [soft off behavior](../../../keymaps/behaviors/soft-off.md) to trigger entering the soft-off state. To use said behavior outside of a keymap, add an instance of the behavior to your `.overlay`/`.dts` file:
+
+```dts
+/ {
+ behaviors {
+ hw_soft_off: hw_soft_off {
+ compatible = "zmk,behavior-soft-off";
+ #binding-cells = <0>;
+ hold-time-ms = <2000>; // Only turn off if the key is held for 2 seconds or longer.
+ };
+ };
+};
+```
diff --git a/docs/docs/development/hardware-integration/includes/_soft-off-waker.md b/docs/docs/development/hardware-integration/includes/_soft-off-waker.md
new file mode 100644
index 0000000000..214abc970a
--- /dev/null
+++ b/docs/docs/development/hardware-integration/includes/_soft-off-waker.md
@@ -0,0 +1,16 @@
+### Soft off waker
+
+We need to add another device which will be enabled only when the keyboard is going into soft off state, and will configure the previously declared GPIO key with the correct interrupt configuration to wake the device from soft off once it is pressed.
+
+```dts
+/ {
+ wakeup_scan: wakeup_scan {
+ compatible = "zmk,gpio-key-wakeup-trigger";
+ trigger = <&soft_off_gpio_key>;
+ wakeup-source;
+ extra-gpios = <&gpio0 12 GPIO_ACTIVE_HIGH>
+ };
+};
+```
+
+The properties for the `gpio-key-wakeup-trigger` node can be found in the [appropriate configuration section](../../../config/power.md#gpio-key-wakeup-trigger).
diff --git a/docs/docs/development/hardware-integration/soft-off-setup.mdx b/docs/docs/development/hardware-integration/soft-off-setup.mdx
new file mode 100644
index 0000000000..eecee8870b
--- /dev/null
+++ b/docs/docs/development/hardware-integration/soft-off-setup.mdx
@@ -0,0 +1,158 @@
+---
+title: Adding Soft Off To A Keyboard
+sidebar_label: Soft Off Setup
+toc_max_heading_level: 2
+---
+
+import Tabs from "@theme/Tabs";
+import TabItem from "@theme/TabItem";
+
+import SoftOffBehavior from "./includes/_soft-off-behavior.md";
+import SoftOffWaker from "./includes/_soft-off-waker.md";
+import GpioKeyDirect from "./includes/_gpio-key-direct.md";
+import GpioKeyMatrix from "./includes/_gpio-key-matrix.md";
+import GpioKeyWakeup from "./includes/_gpio-key-wakeup.md";
+import SidebandDirect from "./includes/_sideband-direct.md";
+import SidebandMatrix from "./includes/_sideband-matrix.md";
+import SidebandWakeupDirect from "./includes/_sideband-wakeup-direct.md";
+
+Advanced methods of adding [soft off](../../features/low-power-states.md#soft-off) to a keyboard are detailed below. The first two tabs describe methods involving hardware changes, while the last describes the firmware changes necessary to define a single specific key switch for waking up.
+
+<Tabs groupId="advanced-methods" defaultValue="direct">
+ <TabItem value="direct" label="Direct Pin"></TabItem>
+ <TabItem value="matrix" label="Matrix Integrated Pin"></TabItem>
+ <TabItem value="wakeup" label="Wakeup-only Key Switch">
+ The exact method of reusing a key switch to wake from the soft off state
+ differs depending on whether said key switch is part of a direct GPIO kscan
+ or part of a matrix kscan.
+ <Tabs groupId="kscan-type" defaultValue="mkscan">
+ <TabItem value="dkscan" label="Direct GPIO kscan"></TabItem>
+ <TabItem value="mkscan" label="Matrix kscan"></TabItem>
+ </Tabs>
+ </TabItem>
+</Tabs>
+
+## Hardware Changes
+
+<Tabs groupId="advanced-methods" defaultValue="direct" className="secrettabs">
+ <TabItem value="direct" label="Direct Pin">
+
+ Add a direct push button between a GPIO pin and ground. This button will act as an on/off switch.
+
+ Alternatively, if you wish to integrate a dedicated GPIO pin into a key switch combination using a direct kscan, tie all of the MCU pins that you wish to combine to the dedicated GPIO pin through an OR gate. All firmware changes then follow identically to the direct push button.
+
+ </TabItem>
+ <TabItem value="matrix" label="Matrix Integrated Pin">
+ To integrate the dedicated GPIO pin into your matrix, you will need to tie multiple switch outputs in the matrix together through AND gates and connect the result to the dedicated GPIO pin. This way you can use a (hardware defined) key combination in your existing keyboard matrix to trigger soft on/off.
+
+ Ideally the switches used should be driven by the same matrix output pin so that both will be active simultaneously on the AND gate inputs. The alternative is to connect the switch to two MOSFETs that trigger both the regular matrix connect and the connect to the AND gate to ensure both pins are active/high at the same time even if scanning sets them high at different times.
+
+ </TabItem>
+ <TabItem value="wakeup" label="Wakeup-only Key Switch">
+ No hardware changes are necessary for this approach.
+ </TabItem>
+</Tabs>
+
+## Firmware Changes
+
+Several items work together to make both triggering soft off properly, and setting up the device to _wake_ from soft off work as expected.
+
+<Tabs groupId="advanced-methods" defaultValue="direct" className="secrettabs">
+ <TabItem value="direct" label="Direct Pin">
+ <SoftOffBehavior />
+ </TabItem>
+ <TabItem value="matrix" label="Matrix Integrated Pin">
+ <SoftOffBehavior />
+ </TabItem>
+ <TabItem value="wakeup" label="Wakeup-only Key Switch">
+
+### Soft off behavior
+
+For this approach, you will need to make sure that the [soft off behavior](../../keymaps/behaviors/soft-off.md) is present in your keymap, to trigger soft off.
+
+ </TabItem>
+</Tabs>
+
+### GPIO key
+
+Zephyr's basic [GPIO Key](https://docs.zephyrproject.org/3.5.0/build/dts/api/bindings/input/gpio-keys.html) concept is used to configure the soft off GPIO pin.
+{/* secrettabs hides this tab selector. GPIO key changes its "orientation" between simple pin and matrix integrated. */}
+
+<Tabs groupId="advanced-methods" defaultValue="direct" className="secrettabs">
+ <TabItem value="direct" label="Direct Pin">
+ <GpioKeyDirect />
+ </TabItem>
+ <TabItem value="matrix" label="Matrix Integrated Pin">
+ <GpioKeyMatrix />
+ </TabItem>
+ <TabItem value="wakeup" label="Wakeup-only Key Switch">
+ <GpioKeyWakeup />
+ </TabItem>
+</Tabs>
+
+GPIO keys are defined using child nodes under the `gpio-keys` compatible node. Each child needs just one property defined:
+
+- The `gpios` property should be a [phandle-array](https://docs.zephyrproject.org/3.5.0/build/dts/phandles.html#zero-or-more-nodes-with-metadata-phandle-array-type) with a fully defined GPIO pin and with the correct pull up/down and active high/low flags set.
+
+<Tabs groupId="advanced-methods" defaultValue="direct" className="secrettabs">
+ <TabItem value="direct" label="Direct Pin">
+ <SidebandDirect />
+ </TabItem>
+ <TabItem value="matrix" label="Matrix Integrated Pin">
+ <SidebandMatrix />
+ </TabItem>
+ <TabItem value="wakeup" label="Wakeup-only Key Switch">
+ <Tabs groupId="kscan-type" defaultValue="mkscan" className="secrettabs">
+ <TabItem value="dkscan" label="Direct GPIO kscan">
+ <SidebandWakeupDirect />
+ </TabItem>
+ <TabItem value="mkscan" label="Matrix kscan"></TabItem>
+ </Tabs>
+ </TabItem>
+</Tabs>
+
+<Tabs groupId="advanced-methods" defaultValue="direct" className="secrettabs">
+ <TabItem value="direct" label="Direct Pin"></TabItem>
+ <TabItem value="matrix" label="Matrix Integrated Pin">
+ You also need to update the `zmk,kscan` chosen value to point to the new kscan instance:
+
+```dts
+/ {
+ chosen {
+ ...
+ zmk,kscan = &side_band_behavior_triggers;
+ ...
+ };
+};
+```
+
+ <SoftOffWaker />
+
+ </TabItem>
+ <TabItem value="wakeup" label="Wakeup-only Key Switch">
+ <Tabs groupId="kscan-type" defaultValue="mkscan" className="secrettabs">
+ <TabItem value="dkscan" label="Direct GPIO kscan"></TabItem>
+ <TabItem value="mkscan" label="Matrix kscan"><SoftOffWaker /></TabItem>
+ </Tabs>
+ </TabItem>
+</Tabs>
+
+Finally, we will list the `wakeup_scan` device in an additional configuration section so that the ZMK soft off process knows it needs to enable this device as part of the soft off processing so it can wake the keyboard from soft off when pressed:
+
+```dts
+/ {
+ soft_off_wakers {
+ compatible = "zmk,soft-off-wakeup-sources";
+ wakeup-sources = <&wakeup_scan>;
+ };
+};
+```
+
+Here are the properties for the node:
+
+- The `compatible` property for the node must be `zmk,soft-off-wakeup-sources`.
+- The `wakeup-sources` property is a [phandle array](../../config/index.md#devicetree-property-types) pointing to all the devices that should be enabled during the shutdown process to be sure they can later wake the keyboard.
+
+:::tip
+If you add your kscan to the `wakeup-sources` array, then your keyboard will wake upon pressing any key in your kscan. Essentially, this causes `&soft_off` to behave like a behavior that puts the keyboard in deep sleep. If you choose to do so, then you can omit everything aside from the `soft_off_wakers` node.
+:::
diff --git a/docs/docs/features/low-power-states.md b/docs/docs/features/low-power-states.md
new file mode 100644
index 0000000000..4818ecd354
--- /dev/null
+++ b/docs/docs/features/low-power-states.md
@@ -0,0 +1,81 @@
+---
+title: Low Power States
+sidebar_label: Low Power States
+---
+
+## Idle
+
+In the idle state, peripherals such as displays and lighting are disabled, but the keyboard remains connected to Bluetooth so it can immediately respond when you press a key. Idle state is entered automatically after a timeout period that is [30 seconds by default](../config/power.md#low-power-states).
+
+## Deep Sleep
+
+In the deep sleep state, the keyboard enters a software power-off state. Among others, this:
+
+- Disconnects the keyboard from all Bluetooth connections
+- Disables any peripherals such as displays and lighting
+- If possible, disables external power output
+- Clears the contents of RAM, including any unsaved [Studio](studio.md) changes
+
+This state uses very little power, but it may take a few seconds to reconnect after waking. A [wakeup source](#wakeup-sources) is required to wake from deep sleep.
+
+### Config
+
+Deep sleep must be enabled via its corresponding [config](../config/power.md#low-power-states).
+
+### Wakeup Sources
+
+Using deep sleep requires `kscan` nodes to have the `wakeup-source` property to enable them to wake the keyboard, e.g.:
+
+```dts
+/ {
+ kscan: kscan {
+ compatible = "zmk,kscan-gpio-matrix";
+ diode-direction = "col2row";
+ wakeup-source;
+
+ ...
+ };
+};
+```
+
+It is recommended to add the `wakeup-source` property to `kscan` devices even if the deep sleep feature is not used -- there is no downside to it.
+
+## Soft Off
+
+The soft off feature is used to turn the keyboard on and off explicitly, rather than through a timeout like the deep sleep feature. Depending on the keyboard, this may be through a dedicated on/off push button defined in hardware, or merely through an additional binding in the keymap to turn the device off and an existing reset button to turn the device back on.
+
+The feature is intended as an alternative to using a hardware switch to physically cut power from the battery to the keyboard. This can be useful for existing PCBs not designed for wireless that don't have a power switch, or for new designs that favor a push button on/off like found on other devices. It yields power savings comparable to the deep sleep state.
+
+:::note
+
+The device enters the same software power-off state as in deep sleep, but is significantly more restrictive in the sources which can wake it. Power is _not_ technically removed from the entire system, unlike a hardware switch.
+
+:::
+
+A device can be put in the soft off state by:
+
+- Triggering a hardware-defined dedicated GPIO pin, if one exists;
+- Triggering the [soft off behavior](../keymaps/behaviors/soft-off.md) from the keymap.
+
+Once in the soft off state, the device can only be woken up by:
+
+- Triggering any GPIO pin specified to enable waking from sleep, if one exists;
+- Pressing a reset button found on the device.
+
+The GPIO pin used to wake from sleep can be a hardware-defined one, such as for a dedicated on-off push button, or it can be a single specific key switch reused for waking up (which may be accidentally pressed, e.g. while the device is being carried in a bag). To allow the simultaneous pressing of multiple key switches to trigger and exit soft off, some keyboards make use of additional hardware to integrate the dedicated GPIO pin into the keyboard matrix.
+
+### Config
+
+Soft off must be enabled via [its corresponding config](../config/power.md#low-power-states) before it can be used.
+
+### Using Soft Off
+
+If your keyboard has hardware designed to take advantage of soft off, refer to your keyboard's documentation.
+
+For keyboards which do not have such hardware, using soft off is as simple as placing the [soft off behavior](../keymaps/behaviors/soft-off.md) in your keymap and then invoking it.
+
+You can then wake up the keyboard by pressing the reset button once, and repeating this for each side for split keyboards.
+
+### Adding Soft Off to a Keyboard
+
+Please refer to the [corresponding page under hardware integration](../development/hardware-integration/soft-off-setup.mdx) for details.
diff --git a/docs/docs/features/soft-off.md b/docs/docs/features/soft-off.md
deleted file mode 100644
index 35852a5807..0000000000
--- a/docs/docs/features/soft-off.md
+++ /dev/null
@@ -1,275 +0,0 @@
----
-title: Soft Off Feature
-sidebar_label: Soft Off
----
-
-Similar to the deep sleep feature that sends the keyboard into a low power state after a certain period of inactivity, the soft off feature is used to turn the keyboard on and off explicitly. Depending on the keyboard, this may be through a dedicated on/off push button, or merely through an additional binding in the keymap to turn the device off and the existing reset button to turn the device back on.
-
-The feature is intended as an alternative to using a hardware switch to physically cut power from the battery to the keyboard. This can be useful for existing PCBs not designed for wireless that don't have a power switch, or for new designs that favor a push button on/off like found on other devices.
-
-:::note
-
-The power off is accomplished by putting the MCU into a "soft off" state. Power is _not_ technically removed from the entire system, but the device will only be woken from the state by a few possible events.
-
-:::
-
-Once powered off, the keyboard will only wake up when:
-
-- You press the same button/sequence that you pressed to power off the keyboard, or
-- You press a reset button found on the keyboard.
-
-## Config
-
-Refer to the [soft off config](../config/power.md#soft-off) for details on enabling soft off.
-
-## Soft Off With Existing Designs
-
-For existing designs, using soft off is as simple as placing the [Soft Off Behavior](../keymaps/behaviors/soft-off.md) in your keymap and then invoking it.
-
-You can then wake up the keyboard by pressing the reset button once, and repeating this for each side for split keyboards.
-
-## Hardware Changes For New Designs
-
-ZMK's dedicated soft on/off pin feature requires a dedicated GPIO pin to be used to trigger powering off, and to wake the core from the
-soft off state when it goes active again later.
-
-### Simple Direct Pin
-
-The simplest way to achieve this is with a push button between a GPIO pin and ground.
-
-### Matrix-Integrated Hardware Combo
-
-Another, more complicated option is to tie two of the switch outputs in the matrix together through an AND gate and connect that to the dedicated GPIO pin. This way you can use a key combination in your existing keyboard matrix to trigger soft on/off. To make this work best, the two switches used should both be driven by the same matrix input pin so that both will be active simultaneously on the AND gate inputs. The alternative is to connect the switch to two MOSFETs that trigger both the regular matrix connect and the connect to the AND gate to ensure both pins are active/high at the same time even if scanning sets them high at different times.
-
-## Firmware Changes For New Designs
-
-Several items work together to make both triggering soft off properly, and setting up the device to _wake_ from soft off work as expected. In addition, some small changes are needed to keep the regular idle deep sleep functionality working.
-
-### Wakeup Sources
-
-Zephyr has general support for the concept of a device as a "wakeup source", which ZMK has not previously used. Adding soft off requires properly updating the existing `kscan` devices with the `wakeup-source` property to ensure they will still work to wake the device from regular inactive deep sleep, e.g.:
-
-```
-/ {
- kscan0: kscan_0 {
- compatible = "zmk,kscan-gpio-matrix";
- label = "KSCAN";
- diode-direction = "col2row";
- wakeup-source;
-
- ...
- };
-};
-```
-
-### GPIO Key
-
-Zephyr's basic GPIO Key concept is used to configure the GPIO pin that will be used for both triggering soft off and waking the device later. Here is an example for a keyboard with a dedicated on/off push button that is a direct wire between the GPIO pin and ground:
-
-```
-/ {
- keys {
- compatible = "gpio-keys";
- soft_off_key: soft_off_key {
- gpios = <&gpio0 2 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>;
- };
- };
-};
-```
-
-GPIO keys are defined using child nodes under the `gpio-keys` compatible node. Each child needs just one property defined:
-
-- The `gpios` property should be a phandle-array with a fully defined GPIO pin and with the correct pull up/down and active high/low flags set. In the above example the soft on/off would be triggered by pulling the specified pin low, typically by pressing a switch that has the other leg connected to ground.
-
-### Soft Off Behavior Instance
-
-To use the [soft off behavior](../keymaps/behaviors/soft-off.md) outside of a keymap, add an instance of the behavior to your `.overlay`/`.dts` file:
-
-```
-/ {
- behaviors {
- hw_soft_off: hw_soft_off {
- compatible = "zmk,behavior-soft-off";
- #binding-cells = <0>;
- hold-time-ms = <5000>;
- };
- };
-};
-```
-
-### KScan Sideband Behavior
-
-The kscan sideband behavior driver will be used to trigger the [soft off behavior](../keymaps/behaviors/soft-off.md) "out of band" from the normal keymap processing. To do so, it will decorate/wrap an underlying kscan driver. What kscan driver will vary for simple direct pin vs. matrix-integrated hardware combo.
-
-#### Simple direct pin
-
-With a simple direct pin setup, the The [direct kscan](../config/kscan.md) driver can be used with a GPIO key, to make a small "side matrix":
-
-```
- soft_off_direct_scan: soft_off_direct_scan {
- compatible = "zmk,kscan-gpio-direct";
- input-keys = <&on_off_key>;
- wakeup-source;
- };
-```
-
-With that in place, the kscan sideband behavior will wrap the new driver:
-
-```
-/ {
- side_band_behavior_triggers: side_band_behavior_triggers {
- compatible = "zmk,kscan-sideband-behaviors";
-
- kscan = <&soft_off_direct_scan>;
- auto-enable;
- wakeup-source;
-
- soft_off {
- column = <0>;
- row = <0>;
- bindings = <&hw_soft_off>;
- };
- };
-};
-```
-
-Finally, we will list the kscan instance in an additional configuration section so that the ZMK soft off process knows it needs to enable this device as part of the soft off processing so it can _also_ wake the keyboard from soft off when pressed:
-
-```
-/ {
- soft_off_wakers {
- compatible = "zmk,soft-off-wakeup-sources";
- wakeup-sources = <&soft_off_direct_scan>;
- };
-};
-```
-
-Here are the properties for the node:
-
-- The `compatible` property for the node must be `zmk,soft-off-wakeup-sources`.
-- The `wakeup-sources` property is a [phandle array](../config/index.md#devicetree-property-types) pointing to all the devices that should be enabled during the shutdown process to be sure they can later wake the keyboard.
-
-#### Matrix-integrated hardware combo
-
-For this case, you will supplement the existing kscan matrix, by adding the additional pin as another entry in
-the `row-gpios`/`col-gpios` for whichever pins are used to read the matrix state. For example, for an existing matrix like:
-
-```
- kscan: kscan {
- compatible = "zmk,kscan-gpio-matrix";
- wakeup-source;
- label = "KSCAN";
- debounce-press-ms = <1>;
- debounce-release-ms = <5>;
-
- diode-direction = "col2row";
-
- col-gpios
- = <&gpio0 12 (GPIO_ACTIVE_HIGH)>
- , <&gpio1 9 (GPIO_ACTIVE_HIGH)>
- ;
- row-gpios
- = <&gpio0 19 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>
- , <&gpio0 4 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>
- ;
- };
-```
-
-you would add another row value:
-
-```
- kscan: kscan {
- compatible = "zmk,kscan-gpio-matrix";
- wakeup-source;
- label = "KSCAN";
- debounce-press-ms = <1>;
- debounce-release-ms = <5>;
-
- diode-direction = "col2row";
-
- col-gpios
- = <&gpio0 12 (GPIO_ACTIVE_HIGH)>
- , <&gpio1 9 (GPIO_ACTIVE_HIGH)>
- ;
- row-gpios
- = <&gpio0 19 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>
- , <&gpio0 4 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>
- , <&gpio0 2 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>
- ;
- };
-```
-
-With that in place, you would decorate the kscan driver:
-
-```
- side_band_behavior_triggers: side_band_behavior_triggers {
- compatible = "zmk,kscan-sideband-behaviors";
- wakeup-source;
- kscan = <&kscan>;
- soft_off {
- column = <0>;
- row = <3>;
- bindings = <&hw_soft_off>;
- };
- };
-```
-
-Critically, the `column` and `row` values would correspond to the location of the added entry.
-
-Lastly, which is critical, you would update the `zmk,kscan` chosen value to point to the new kscan instance:
-
-```
- chosen {
- ...
- zmk,kscan = &side_band_behavior_triggers;
- ...
- };
-```
-
-Here are the properties for the kscan sideband behaviors node:
-
-- The `compatible` property for the node must be `zmk,kscan-sideband-behaviors`.
-- The `kscan` property is a phandle to the inner kscan instance that will have press/release events intercepted.
-
-The child nodes allow setting up the behaviors to invoke directly for a certain row and column:
-
-- The `row` and `column` properties set the values to intercept and trigger the behavior for.
-- The `bindings` property references the behavior that should be triggered when the matching row and column event triggers.
-
-### Soft Off Waker
-
-Next, we need to add another device which will be enabled only when the keyboard is going into soft off state, and will configure the previously declared GPIO key with the correct interrupt configuration to wake the device from soft off once it is pressed.
-
-```
-/ {
- wakeup_source: wakeup_source {
- compatible = "zmk,gpio-key-wakeup-trigger";
-
- trigger = <&on_off_key>;
- wakeup-source;
- };
-};
-```
-
-Here are the properties for the node:
-
-- The `compatible` property for the node must be `zmk,gpio-key-wakeup-trigger`.
-- The `trigger` property is a phandle to the GPIO key defined earlier.
-- The `wakeup-source` property signals to Zephyr this device should not be suspended during the shutdown procedure.
-- An optional `extra-gpios` property contains a list of GPIO pins (including the appropriate flags) to set active before going into power off, if needed to ensure the GPIO pin will trigger properly to wake the keyboard. This is only needed for matrix integrated combos. For those keyboards, the list should include the matrix output needs needed so the combo hardware is properly "driven" when the keyboard is off.
-
-Once that is declared, we will list it in an additional configuration section so that the ZMK soft off process knows it needs to enable this device as part of the soft off processing:
-
-```
-/ {
- soft_off_wakers {
- compatible = "zmk,soft-off-wakeup-sources";
- wakeup-sources = <&wakeup_source>;
- };
-};
-```
-
-Here are the properties for the node:
-
-- The `compatible` property for the node must be `zmk,soft-off-wakeup-sources`.
-- The `wakeup-sources` property is a [phandle array](../config/index.md#devicetree-property-types) pointing to all the devices that should be enabled during the shutdown process to be sure they can later wake the keyboard.
diff --git a/docs/docs/keymaps/behaviors/soft-off.md b/docs/docs/keymaps/behaviors/soft-off.md
index bb1f36ddac..d51a49255e 100644
--- a/docs/docs/keymaps/behaviors/soft-off.md
+++ b/docs/docs/keymaps/behaviors/soft-off.md
@@ -7,9 +7,9 @@ sidebar_label: Soft Off
The soft off behavior is used to force the keyboard into an off state. Depending on the specific keyboard hardware, the keyboard can be turned back on again either with a dedicated on/off button that is available, or using the reset button found on the device.
-Refer to the [soft off config](../../config/power.md#soft-off) for details on enabling soft off in order to use this behavior.
+Refer to the [soft off config](../../config/power.md#low-power-states) for details on enabling soft off in order to use this behavior.
-For more information, see the [Soft Off Feature](../../features/soft-off.md) page.
+For more information, see the [soft off section](../../features/low-power-states.md) of the low power states feature page.
### Behavior Binding
diff --git a/docs/sidebars.js b/docs/sidebars.js
index bc5fe8293d..6452130acc 100644
--- a/docs/sidebars.js
+++ b/docs/sidebars.js
@@ -37,7 +37,7 @@ module.exports = {
"features/split-keyboards",
"features/debouncing",
"features/battery",
- "features/soft-off",
+ "features/low-power-states",
"features/encoders",
"features/displays",
"features/backlight",
@@ -133,6 +133,7 @@ module.exports = {
"development/hardware-integration/pinctrl",
"development/hardware-integration/shift-registers",
"development/hardware-integration/encoders",
+ "development/hardware-integration/soft-off-setup",
],
},
{