25. Linux 触摸屏驱动
Linux 触摸屏驱动开发需要理解 Linux 内核中的输入子系统(Input Subsystem)及其与用户空间的交互机制。此章节讨论 LVDS 接口的触摸屏,详细描述从设备树(DTS)的配置,到驱动注册、事件报告,再到用户空间的传递流程。
25.1 LVDS 接口简介
LVDS(Low Voltage Differential Signaling)是一种用于传输视频数据的接口,广泛用于笔记本电脑和平板显示器中。虽然 LVDS 本身用于视频信号传输,但触摸屏部分通常通过 I2C 或 SPI 或 USB 接口与主机通信。开发 Linux 触摸屏驱动时,需分别处理视频显示和触摸输入两个部分。
在Neardi RK3588设备上面, 是由mipi转LVDS接口。这里的触摸屏型号是EV101WXM-N10, DTS设置如下:
// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
/*
* Copyright (c) 2020 Rockchip Electronics Co., Ltd.
*
*/
/ {
backlight: backlight {
status="okay";
compatible = "pwm-backlight";
pwms = <&pwm7 0 25000 0>;
brightness-levels = <
0 20 20 21 21 22 22 23
23 24 24 25 25 26 26 27
27 28 28 29 29 30 30 31
31 32 32 33 33 34 34 35
35 36 36 37 37 38 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 210 211 212 213 214 215
216 217 218 219 220 221 222 223
224 225 226 227 228 229 230 231
232 233 234 235 236 237 238 239
240 241 242 243 244 245 246 247
248 249 250 251 252 253 254 255
>;
default-brightness-level = <200>;
enable-gpios = <&gpio2 RK_PC1 GPIO_ACTIVE_HIGH>;
pinctrl-names = "default";
pinctrl-0 = <&lcd_en>;
};
};
&pwm7{
status = "okay";
pinctrl-names = "active";
pinctrl-0 = <&pwm7m3_pins>;
};
/*
* mipi_dcphy0 needs to be enabled
* when dsi0 is enabled
*/
&mipi_dcphy0 {
status = "okay";
};
&dsi0_in_vp2 {
status = "disabled";
};
&dsi0_in_vp3 {
status = "okay";
};
&route_dsi0 {
status = "disabled";
connect = <&vp3_out_dsi0>;
};
&dsi0 {
status = "okay";
//rockchip,lane-rate = <854>;
enable-gpios = <&gpio1 RK_PD6 GPIO_ACTIVE_HIGH>; // lvds_pwren
reset-gpios = <&gpio1 RK_PD7 GPIO_ACTIVE_HIGH>; // lvds_rst
dsi0_panel: panel@0 {
status = "okay";
compatible = "simple-panel-dsi";
reg = <0>;
backlight = <&backlight>;
reset-delay-ms = <60>;
enable-delay-ms = <60>;
prepare-delay-ms = <60>;
unprepare-delay-ms = <60>;
disable-delay-ms = <60>;
dsi,flags = <(MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST |
MIPI_DSI_MODE_VIDEO_HBP | MIPI_DSI_MODE_LPM )>;
dsi,format = <MIPI_DSI_FMT_RGB888>;
dsi,lanes = <4>;
panel-init-sequence = [
23 02 02 27 AA
23 02 02 48 02
23 02 02 B6 20
23 02 02 01 00
23 02 02 02 20
23 02 02 03 35
23 02 02 04 30
23 02 02 05 01
23 02 02 06 0A
23 02 02 07 00
23 02 02 08 03
23 02 02 09 05
23 02 02 0A 06
23 02 02 0B 82
23 02 02 0C 22
23 02 02 0D 01
23 02 02 0E 80
23 02 02 0F 20
23 02 02 10 20
23 02 02 11 03
23 02 02 12 1B
23 02 02 13 03
23 02 02 14 01
23 02 02 15 23
23 02 02 16 40
23 02 02 17 00
23 02 02 18 01
23 02 02 19 23
23 02 02 1A 40
23 02 02 1B 00
23 02 02 1E 46
23 02 02 51 30
23 02 02 1F 10
23 02 02 2A 01
];
disp_timings0: display-timings {
native-mode = <&dsi0_timing0>;
dsi0_timing0: timing0 {
clock-frequency = <110000000>;
hactive = <1280>;
vactive = <800>;
hback-porch = <10>;
hfront-porch = <48>;
hsync-len = <1>;
vback-porch = <6>;
vfront-porch = <3>;
vsync-len = <5>;
hsync-active = <0>;
vsync-active = <0>;
de-active = <0>;
pixelclk-active = <1>;
};
};
ports {
#address-cells = <1>;
#size-cells = <0>;
port@0 {
reg = <0>;
panel_in_dsi: endpoint {
remote-endpoint = <&dsi_out_panel>;
};
};
};
};
ports {
#address-cells = <1>;
#size-cells = <0>;
port@1 {
reg = <1>;
dsi_out_panel: endpoint {
remote-endpoint = <&panel_in_dsi>;
};
};
};
};
&pinctrl {
backlight {
/* for edp and dsi2lvds */
lcd_en: lcd-en {
rockchip,pins = <2 RK_PC1 RK_FUNC_GPIO &pcfg_pull_none>;
};
};
};
25.1.1 背光控制
backlight: backlight {
status="okay";
compatible = "pwm-backlight";
pwms = <&pwm7 0 25000 0>;
// other settings...
25.1.2 PWM控制器配置
&pwm7 {
status = "okay";
pinctrl-names = "active";
pinctrl-0 = <&pwm7m3_pins>;
};
25.1.3 MIPI DSI PHY配置
&mipi_dcphy0 {
status = "okay";
};
- 表示MIPI DC PHY的状态为可用,这是MIPI DSI接口所需的物理层配置。
25.1.4 MIPI DSI配置
&dsi0 {
status = "okay";
enable-gpios = <&gpio1 RK_PD6 GPIO_ACTIVE_HIGH>; // lvds_pwren
reset-gpios = <&gpio1 RK_PD7 GPIO_ACTIVE_HIGH>; // lvds_rst
dsi0_panel: panel@0 {
status = "okay";
compatible = "simple-panel-dsi";
reg = <0>;
backlight = <&backlight>;
// other settings ...
};
...
};
status = "okay";: DSI接口可用。
enable-gpios 和 reset-gpios: 控制LVDS的使能和复位引脚。
dsi0_panel: panel@0: DSI面板节点,定义该面板的具体参数。
25.1.5 面板初始化
panel-init-sequence = [
23 02 02 27 AA
// other settings...
];
- 该序列定义了面板初始化的指令,具体数据应根据面板的规格书进行设置。
25.1.6 显示时序配置
disp_timings0: display-timings {
native-mode = <&dsi0_timing0>;
dsi0_timing0: timing0 {
clock-frequency = <110000000>;
hactive = <1280>;
vactive = <800>;
// other settings ...
};
};
25.1.7 端口配置
ports {
#address-cells = <1>;
#size-cells = <0>;
port@0 {
reg = <0>;
panel_in_dsi: endpoint {
remote-endpoint = <&dsi_out_panel>;
};
};
// other settings ...
};
- 定义端口和相应的端点,panel_in_dsi和dsi_out_panel用于描述数据流的连接。
port和endpoint的设置用于定义设备间的连接,特别是在处理多媒体(如显示和摄像头)时。
port:
port节点表示设备的一个物理或逻辑连接点。每个port可以有多个endpoint,每个endpoint负责与其他设备的连接。 每个port都有一个唯一的reg属性,用于标识其地址。
endpoint:
endpoint节点表示数据流的实际传输点。它定义了如何在设备之间传输数据,以及所需的连接信息。remote-endpoint属性用于指向另一个设备的endpoint,表示两个设备之间的数据流方向。