荔枝派Dock驱动DSI屏幕(十二)

目录

一. LCD的驱动

二. 荔枝派Dock驱动MIPI屏幕

2.1 内核配置

2.2 设备树配置

2.3 LCD驱动

2.4 测试屏幕

2.4.1 花屏测试

2.4.2 colorbar 测试

2.4.3 获取屏幕的图层信息,帧率等等

2.4.4 特殊情况

2.4.4.1 屏幕花屏

2.4.4.2 屏幕时序参数之前一直调整错误

2.5 添加开机LOGO

2.6 触摸测试

2.6.1 检查Kconfig和Makefile

2.6.2 make menuconfig

2.6.3 make kernel_menuconfig

2.6.4 设备树dts修改

2.6.5 TWI配置

2.6.6 成功实现触摸

2.6.6.1 启动即加载edt_ft5x06.ko

2.6.6.2 查看系统连接的触摸设备

2.6.6.3 使用getevent工具

2.7 特殊情况

2.7.1 IIC引脚为输入状态

2.7.2 但是我IIC在启动时还是报错

2.7.3 查看iic设备节点

2.7.4 edt_ft5x06 请求中断错误

2.7.5 vcc和iovdc报错

2.7.6 坐标不对

四. 参考资料


因为Lichee RV Dock 店家提供的镜像文件只能驱动RGB屏,并且也不满足项目要求。因此我是单独购买的适配树莓派的15线MIPI屏幕,下面是店家的链接:

树莓派4.3寸5寸7寸电容触摸屏MIPI DSI接口屏I2C触摸Raspberry Pi-淘宝网 (taobao.com)

一. LCD的驱动

显示驱动可以划分为三个层面:驱动层,框架层及底层底层与图形硬件相连接,主要负责将上层配置的功能参数转换成硬件所需要的参数,并配置到相应寄存器中。

显示框架层对底层进行抽象封装成一个的功能模块。驱动层对外封装功能接口,通过内核向用户空间提供相应的设备结点及统一的接口

在驱动层,分为三个驱动,分别是framebuffer驱动,display驱动,LCD&HDMI驱动framebuffer 驱动与 framebuffer core 对接,实现 linux 标准的framebuffer 接口。display驱动时整个显示驱动中的核心驱动模块,所有的接口都由display驱动来提供,包括lcd的接口

二. 荔枝派Dock驱动MIPI屏幕

2.1 内核配置

make kernel_menuconfig

│ Symbol: LCD_SUPPORT_TFT08006 [=y]                                                                                                                                                                     │
  │ Type  : bool                                                                                                                                                                                          │
  │ Prompt: LCD support TFT08006 panel                                                                                                                                                                    │
  │   Location:                                                                                                                                                                                           │
  │     -> Device Drivers                                                                                                                                                                                 │
  │       -> Graphics support                                                                                                                                                                             │
  │         -> Frame buffer Devices                                                                                                                                                                       │
  │           -> Video support for sunxi                                                                                                                                                                  │
  │ (1)         -> LCD panels select                                                                                                                                                                      │
  │   Defined at drivers/video/fbdev/sunxi/disp2/disp/lcd/Kconfig:178                                                                                                                                     │
  │   Depends on: HAS_IOMEM [=y] && FB [=y] && DISP2_SUNXI [=y]   

目录下其它项可以全部取消选择

2.2 设备树配置

1. 第一部分,决定该配置是否使用,以及使用哪个屏驱动,lcd_driver_name 决定了用哪个屏 驱动来初始化。

2. 第二部分,决定该配置是 dsi 接口,而且 dsi 接口使用的是 video mode。

3. 第三部分,决定了 SoC 中的 LCD 模块发送时序,请查看屏时序参数说明。

4. 第四部分,背光相关的设置。请看背光相关参数。

5. 第五部分,dsi 接口的详细设置。

6. 第六部分,显示效果相关的设置。

7. 第七部分,管脚和电源设置。请看电源和管脚参数。

&lcd0 {
	lcd_used            = <1>;

	lcd_driver_name     = "tft08006";
	lcd_backlight       = <100>;
	lcd_if              = <4>;
	//0:Video mode:实时刷屏,有ht,hbp等时序参数的定义
	lcd_dsi_if          = <0>;

	lcd_x               = <800>;
	lcd_y               = <480>;
	lcd_width           = <52>;
	lcd_height          = <52>;
	//lcd_dclk_freq=lcd_ht*lcd_vt*fps
	lcd_dclk_freq       = <26>;


	// lcd_pwm_used        = <1>;
	// lcd_pwm_ch          = <2>;
	// lcd_pwm_freq        = <1000>;
	// lcd_pwm_pol         = <0>;
	// lcd_pwm_max_limit   = <255>;


	/*
	由下面两条公式得知,我们不需要设置lcd_hfp和lcd_vfp参数,因为驱动会自动根据其它几个已知
	参数中算出lcd_hfp和lcd_vfp。
	lcd_ht = lcd_x + lcd_hspw + lcd_hbp + lcd_hfp
	lcd_vt = lcd_y + lcd_vspw + lcd_vbp + lcd_vf
	*/
	lcd_hbp             = <46>;
	lcd_ht              = <900>;
	lcd_hspw            = <4>;
	lcd_vbp             = <21>;
	lcd_vt              = <550>;
	lcd_vspw            = <4>;

	//1:1 data lane
	lcd_dsi_lane        = <1>;
	//0:Package Pixel Stream,24bit RGB
	lcd_dsi_format		= <0>;
	//0:frame trigged automatically
	//刷屏时间为lcd_ht x lcd_vt
	lcd_dsi_te			= <0>;

	//0:一个port
	lcd_dsi_port_num	= <0>;
	//0:normal mode
	lcd_tcon_mode 		= <0>;
	//0:中断自动根据时序,由场消隐信号内部触发
	lcd_cpu_mode		= <0>;
	//0:Single Link(1 clock pair+3/4 data pair)
	// lcd_lvds_if         = <0>;
	// //0:8bit per color(4 data pair)
	// lcd_lvds_colordepth = <0>;
	// lcd_lvds_mode       = <0>;
	//0:RGB888 --- RGB888 direct
	lcd_frm             = <0>;
	//这些参数只有在 lcd_if=0 时才有效
	// lcd_hv_clk_phase    = <0>;
	//0:vsync active low,hsync active low
	//lcd_hv_sync_polarity= <0>;
	lcd_io_phase        = <0x0000>;
	//0:Lcd的Gamma校正功能关闭
	lcd_gamma_en        = <0>;
	lcd_bright_curve_en = <0>;
	//0:Lcd的色彩映射功能关闭
	lcd_cmap_en         = <0>;
	//0:disable
	lcd_fsync_en        = <0>;
	//LCD 的 fsync 功能,其中的有效电平时间长度,单位:像素时钟的个数。
	lcd_fsync_act_time  = <1000>;
	//无效电平时间长度
	lcd_fsync_dis_time  = <1000>;
	//0:有效电平为低
	lcd_fsync_pol       = <0>;

	deu_mode            = <0>;
	lcdgamma4iep        = <22>;
	smart_color         = <90>;

/*	lcd_gpio_0 =  <&pio PG 13 GPIO_ACTIVE_HIGH>;*/
	pinctrl-0 = <&dsi2lane_pins_a>;
	pinctrl-1 = <&dsi2lane_pins_b>;
};

lcd_ht = lcd_x +HFP+lcd_hbp+lcd_hspw

lcd_vt = lcd_y  +VFP+lcd_vbp +lcd_vspw

Tina SDK 2.0有一个限制,就是spw不得小于等于3,否则卡住。

2.3 LCD驱动

LCD显示屏与其他驱动不一样,LCD屏幕种类繁多,接口丰富,各式各样屏幕参数层出不穷,所以LCD屏幕驱动都是以单独的模块存在的,驱动文件位于:

kernel/linux-4.9/drivers/video/fbdev/sunxi/disp2/disp/lcd

从接口上来分,LCD 屏幕可以分为 RGB 屏幕,LVDS 屏幕,MIPI DSI 屏幕,eDP 屏幕、SPI 屏幕、IIC 屏幕。

我们项目中使用的是MIPI屏

MIPI-DSI 的管脚是差分的,分为两种管脚:一种是时钟管脚,另外一种是数据管脚

数据管脚的数量是可变的,数量的单位是 lane ,lane 也指一对差分管脚,每一条 lane 实际包含两条线。一般来说 LCD 屏说明书里面的说的 lane 的数量是指数据管脚的数量不包括时钟管脚。比如说某 4 lane MIPI-DSI 屏就总共有 (4+1)*2 根脚,也就是4对数据差分管脚,一对时钟差分管脚

2.4 测试屏幕

我们先关闭 Uboot 的屏幕驱动,保留 Kernel 的驱动方便调试

先前往 Uboot 配置文件夹修改配置文件关闭屏幕驱动。

brandy/brandy-2.0/u-boot-2018/configs/sun8iw21p1_defconfig

把 CONFIG_DISP2_SUNXI=y 注释了

之后就可以编译镜像了,生成镜像烧录到SD上,在板子上运行即可

2.4.1 花屏测试

cat /dev/urandom > /dev/fb0

这个测试一定会显示 cat: write error: No space left on device ,这样才是正常情况,因为 FB0 可以类比为屏幕的显存,显存是固定大小的可以被消耗完,当显存填满的时候就会报错 No space left on device。如果执行这一行命令一直没出现这个报错则有可能底层显示驱动配置有问题。

2.4.2 colorbar 测试

echo 8 > /sys/class/disp/disp/attr/colorbar

2.4.3 获取屏幕的图层信息,帧率等等

cat /sys/class/disp/disp/attr/sys

2.4.4 特殊情况

2.4.4.1 屏幕花屏

原因可能是fps过高,我们在之前board.dts中[lcd0]节点的设置可能存在问题,一定要满足下面的式子:

lcd_dclk_freq*num_of_pixel_clk=lcd_ht*lcd_vt*fps /1e9

其中,num_of_pixel_clk 通常为 1,表示发送一个像素所需要的时钟周期为 1 一个,低分辨率 的 MCU 和串行接口通常需要 2 到 3 个时钟周期才能发送完一个像素。

所以一般lcd_dclk_freq=lcd_ht*lcd_vt*fps

fps一般取60,lcd_dclk_freq,lcd_ht,lcd_vt则是我们board.dts中设置的时序参数

2.4.4.2 屏幕时序参数之前一直调整错误

因为我的Tina SDK 2.0是有MIPI的驱动的,所以我没有去修改驱动,只是去修改设备树的设置。下面是最终的设备树配置:

    lcd_dclk_freq       = <26>;    
    lcd_hbp             = <46>;
    lcd_ht              = <900>;//885
    lcd_hspw            = <4>;
    lcd_vbp             = <21>;
    lcd_vt              = <550>;//535
    lcd_vspw            = <4>;

lcd_dclk_freq       

传输像素传送频率。单位为 MHz。 fps = (lcd_dclk_freq×1000×1000) / (ht×vt)。 这个值根据以下公式计算: lcd_dclk_freq=lcd_ht*lcd_vt*fps

lcd_hbp

指有效行间,行同步信号(hsync)开始,到有效数据开始之间的 dclk 的 cycle 个数,包括同步 信号区。见上图,注意的是包含了 hspw 段。

lcd_vbp则是列的            

lcd_ht

指一行总的 dclk 的 cycle 个数

lcd_vt 则是列的           

lcd_hspw          

指行同步信号的宽度。单位为 1 个 dclk 的时间(即是 1 个 data cycle 的时间)。

lcd_vspw则是列的

至于我是如何调节参数的呢,开始是屏幕的商家给我一组参数

    lcd_hbp             = <46>;
    lcd_ht              = <880>;
    lcd_hspw            = <4>;
    lcd_vbp             = <21>;
    lcd_vt              = <530>;
    lcd_vspw            = <4>;
    lcd_dclk_freq       = <26>;

但是屏幕一直显示不正确,并且一直在调整lcd_dclk_freq,lcd_hbp等,最后成功是因为,其他参数没有再改变,而是只改变lcd_ht和 lcd_vt 参数,即只改变 lcd_hfp和lcd_vfp                

因为我没有具体用示波器去测试波形,所以只能提供一个我是如何瞎调整参数的过程

最后效果:         

开机 LOGO 是由 UBOOT 所提供的支持,所以需要配置 UBOOT 的显示屏驱动。

在这之前,先前往 Uboot 检查是否开启了屏幕启动logo

/home/allwinner/LicherPI/tina-d1-h/tina_d1_open_v2/lichee/brandy-2.0/u-boot-2018/configs/sun20iw1p1_defconfig

把 CONFIG_DISP2_SUNXI=y 取消注释

然后如同 Kernel 一样,修改 Uboot 的设备树即可。

device/config/chips/v853/configs/vision/uboot-board.dts

&lcd0 {
	lcd_used            = <1>;

	lcd_driver_name     = "tft08006";
	lcd_backlight       = <100>;
	lcd_if              = <4>;
	//0:Video mode:实时刷屏,有ht,hbp等时序参数的定义
	lcd_dsi_if          = <0>;

	lcd_x               = <800>;
	lcd_y               = <480>;
	lcd_width           = <52>;
	lcd_height          = <52>;
	//lcd_dclk_freq=lcd_ht*lcd_vt*fps
	lcd_dclk_freq       = <26>;


	// lcd_pwm_used        = <1>;
	// lcd_pwm_ch          = <2>;
	// lcd_pwm_freq        = <1000>;
	// lcd_pwm_pol         = <0>;
	// lcd_pwm_max_limit   = <255>;


	/*
	由下面两条公式得知,我们不需要设置lcd_hfp和lcd_vfp参数,因为驱动会自动根据其它几个已知
	参数中算出lcd_hfp和lcd_vfp。
	lcd_ht = lcd_x + lcd_hspw + lcd_hbp + lcd_hfp
	lcd_vt = lcd_y + lcd_vspw + lcd_vbp + lcd_vf
	*/
	lcd_hbp             = <46>;
	lcd_ht              = <900>;
	lcd_hspw            = <4>;
	lcd_vbp             = <21>;
	lcd_vt              = <550>;
	lcd_vspw            = <4>;

	//1:1 data lane
	lcd_dsi_lane        = <1>;
	//0:Package Pixel Stream,24bit RGB
	lcd_dsi_format		= <0>;
	//0:frame trigged automatically
	//刷屏时间为lcd_ht x lcd_vt
	lcd_dsi_te			= <0>;

	//0:一个port
	lcd_dsi_port_num	= <0>;
	//0:normal mode
	lcd_tcon_mode 		= <0>;
	//0:中断自动根据时序,由场消隐信号内部触发
	lcd_cpu_mode		= <0>;
	//0:Single Link(1 clock pair+3/4 data pair)
	// lcd_lvds_if         = <0>;
	// //0:8bit per color(4 data pair)
	// lcd_lvds_colordepth = <0>;
	// lcd_lvds_mode       = <0>;
	//0:RGB888 --- RGB888 direct
	lcd_frm             = <0>;
	//这些参数只有在 lcd_if=0 时才有效
	// lcd_hv_clk_phase    = <0>;
	//0:vsync active low,hsync active low
	//lcd_hv_sync_polarity= <0>;
	lcd_io_phase        = <0x0000>;
	//0:Lcd的Gamma校正功能关闭
	lcd_gamma_en        = <0>;
	lcd_bright_curve_en = <0>;
	//0:Lcd的色彩映射功能关闭
	lcd_cmap_en         = <0>;
	//0:disable
	lcd_fsync_en        = <0>;
	//LCD 的 fsync 功能,其中的有效电平时间长度,单位:像素时钟的个数。
	lcd_fsync_act_time  = <1000>;
	//无效电平时间长度
	lcd_fsync_dis_time  = <1000>;
	//0:有效电平为低
	lcd_fsync_pol       = <0>;

	deu_mode            = <0>;
	lcdgamma4iep        = <22>;
	smart_color         = <90>;

/*	lcd_gpio_0 =  <&pio PG 13 GPIO_ACTIVE_HIGH>;*/
	pinctrl-0 = <&dsi2lane_pins_a>;
	pinctrl-1 = <&dsi2lane_pins_b>;
};

如果希望修改开机 LOGO,可以修改下面路径里的这个图片文件

openwrt/target/v853/v853-common/boot-resource/boot-resource/bootlogo.bmp

注意,图片不宜过大,太大的图片容易导致加载缓慢。而且图片需要 BMP 格式,24位深

打包烧写即可,替换 bootlogo 不需要编译

2.6 触摸测试

我使用的屏幕驱动是:FT5446,因为我的SDK里是有edt-ft5x06.c驱动文件的,但后面会发现不能直接使用,后文会细说。

2.6.1 检查Kconfig和Makefile

drivers/input/touchscreen/Kconfig文件查看是否有我们的触摸kconfig路径,如果没有可以按如下添加

config TOUCHSCREEN_EDT_FT5X06
    tristate "EDT FocalTech FT5x06 I2C Touchscreen support"
    depends on I2C
    help
      Say Y here if you have an EDT "Polytouch" touchscreen based
      on the FocalTech FT5x06 family of controllers connected to
      your system.

      If unsure, say N.

      To compile this driver as a module, choose M here: the
      module will be called edt-ft5x06.

drivers/input/touchscreen/Makefile文件查询是否有如下配置,如果没有可以添加

obj-$(CONFIG_TOUCHSCREEN_EDT_FT5X06)    += edt-ft5x06.o

2.6.2 make menuconfig

选择:Kernel modules > Input modules -> kmod-input-core[*]
选择:Kernel modules > Input modules -> kmod-touchscreen-ft5x[*] # 其他触屏不选

2.6.3 make kernel_menuconfig

选择:Device Drivers > Input device support > Touchscreens -> EDT [M] # 其他不选

2.6.4 设备树dts修改

&twi2 {
	/*
	 * 定义了IIC控制器twi2的基本配置,包括时钟频率,引脚控制和DMA设置
	 */
	clock-frequency = <400000>;
	pinctrl-names = "default", "sleep";
	pinctrl-0 = <&twi2_pins_a>;
	pinctrl-1 = <&twi2_pins_b>;	
	dmas = <&dma 45>, <&dma 45>;
	dma-names = "tx", "rx";
	status = "okay";

	edt_ft5x06: edt_ft5x06@38{ 
		status = "okay";
		compatible = "edt,edt-ft5406";
		reg = <0x38>;
		touchscreen-size-x = <800>;
		touchscreen-size-y = <480>; 
		touch_type = <1>;
	};
};

2.6.5 TWI配置

执行命令

make kernel_menuconfig

Device Drivers->I2C support,选择I2C device interface

选择 I2C HardWare Bus support 选项,进入下一级配置

选择 SUNXI I2C controller 选项,可选择直接编译进内核,也可编译成模块。

2.6.6 成功实现触摸

按照上面的驱动和TWI配置后,编译烧录。insmod后,便可以看到edt_ft5x06已经加载成功。

2.6.6.1 启动即加载edt_ft5x06.ko

如果你希望在系统启动时自动加载某个模块,可以在 /etc/modules.d 中创建一个新文件,或编辑现有的文件。例如:

cd /etc/modules.d

vim edt-ft5x06.conf

在文件中添加:

edt-ft5x06

保存并退出编辑器。这样,edt-ft5x06 模块将在每次系统启动时自动加载。

2.6.6.2 查看系统连接的触摸设备
cat /dev/input/
2.6.6.3 使用getevent工具

触摸屏幕就会看到打印信息
在这里插入图片描述

2.7 特殊情况

如果按照上述方法无法成功触摸,那么大家可以看看有没有如下问题

2.7.1 IIC引脚为输入状态

 cat /sys/kernel/debug/pinctrl/2000000.pinctrl/pinmux-pins

查看发现

pin 32 (PB0): device 2502800.twi function gpio_in group PB0
pin 33 (PB1): device 2502800.twi function gpio_in group PB1

我就直接在dst中把休眠模式也改成iic

    twi2_pins_b: twi2@1 {

        // pins = "PB0", "PB1";

        // function = "gpio_in";

        pins = "PB0", "PB1";

        function = "twi2";

        drive-strength = <10>;

    };

成功设置为twi2

2.7.2 但是我IIC在启动时还是报错

使用 i2cdetect -y 2检查总线是否识别到设备,发现如下报错

-- [  641.161547] sunxi-i2c sunxi-i2c2: Bus error
[  641.166285] sunxi-i2c sunxi-i2c2: engine-mode: bus state: 0x0, isn't idle
[  641.173853] sunxi-i2c sunxi-i2c2: STOP failed!
[  641.179027] sunxi-i2c sunxi-i2c2: engine-mode: xfer failed(dev addr:0x38)

 常见的i2c工具命令:

i2cdetect -l //获取i2c设备信息
i2cdump -y i2c-number i2c-reg //把相关的i2c设备数据dump出来,如i2cdump -y 1 0x50
i2cget -y i2c-number i2c-reg data_rege //读取i2c设备某个地址的数据,如i2cget -y 1 0x50 1
i2cset -y i2c-number i2c-reg data_rege data //往i2c设备某个地址写数据,如i2cset -y 1 0x50 1 1

后来通过查询资料可能是因为IIC没有上拉,发现确实板上没有上拉,因此我将屏幕上电阻焊接实现上拉,果然就没有报错了。

2.7.3 查看iic设备节点

最后,我们可以查看iic设备节点,看38地址下是否是我们的edt-ft5x06设备,确认I2C设备是否被识别并正确注册

 节点位置:/sys/bus/i2c/devices/

进入2-0038,这个目录表示I2C总线上的一个设备,地址为0x38,在总线i2c-2上,并且我们查看name就发下就是ft-5406

 这里是设备模块别名信息,设备的模块名称

这里我们可以看到设备树已经配置

2.7.4 edt_ft5x06 请求中断错误

通过上面对iic的修改,我们重新启动发现只报如下错误了:


[    9.087323] edt_ft5x06 2-0038: Unable to request touchscreen IRQ.
[    9.143196] edt_ft5x06: probe of 2-0038 failed with error -22

但是因为我使用的是15线的MIPI,本来就没有中断引脚,不能用中断来判断触摸,所以我们得修改驱动为查询的方式判断触摸。

我在edt_ft5x06.c中,结构体edt_ft5x06_ts_data添加 

struct delayed_work poll_work;

struct edt_ft5x06_ts_data {
	struct i2c_client *client;
	struct input_dev *input;
	struct touchscreen_properties prop;
	u16 num_x;
	u16 num_y;
	struct regulator *vcc;
	struct regulator *iovcc;

	struct gpio_desc *reset_gpio;
	struct gpio_desc *wake_gpio;

#if defined(CONFIG_DEBUG_FS)
	struct dentry *debug_dir;
	u8 *raw_buffer;
	size_t raw_bufsize;
#endif

	struct mutex mutex;
	bool factory_mode;
	enum edt_pmode suspend_mode;
	int threshold;
	int gain;
	int offset;
	int offset_x;
	int offset_y;
	int report_rate;
	int max_support_points;

	char name[EDT_NAME_LEN];

	struct edt_reg_addr reg_addr;
	enum edt_ver version;

	 // 添加的工作队列成员
    struct delayed_work poll_work;
};

 在edt_ft5x06_ts_probe初始化函数中添加如下代码,使用工作队列的方式进行轮询查询坐标变化

int edt_ft5x06_ts_probe(struct i2c_client *client, const struct i2c_device_id *id) {
    // 省略中间代码

    // 初始化工作队列
    INIT_DELAYED_WORK(&tsdata->poll_work, edt_ft5x06_poll_work);
    schedule_delayed_work(&tsdata->poll_work, msecs_to_jiffies(100)); // 启动工作队列

    // 省略中间代码

    return 0;
}

并且注释原先中断的代码。

error = devm_request_threaded_irq(&client->dev, client->irq,
                                    NULL, edt_ft5x06_ts_isr, irq_flags,
                                    client->name, tsdata);
if (error) {
    dev_err(&client->dev, "Unable to request touchscreen IRQ.\n");
    return error;
}

添加edt_ft5x06_poll_work的定义:

static void edt_ft5x06_poll_work(struct work_struct *work) {
    struct edt_ft5x06_ts_data *tsdata = container_of(work, struct edt_ft5x06_ts_data, poll_work.work);
    struct device *dev = &tsdata->client->dev;
    u8 cmd;
    u8 rdbuf[63];
    int i, type, x, y, id;
    int offset, tplen, datalen, crclen;
    int error;

    switch (tsdata->version) {
    case EDT_M06:
        cmd = 0xf9;
        offset = 5;
        tplen = 4;
        crclen = 1;
        break;

    case EDT_M09:
    case EDT_M12:
    case EV_FT:
    case GENERIC_FT:
        cmd = 0x0;
        offset = 3;
        tplen = 6;
        crclen = 0;
        break;

    default:
        goto out;
    }

    memset(rdbuf, 0, sizeof(rdbuf));
    datalen = tplen * tsdata->max_support_points + offset + crclen;

    error = edt_ft5x06_ts_readwrite(tsdata->client, sizeof(cmd), &cmd, datalen, rdbuf);
    if (error) {
        dev_err_ratelimited(dev, "Unable to fetch data, error: %d\n", error);
        goto out;
    }

    if (tsdata->version == EDT_M06) {
        if (rdbuf[0] != 0xaa || rdbuf[1] != 0xaa || rdbuf[2] != datalen) {
            dev_err_ratelimited(dev, "Unexpected header: %02x%02x%02x!\n", rdbuf[0], rdbuf[1], rdbuf[2]);
            goto out;
        }

        if (!edt_ft5x06_ts_check_crc(tsdata, rdbuf, datalen))
            goto out;
    }

    for (i = 0; i < tsdata->max_support_points; i++) {
        u8 *buf = &rdbuf[i * tplen + offset];

        type = buf[0] >> 6;
        if (type == TOUCH_EVENT_RESERVED)
            continue;

        if (tsdata->version == EDT_M06 && type == TOUCH_EVENT_DOWN)
            continue;

        x = get_unaligned_be16(buf) & 0x0fff;
        y = get_unaligned_be16(buf + 2) & 0x0fff;
        if (tsdata->version == EV_FT)
            swap(x, y);

        id = (buf[2] >> 4) & 0x0f;

        input_mt_slot(tsdata->input, id);
        if (input_mt_report_slot_state(tsdata->input, MT_TOOL_FINGER, type != TOUCH_EVENT_UP))
            touchscreen_report_pos(tsdata->input, &tsdata->prop, x, y, true);
    }

    input_mt_report_pointer_emulation(tsdata->input, true);
    input_sync(tsdata->input);

out:
    // 重新安排下次轮询
    schedule_delayed_work(&tsdata->poll_work, msecs_to_jiffies(100));
}

按照上面进行修改了,编译出edt-ft5x06.ko文件,用ADB移植到开发板上,加载运行。

2.7.5 vcc和iovdc报错

按照上面的修改后,又出现了新的错误:

[    8.197004] edt_ft5x06 2-0038: 2-0038 supply vcc not found, using dummy regulator
[    8.229412] edt_ft5x06 2-0038: 2-0038 supply iovcc not found, using dummy regulator

我们在edt_ft5x06_ts_probe初始化中去掉虚拟电源

struct edt_ft5x06_ts_data {
    struct i2c_client *client;
    struct input_dev *input;
    struct touchscreen_properties prop;
    u16 num_x;
    u16 num_y;
    // 删除电源相关成员
    // struct regulator *vcc;
    // struct regulator *iovcc;

    struct gpio_desc *reset_gpio;
    struct gpio_desc *wake_gpio;

#if defined(CONFIG_DEBUG_FS)
    struct dentry *debug_dir;
    u8 *raw_buffer;
    size_t raw_bufsize;
#endif

    struct mutex mutex;
    bool factory_mode;
    enum edt_pmode suspend_mode;
    int threshold;
    int gain;
    int offset;
    int offset_x;
    int offset_y;
    int report_rate;
    int max_support_points;

    char name[EDT_NAME_LEN];

    struct edt_reg_addr reg_addr;
    enum edt_ver version;

    // 添加的工作队列成员
    struct delayed_work poll_work;
};

	// tsdata->vcc = devm_regulator_get(&client->dev, "vcc");
	// if (IS_ERR(tsdata->vcc)) {
	// 	error = PTR_ERR(tsdata->vcc);
	// 	if (error != -EPROBE_DEFER)
	// 		dev_err(&client->dev,
	// 			"failed to request regulator: %d\n", error);
	// 	return error;
	// }

	// tsdata->iovcc = devm_regulator_get(&client->dev, "iovcc");
	// if (IS_ERR(tsdata->iovcc)) {
	// 	error = PTR_ERR(tsdata->iovcc);
	// 	if (error != -EPROBE_DEFER)
	// 		dev_err(&client->dev,
	// 			"failed to request iovcc regulator: %d\n", error);
	// 	return error;
	// }

	// error = regulator_enable(tsdata->iovcc);
	// if (error < 0) {
	// 	dev_err(&client->dev, "failed to enable iovcc: %d\n", error);
	// 	return error;
	// }

	// /* Delay enabling VCC for > 10us (T_ivd) after IOVCC */
	// usleep_range(10, 100);

	// error = regulator_enable(tsdata->vcc);
	// if (error < 0) {
	// 	dev_err(&client->dev, "failed to enable vcc: %d\n", error);
	// 	regulator_disable(tsdata->iovcc);
	// 	return error;
	// }

这样我编译出.ko文件,再运行,可以发现已经成功了。

2.7.6 坐标不对

正当我高兴的时候,又出现问题了。原来的默认坐标原点在右下角,但我需要的是在左上角。

我们可以使用QT_QPA_EVDEV_TOUCHSCREEN_PARAMETERS,添加如下配置即可:

export QT_QPA_EVDEV_TOUCHSCREEN_PARAMETERS=/dev/input/event2:rotate=180

/*

/dev/input/    指定输入设备,没有指定 Qt 会通过 libudev 检索 或则 遍历找到一个有效的节点
rotate    触摸屏幕旋转,必须是 90 , 180 , 270 中的一个
invertx and inverty    指定 X / Y 倒置的坐标

*/

这样我们就可以正常使用QT进行屏幕触摸了。

这样我们就可以正常使用QT进行屏幕触摸了。

这样我们就可以正常使用QT进行屏幕触摸了。

四. 参考资料


请问这个树莓派MIPI DSI 显示屏是不是用 接口芯片转的? | 全志在线开发者论坛 (aw-ol.com)

小麻雀直接驱动树莓派的DSI屏 | 全志在线开发者论坛 (aw-ol.com)

LCD 屏幕 - V853 (aw-ol.com)

D1_Tina_Linux_LCD_调试指南.pdf

LCD 屏幕 - V853 (aw-ol.com)

IMX6Q移植ft5x06_ts触摸屏驱动_imx6q usb 触摸 驱动-CSDN博客

各位大神有弄过电容屏的触摸吗 不是电阻屏 / 全志 SOC / WhyCan Forum(哇酷开发者社区)

百问网全志D1h开发板MIPI屏幕触摸功能适配_全志 mipi屏-CSDN博客

百问网全志D1h开发板MIPI屏幕触摸功能适配_mipi dsi 触屏-CSDN博客m

RK3568驱动指南|第十五篇 I2C-第170章 I2C client代码编写(设备树)_rk3568使用设备树配置i2c1-CSDN博客

1触摸屏驱动--从零开始自制linux掌上电脑(F1C200S) <嵌入式项目>_atk4384-CSDN博客

linux设备适配触摸屏(gt1151)_gt1151驱动-CSDN博客

D1_Linux_TWI_开发指南.pdf (whycan.com)

全志D1-H/D1s RISC-V(基于平头哥C906) 哪吒开发板超全资料合集 / 全志 SOC / WhyCan Forum(哇酷开发者社区)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值