学习交流加
个人qq:
1126137994个人微信:
liu1126137994学习交流资源分享qq群:
962535112
今天来记录一下I.MX6开发板移植触摸屏驱动程序的过程分析。在移植驱动程序之前,为了学习,先去分析一下触摸屏驱动程序的框架。加qq1126137994 一起学习更多技术。
文章目录
1、tsc.c触摸屏驱动程序的分析2、tsc.c触摸屏驱动程序的移植3、触摸屏的校准1、tsc.c触摸屏驱动程序的分析
I.MX6的触摸屏驱动程序的文件名为:TSC.C。
在tsc.c文件中初始化tsc_init函数注册tsc_driver结构体,当tsc_driver结构体成员驱动name与平台设备层中name匹配相同时调用tsc_probe初始化函数,该函数是tsc设备驱动函数的入口。imx6的具体tsc设备驱动的实现的主要工作在tsc_probe里完成。
下面是分析tsc_probe函数的调用关系(并非程序源码,只是列举出关键的函数调用):
tsc_probeinput_dev = input_allocate_device();//(向input核心层申请)分配一个input_dev结构体。INIT_DELAYED_WORK;//初始化工作队列,把tsc工作任务注册到工作队列中,为下面执行队列的任务作好准备。tsc_work;//通过input_report_abs函数向上层上报触摸屏屏的X、Y坐标和压力值,执行tsc_calculate_pressure函数进行压力校准,init_platform_hw;//?input_set_abs_params;//通过input_dev结构体设置按键和绝对位置事件以及事件下需要处理的ABS_X、ABS_Y、ABS_PRESSURE的具体事件内容request_irq(ts->irq, tsc_irq, 0,client->dev.driver->name, ts);//为tsc中断引脚申请一个中断处理函数,schedule_delayed_work;//中断的上半部分tsc_work; //中断的下半部分,tsc_read_values;//读取xy坐标 以及获取压力值tc->y = tsc_xfer(tsc, READ_Y);tc->x = tsc_xfer(tsc, READ_X);tsc_xfer(tsc, PWRDOWN);//另一次循环测量rt = tsc_calculate_pressure // 计算压力 input_report_abs(input, ABS_X, tc.x);input_report_abs(input, ABS_Y, tc.y);input_report_abs(input, ABS_PRESSURE, rt);//上报获取到的值tsc_xfer;data = i2c_smbus_read_word_data; //检测IIC总线的读写操作val = swab16(data) >> 4; //去掉低4位无效数据(#defineMAX_12BIT 由定义知最大为12bit,所以需要去掉低4位)return val;//tsc_xfer返回一个val值,就是xy坐标的值input_register_device; //像input核心层注册input_dev结构体arch\mips\boot\Elf2ecoff.c中有如下定义#define swab16(x) \(( \(((x) & 0x00ffU) << 8) | \(((x) & 0xff00U) >> 8) )) //将x的值的高8位和低8位互换
当按下触摸板后产生中断,中断里面调用延时函数进入底半部程序。在调度函数里面,先读取坐标,计算压力,然后根据压力大小上报坐标。若触摸板一直按下,那么就重新调用,并通过压力值来看触摸板是否释放。
2、tsc.c触摸屏驱动程序的移植
触摸屏驱动程序的核心部分分析完了,下面就开始移植触摸屏驱动程序,其实,内核自带的驱动程序移植起来非常简单,在理解驱动程序的前提下,在平台设备文件中添加一些私有数据信息,以及配置中断引脚等即可。
IMX6的板级初始化函数:Board-mx6q_sabresd.c
由与tsc与imx6之间的通信是通过IIC总线进行的,因此在imx6的平台设备层(platform_device)的mx6_sabresd_board_init函数里就需要配置与tsc有关的IIC总线。由于是TSC所挂的IIC总线是第二根,在平台初始化函数里将会调用i2c_register_board_info函数注册mxc_i2c2_board_info结构体数组。
向mxc_i2c2_board_info结构体数组里添加如下成员:
{I2C_BOARD_INFO("tsc",0x48),.platform_data = (void *)& tsc_data_lyy,.irq = gpio_io_irq(SABRESD_TS_INT),}
其中由于TSC的A0、A1两个引脚下拉,通过I2C_BOARD_INFO函数注册的从机设备地址是0x48;通过gpio_to_irq函数获取TSC中断号,之后会传给平台驱动层,当申请中断会用到;
再构建tsc_data_lyy结构体,并添加4个成员:init_platform_hw函数、get_pendown_state函数、irq_pin中断引脚的选择、触摸屏驱动相关参数。
/* * 注意:一下添加的函数,位置没有固定要求,但是为了整齐统一,还是把它放到与其它设备定义的相通的位置,方便以后查看*/#ifdef CONFIG_TOUCHSCREEN_TSC#include <linux/i2c/tsc.h>(在头文件里也添加一下)static int tsc_hw_init(void){int err;err = gpio_request(SABRESD_TS_INT,"tsc irq");if(err<0){pr_err("tsc irq gpio request err\n");return err;}err = gpio_direction_input(SABRESD_TS_INT);if(err<0){pr_err("tsc irq gpio init input err %d\n",err);gpio_free(SABRESD_TS_INT);return err;}printk("tsc irq gpio init success!\n");return 0;}static void tsc_hw_remove(void){gpio_free(SABRESD_TS_INT);}static int tsc_get_pendown_state(void){int state;state = gpio_get_value(SABRESD_TS_INT);//printk("tsc get state = %x\n",state);return (state == 0)? 1:0;}static struct tsc_platform_data tsc_data_lyy= {.model = ,.x_plate_ohms =180,.init_platform_hw = tsc_hw_init,.exit_platform_hw = tsc_hw_remove,.get_pendown_state = tsc_get_pendown_state,};#endif
更改中断引脚号:
将宏SABRESD_TS_INT改为:(之前是3,26)#define SABRESD_TS_INTIMX_GPIO_NR(6, 7) //lyy (申请中断引脚)
注:在Linux启动的时候会将信息进行收集,i2c适配器会扫描已经静态注册的i2c_board_info,通过调用i2c_register_board_info函数将包含所有I2C设备的i2c_board_info信息的i2c_devinfo变量加入到__i2c_board_list链表中,并调用i2c_new_device为其实例化一个i2c_client。在驱动加载的时候遇到同名的i2c_board_info就会将i2c_client和driver绑定,并且执行driver的probe函数。这种方式一般放在平台的代码中。
i2c_register_board_info(2, mxc_i2c2_board_info,ARRAY_SIZE(mxc_i2c2_board_info));
注释:
上面的工作,基本完成了驱动程序的移植,但是后来经过测试,发现显示有错误:
Failed to register i2c client tsc at 0x48 (-16)
Can’t create device at 0x48
一开始以为是i2c总线没有识别到,但是经过调试,发现是中断引脚的复用了。
1、首先确定中断的引脚,查看原理图知使用的是:MX6Q_PAD_NANDF_CLE__GPIO_6_7,在mach-mx6\Board-mx6q_sabresd.h 中加入定义:MX6Q_PAD_NANDF_CLE__GPIO_6_7,当然如果有其它设备用了这个引脚,要将其注销2、在板极文件board-mx6q_sabresd.c中注册和申请I2C驱动首先申请中断的信号,并注释掉原来关于GPIO_6_7的引脚(不然无法识别tsc设备)添加头文件:#define SABRESD_TS_INTIMX_GPIO_NR(6, 7) //lyy注释掉之前的://#define SABRESD_CAP_TCH_INT1IMX_GPIO_NR(6, 7)//之前的
OK!到此,程序添加成功,下一步就是校准触摸屏了!!!
3、触摸屏的校准
校准的目的:为了与显示屏的坐标一一对应。我们一般采用软件校准,使用Tslib库里的校准软件进行校准们首先需要移植Tslib库。
编译tslib(放到rootfs/tslib/tslib):tar xzf tslib-1.4.tar.gzcd tslib./autogen.sh mkdir tmpecho "ac_cv_func_malloc_0_nonnull=yes" >arm-linux.cache./configure --host=arm-linux --cache-file=arm-linux.cache --prefix=$(pwd)/tmpmakemake install
我的这一部分是放到开发的环境中做的,其实可以直接在单板上搞,如果单板上是有编译器的话。
然后将系统烧写的单板,在单板上操作:
cd /tslib/tslib/tmpcp * / -rfd1.修改 /etc/ts.conf第1行(去掉#号和第一个空格):# module_raw input改为:module_raw input2.export TSLIB_TSDEVICE=/dev/input/event1export TSLIB_CALIBFILE=/etc/pointercalexport TSLIB_CONFFILE=/etc/ts.confexport TSLIB_PLUGINDIR=/lib/tsexport TSLIB_CONSOLEDEVICE=noneexport TSLIB_FBDEVICE=/dev/fb0
测试:
ts_calibrate
ts_test
备注:如果出现段错误,解决办法如下:
1、ts.conf文件中的各个设置选项之前不能有空格,否则会出现: Segmentation fault 错误,
我就不小心在module…之前多了个空格,害我查了好久。
2、不要在pointercal对应的目录下,建立一个空的pointercal文件,否则在运行ts_calibrate时,
也可能会出现Segmentation fault
想一起探讨以及获得各种学习资源加我(有我博客中写的代码的原稿):
qq:1126137994
微信:liu1126137994
可以共同交流关于嵌入式,操作系统,C++语言,C语言,数据结构等技术问题。