mXT224S Touchscreen: Kernel Dev

Adding touchscreen support

31 Jan 2024

This is a continuation from my previous post about my journey into Linux kernel development.

Before we start, I’ll give a link to my patch. If you haven’t noticed, it’s already on v2! That’s because I’ve gotten some comments since submitting my patch. Small changes, but it’s worth going over. Since I’ve already posted v2, in this blog post I’ll be giving a rundown on how I completed v2 instead of v1.

I’ll be skipping out on some hand holding this time. If there are some things you don’t understand, look at my previous post, otherwise feel free to contact me on Mastodon. Let’s start, shall we?

inline comments for GSBI3 patch

My touchscreen in on GSBI3 (GSBI is short for Generic Serial Bus Interface), which I found out isn’t in the msm8960.dtsi. This commit essentially takes the apq8064.dtsi gsbi3 node, and copies it here. A quick look at the compatibles shows that these versions are also for the msm8960.

+		gsbi3: gsbi@16200000 {
+			compatible = "qcom,gsbi-v1.0.0";

This is where things got a bit dicey. I tried to verify the below properties in the downstream kernel, however I could only verify the following:

The rest seem to be deeply nested within gpio-msm-common.c and gpio-msm-v2.c, which seem to be the file for the interrupt controller. I could’ve spent more time verifying the following, however the properties seemed to be fine, so I decided to just try it. It worked on the first try :).

Part of the reason I had to send a v2 was because the properties weren’t organized to the new DTS coding style standard.

+			reg = <0x16200000 0x100>;
+			ranges;
+			cell-index = <3>;
+			clocks = <&gcc GSBI3_H_CLK>;
+			clock-names = "iface";
+			#address-cells = <1>;
+			#size-cells = <1>;
+			status = "disabled";
+

Same deal here. Here’s what I verified:

We reference i2c3_default_state and i2c3_sleep_state, which I’ll get to next. (Hint: it’s the #include "qcom-msm8960-pins.dtsi" at the bottom)

+			gsbi3_i2c: i2c@16280000 {
+				compatible = "qcom,i2c-qup-v1.1.1";
+				reg = <0x16280000 0x1000>;
+				pinctrl-0 = <&i2c3_default_state>;
+				pinctrl-1 = <&i2c3_sleep_state>;
+				pinctrl-names = "default", "sleep";
+				interrupts = <GIC_SPI 151 IRQ_TYPE_LEVEL_HIGH>;
+				clocks = <&gcc GSBI3_QUP_CLK>,
+					 <&gcc GSBI3_H_CLK>;
+				clock-names = "core", "iface";
+				#address-cells = <1>;
+				#size-cells = <0>;
+				status = "disabled";
+			};
+		};
 	};
 };
+#include "qcom-msm8960-pins.dtsi"

This is the new file I created: qcom-msm8960-pins.dtsi. Here we define two states for the system: when the system is on, and when the system suspends. The states can be found here downstream.

You might notice that this looks extremely different from qcom-apq8064-pins.dtsi. This is because 1) I removed everything that I didn’t need, 2) combined the pins in each state, 3) changed the properties to match downstream and 4) renamed them. It was actually because I didn’t name them according to the yaml specification that I had to submit a v2. You can find that here.

To actually see what DTS errors you have, it’s useful to read this document.

+// SPDX-License-Identifier: GPL-2.0-only
+
+&msmgpio {
+	i2c3_default_state: i2c3-default-state {
+		i2c3-pins {
+			pins = "gpio16", "gpio17";
+			function = "gsbi3";
+			drive-strength = <8>;
+			bias-disable;
+		};
+	};
+
+	i2c3_sleep_state: i2c3-sleep-state {
+		i2c3-pins {
+			pins = "gpio16", "gpio17";
+			function = "gpio";
+			drive-strength = <2>;
+			bias-bus-hold;
+		};
+	};
+};

inline comments for adding mXT224S patch

Now that we have a working GSBI node, let’s add our touchscreen (at the time I didn’t know the GSBI node was working. I had to confirm it worked if it worked with my touchscreen. But us readers are omniscient :)).

This essentially says to turn the GSBI3 into an I2C controller (bitbanged)

+&gsbi3 {
+	qcom,mode = <GSBI_PROT_I2C>;
+	status = "okay";
+};

Here we add the touchscreen. Luckily for us, we don’t have to develop a driver since Atmel maintains one. We can also use other device patches as a reference to our own (even though it has changed significantly since this patch, it’s still helpful)

The relevant downstream snippets are here: 1, 2

That leaves us with guessing when the interrupt is triggered (I just copied the reference and twiddled with it a bit when things didn’t work, but it eventually ended up being what the reference was) and the pinctrl.

+&gsbi3_i2c {
+	status = "okay";
+
+	// Atmel mXT224S touchscreen
+	touchscreen@4a {
+		compatible = "atmel,maxtouch";
+		reg = <0x4a>;
+		interrupt-parent = <&msmgpio>;
+		interrupts = <11 IRQ_TYPE_EDGE_FALLING>;
+		vdda-supply = <&pm8921_lvs6>;
+		vdd-supply = <&pm8921_l17>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&touchscreen>;
+	};
+};

And finally the pinctrl. I believe it represents the state of the interrupt, and eventually landed on something like this. This node gave me trouble initially. My panel was successfully getting detected by Linux, however I couldn’t interact with it consistently. I messed around with changing output-enable to input-enable and changing the gpio, but finally I figured something out.

&msmgpio {
+	touchscreen: touchscreen-int-state {
+		pins = "gpio11";
+		function = "gpio";
+		output-enable;
+		bias-disable;
+		drive-strength = <2>;
+	};
};

The regulator gave me a bit of trouble as well. It’s defined differently in board-8960-regulator.c and in board-express.c

Eventually, I caved into my hunch that the min microvolt should be raised since the panel was randomly powering off and not outputting anything. That helped me solve the other part of the puzzle.

 &pm8921 {
 		pm8921_l17: l17 {
-			regulator-min-microvolt = <1800000>;
+			regulator-min-microvolt = <3300000>;
 			regulator-max-microvolt = <3300000>;
 			bias-pull-down;
 		};
};

testing

evtest works fine. If your touchscreen is in a z state like mine was, you’ll see random output appearing on screen. If your panel suddenly stops outputting events and interacting with it doesn’t do anything, check your regulators.

Make sure to enable the atmel mxt224 config and CONFIG_I2C_GPIO beforehand. You might also need CONFIG_PINCTRL_MSM8960. To get extra debugging info in dmesg, enable CONFIG_DEBUG_DRIVER and/or CONFIG_DEBUG_FS. You can find more debug options here. You can also ignore this in dmesg : Direct firmware load for maxtouch.cfg failed with error -2

wrap up

As you can see, trying to mainline a device requires a bit of guesswork and luck, especially for a device this old. I’m still trying to get touchkeys working, but downstream is messy. Qualcomm has only released the datasheet for the APQ8064 and not the MSM8960. Even though these SoCs are practically the same, the differences are subtle and hard to notice, or not even present. Hopefully this doesn’t lead to something catastrophic later.

I wish companies didn’t do planned obsolescence. For very little effort, they can easily have a device last many more years.

state of device

what’s working

what’s left

This list will potentially grow later as I find more things