第5阶段:完善触摸屏

目标

支持 Goodix GT9271 多点电容触摸屏。

DTS 改动分析

Y927 触摸屏挂在 blsp_i2c5,I2C 地址 0x14,中断走 tlmm GPIO13、复位走 tlmm GPIO12,AVDD28(约 2.85V 模拟供电)由 PM8916 LDO16 提供,VDDIO(1.8V 数字 IO 供电)由 PM8916 LDO6 提供。

主线 Goodix 驱动 drivers/input/touchscreen/goodix.c 已经支持 goodix,gt9271 这条 compatible,所以不需要写驱动,只要把 DTS 写对。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
/* AVDD28 走 PM8916 LDO16,dtsi 默认未声明这条 LDO,板级要补上 */
&pm8916_rpm_regulators {
pm8916_l16: l16 {
regulator-min-microvolt = <2850000>;
regulator-max-microvolt = <2850000>;
};
};

&blsp_i2c5 {
status = "okay";

touchscreen@14 {
compatible = "goodix,gt9271";
reg = <0x14>;
interrupt-parent = <&tlmm>;
interrupts = <13 IRQ_TYPE_EDGE_FALLING>;
irq-gpios = <&tlmm 13 GPIO_ACTIVE_HIGH>;
reset-gpios = <&tlmm 12 GPIO_ACTIVE_HIGH>;
AVDD28-supply = <&pm8916_l16>;
VDDIO-supply = <&pm8916_l6>;
touchscreen-size-x = <720>;
touchscreen-size-y = <1280>;
pinctrl-names = "default";
pinctrl-0 = <&touchscreen_default>;
};
};

&tlmm {
touchscreen_default: touchscreen-default-state {
touch-pins {
pins = "gpio13"; /* IRQ */
function = "gpio";
drive-strength = <2>;
bias-pull-up;
};

reset-pins {
pins = "gpio12"; /* RESET */
function = "gpio";
drive-strength = <2>;
bias-disable;
};
};
};

⚠️ pm8916_l16msm8916-pm8916.dtsi 里默认没声明。dtsi 只把 ARM/屏幕主链路必需的 LDO(l2/l5/l6/l7/l8/l9/l11/l12/l13)注册到 pm8916_rpm_regulators;l16/l17/l18 这种边缘 LDO 谁用谁声明。漏写直接编译报错:

1
Reference to non-existent node or label "pm8916_l16"

Y927 上 AVDD28 实测 2.85V,min/max 都锁这个值即可。

⚠️ touchscreen_default pinctrl 状态必须显式定义在 &tlmm。漏写同样报 Reference to non-existent node or label "touchscreen_default"。GT9271 IRQ 引脚需要外部上拉(bias-pull-up),否则中断电平浮动;reset 是单纯输出,bias-disable 即可。

⚠️ 不要执行 i2cdetect -y 0 全总线扫描。Y927 i2c-0 上有些下游设备会卡住串口 shell,要单点测就用 i2cget

头文件需要新增

DTS 顶部必须有 <dt-bindings/interrupt-controller/irq.h>,才认 IRQ_TYPE_EDGE_FALLING 这个宏:

1
2
3
4
#include "msm8916-pm8916.dtsi"
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/input/input.h>
#include <dt-bindings/interrupt-controller/irq.h> /* 新增 */

内核配置

msm8916_defconfig 默认是 CONFIG_TOUCHSCREEN_GOODIX=m(模块),当前 initramfs 里没有 modprobe 流程,模块永远不会被加载,触摸屏不会出现在 /proc/bus/input/devices。必须把它改成 builtin:

1
2
3
4
5
cd ~/y927/linux
./scripts/config --enable TOUCHSCREEN_GOODIX
make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- olddefconfig
grep TOUCHSCREEN_GOODIX= .config
# 期望输出:CONFIG_TOUCHSCREEN_GOODIX=y

等价于直接编辑 .config

1
2
3
CONFIG_INPUT_TOUCHSCREEN=y
CONFIG_TOUCHSCREEN_GOODIX=y # ← 必须 =y,不是 =m
CONFIG_REGULATOR_FIXED_VOLTAGE=y

⚠️ 这跟第 3 阶段 DRM_MSM=m → =y 是同一个坑。msm8916_defconfig 是 postmarketOS 的 distro 默认配置,假定 rootfs 里有完整的 modprobe / udev 链路;最小 initramfs 阶段必须把所有调试要用到的驱动都做成 builtin。

完整 DTS

最终的 arch/arm64/boot/dts/qcom/msm8916-vivo-y927.dts

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
// SPDX-License-Identifier: GPL-2.0-only

/dts-v1/;

#include "msm8916-pm8916.dtsi"
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/input/input.h>
#include <dt-bindings/interrupt-controller/irq.h>

/ {
model = "vivo Y927 (PD1410V)";
compatible = "vivo,y927", "qcom,msm8916";
chassis-type = "handset";

aliases {
mmc0 = &sdhc_1; // eMMC 固化为 /dev/mmcblk0
mmc1 = &sdhc_2; // SD 卡 固化为 /dev/mmcblk1
};

usb_id: usb-id {
compatible = "linux,extcon-usb-gpio";
id-gpios = <&tlmm 110 GPIO_ACTIVE_HIGH>;
pinctrl-names = "default";
pinctrl-0 = <&usb_id_default>;
};

/* 背光(GPIO8 控制) */
backlight: backlight {
compatible = "gpio-backlight";
gpios = <&tlmm 8 GPIO_ACTIVE_HIGH>;
default-on;
};

/* LCD 偏压电源 VSP */
reg_lcd_enp: regulator-lcd-enp {
compatible = "regulator-fixed";
regulator-name = "lcd_enp";
gpio = <&tlmm 97 GPIO_ACTIVE_HIGH>;
enable-active-high;
regulator-always-on; /* lmdpdg 生成的 panel 驱动不读 vsp/vsn-supply */
regulator-boot-on; /* 必须 always-on,否则 fixed regulator 启动时被拉低,屏黑 */
};

/* LCD 偏压电源 VSN */
reg_lcd_enn: regulator-lcd-enn {
compatible = "regulator-fixed";
regulator-name = "lcd_enn";
gpio = <&tlmm 98 GPIO_ACTIVE_HIGH>;
enable-active-high;
regulator-always-on;
regulator-boot-on;
};

/* 预留 lk1st splash framebuffer 不被内核踩踏 */
reserved-memory {
cont-splash@83200000 {
reg = <0 0x83200000 0 0x800000>;
no-map;
};
};

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

pinctrl-names = "default";
pinctrl-0 = <&gpio_keys_default>;

label = "GPIO Buttons";

button-volume-up {
label = "Volume Up";
gpios = <&tlmm 107 GPIO_ACTIVE_LOW>;
linux,code = <KEY_VOLUMEUP>;
};
};
};

&usb {
dr_mode = "peripheral";
extcon = <&usb_id>, <&usb_id>;
status = "okay";
};

&usb_hs_phy {
extcon = <&usb_id>;
status = "okay";
};

&tlmm {
usb_id_default: usb-id-default {
pins = "gpio110";
function = "gpio";
drive-strength = <8>;
bias-pull-up;
};

/* DSI reset pin (GPIO25) */
mdss_default: mdss-default-state {
pins = "gpio25";
function = "gpio";
drive-strength = <8>;
bias-disable;
};
mdss_sleep: mdss-sleep-state {
pins = "gpio25";
function = "gpio";
drive-strength = <2>;
bias-pull-down;
};
gpio_keys_default: gpio-keys-default-state {
pins = "gpio107";
function = "gpio";
drive-strength = <2>;
bias-pull-up;
};

/* 触摸屏 IRQ (GPIO13) + RESET (GPIO12) */
touchscreen_default: touchscreen-default-state {
touch-pins {
pins = "gpio13";
function = "gpio";
drive-strength = <2>;
bias-pull-up;
};
reset-pins {
pins = "gpio12";
function = "gpio";
drive-strength = <2>;
bias-disable;
};
};
};

&pm8916_resin {
linux,code = <KEY_VOLUMEDOWN>;
status = "okay";
};

/* PM8916 LDO16:触摸屏 AVDD28 (2.85V)。dtsi 里默认未声明 LDO16,板级要补上。 */
&pm8916_rpm_regulators {
pm8916_l16: l16 {
regulator-min-microvolt = <2850000>;
regulator-max-microvolt = <2850000>;
};
};


&sdhc_1 {
status = "okay"; // eMMC(内部存储)
};

&sdhc_2 {
status = "okay"; // SD 卡(TF 卡槽)
cd-gpios = <&tlmm 38 GPIO_ACTIVE_LOW>;
};

/* ====== DSI 主机 + 面板 ====== */
&mdss {
status = "okay";
};

&mdss_dsi0 {
pinctrl-names = "default", "sleep";
pinctrl-0 = <&mdss_default>;
pinctrl-1 = <&mdss_sleep>;
status = "okay";

panel@0 {
compatible = "vivo,y927-hx8394a";
reg = <0>;
reset-gpios = <&tlmm 25 GPIO_ACTIVE_LOW>;
backlight = <&backlight>;
vsp-supply = <&reg_lcd_enp>;
vsn-supply = <&reg_lcd_enn>;

port {
panel_in: endpoint {
remote-endpoint = <&mdss_dsi0_out>;
};
};
};
};

/* DSI host 输出端:data-lanes + remote-endpoint 必须放在这里 */
&mdss_dsi0_out {
data-lanes = <0 1 2 3>;
remote-endpoint = <&panel_in>;
};


/* ====== 触摸屏 (Goodix GT9271 on BLSP I2C5 @ 0x14) ====== */
&blsp_i2c5 {
status = "okay";

touchscreen@14 {
compatible = "goodix,gt9271";
reg = <0x14>;
interrupt-parent = <&tlmm>;
interrupts = <13 IRQ_TYPE_EDGE_FALLING>;
irq-gpios = <&tlmm 13 GPIO_ACTIVE_HIGH>;
reset-gpios = <&tlmm 12 GPIO_ACTIVE_HIGH>;
AVDD28-supply = <&pm8916_l16>;
VDDIO-supply = <&pm8916_l6>;
touchscreen-size-x = <720>;
touchscreen-size-y = <1280>;
pinctrl-names = "default";
pinctrl-0 = <&touchscreen_default>;
};
};

GPIO 对照

GPIO 功能 方向
12 触摸 RESET 输出高有效
13 触摸 IRQ 输入下降沿

编译 Linux 内核

1
2
cd ~/y927/linux
make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- -j$(nproc) Image.gz dtbs

构建 boot.img 文件

沿用第 4.1 阶段已经打好的 initramfs-phase-4.cpio.gz(含 evtest),不必重新做 initramfs。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
cd ~/y927/linux

# 拼接内核 + DTB
cat arch/arm64/boot/Image.gz \
arch/arm64/boot/dts/qcom/msm8916-vivo-y927.dtb \
> vmlinuz-dtb

~/y927/lk2nd/lk2nd/scripts/mkbootimg \
--kernel vmlinuz-dtb \
--ramdisk $HOME/y927/initramfs/initramfs-phase-4.cpio.gz \
--cmdline "console=tty0 console=ttyMSM0,115200 panic=1 initcall_blacklist=simpledrm_platform_driver_init" \
--base 0x80000000 \
--kernel_offset 0x00008000 \
--ramdisk_offset 0x01000000 \
--second_offset 0x00f00000 \
--tags_offset 0x00000100 \
--pagesize 2048 \
--header_version 0 \
--output boot-phase5.img

刷入 boot.img 文件

1
2
fastboot flash boot boot-phase5.img
fastboot reboot

测试

1
sudo picocom -b 115200 /dev/ttyACM0

2026-06-14 13:20 触摸屏被成功识别。

1. dmesg 确认驱动 probe 成功

1
2
3
4
5
6
7
8
9
~ # busybox dmesg | busybox grep -iE "goodix|gt9|touch|input:|78b9000|l16:"
[ 0.228049] i2c_qup 78b9000.i2c: using default clock-frequency 100000
[ 0.232333] input: pm8941_pwrkey as /devices/.../pwrkey/input/input0
[ 0.233669] input: pm8941_resin as /devices/.../resin/input/input1
[ 0.348494] input: GPIO Buttons as /devices/platform/gpio-keys/input/input2
[ 0.367162] l16: Bringing 0uV into 2850000-2850000uV
[ 0.459889] Goodix-TS 0-0014: ID 9159, version: 1015
[ 0.460097] Goodix-TS 0-0014: Direct firmware load for goodix_9159_cfg.bin failed with error -2
[ 0.482771] input: Goodix Capacitive TouchScreen as /devices/.../i2c-0/0-0014/input/input3

Y927 实测芯片 ID 是 9159,不是 DTS 里写的 gt9271 —— 但 compatible = "goodix,gt9271" 是兼容字符串,主线 Goodix 驱动通过 I2C 通讯握手时会自动读取真实 chip ID 并查内置配置表,所以不影响识别。Direct firmware load for goodix_9159_cfg.bin failed with error -2 表示外部固件配置文件不存在(rootfs 里没放 /lib/firmware/goodix_9159_cfg.bin),驱动会 fallback 到芯片内部 OTP/Flash 里固化的出厂参数,依旧能正常工作。

2. /proc/bus/input/devices 多一个 Goodix Capacitive TouchScreen

1
2
3
4
5
6
7
8
9
10
11
12
~ # busybox cat /proc/bus/input/devices
...
I: Bus=0018 Vendor=0416 Product=23c7 Version=1015
N: Name="Goodix Capacitive TouchScreen"
P: Phys=input/ts
S: Sysfs=/devices/platform/soc@0/78b9000.i2c/i2c-0/0-0014/input/input3
U: Uniq=
H: Handlers=kbd event3
B: PROP=2
B: EV=b
B: KEY=400 0 0 0 2000000000000001 f800000000000000
B: ABS=265800000000003

3. 用 evtest 监听触摸事件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
~ # evtest /dev/input/event3
Input driver version is 1.0.1
Input device ID: bus 0x18 vendor 0x416 product 0x23c7 version 0x1015
Input device name: "Goodix Capacitive TouchScreen"
Supported events:
Event type 0 (EV_SYN)
Event type 1 (EV_KEY)
Event code 330 (BTN_TOUCH)
Event type 3 (EV_ABS)
Event code 0 (ABS_X)
Event code 1 (ABS_Y)
Event code 24 (ABS_PRESSURE)
Event code 47 (ABS_MT_SLOT)
Event code 48 (ABS_MT_TOUCH_MAJOR)
Event code 53 (ABS_MT_POSITION_X)
Event code 54 (ABS_MT_POSITION_Y)
...
Testing ... (interrupt to exit)

按下手指时输出形如:

1
2
3
4
Event: time 12.345, type 3 (EV_ABS), code 53 (ABS_MT_POSITION_X), value 360
Event: time 12.345, type 3 (EV_ABS), code 54 (ABS_MT_POSITION_Y), value 640
Event: time 12.345, type 1 (EV_KEY), code 330 (BTN_TOUCH), value 1
Event: time 12.345, -------------- SYN_REPORT ------------

ABS_MT_POSITION_X / ABS_MT_POSITION_Y 跟随手指移动 (0–720, 0–1280),按下/松开时 BTN_TOUCH 翻转 1/0,多点电容触摸链路全通。

提示:evtest 启动后会一直占用串口 stdin,结束时按 Ctrl+C 退出。如果 Ctrl+C 不能恢复 shell(少数情况下 evtest 还在 grab 状态),重启手机即可。