gslx680.c触摸屏驱动

news/2025/1/31 7:11:19/

转:http://blog.csdn.net/zgkxzx/article/details/56980769


前言

gslx680电容触摸屏是一种目前Android嵌入式设备中比较常用的触摸屏类型。这里我们以Exynos4412为Android bsp平台,移植一款gslx680电容触摸屏。
关于电容触摸屏的原理,这里不进行讲解,不明白的,可以参照一下博客:http://blog.csdn.net/xubin341719/article/details/7820492
这里只从实际工程出发,讲解移植过程。谢谢~~

一、具体操作配置

1.添加GSLX68X到内核的Kconfig配置

路径:xxx/kernel/drivers/input/touchscreen/Kconfig
这里写图片描述

2.编写Makefile文件

路径:xxx/kernel/drivers/input/touchscreen/Makefile
这里写图片描述

3.在触摸屏驱动目录xxx/kernel/drivers/input/touchscreen/文件夹下,添加一下文件:

gslx680.c
gslx680.h
gsl_point_id
查看附件
这里写图片描述
注意:gsl_point_id是一个Linux库文件

4.因为TP采用的是I2C总线驱动,还要在linux/arch/arm/mach-exynos/mach-smdk4x12.c文件中添加

这里写图片描述
这里的IIC地址一定要与程序上面一致,并且和设备的吻合

二、程序分析

1.定义地址和参数

#define GSLX680_I2C_NAME "gslX680"        //IIC的设备名
#define GSLX680_I2C_ADDR 0x40             //IIC 设备的地址
#define IRQ_PORT        IRQ_EINT(7)     //TP的中断引脚
#define GSL_DATA_REG    0x80            //IIC 设备具体功能寄存器的地址 这个是数据寄存器
#define GSL_STATUS_REG  0xe0            //状态寄存器
#define GSL_PAGE_REG    0xf0
#define PRESS_MAX 255            //手指按下的最大值
#define MAX_FINGERS 10             //支持的最大手指数
#define MAX_CONTACTS 10             //支持的最大关联
#define DMA_TRANS_LEN   0x20           //DMA传输的最大长度
  • 1

2.设备的驱动初始化函数

首先,在加载驱动后,Linux系统通过module_init(gsl_ts_init);进行设备的初始化

static int __init gsl_ts_init(void)
{int ret;if(strcasecmp(tp_name, "gslx680") == 0){printk("Initial gslx680 Touch Driver\n");}else{return 0;}print_info("==gsl_ts_init==\n");ret = i2c_add_driver(&gsl_ts_driver);print_info("ret=%d\n",ret);return ret;
}
  • 1

主要是通过i2c_add_driver(&gsl_ts_driver)将

static struct i2c_driver gsl_ts_driver = {.driver = {.name = GSLX680_I2C_NAME,.owner = THIS_MODULE,
},
#ifndef CONFIG_HAS_EARLYSUSPEND.suspend    = gsl_ts_suspend,.resume = gsl_ts_resume,
#endif.probe  = gsl_ts_probe,.remove = __devexit_p(gsl_ts_remove),.id_table   = gsl_ts_id,
};
  • 1

挂载到IIC总线

3.设备的探针函数

设备的探测函数,退出函数、设备的ID等等都注册上去。
在设备工作时,首先是探测函数

static int __devinit gsl_ts_probe(struct i2c_client *client,const struct i2c_device_id *id)
{struct gsl_ts *ts;int rc;print_info("GSLX680 Enter %s\n", __func__);if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {dev_err(&client->dev, "I2C functionality not supported\n");return -ENODEV;}ts = kzalloc(sizeof(*ts), GFP_KERNEL);if (!ts)return -ENOMEM;print_info("==kzalloc success=\n");ts->client = client;i2c_set_clientdata(client, ts);ts->device_id = id->driver_data;rc = gslX680_ts_init(client, ts); //初始化gls1680if (rc < 0) {dev_err(&client->dev, "GSLX680 init failed\n");goto error_mutex_destroy;}gsl_client = client;gslX680_init();/初始化gls1680相关的IO端口init_chip(ts->client);check_mem_data(ts->client);rc= request_irq(client->irq, gsl_ts_irq, IRQF_TRIGGER_RISING, client->name, ts); //中断请求 ,注册终端,上升沿触发 gsl_ts_irq 回调函数if (rc < 0) {print_info( "gsl_probe: request irq failed\n");goto error_req_irq_fail;}/* create debug attribute *///rc = device_create_file(&ts->input->dev, &dev_attr_debug_enable);
#ifdef CONFIG_HAS_EARLYSUSPENDts->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1;//ts->early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB + 1;ts->early_suspend.suspend = gsl_ts_early_suspend;ts->early_suspend.resume = gsl_ts_late_resume;register_early_suspend(&ts->early_suspend);
#endif
#ifdef GSL_MONITORprint_info( "gsl_ts_probe () : queue gsl_monitor_workqueue\n");INIT_DELAYED_WORK(&gsl_monitor_work, gsl_monitor_worker);gsl_monitor_workqueue = create_singlethread_workqueue("gsl_monitor_workqueue");queue_delayed_work(gsl_monitor_workqueue, &gsl_monitor_work, 1000);
#endifprint_info("[GSLX680] End %s\n", __func__);return 0;//exit_set_irq_mode:
error_req_irq_fail:free_irq(ts->irq, ts);
error_mutex_destroy:input_free_device(ts->input);kfree(ts);return rc;
}
  • 1

4.设备初始化

static int gslX680_ts_init(struct i2c_client *client, struct gsl_ts *ts)
{struct input_dev *input_device;int i, rc = 0;printk("[GSLX680] Enter %s\n", __func__);ts->dd = &devices[ts->device_id];if (ts->device_id == 0) {ts->dd->data_size = MAX_FINGERS * ts->dd->touch_bytes + ts->dd->touch_meta_data;ts->dd->touch_index = 0;}printk("ts->dd->data_size is %d\n", ts->dd->data_size);ts->touch_data = kzalloc(ts->dd->data_size, GFP_KERNEL);if (!ts->touch_data) {pr_err("%s: Unable to allocate memory\n", __func__);return -ENOMEM;}input_device = input_allocate_device(); //申请输入子系统设备if (!input_device) {rc = -ENOMEM;goto error_alloc_dev;}ts->input = input_device;input_device->name = GSLX680_I2C_NAME;input_device->id.bustype = BUS_I2C;input_device->dev.parent = &client->dev;input_set_drvdata(input_device, ts);/*set_bit()告诉input输入子系统支持哪些事件,哪些按键*/set_bit(ABS_MT_POSITION_X, input_device->absbit);//设置接触面的中心点X坐标set_bit(ABS_MT_POSITION_Y, input_device->absbit);//设置接触面的中心点Y坐标set_bit(ABS_MT_TOUCH_MAJOR, input_device->absbit);//设置触摸方向set_bit(ABS_MT_WIDTH_MAJOR, input_device->absbit);//设置手指触摸接触面积大小set_bit(ABS_PRESSURE, input_device->absbit);//设置压力set_bit(BTN_TOUCH, input_device->keybit);//按键触摸set_bit(EV_ABS, input_device->evbit);//绝对位移set_bit(EV_KEY, input_device->evbit);//按键类型set_bit(EV_SYN,input_device->evbit);//同步__set_bit(INPUT_PROP_DIRECT, input_device->propbit);input_mt_init_slots(input_device, (MAX_CONTACTS + 1));
//设置子系统的参数上报input_set_abs_params(input_device,ABS_MT_POSITION_X, 0, SCREEN_MAX_X, 0, 0);input_set_abs_params(input_device,ABS_MT_POSITION_Y, 0, SCREEN_MAX_Y, 0, 0);input_set_abs_params(input_device,ABS_MT_TOUCH_MAJOR, 0, PRESS_MAX, 0, 0);input_set_abs_params(input_device,ABS_MT_WIDTH_MAJOR, 0, 200, 0, 0);input_set_abs_params(input_device, ABS_MT_TRACKING_ID, 0, 5, 0, 0);input_set_abs_params(input_device,ABS_PRESSURE, 0, PRESS_MAX, 0 , 0);input_set_abs_params(input_device, ABS_MT_PRESSURE, 0, PRESS_MAX, 0, 0);
#ifdef HAVE_TOUCH_KEYinput_device->evbit[0] = BIT_MASK(EV_KEY);
//input_device->evbit[0] = BIT_MASK(EV_SYN) | BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);for (i = 0; i < MAX_KEY_NUM; i++)set_bit(key_array[i], input_device->keybit);
#endif
//中断设置client->irq = IRQ_PORT;ts->irq = client->irq;
//创建单线程的工作队列ts->wq = create_singlethread_workqueue("kworkqueue_ts");if (!ts->wq) {dev_err(&client->dev, "Could not create workqueue\n");goto error_wq_create;}
//工作队列的挂起flush_workqueue(ts->wq);
//初始化工作队列,对应的处理函数为gslX680_ts_workerINIT_WORK(&ts->work, gslX680_ts_worker);
//注册输入设备子系统rc = input_register_device(input_device);if (rc)goto error_unreg_device;return 0;
error_unreg_device:destroy_workqueue(ts->wq);
error_wq_create:input_free_device(input_device);
error_alloc_dev:kfree(ts->touch_data);return rc;
}
  • 1

5.IO的初始化

static int gslX680_init(void)
{/* shutdown pin */gpio_request_one(EXYNOS4_GPX0(6), GPIOF_OUT_INIT_HIGH, "GPX0");s3c_gpio_setpull(EXYNOS4_GPX0(6),S3C_GPIO_PULL_UP);s3c_gpio_cfgpin(EXYNOS4_GPX0(6), S3C_GPIO_OUTPUT);gpio_set_value(EXYNOS4_GPX0(6), 1);mdelay(50);gpio_set_value(EXYNOS4_GPX0(6), 0);/* config interrupt pin */s5p_register_gpio_interrupt(EXYNOS4_GPX0(7));//s3c_gpio_cfgpin(EXYNOS4_GPX0(7), S3C_GPIO_SFN(0xf));//引脚配置,输入s3c_gpio_setpull(EXYNOS4_GPX0(7), S3C_GPIO_PULL_UP);//上拉irq_set_irq_type(EXYNOS4_GPX0(7), IRQ_TYPE_EDGE_RISING);//上升沿触发终端return 0;
}
  • 1

6.触摸屏终端回调函数

看看中断回调函数,中断回调函数相当于中断的上半部,主要是做一些简单工作,复制事情交给中断下半部实现,也就是开启的工作队列线程。

static irqreturn_t gsl_ts_irq(int irq, void *dev_id)
{struct gsl_ts *ts = dev_id;print_info("========gslX680 Interrupt=========\n");disable_irq_nosync(ts->irq);//关闭中断if (!work_pending(&ts->work)) {queue_work(ts->wq, &ts->work);//将工作线程再次加入工作队列}return IRQ_HANDLED;
}
  • 1

这里我们看看中断下半部核心处理部分,包括数据采集与上报子系统等等

static void gslX680_ts_worker(struct work_struct *work)
{int rc, i,j;u8 id, touches, read_buf[4] = {0};u16 x, y;struct gsl_ts *ts = container_of(work, struct gsl_ts,work);print_info("=====gslX680_ts_worker=====\n");
#ifdef GSL_MONITORif(i2c_lock_flag != 0)goto i2c_lock_schedule;elsei2c_lock_flag = 1;
#endif
#ifdef GSL_NOID_VERSIONu32 tmp1;u8 buf[4] = {0};struct gsl_touch_info cinfo = {0};
#endifrc = gsl_ts_read(ts->client, 0x80, ts->touch_data, ts->dd->data_size);//读取触摸屏的信息if (rc < 0) {dev_err(&ts->client->dev, "read failed\n");goto schedule;}touches = ts->touch_data[ts->dd->touch_index];//触点数print_info("-----touches: %d -----\n", touches);
#ifdef GSL_NOID_VERSIONcinfo.finger_num = touches;print_info("tp-gsl finger_num = %d\n",cinfo.finger_num);for(i = 0; i < (touches < MAX_CONTACTS ? touches : MAX_CONTACTS); i ++) {cinfo.x[i] = join_bytes( ( ts->touch_data[ts->dd->x_index + 4 * i + 1] & 0xf),ts->touch_data[ts->dd->x_index + 4 * i]);cinfo.y[i] = join_bytes(ts->touch_data[ts->dd->y_index + 4 * i + 1],ts->touch_data[ts->dd->y_index + 4 * i ]);cinfo.id[i] = ((ts->touch_data[ts->dd->x_index + 4 * i + 1] & 0xf0)>>4);print_info("tp-gsl before: x[%d] = %d, y[%d] = %d, id[%d] = %d \n",i,cinfo.x[i],i,cinfo.y[i],i,cinfo.id[i]);}cinfo.finger_num=(ts->touch_data[3]<<24)|(ts->touch_data[2]<<16)|(ts->touch_data[1]<<8)|(ts->touch_data[0]);gsl_alg_id_main(&cinfo);tmp1=gsl_mask_tiaoping();print_info("[tp-gsl] tmp1=%x\n",tmp1);if(tmp1>0&&tmp1<0xffffffff) {buf[0]=0xa;buf[1]=0;buf[2]=0;buf[3]=0;gsl_ts_write(ts->client,0xf0,buf,4);buf[0]=(u8)(tmp1 & 0xff);buf[1]=(u8)((tmp1>>8) & 0xff);buf[2]=(u8)((tmp1>>16) & 0xff);buf[3]=(u8)((tmp1>>24) & 0xff);print_info("tmp1=%08x,buf[0]=%02x,buf[1]=%02x,buf[2]=%02x,buf[3]=%02x\n",tmp1,buf[0],buf[1],buf[2],buf[3]);gsl_ts_write(ts->client,0x8,buf,4);}touches = cinfo.finger_num;
#endiffor(i = 1; i <= MAX_CONTACTS; i ++) {if(touches == 0)id_sign[i] = 0;id_state_flag[i] = 0;}for(i= 0; i < (touches > MAX_FINGERS ? MAX_FINGERS : touches); i ++) {
#ifdef GSL_NOID_VERSIONid = cinfo.id[i];x = cinfo.x[i];y = cinfo.y[i];
#elsex = join_bytes( ( ts->touch_data[ts->dd->x_index + 4 * i + 1] & 0xf),ts->touch_data[ts->dd->x_index + 4 * i]);y = join_bytes(ts->touch_data[ts->dd->y_index + 4 * i + 1],ts->touch_data[ts->dd->y_index + 4 * i ]);
//id = ts->touch_data[ts->dd->id_index + 4 * i] >> 4;id = ts->touch_data[ts->dd->id_index + 4 * i] >> 4;
#endifprint_info("-->x = %d, y = %d,id = %d, max = %d,ts->dd->x_index = %d\n",x,y,id,MAX_CONTACTS,ts->dd->id_index);
//id = touches;if(1 <=id && id <= MAX_CONTACTS) {
#ifdef FILTER_POINTfilter_point(x, y ,id);//滤波
#elserecord_point(x, y , id);//记录处理
#endifprint_info("-->x_new = %d, y_new = %d\n",x_new,y_new);report_data(ts, x_new, y_new, 10, id);  //上报数据id_state_flag[id] = 1;}}for(i = 1; i <= MAX_CONTACTS; i ++) {if( (0 == touches) || ((0 != id_state_old_flag[i]) && (0 == id_state_flag[i])) ) {
#ifdef REPORT_DATA_ANDROID_4_0input_mt_slot(ts->input, i);input_report_abs(ts->input, ABS_MT_TRACKING_ID, -1);input_mt_report_slot_state(ts->input, MT_TOOL_FINGER, false);
#endifid_sign[i]=0;}id_state_old_flag[i] = id_state_flag[i];}if(0 == touches) {
#ifndef REPORT_DATA_ANDROID_4_0input_mt_sync(ts->input);
#endif
#ifdef HAVE_TOUCH_KEYif(key_state_flag) {input_report_key(ts->input, key, 0);input_sync(ts->input);key_state_flag = 0;}
#endif}input_sync(ts->input);//同步更新
schedule:
#ifdef GSL_MONITORi2c_lock_flag = 0;
i2c_lock_schedule:
#endifenable_irq(ts->irq);//再次开启中断
}
  • 1

7. 上报输入子系统

static void report_data(struct gsl_ts *ts, u16 x, u16 y, u8 pressure, u8 id)
{swap(x, y);
//  print_info("#####id=%d,x=%d,y=%d######\n",id,x,y);print_info("#####id=%d,x=%d,y=%d######\n",id,x,y);if(x > SCREEN_MAX_X || y > SCREEN_MAX_Y) {
#ifdef HAVE_TOUCH_KEYreport_key(ts,x,y);
#endifreturn;}input_mt_slot(ts->input, id);input_report_abs(ts->input, ABS_MT_TRACKING_ID, id);input_report_abs(ts->input, ABS_MT_POSITION_X, x);input_report_abs(ts->input, ABS_MT_POSITION_Y, y);input_report_abs(ts->input, ABS_MT_PRESSURE, pressure);input_report_key(ts->input, BTN_TOUCH, 1);
}
  • 1

至此,glax680电容触摸屏的驱动移植与分析完毕,希望能给大家带来一点点的帮助…
参考资料下载地址:http://download.csdn.net/detail/zgkxzx/9763694



http://www.ppmy.cn/news/619953.html

相关文章

TVP新书上架 | 融合:产业数字化转型的十大关键技术

新书速递 近期&#xff0c;在腾讯云 TVP 联合出书计划中&#xff0c;腾讯云 TVP 山金孝老师推出了新书《融合&#xff1a;产业数字化转型的十大关键技术》。 《融合&#xff1a;产业数字化转型的十大关键技术》 作者&#xff1a;山金孝 李琦 中译出版社 内容简介 数字经济已成…

烽火HG680-J_卡刷免拆和强刷_免费固件_华为开机动画

烽火HG680-J_卡刷免拆和强刷_免费固件_华为开机动画 固件特点&#xff1a; 1、修改dns&#xff0c;三网通用&#xff1b; 2、开放原厂固件屏蔽的市场安装和u盘安装apk&#xff1b; 3、无开机广告&#xff0c;无系统更新&#xff0c;不在被强制升级&#xff1b; 4、大量精简…

烽火HG680LC固件,Magisk,Adb,Root,精简

自动启用网络adb 精简所有应用&#xff0c;只剩下必要软件 Magisk Root&#xff0c;甚至可以刷模块 短接C51用USB burning tool刷入 适用于S905L3 下载链接 https://download.csdn.net/download/m0_67258728/86510170

电信 烽火HG680KA拆刷成功总结,这个方法不需要拆机

不知道自己配置的&#xff0c;可以在系统信息里面查看&#xff0c;我的配置信息如下&#xff1a; 湖南电信带IPTV的烽火HG680KA&#xff0c;如图 主板是MV300 芯片是 如果和我一样的就可以尝试用我的方法 固件特点&#xff1a; 1、不改原机三码&#xff1b; 2、设置调出原厂…

烽火HG680-KA刷当贝桌面-解决无法打开ADB

自用机顶盒烽火HG680-KA刷当贝桌面&#xff0c;解决无法打开ADB 简单介绍硬件型号固件版本 失败经历操作步骤准备工作拆机流程TTL打开ADB并刷机 成果 简单介绍 偶然发现家里有一个闲置的机顶盒&#xff0c;正好家里没有办理IPTV&#xff0c;于是就产生了刷个当贝桌面&#xff…

Android底层驱动移植--gslx680电容触摸屏驱动

###前言 gslx680电容触摸屏是一种目前Android嵌入式设备中比较常用的触摸屏类型。这里我们以Exynos4412为Android bsp平台&#xff0c;移植一款gslx680电容触摸屏。 关于电容触摸屏的原理&#xff0c;这里不进行讲解&#xff0c;不明白的&#xff0c;可以参照一下博客&#xff…

leetcode680

给定一个非空字符串 s&#xff0c;最多删除一个字符。判断是否能成为回文字符串。 示例 1: 输入: “aba” 输出: True 示例 2: 输入: “abca” 输出: True 解释: 你可以删除c字符。 class Solution {public boolean validPalindrome(String s) {int i-1,js.length();while(…

ZD680无人机组装调试流程

在权盛电子店里买了ZD680无人机套装&#xff0c;记录拼装调试的大体流程。 下面部分操作说明来源于权盛电子提供的教程。 一、配置清单 机架&#xff1a;ZD680&#xff0c;轴距680mm&#xff0c;机臂直径20mm&#xff0c;材质碳纤&#xff0c;载重3kg 电机&#xff1a;致盈…