程序项目代做,有需求私信(小程序、网站、爬虫、电路板设计、驱动、应用程序开发、毕设疑难问题处理等)

Rockchip RK3399 - USB触摸屏接口驱动

----------------------------------------------------------------------------------------------------------------------------

开发板 :NanoPC-T4开发板
eMMC16GB
LPDDR34GB
显示屏 :15.6英寸HDMI接口显示屏
u-boot2023.04
linux6.3
----------------------------------------------------------------------------------------------------------------------------

一、触摸屏接口分类

触摸屏主要包括电阻触摸屏和电容触摸屏,这个我们在linux驱动移植-LCD触摸屏设备驱动》中已经详细介绍了,这里不再重复介绍。

linux驱动移植-LCD触摸屏设备驱动》这篇文章中我们介绍了SoC S3C2440触摸屏驱动的实现,对于S3C2440来说,其只支持四线电阻触摸屏。在测试时我们使用的LCD型号为LCD-T35(TD035STEB4),其4线连接在S3C2440AIN4~AIN7引脚上,通过AIN4~AIN7引脚来接收模拟输入信号。

在驱动程序中,我们通过接收触摸屏按下/松开中断,在中断处理程序中获取ADC采样值,计算X/Y坐标,并上报坐标、点击等事件。

当前市面上使用的触摸屏一般都使用了I2C接口,当然也有SPIUSB等接口。同时支持多点触摸,那什么是多点触摸呢?

顾名思义,多点触摸技术指的是允许用户同时通过多个手指来控制图形界面的一种技术,与多点触摸技术相对应的当然就是单点触摸。

1.1 I2C 接口触摸屏

首先,需要了解I2C触摸屏的工作原理。I2C触摸屏是一种通过I2C接口连接到SoC的输入设备,它的工作原理类似于普通的触摸屏。一般来言,I2C触摸屏内部驱动板都会有一个触摸IC,比如FT5426

  • 此芯片一端连接触摸屏的模拟信号,对触摸动作采样然后AD转换;
  • 另一端通过I2C连接SoC,即将AD转换后的数据通过I2C接口发给SoC

对于I2C接口触摸屏来说:

  • 所谓的触摸驱动本质上就是I2C设备驱动;

  • 触摸IC提供了中断信号引脚,当检测到触摸信息后就会触发中断,那么就要在中断处理程序里来读取触摸信息;得到的是触摸位置绝对信息以及触摸屏是否有按下;

1.2 USB接口触摸屏

现在我手里有一个NanoPC-T4开发板,同时还有一个15.6英寸HDMI接口显示屏,并且该显示屏支持Type-C十点触摸。因此我的目标,就是移植USB触摸屏驱动到内核6.3版本上。

首先,需要了解usb触摸屏的工作原理。USB触摸屏是一种通过USB接口连接到SoC的输入设备,它的工作原理类似于普通的触摸屏。一般来言,USB触摸屏内部驱动板都会有一个USB芯片;

  • 此芯片一端连接触摸屏的模拟信号,对触摸动作采样然后AD转换;
  • 另一端通过USB连接SoC,即将AD转换后的数据通过USB接口发给SoC

linux内核中,USB HID transport layer驱动程序实现了USB接口的HID设备,其中包括USB接口的keyboards(键盘)、mice(鼠标)、joysticks(摇杆)、graphic tablets(绘图板)、触摸屏等其他的。具体来说,它会通过USB总线获取来自触摸屏的数据,并将其转换为标准的输入事件(例如按键、鼠标移动等),然后将其传递给系统。

二、多点触摸

2.1 多点触摸协议

linux内核中有一份详细的文档介绍了多点电容触摸协议,位置在Documentation/input/multi-touch-protocol.rst ,多点触摸协议又简称MT协议,MT协议又分为:

  • TypeA:适用于触摸点不能被区分或者跟踪触摸设备,此类型的设备上报原始数据,这种类型用得比较少;
  • TypeB:适用于触摸点能够被硬件追踪并区分触摸点的触摸设备,两次相同的触摸数据不上报,而是缓存在slot对象中,且通过slot更新某一个触摸点的信息;FT5626就属于才类型,一般的多点触摸IC都有此能力。

2.2 多点触摸事件

触摸点的信息是通过一系列ABS_MT事件上报给linux内核,只有ABS_MT事件用于多点触摸,ABS_MT事件定义在文件include/uapi/linux/input-event-codes.h中,相关定义为:

/*
 * 0x2e is reserved and should not be used in input drivers.
 * It was used by HID as ABS_MISC+6 and userspace needs to detect if
 * the next ABS_* event is correct or is just ABS_MISC + n.
 * We define here ABS_RESERVED so userspace can rely on it and detect
 * the situation described above.
 */
#define ABS_RESERVED            0x2e

#define ABS_MT_SLOT             0x2f    /* MT slot being modified */
#define ABS_MT_TOUCH_MAJOR      0x30    /* Major axis of touching ellipse */
#define ABS_MT_TOUCH_MINOR      0x31    /* Minor axis (omit if circular) */
#define ABS_MT_WIDTH_MAJOR      0x32    /* Major axis of approaching ellipse */
#define ABS_MT_WIDTH_MINOR      0x33    /* Minor axis (omit if circular) */
#define ABS_MT_ORIENTATION      0x34    /* Ellipse orientation */
#define ABS_MT_POSITION_X       0x35    /* Center X touch position */
#define ABS_MT_POSITION_Y       0x36    /* Center Y touch position */
#define ABS_MT_TOOL_TYPE        0x37    /* Type of touching device */
#define ABS_MT_BLOB_ID          0x38    /* Group a set of packets as a blob */
#define ABS_MT_TRACKING_ID      0x39    /* Unique ID of initiated contact */
#define ABS_MT_PRESSURE         0x3a    /* Pressure on contact area */
#define ABS_MT_DISTANCE         0x3b    /* Contact hover distance */
#define ABS_MT_TOOL_X           0x3c    /* Center X tool position */
#define ABS_MT_TOOL_Y           0x3d    /* Center Y tool position */

其中:

  • ABS_MT_SLOT:上报触摸点ID
  • ABS_MT_TRACKING_ID:为触摸点分配ID,用于轨迹跟踪;
  • ABS_MT_POSITION_X:上报触摸点X轴坐标信息;
  • ABS_MT_POSITION_Y:上报触摸点Y轴坐标信息;
  • ABS_MT_TOUCH_MAJOR:上报触摸区域长轴信息(触点椭圆形);
  • ABS_MT_WIDTH_MAJOR:上报触摸区域短轴信息(触点椭圆形);
2.2.1 TYPE A

TYPE A上报方式:

ABS_MT_POSITION_X x[0]		// 第一个点X轴坐标
ABS_MT_POSITION_Y y[0]		// 第一个点Y轴坐标
SYN_MT_REPORT               // 点与点之间使用
ABS_MT_POSITION_X x[1]      // 第二个点X轴坐标
ABS_MT_POSITION_Y y[1]      // 第二个点Y轴坐标 
SYN_MT_REPORT               // 点与点之间使用
SYN_REPORT					//同步事件

(1) 上报触摸点的X轴坐标和Y轴坐标,通过 input_report_abs函数来完成,此函数原型如下所示:

static inline void input_report_abs(struct input_dev *dev, unsigned int code, int value)
{
        input_event(dev, EV_ABS, code, value);
}

(2) 对于TYPE A类型的设备,通过input_mt_sync函数来隔离不同的触摸点数据信息,此函数原型如下所示:

tatic inline void input_mt_sync(struct input_dev *dev)
{
        input_event(dev, EV_SYN, SYN_MT_REPORT, 0);
}

此函数只有1个参数,类型为input_dev,用于指定具体的input_dev设备,input_mt_sync函数会触发同步事件SYN_MT_REPORT事件码,此事件会通知接收者获取当前触摸数据,并且准备接收下一个触摸点数据。

(3) 当所有的触摸点坐标都上传完毕以后就得发送SYN_REPORT事件,使用input_sync函数来完成;

static inline void input_sync(struct input_dev *dev)
{
        input_event(dev, EV_SYN, SYN_REPORT, 0);
}
2.2.2 TYPE B

TYPE B上报方式:

ABS_MT_SLOT 0				// 上报触摸点序号
ABS_MT_TRACKING_ID 45		// 为触摸点分配ID
ABS_MT_POSITION_X x[0]		// 上报触摸点X轴坐标信息
ABS_MT_POSITION_Y y[0]		// 上报触摸点Y轴坐标信息
ABS_MT_SLOT 1				// 以下同上
ABS_MT_TRACKING_ID 46		
ABS_MT_POSITION_X x[1]
ABS_MT_POSITION_Y y[1]
SYN_REPORT					// 同步事件

对于协议B,内核驱动应该把每一个识别出的触摸点和一个slot相关联,使用slot来传播触摸状态的改变,通过修改关联slotABS_MT_TRACKING_ID来达到对触摸点的创建,替换和销毁。

  • ABS_MT_TRACKING_ID用来跟踪触摸点属于哪一条线,如果触摸点的ID值与上一次事件中ID值相等,那么他们就属于同一条线,ID值并不是随便赋值的,而是硬件上跟踪了触摸点的轨迹,比如按下一个点硬件会跟踪这个点的ID,只要不抬起上报的点都会和这个ID相关;
  • 上报ABS_MT_TRACKING_ID -1系统会清除对应的IDslot

(1) 对于TYPE B类型的设备,上报触摸点信息的时候需要通过input_mt_slot函数来区分是哪一个触摸点,此函数原型如下所示:

static inline void input_mt_slot(struct input_dev *dev, int slot)
{
        input_event(dev, EV_ABS, ABS_MT_SLOT, slot);
}

此函数只有2个参数:

  • 第一个参数为input_dev设备;
  • 第二个参数slot用于指定当前上报的是哪个触摸点的信息;比如10点触摸,触摸设备最多可以同时支持10个触摸点,slot可以理解为是第几个触摸点;

input_mt_slot函数会触发绝对位移事件ABS_MT_SLOT事件码,此事件会告诉接收者当前正在更新的是哪个触摸点(slot)的数据。

(2) 根据Type B的要求,每个slot必须关联一个ABS_MT_TRACKING_ID,通过修改slot关联的 ABS_MT_TRACKING_ID来完成对触摸点的添加、替换或删除。具体用到的函数就是input_mt_report_slot_state;

bool input_mt_report_slot_state(struct input_dev *dev,
                                unsigned int tool_type, bool active);

其中第3个参数,active包括:

  • true:连续触摸,内核会自动分配一个ABS_MT_TRACKING_IDslot

  • false:触摸点抬起,表示某个触摸点无效了,内核会分配一个-1slot

三、测试

本节实验是在《Rockchip RK3399 -USB调试》文章的基础上进行的,因此需要先参考这篇文章进行内核和设备树的配置。

3.1 配置设备树

由于我们的触摸屏为Type C接口,而我们使用的开发板NanoPC-T4只有1个USB3.0 Type-C接口,因此我们需要将这个接口配置为HOST(主机)。

USB3.0 Type-C接口对应的USB控制器为USB3.0 OTG0(DWC3/xHCI)、对应的USB PHYUSB3.0 Type-C PHY0USB2.0 OTG PHY0

因此对应的设备树配置,包括USB3.0 OTG0(DWC3/xHCI)控制器设备树配置和USB3.0 Type-C PHY0、USB2.0 OTG PHY0设备树配置。

3.1.1 控制器配置

(1) USB3.0 OTG0(DWC3/xHCI)控制器设备节点usbdrd3_0,定义在arch/arm64/boot/dts/rockchip/rk3399.dtsi

usbdrd3_0: usb@fe800000 {
		compatible = "rockchip,rk3399-dwc3";
		#address-cells = <2>;
		#size-cells = <2>;
		ranges;
		clocks = <&cru SCLK_USB3OTG0_REF>, <&cru SCLK_USB3OTG0_SUSPEND>,
				 <&cru ACLK_USB3OTG0>, <&cru ACLK_USB3_RKSOC_AXI_PERF>,
				 <&cru ACLK_USB3>, <&cru ACLK_USB3_GRF>;
		clock-names = "ref_clk", "suspend_clk",
					  "bus_clk", "aclk_usb3_rksoc_axi_perf",
					  "aclk_usb3", "grf_clk";
		resets = <&cru SRST_A_USB3_OTG0>;
		reset-names = "usb3-otg";
		status = "disabled";
		usbdrd_dwc3_0: usb@fe800000 {
				compatible = "snps,dwc3";
				reg = <0x0 0xfe800000 0x0 0x100000>;
				interrupts = <GIC_SPI 105 IRQ_TYPE_LEVEL_HIGH 0>;
				clocks = <&cru SCLK_USB3OTG0_REF>, <&cru ACLK_USB3OTG0>,
						 <&cru SCLK_USB3OTG0_SUSPEND>;
				clock-names = "ref", "bus_early", "suspend";
				dr_mode = "otg";
				phys = <&u2phy0_otg>, <&tcphy0_usb3>;
				phy-names = "usb2-phy", "usb3-phy";
				phy_type = "utmi_wide";
				snps,dis_enblslpm_quirk;
				snps,dis-u2-freeclk-exists-quirk;
				snps,dis_u2_susphy_quirk;
				snps,dis-del-phy-power-chg-quirk;
				snps,dis-tx-ipgap-linecheck-quirk;
				power-domains = <&power RK3399_PD_USB3>;
				status = "disabled";
		};
};
3.1.2 PHY配置

(1) USB3.0 Type-C PHY0设备节点tcphy0_usb3,定义在arch/arm64/boot/dts/rockchip/rk3399.dtsi

tcphy0: phy@ff7c0000 {
		compatible = "rockchip,rk3399-typec-phy";
		reg = <0x0 0xff7c0000 0x0 0x40000>;
		clocks = <&cru SCLK_UPHY0_TCPDCORE>,
				 <&cru SCLK_UPHY0_TCPDPHY_REF>;
		clock-names = "tcpdcore", "tcpdphy-ref";
		assigned-clocks = <&cru SCLK_UPHY0_TCPDCORE>;
		assigned-clock-rates = <50000000>;
		power-domains = <&power RK3399_PD_TCPD0>;
		resets = <&cru SRST_UPHY0>,
				 <&cru SRST_UPHY0_PIPE_L00>,
				 <&cru SRST_P_UPHY0_TCPHY>;
		reset-names = "uphy", "uphy-pipe", "uphy-tcphy";
		rockchip,grf = <&grf>;
		status = "disabled";

		tcphy0_dp: dp-port {
				#phy-cells = <0>;
		};

		tcphy0_usb3: usb3-port {
				#phy-cells = <0>;
		};
};

(2) USB2.0 OTG PHY0设备节点u2phy0_otg,定义在arch/arm64/boot/dts/rockchip/rk3399.dtsi

u2phy0: usb2phy@e450 {
		compatible = "rockchip,rk3399-usb2phy";
		reg = <0xe450 0x10>;
		clocks = <&cru SCLK_USB2PHY0_REF>;
		clock-names = "phyclk";
		#clock-cells = <0>;
		clock-output-names = "clk_usbphy0_480m";
		status = "disabled";

		u2phy0_host: host-port {
				#phy-cells = <0>;
				interrupts = <GIC_SPI 27 IRQ_TYPE_LEVEL_HIGH 0>;
				interrupt-names = "linestate";
				status = "disabled";
		};

		u2phy0_otg: otg-port {
				#phy-cells = <0>;
				interrupts = <GIC_SPI 103 IRQ_TYPE_LEVEL_HIGH 0>,
							 <GIC_SPI 104 IRQ_TYPE_LEVEL_HIGH 0>,
							 <GIC_SPI 106 IRQ_TYPE_LEVEL_HIGH 0>;
				interrupt-names = "otg-bvalid", "otg-id",
								  "linestate";
				status = "disabled";
		};
};
3.1.3 电源配置

(1) USB2.0 PHY0芯片三路电源依次为VCCA0V9_S3VCCA1V8_S3VCC3V3_S3

arch/arm64/boot/dts/rockchip/rk3399-evb.dts配置vcc3v3_s3设备节点;

&i2c0 {
    ...... 

    rk808: pmic@1b {
		......

        regulators {
           
		    ......
			
            vcc3v3_s3: SWITCH_REG1 {
                regulator-always-on;
                regulator-boot-on;
                regulator-name = "vcc3v3_s3";

                regulator-state-mem {
                    regulator-off-in-suspend;
                };
            };
			
			......

        };
    };
};

完整的rk808设备节点配置参考:rk808驱动配置

(2) USB3.0 Type-C PHY0芯片三路电源和USB2.0 PHY0芯片三路电源一样。

(3) USB3.0 Type-C接口电源VBUS_TYPECRT9724GQW提供的,其输入端为VCC5V0_SYS。由GPIO4_D2引脚使能,高电平有效;

arch/arm64/boot/dts/rockchip/rk3399-evb.dts配置vbus_typec

vcc5v0_sys: vcc5v0-sys {
		compatible = "regulator-fixed";
		regulator-name = "vcc5v0_sys";
		regulator-always-on;
		regulator-boot-on;
		regulator-min-microvolt = <5000000>;
		regulator-max-microvolt = <5000000>;
};

vbus_typec: vbus-typec {
		compatible = "regulator-fixed";
		enable-active-high;
		gpio = <&gpio4 RK_PD2 GPIO_ACTIVE_HIGH>;
		pinctrl-names = "default";
		pinctrl-0 = <&vbus_typec_en>;
		regulator-name = "vbus_typec";
		vin-supply = <&vcc5v0_sys>;
};

由于vbus_typec节点配置了default状态对应的引脚配置节点为vbus_typec_en,因此需要在pinctrl节点下增加引脚配置节点vbus_typec_en,这个节点在fusb配置中介绍。

3.1.4 使能

下面介绍的都是配置在arch/arm64/boot/dts/rockchip/rk3399-evb.dts文件。

(1) 使能usbdrd3_0

通过dr_mode属性设置USB控制器的模式:

/* Configurate and Enable USB3.0/2.0 OTG Controller notifier */
&usbdrd3_0 {
	status = "okay";
};

&usbdrd_dwc3_0 {
	/* 配置dr_mode为host */
	dr_mode = "host";
	status = "okay";
};

(2) 使能tcphy0_usb3

/* Enable USB3.0 PHY */
&tcphy0 {
	status = "okay";
};

&tcphy0_usb3{
	status = "okay";
};

(3) 使能u2phy0_otg,同时配置USB2.0 OTG PHY0 phy-supply属性,用于控制USB电源VBUS

/* Enable USB2.0 PHY */
&u2phy0 {
     status = "okay";
};

&u2phy0_otg {
	phy-supply = <&vbus_typec>;
	status = "okay";
};

3.2 编译内核

亲爱的读者和支持者们,自动博客加入了打赏功能,陆陆续续收到了各位老铁的打赏。在此,我想由衷地感谢每一位对我们博客的支持和打赏。你们的慷慨与支持,是我们前行的动力与源泉。

日期姓名金额
2023-09-06*源19
2023-09-11*朝科88
2023-09-21*号5
2023-09-16*真60
2023-10-26*通9.9
2023-11-04*慎0.66
2023-11-24*恩0.01
2023-12-30I*B1
2024-01-28*兴20
2024-02-01QYing20
2024-02-11*督6
2024-02-18一*x1
2024-02-20c*l18.88
2024-01-01*I5
2024-04-08*程150
2024-04-18*超20
2024-04-26.*V30
2024-05-08D*W5
2024-05-29*辉20
2024-05-30*雄10
2024-06-08*:10
2024-06-23小狮子666
2024-06-28*s6.66
2024-06-29*炼1
2024-06-30*!1
2024-07-08*方20
2024-07-18A*16.66
2024-07-31*北12
2024-08-13*基1
2024-08-23n*s2
2024-09-02*源50
2024-09-04*J2
2024-09-06*强8.8
2024-09-09*波1
2024-09-10*口1
2024-09-10*波1
2024-09-12*波10
2024-09-18*明1.68
2024-09-26B*h10
2024-09-3010
2024-10-02M*i1
2024-10-14*朋10
2024-10-22*海10
2024-10-23*南10
2024-10-26*节6.66
2024-10-27*o5
2024-10-28W*F6.66
2024-10-29R*n6.66
2024-11-02*球6
2024-11-021*鑫6.66
2024-11-25*沙5
2024-11-29C*n2.88
posted @   大奥特曼打小怪兽  阅读(1334)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
如果有任何技术小问题,欢迎大家交流沟通,共同进步

公告 & 打赏

>>

欢迎打赏支持我 ^_^

最新公告

程序项目代做,有需求私信(小程序、网站、爬虫、电路板设计、驱动、应用程序开发、毕设疑难问题处理等)。

了解更多

点击右上角即可分享
微信分享提示