20 Jan 2024
Recently laid off from my job, and I suddenly had a lot of time left before me. Why not use that time to pursue my personal projects?
I started off by trying to mainline my touchkeys. I got this idea from toonis who mainlined cypress-sf a while back.
Even though touchkeys are relatively simple, there were a lot of moving parts. I don’t want to get too deep into it currently, as I’m planning to make another blog post about it, but making your own driver, modifying the dts, and reading downstream files was quite challenging for a beginner like me.
I don’t exactly remember how I discovered gpio-keys, but I think it was when I was referring to qcom-apq8064-asus-nexus7-flo.dts where I first saw it. It seemed like a simpler form of the touchkeys since I didn’t have to modify any drivers, so why not go ahead and add it for my device?
Looking back I’m glad I did this first. Otherwise the hiccups I encountered (described later) would’ve confused me even more.
downstream to mainline
Before we start, here’s my patch to mainline.
By playing around with the touchkeys, I learned that the board-<codename>.c file is basically the old way of doing a dts file. For me, it was board-express.c and here was the main part that I was looking at.
Now how does that translate to my patch?
inline comments for gpio-keys
gpio-keys means that this node is for the touchscreen. Just kidding. The node name is pretty self explanatory.
/ {
gpio-keys {
compatible tells us that “gpio-keys” is the driver that we want to select
compatible = "gpio-keys";
I believe the value of pinctrl-names can be arbitrary, but most dts files I found left them as “default”. pinctrl-0 should refer to the gpios in the gpio controller (inline comments for this below)
pinctrl-names = "default";
pinctrl-0 = <&gpio_keys_pin_a>;
Each subnode has a pattern:
- label = an arbitrary label describing what this is
- gpios = Consists of three things separated by spaces
- A phandle (think of it as a reference) to the GPIO controller
- GPIO number
- When should Linux consider the button has been pressed
- debounce-interval = how long it takes between presses
- linux,code = what the key does
For the Home button we add wakeup-event-action
and wakeup-source
to use it to wake the phone from suspend
Downstream, it’s defined here and I got the GPIO numbers from here. I think it’s pretty simple to match them up with the definitions in the DTS.
Here’s the documentation to learn more. You can also look at similar DTS files to your own to see how to approach it
key-home {
label = "Home";
gpios = <&msmgpio 40 GPIO_ACTIVE_LOW>;
debounce-interval = <5>;
linux,code = <KEY_HOMEPAGE>;
wakeup-event-action = <EV_ACT_ASSERTED>;
wakeup-source;
};
key-volume-up {
label = "Volume Up";
gpios = <&msmgpio 50 GPIO_ACTIVE_LOW>;
debounce-interval = <5>;
linux,code = <KEY_VOLUMEUP>;
};
key-volume-down {
label = "Volume Down";
gpios = <&msmgpio 81 GPIO_ACTIVE_LOW>;
debounce-interval = <5>;
linux,code = <KEY_VOLUMEDOWN>;
};
};
};
inline comments for gpio controller
msmgpio is the GPIO controller. My phone has a couple of interrupt controllers like this, so how do I verify this? You can do cat /proc/interrupts
and see what controller is being used. For me it was the following:
- 328: 0 msmgpio Home
- 338: 0 msmgpio Vol Up
- 369: 0 msmgpio Vol Down
Note: Mainline can be labeled differently, but this should help you start searching for the controller downstream. I got lucky in this case.
&msmgpio {
For this to make sense, you have to look at my downstream code
- pins = GPIOs that we want to use
- function = .func in downstream
- bias-diable = .pull in downstream
- drive-strength = .drv in downstream
gpio_keys_pin_a: gpio-keys-active-state {
pins = "gpio40", "gpio50", "gpio81";
function = "gpio";
bias-disable;
drive-strength = <8>;
};
};
configs to enable
Now that I got an updated DTS, I tried testing with evtest (more below), but it didn’t work. Here are the two problems I ran into, and their solutions
cat /sys/kernel/debug/devices_deferred
- Needed to add CONFIG_DEBUG_FS. This was because I saw gpio-keys being deferred in dmesg, and this would explain why it was being deferred.
- PINCTRL_MSM8960
cat /sys/kernel/debug/devices_deferred
outputs something likegpio-keys platform: wait for supplier /soc/pinctrl@800000/gpio-keys-active-state
. If you look above,gpio-keys-active-state
is under&msmgpio
. Looking in the dtsi where themsmgpio
is defined, I saw this compatible. Next search for where this compatible is defined, in this case it was this driver. Then you go into the Makefile in that directory and see what Kconfig enable that. For me it was this
testing with evtest
Finally tested with evtest. You can either compile it statically for your platform of choice, or install it from postmarketOS/$DISTRO when packaging up your kernel. It’s has a pretty simple interface and should show you a list of inputs, if any are detected.
You can also refer to this and this for more information
thanks
Huge thanks to Alexey Min for helping me! He helped me in the configs to enable
section and helped me understand that drive-strength
can take a value.
next post
Here’s my next post in this series