GPIOs
Last updated
Last updated
if we take a look at the ACPI table we see several GpioIO functions.
Identifying the Volume keys is easy. We can dump the GPIO-Controller from UEFI shell while a volume key is pressed or released.
We see that we changed something with a button press. Nice! We see that 1 Byte has changed from 0xC0 to 0x80 at address 0x438 In binary: 1100 0000 -> 1000 0000 => Bit 6 has changed.
Lets take a look at 0x438
Now we know that we changed Pin6 in Port S => Vol-Down is connected to PS6
S is the 19th letter of the Alphabet counting from 1 (A=1, B=2, C=3,...) S is the 18th letter of the Alphabet counting from 0 (A=0, B=1, C=2,...) TRM tells us that every port has 8 pins. So lets multiply 18 by 8 which equals 144 and add our PinOffset: 6 144+6 = 150 Convert 150 from dec to hex: 0x96
We can match the 4 GPIOs to the SurfaceHomeButtonDriver. We can see that Windows knows 4 Interrupts. At the moment we dont know how to map the WindowsIRQ to ACPI-IRQ or LinuxIRQ
Linux enumerates GPIO in the same way as ACPI:
portNumber * 8 + pinOffset (+ gpioControllerOffset)
(gpioControllerOffset is 0 on tegra 3)
We know that we deal with:
Vol-Down: 0x96 / 150d
Vol-Up: 0x97 / 151d
We guess 0x97 because it is a normal shared interrupt.
The other 2 interrupts are WakeUp Interrupts which should belong to the Power/WindowsButton
include libgpiod
in your root filesystem
type gpiomon <BUS> <Gpio-Number>
Press the button a few times you should see the gpio chaning in realtime
first we must set the pins to GPIO mode. Tegra standard is SFIO mode. 0x6000 d000 is the GPIO Controller base 0x0000 0408 is PortS CNF register. We want to set pin 6/7 to GPIO mode -> 0b1100 0000 -> 0xC0
we can write memory with devmem
devmem 0x6000d408 8 0xC0
Now the GPIO Controller treats PS6/7 as GPIO
cd /sys/class/gpio
ls ./
should show export, gpiochip0, unexport
gpiochip0 is the gpio controller; 0 tells the offset
we can export a pin to userspace
echo 150 > export
echo 151 > export
Now we can use PS6/7
check the direction with
cat gpio150/direction
it should show "in"
but you can set it with echo in > gpio150/direction
Now we can read the value
cat gpio150/value
this should return 1
if you press VOL-Down it should return 0
This tells us that the pin is pulled up and active_low.
Now remove the gpio from userspace that it can be used by drivers again
echo 150 > unexport
echo 151 > unexport