Configuring GPIO Wake

Hello,

What methods are available to configure a wakeable GPIO pin as a wake interrupt prior to sleeping?
Can this be done by exporting it and configuring it in the shell?

I’ve never written a kernel module, but if anybody can point me to a good starting point or simple example I would appreciate it. I assume the registers mentioned in the TRM are only accessible to kernel-level programs and are otherwise hidden by the OS.

To be a little more specific, I intend to use gpio186 (wake63) / Motion Interrupt / etc., as the wake pin. When the Jetson module is sleeping and it gets pulled high the PMC should wake the OS.

It looks like creating and compiling a new device tree file will be the best way to enable that pin to be used as a wake source. The PMC driver has a function “tegra_pmc_add_wakeup_event” which appears to use OF (Open Firmware = device tree) and looks for “nvidia,pmc-wakeup”.

Example .dts from kernel-4.4/Documentation/devicetree/bindings/arm/tegra/nvidia,tegra20-pmc.txt

/ SoC dts including file
pmc: pmc {
	compatible = "nvidia,tegra114-pmc";
	reg = <0x7000e400 0x400>;
	clocks = <&tegra_car 261>, <&clk32k_in>;
	clock-names = "pclk", "clk32k_in";
};

/ Tegra board dts file
{
	...
	pmc {
		...
		nvidia,suspend-mode = <0>;
		#nvidia,wake-cells = <3>;
		...
	};
	...
	pmic {
		...
		nvidia,pmc-wakeup = <&pmc
				PMC_WAKE_TYPE_EVENT 18 PMC_TRIGGER_TYPE_LOW>;
		...
	};
	...
	gpio-keys {
		power {
			...
			nvidia,pmc-wakeup = <&pmc
				PMC_WAKE_TYPE_GPIO 16 PMC_TRIGGER_TYPE_NONE>;
			...
		};
	};
};

In kernel-4.4/arch/arm/boot/dts/tegra124-jetson-tk1.dts (and similar tegraxx*.dts files), there is a gpio-keys section that defines a node named power and gives it the property gpio-key,wakeup.

kernel-4.4/arch/arm/boot/dts/tegra124-jetson-tk1.dts

gpio-keys {
	compatible = "gpio-keys";

	power {
		label = "Power";
		gpios = <&gpio TEGRA_GPIO(Q, 0) GPIO_ACTIVE_LOW>;
		linux,code = <KEY_POWER>;
		debounce-interval = <10>;
		gpio-key,wakeup;
	};
};

I am a complete noob to device tree, but it looks like &gpio, etc., are other nodes defined in the included device tree source files (.dtsi) and used here. The TEGRA_GPIO(bank, offset) macro is defined in one of the header files.

kernel-4.4/arch/arm/boot/dts/include/dt-bindings/gpio/tegra-gpio.h

/*
 * This header provides constants for binding nvidia,tegra*-gpio.
 *
 * The first cell in Tegra's GPIO specifier is the GPIO ID. The macros below
 * provide names for this.
 *
 * The second cell contains standard flag values specified in gpio.h.
 */

#ifndef _DT_BINDINGS_GPIO_TEGRA_GPIO_H
#define _DT_BINDINGS_GPIO_TEGRA_GPIO_H

#include <dt-bindings/gpio/gpio.h>

#define TEGRA_GPIO_BANK_ID_A 0
#define TEGRA_GPIO_BANK_ID_B 1
#define TEGRA_GPIO_BANK_ID_C 2
#define TEGRA_GPIO_BANK_ID_D 3
#define TEGRA_GPIO_BANK_ID_E 4
#define TEGRA_GPIO_BANK_ID_F 5
#define TEGRA_GPIO_BANK_ID_G 6
#define TEGRA_GPIO_BANK_ID_H 7
#define TEGRA_GPIO_BANK_ID_I 8
#define TEGRA_GPIO_BANK_ID_J 9
#define TEGRA_GPIO_BANK_ID_K 10
#define TEGRA_GPIO_BANK_ID_L 11
#define TEGRA_GPIO_BANK_ID_M 12
#define TEGRA_GPIO_BANK_ID_N 13
#define TEGRA_GPIO_BANK_ID_O 14
#define TEGRA_GPIO_BANK_ID_P 15
#define TEGRA_GPIO_BANK_ID_Q 16
#define TEGRA_GPIO_BANK_ID_R 17
#define TEGRA_GPIO_BANK_ID_S 18
#define TEGRA_GPIO_BANK_ID_T 19
#define TEGRA_GPIO_BANK_ID_U 20
#define TEGRA_GPIO_BANK_ID_V 21
#define TEGRA_GPIO_BANK_ID_W 22
#define TEGRA_GPIO_BANK_ID_X 23
#define TEGRA_GPIO_BANK_ID_Y 24
#define TEGRA_GPIO_BANK_ID_Z 25
#define TEGRA_GPIO_BANK_ID_AA 26
#define TEGRA_GPIO_BANK_ID_BB 27
#define TEGRA_GPIO_BANK_ID_CC 28
#define TEGRA_GPIO_BANK_ID_DD 29
#define TEGRA_GPIO_BANK_ID_EE 30
#define TEGRA_GPIO_BANK_ID_FF 31

#define TEGRA_GPIO(bank, offset) \
	((TEGRA_GPIO_BANK_ID_##bank * 8) + offset)

#endif

I’d really appreciate it if somebody could help explain where the bank values are coming from, because I can’t find them in the TRM. I hope I’m just overlooking something simple.

hello Fred_Z,

is there any use-case would like to detect and prevent device go into sleeping ?
how about just disable system suspend with following commands,
thanks

$ gsettings get org.gnome.desktop.session idle-delay
$ gsettings set org.gnome.desktop.session idle-delay 0
$ sudo reboot

Hi JerryChang,

The Jetson in my case will be replacing a Raspberry Pi. By my estimation, with the usage I need, the Jetson should be capable of using less power and enable a more sophisticated approach to my problem than a 100% uptime Pi because 95% of the time, nothing interesting is happening. But I only want so big of a solar panel and there is only so much power I can store in the box so I need to use it wisely. Hence the need to make the Jetson sleep when it’s not needed.

To achieve this, after nothing interesting happens for some time, the Jetson will enter deep sleep / LP0. A low power PIR will monitor its surroundings to determine when something is going on. The PIR will drive gpio186 high which should signal to the Jetson it is time to wake up.

I think the device tree approach will let me use gpio186 as a wake source the same way gpio189 (power button) seems to be enabled as a wake source. My next step is to use the same code for the power button on the motion interrupt and see how the device responds from LP0, but I am having trouble translating one button to another.

In the .dts file, the power button’s pin is described as the first pin in bank Q (which is equivalent to 128). The banks are 8 units in size and there are 32 of them ordered from “A” -> “Z” -> “AA” -> “FF” = 256 total.

tegra-124-jetson-tk1.dts has some more examples:

cd-gpios = <&gpio TEGRA_GPIO(V, 2) GPIO_ACTIVE_LOW>; /* = 21 * 8 + 2 = 170*/
power-gpios = <&gpio TEGRA_GPIO(R, 0) GPIO_ACTIVE_HIGH>; /* = 17 * 8 + 0 = 136*/
wp-gpios = <&gpio TEGRA_GPIO(Q, 4) GPIO_ACTIVE_HIGH>; /* = 16 * 8 + 4 = 132*/

Various files:

nvidia,hpd-gpio = <&gpio TEGRA_GPIO(N, 7) 1>; /* PN7 */
nvidia,panel-bl-pwm-gpio = <&gpio TEGRA_GPIO(H, 1) 0>; /* PH1 */
gps-wakeup-gpio = <&gpio TEGRA_GPIO(Q, 5) 0>;
pwdn-gpios = < &gpio TEGRA_GPIO(X, 1) GPIO_ACTIVE_HIGH  /* GMSL_IN1_PDN */
        &gpio TEGRA_GPIO(H, 2) GPIO_ACTIVE_HIGH     /* TA_TV1_TV2_ENA */
        &gpio TEGRA_GPIO(H, 5) GPIO_ACTIVE_HIGH>;   /* TA_TV3_TV4_ENA */
interrupts = <TEGRA_GPIO(V, 2) 2>; /* gpio PS3 : falling edge sensitive */
nvidia,slave-ready-gpio = <&gpio TEGRA_GPIO(I, 3) GPIO_ACTIVE_LOW>; /*PI3*/

Digging through the assorted names and numbers for the GPIO I can’t find a consistent scheme that matches up to the pinmux tables, pinmux driver, or anything else.

hello Fred_Z,

please refer to [Tegra Linux Drivern Package TX2 Adaptation Guide]-> [GPIO Changes] for the details of the GPIO mapping formula.
thanks

Hi JerryChang,

I had some success.

I decompiled the tegra210-jetson-tx1-p2597-2180-a01-devkit.dtb and inserted the following motion_wake entry into gpio-keys:

gpio-keys {
		compatible = "gpio-keys";
		gpio-keys,name = "gpio-keys";

		power {
			label = "Power";
			gpios = <0x78 0xbd 0x1>; /* px 05 */
			linux,code = <0x74>; /* KEY_POWER = 116 = 0x74 */
			gpio-key,wakeup;
			nvidia,pmc-wakeup = <0x56 0x0 0x18 0x0>; /* wake24 */
		};

		volume_down {
			label = "Volume Down";
			gpios = <0x78 0xc0 0x1>;
			linux,code = <0x72>;
		};

		volume_up {
			label = "Volume Up";
			gpios = <0x78 0xbe 0x1>;
			linux,code = <0x73>;
		};
		
		[b]motion_wake {
			label = "Motion Wake";
			gpios = <0x78 <u>0xba</u> 0x1>; /* px 02, 0xbd (power) - 0x03 = 0xba */
			linux,code = <<u>0x8f</u>>; /* KEY_WAKEUP = 143 = 0x8f */
			gpio-key,wakeup;
			nvidia,pmc-wakeup = <0x56 0x0 <u>0x3f</u> 0x0>; /* wake63 */
		};[/b]
	};
$ sudo /path/to/flash.sh -d /path/to/new/tegra210-jetson-tx1-p2597-2180-a01-devkit.dtb jetson-tx1 mmcblk0p1

Interestingly, the first time I ran this script, it flashed the old .dtb again. I changed the name of the .dtb file in 64_TX1/Linux_for_Tegra/kernel/dtb to .dtb.bak20180411 and put my newly compiled file in its place, re-ran the flash script, and it works. I can enter deep sleep and ground the pin to make the system resume.

I still have a few things to do (like invert the logic-level for the wakeup and enable the pull-down resistor for this gpio) but I think that will be relatively straightforward.

Thank you.