您的位置:首页 > 编程语言 > PHP开发

MTK平台tp触摸屏驱动分析

2016-08-24 14:57 681 查看
转自http://m.blog.csdn.net/article/details?id=51362009本博文将讲解基于Goodix触控芯片的tp驱动程序。如有不足之处,敬请指出。

初始化

static int __init tpd_driver_init(void)
{
GTP_INFO("MediaTek gt91xx touch panel driver init\n");
#if defined(TPD_I2C_NUMBER)
i2c_register_board_info(TPD_I2C_NUMBER, &i2c_tpd, 1);
#else
i2c_register_board_info(0, &i2c_tpd, 1);
#endif
if (tpd_driver_add(&tpd_device_driver) < 0)
GTP_INFO("add generic driver failed\n");

return 0;
}
在[code]tpd_driver_init
中主要做了两件事情:[/code]

1、注册一个i2c设备

i2c_register_board_info
在kernel\drivers\i2c\i2c-boardinfo.c 中定义。对应的函数说明如下:i2c_register_board_info - statically declare I2C devices * @busnum: identifies the bus to which these devices belong * @info: vector of i2c device descriptors * @len: how many descriptors in the vector; may be zero to reserve * the specified bus number.因此我们可知道: 
TPD_I2C_NUMBER
表示的是当前注册的i2c设备是在哪个总线上面,需要查看硬件连接图; 
i2c_tpd
表示的是该i2c设备的描述,包括设备名”gt9xx”和i2c的设备地址“(0xBA>> 1)”
static struct i2c_board_info __initdata i2c_tpd = { I2C_BOARD_INFO("gt9xx", (0xBA >> 1))};
1

2、添加一个驱动到静态数组
tpd_driver_list
数组中

if (tpd_driver_add(&tpd_device_driver) < 0)GTP_INFO("add generic driver failed\n");
12其中
tpd_device_driver
的定义为:
static struct tpd_driver_t tpd_device_driver ={.tpd_device_name = "gt9xx",.tpd_local_init = tpd_local_init,.suspend = tpd_suspend,.resume = tpd_resume,#ifdef TPD_HAVE_BUTTON.tpd_have_button = 1,#else.tpd_have_button = 0,#endif};
这几个选项都是必须的。其中的
tpd_device_name
不能为”generic”,那样的话就会识别为R-Touch(推测此处表示为电阻屏),被保存到
tpd_driver_li
st[0]
中。否则为C-Touch(推测此处表示为电容屏),保存到
tpd_driver_list
的非0位置处。在TP驱动中要自己实现这几个函数的所有内容。

tpd_local_init()

static int tpd_local_init(void){#if GTP_ESD_PROTECTclk_tick_cnt = 2 * HZ;   // HZ: clock ticks in 1 second generated by systemGTP_DEBUG("Clock ticks for an esd cycle: %d", clk_tick_cnt);INIT_DELAYED_WORK(>p_esd_check_work, gtp_esd_check_func);gtp_esd_check_workqueue = create_workqueue("gtp_esd_check");spin_lock_init(&esd_lock);          // 2.6.39 & later// esd_lock = SPIN_LOCK_UNLOCKED;   // 2.6.39 & before#endif#if GTP_SUPPORT_I2C_DMAtpd->dev->dev.coherent_dma_mask = DMA_BIT_MASK(32);gpDMABuf_va = (u8 *)dma_alloc_coherent(&tpd->dev->dev, GTP_DMA_MAX_TRANSACTION_LENGTH, &gpDMABuf_pa, GFP_KERNEL);if(!gpDMABuf_va){GTP_INFO("[Error] Allocate DMA I2C Buffer failed!\n");}memset(gpDMABuf_va, 0, GTP_DMA_MAX_TRANSACTION_LENGTH);#endifif (i2c_add_driver(&tpd_i2c_driver) != 0){GTP_INFO("unable to add i2c driver.\n");return -1;}if (tpd_load_status == 0) //if(tpd_load_status == 0) // disable auto load touch driver for linux3.0 porting{GTP_INFO("add error touch panel driver.\n");i2c_del_driver(&tpd_i2c_driver);return -1;}input_set_abs_params(tpd->dev, ABS_MT_TRACKING_ID, 0, (GTP_MAX_TOUCH-1), 0, 0);#ifdef TPD_HAVE_BUTTONif (FACTORY_BOOT == get_boot_mode()|| RECOVERY_BOOT == get_boot_mode())  // cty 2014-08-14{tpd_button_setting(TPD_KEY_COUNT, tpd_keys_local_factory, tpd_keys_dim_local);// initialize tpd button data}else{tpd_button_setting(TPD_KEY_COUNT, tpd_keys_local, tpd_keys_dim_local);// initialize tpd button data}#endif#if (defined(TPD_WARP_START) && defined(TPD_WARP_END))TPD_DO_WARP = 1;memcpy(tpd_wb_start, tpd_wb_start_local, TPD_WARP_CNT * 4);memcpy(tpd_wb_end, tpd_wb_start_local, TPD_WARP_CNT * 4);#endif#if (defined(TPD_HAVE_CALIBRATION) && !defined(TPD_CUSTOM_CALIBRATION))memcpy(tpd_calmat, tpd_def_calmat_local, 8 * 4);memcpy(tpd_def_calmat, tpd_def_calmat_local, 8 * 4);#endif// set vendor stringtpd->dev->id.vendor = 0x00;tpd->dev->id.product = tpd_info.pid;tpd->dev->id.version = tpd_info.vid;GTP_INFO("end %s, %d\n", __FUNCTION__, __LINE__);tpd_type_cap = 1;return 0;}
该函数主要做以下几项工作:

1、GTP_ESD_PROTECT

为ESD防护机制。

2、GTP_SUPPORT_I2C_DMA

主要是申请I2C DMA的空间,由
gpDMABuf_va
指向。 
tpd->dev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
表示这个设备能寻址的物理地址的范围为
DMA_BIT_MASK(32)
,这个值相当于
0xffffffffUL
。关于这个成员的解释可以参见 linux下platform_device中的dma_mask与coherent_dma_mask。 接下来的
dma_alloc_coherent()
申请DMA空间。返回值为
gpDMABuf_va
表示虚拟地址,以及返回
gp
DMABuf_pa
表示DMA实际物理地址。至于这两个怎么用还不是很懂。详见:DynamicDMA mapping using the generic device

3、注册i2c设备驱动

if (i2c_add_driver(&tpd_i2c_driver) != 0){GTP_INFO("unable to add i2c driver.\n");return -1;}if (tpd_load_status == 0) //if(tpd_load_status == 0) // disable auto load touch driver for linux3.0 porting{GTP_INFO("add error touch panel driver.\n");i2c_del_driver(&tpd_i2c_driver);return -1;}
probe探测到总线上的设备并把设备和驱动建立连接以完成设备的初始化。这个中间会调用
tpd_i2c_driver
中的
tpd_i2c_probe()
来完成初始化工作。
static struct i2c_driver tpd_i2c_driver ={.probe = tpd_i2c_probe,.remove = tpd_i2c_remove,.detect = tpd_i2c_detect,.driver.name = "b_gt9xx_hotknot",.id_table = tpd_i2c_id,.address_list = (const unsigned short *) forces,};
这里面的内容都要自己去实现,特别是
tpd_i2c_probe()
。如果
tpd_i2c_probe()
中初始化设备全部完成,则要置位全局变量
t
pd_load_status
为1标记成功初始化,否则的话匹配失败需要调用
i2c_del_driver()
删除已注册的驱动。

4、设置input设备
tpd->dev
支持的最大手指触摸个数

input_set_abs_params(tpd->dev, ABS_MT_TRACKING_ID, 0, (GTP_MAX_TOUCH-1), 0, 0);
1input设备
tpd->dev
的申请以及定义和初始化的内容都在mtk_tpd.c这个文件中的
tpd_probe()
函数实现了。推测之所以没有一起初始化的
ABS_MT_TRACKING_ID
的内容是因为每个触控IC的原厂软件实现最大的触摸个数都不太一样,所以这里需要根据情况自己设定。

5、按键的初始化

#ifdef TPD_HAVE_BUTTONif (FACTORY_BOOT == get_boot_mode()|| RECOVERY_BOOT == get_boot_mode())  // cty 2014-08-14{tpd_button_setting(TPD_KEY_COUNT, tpd_keys_local_factory, tpd_keys_dim_local);// initialize tpd button data}else{tpd_button_setting(TPD_KEY_COUNT, tpd_keys_local, tpd_keys_dim_local);// initialize tpd button data}#endif
tpd_button_setting()
函数的内容非常简单,就是将数组
tpd_keys_local[TPD_KEY_COUNT]
t
pd_keys_dim_local[TPD_KEY_COUNT][4]
拷贝给
tpd_keys
tpd_keys_dim
。这两个变量用于
tpd_button_init()
的初始化创建virtualkeys。数组内容要根据TP的分辨率来确定按键的位置。需要根据不同分辨率来确定按键的个数、按键名称、按键的坐标范围。
#define TPD_KEY_COUNT   3#define TPD_KEYS        { KEY_BACK, KEY_HOMEPAGE,KEY_MENU}#define TPD_KEYS_FACTORY    {KEY_BACK , KEY_HOME,KEY_MENU}#define TPD_KEYS_DIM            {{100,1500,50,30},{270,1500,50,30},{450,1500,50,30}}#ifdef TPD_HAVE_BUTTONstatic int tpd_keys_local[TPD_KEY_COUNT] = TPD_KEYS;static int tpd_keys_local_factory[TPD_KEY_COUNT] = TPD_KEYS_FACTORY;static int tpd_keys_dim_local[TPD_KEY_COUNT][4] = TPD_KEYS_DIM;#endif
tp button也是和其它触摸事件一样,以坐标形式的input_event进行上报。在初始化时会通过tpd_button_setting()函数根据定义在tpd_custom_XXX.h文件中的配置信息将虚拟按键的坐标信息写在/sys/board_properties/virtualkeys.mtk-tpd中。工作时,tp driver将按下的点的坐标进行上报,Android上层会读取sys中的按键配置信息,再判断上报的坐标是否属于某个按键的坐标范围,以此将坐标信息转化为具体的按键键值。 详见android虚拟按键是通过哪种机制上报的?MTK虚拟按键的实现在tpd_button.c中实现,具体内容详见Android tp的虚拟按键(virtual key)处理

6、设置input设备
tpd->dev
的信息

// set vendor stringtpd->dev->id.vendor = 0x00;tpd->dev->id.product = tpd_info.pid;tpd->dev->id.version = tpd_info.vid;
其中[code]tpd_info
的信息是在
tpd_i2c_probe()
中调用
gtp_read_version()
获取到的。[/code]

7、设置TP类型为电容屏

tpd_type_cap = 1;
1从变量字面上的意思来看是设置标记TP为电容屏,至于还有何作用还不得而知。

tpd_i2c_probe()

static s32 tpd_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id){s32 err = 0;s32 ret = 0;u16 version_info;#if GTP_HAVE_TOUCH_KEYs32 idx = 0;#endif#ifdef TPD_PROXIMITYstruct hwmsen_object obj_ps;#endifi2c_client_point = client;ret = tpd_power_on(client);if (ret < 0){GTP_ERROR("I2C communication ERROR!");goto out;}#ifdef VELOCITY_CUSTOMtpd_v_magnify_x = TPD_VELOCITY_CUSTOM_X;tpd_v_magnify_y = TPD_VELOCITY_CUSTOM_Y;#endifret = gtp_read_version(client, &version_info);if (ret < 0){GTP_ERROR("Read version failed.");goto out;}ret = gtp_init_panel(client);if (ret < 0){GTP_ERROR("GTP init panel failed.");//goto out;}// Create proc file systemgt91xx_config_proc = proc_create(GT91XX_CONFIG_PROC_FILE, 0660, NULL, >_upgrade_proc_fops);if (gt91xx_config_proc == NULL){GTP_ERROR("create_proc_entry %s failed\n", GT91XX_CONFIG_PROC_FILE);goto out;}#if GTP_CREATE_WR_NODEinit_wr_node(client);#endifthread = kthread_run(touch_event_handler, 0, TPD_DEVICE);if (IS_ERR(thread)){err = PTR_ERR(thread);GTP_INFO(TPD_DEVICE " failed to create kernel thread: %d\n", err);goto out;}#if GTP_HAVE_TOUCH_KEYfor (idx = 0; idx < GTP_MAX_KEY_NUM; idx++){input_set_capability(tpd->dev, EV_KEY, touch_key_array[idx]);}#endif#if GTP_GESTURE_WAKEUP//input_set_capability(tpd->dev, EV_KEY, KEY_POWER);#endif#if GTP_WITH_PEN// pen support__set_bit(BTN_TOOL_PEN, tpd->dev->keybit);__set_bit(INPUT_PROP_DIRECT, tpd->dev->propbit);//__set_bit(INPUT_PROP_POINTER, tpd->dev->propbit); // 20130722#endif// set INT modemt_set_gpio_mode(GPIO_CTP_EINT_PIN, GPIO_CTP_EINT_PIN_M_EINT);mt_set_gpio_dir(GPIO_CTP_EINT_PIN, GPIO_DIR_IN);mt_set_gpio_pull_enable(GPIO_CTP_EINT_PIN, GPIO_PULL_DISABLE);msleep(50);mt_eint_set_hw_debounce(CUST_EINT_TOUCH_PANEL_NUM, 0);if (!int_type)  //EINTF_TRIGGER{mt_eint_registration(CUST_EINT_TOUCH_PANEL_NUM, EINTF_TRIGGER_RISING, tpd_eint_interrupt_handler, 1);}else{mt_eint_registration(CUST_EINT_TOUCH_PANEL_NUM, EINTF_TRIGGER_FALLING, tpd_eint_interrupt_handler, 1);}mt_eint_unmask(CUST_EINT_TOUCH_PANEL_NUM);#if GTP_AUTO_UPDATEret = gup_init_update_proc(client);if (ret < 0){GTP_ERROR("Create update thread error.");}#endif#ifdef TPD_PROXIMITY//obj_ps.self = cm3623_obj;obj_ps.polling = 0;         //0--interrupt mode;1--polling mode;obj_ps.sensor_operate = tpd_ps_operate;if ((err = hwmsen_attach(ID_PROXIMITY, &obj_ps))){GTP_ERROR("hwmsen attach fail, return:%d.", err);}#endif#if GTP_ESD_PROTECTgtp_esd_switch(client, SWITCH_ON);#endiftpd_load_status = 1;return 0;out:return -1;}
一般来说,TP驱动probe()函数中一般会做以下几个工作:

1、
TPD_PROXIMITY

在多数情况下,通话的时候,脸部靠近会自动息屏,脸部拿开会自动亮屏,这个功能主要由接近传感器Proximity Sensor(简称PS)实现。但是有时候在方案设计中,为了省下一颗光感,往往要求触控ic支持此功能。当TP感应上半部分有多数差值到达门限,就会认定脸部靠近,会置对应的标记为在某个寄存器中,驱动中读取该标记位判断是否亮屏或者暗屏。所有与接近感应功能对应的code使用宏
TPD_PROXIMITY
进行控制: (1)、创建 hwsen 对象以及实现其内容
#ifdef TPD_PROXIMITYstruct hwmsen_object obj_ps;#endif#ifdef TPD_PROXIMITY//obj_ps.self = cm3623_obj;obj_ps.polling = 0;         //0--interrupt mode;1--polling mode;obj_ps.sensor_operate = tpd_ps_operate;if ((err = hwmsen_attach(ID_PROXIMITY, &obj_ps))){GTP_ERROR("hwmsen attach fail, return:%d.", err);}#endif
MTK代码里使用了一个hwmsensor模块控制所有的sensor。 代码路径:mediatek/kernel/drivers/hwmon/hwmsen/hwmsen_dev.c,编译成hwmsen_dev.o,系统起来后会生成/dev/hwmsensor设备。 使用
sensor_operate()
接口管理所有sensor驱动,向上提供
hwmsen_unlocked_ioctl()
接口,再往下就是具体的sensor驱动代码了,根据MTK的驱动结构完成
sen
or_operate()
接口并调用hwmsen_dev.c里的
hwmsen_attach()
函数,把
sensor_operate()
接口加到hwmsen_dev的列表里,这样hwmsen_dev里就能调用所有sensor的
sensor_operate()
函数。 详见AndroidSensor学习这篇文章。
obj_ps.polling = 0;
1标记此sensor工作在中断模式下而不是轮询方式,通过中断上报数据。
obj_ps.sensor_operate = tpd_ps_operate;
1主要实现获取通话时候的状态信息并根据此状态信息判断是否上报接近或者远离动作。
hwmsen_attach(ID_PROXIMITY, &obj_ps)
1这是将接近感应传感器设备驱动添加到 hwmsen device 中。 (2)、实现
tpd_ps_operate()
内容 创建两个全局变量:
#ifdef TPD_PROXIMITYstatic s32 tpd_get_ps_value(void){return tpd_proximity_detect;}// 判断是否打开接近感应功能static s32 tpd_enable_ps(s32 enable){u8  state;s32 ret = -1;if (enable){state = 1;tpd_proximity_flag = 1;GTP_INFO("TPD proximity function to be on.");}else{state = 0;tpd_proximity_flag = 0;GTP_INFO("TPD proximity function to be off.");}ret = i2c_write_bytes(i2c_client_point, TPD_PROXIMITY_ENABLE_REG, &state, 1);if (ret < 0){GTP_ERROR("TPD %s proximity cmd failed.", state ? "enable" : "disable");return ret;}GTP_INFO("TPD proximity function %s success.", state ? "enable" : "disable");return 0;}s32 tpd_ps_operate(void *self, u32 command, void *buff_in, s32 size_in,void *buff_out, s32 size_out, s32 *actualout){s32 err = 0;s32 value;hwm_sensor_data *sensor_data;switch (command){case SENSOR_DELAY:if ((buff_in == NULL) || (size_in < sizeof(int))){GTP_ERROR("Set delay parameter error!");err = -EINVAL;}// Do nothingbreak;case SENSOR_ENABLE:if ((buff_in == NULL) || (size_in < sizeof(int))){GTP_ERROR("Enable sensor parameter error!");err = -EINVAL;}else{value = *(int *)buff_in;err = tpd_enable_ps(value);  // 获取是否在通话的状态并赋值给tpd_proximity_flag}break;case SENSOR_GET_DATA:if ((buff_out == NULL) || (size_out < sizeof(hwm_sensor_data))){GTP_ERROR("Get sensor data parameter error!");err = -EINVAL;}else{sensor_data = (hwm_sensor_data *)buff_out;sensor_data->values[0] = tpd_get_ps_value();  // 将检测到的接近或者远离的状态tpd_proximity_detect发送出去sensor_data->value_divide = 1;sensor_data->status = SENSOR_STATUS_ACCURACY_MEDIUM;}break;default:GTP_ERROR("proxmy sensor operate function no this parameter %d!\n", command);err = -1;break;}return err;}#endif
当通话的时候,会调用
tpd_ps_operate()
进入
caseSENSOR_ENABLE:
将通话的标记作为参数传给
tpd_enabl
e_ps(value)
,这个函数很简单,就是赋值给变量
tpd_proximity_flag
,该变量标记此时是否需要打开接近感应功能。如果需要打开接近感应功能,需往ic对应的寄存器写入某个对应的值。当检测到接近全局变量
tpd_proximity_detect
会置为0;当检测到远离,
tpd
_proximity_detect
会置为1。在
case SENSOR_GET_DATA:
中会上报检测到的接近或者远离的状态(
tpd_proximity_detect
为0或者为1)。不过在中断的内核进程中
touch_event_handler()
也有一段同样的code。不知道是走哪个流程的。
#ifdef TPD_PROXIMITYif (tpd_proximity_flag == 1){proximity_status = point_data[GTP_ADDR_LENGTH];GTP_DEBUG("REG INDEX[0x814E]:0x%02X\n", proximity_status);if (proximity_status & 0x60)  //proximity or large touch detect,enable hwm_sensor.{tpd_proximity_detect = 0;//sensor_data.values[0] = 0;}else{tpd_proximity_detect = 1;//sensor_data.values[0] = 1;}//get raw dataGTP_DEBUG(" ps change\n");GTP_DEBUG("PROXIMITY STATUS:0x%02X\n", tpd_proximity_detect);//map and store data to hwm_sensor_datasensor_data.values[0] = tpd_get_ps_value();sensor_data.value_divide = 1;sensor_data.status = SENSOR_STATUS_ACCURACY_MEDIUM;//report to the up-layerret = hwmsen_get_interrupt_data(ID_PROXIMITY, &sensor_data); // 通过中断的方式将接近或者远离的状态上报给 PROXIMITY sensorif (ret){GTP_ERROR("Call hwmsen_get_interrupt_data fail = %d\n", err);}}#endif
注意,如果是检测到在通话中且脸部接近的动作的时候,此时应该要屏蔽上报坐标的功能。(3)、亮屏、暗屏 暗屏和亮屏的动作也会调用
tpd_suspend()
tpd_resume()
。一般suspend的时候ic要进入休眠模式且关闭中断刷新工作队列等工作。在resume的时候要唤醒ic,使能中断以及其他工作。如果是由于通话中接近或者远离导致suspend或者resume都不必做这些工作,只需要直接返回。因为此时要求ic还要能够正常工作。

2、
tpd_power_on()

在这个函数里面,主要做了三件事:

1、给ic上电

#ifdef MT6573// power on CTPmt_set_gpio_mode(GPIO_CTP_EN_PIN, GPIO_CTP_EN_PIN_M_GPIO);mt_set_gpio_dir(GPIO_CTP_EN_PIN, GPIO_DIR_OUT);mt_set_gpio_out(GPIO_CTP_EN_PIN, GPIO_OUT_ONE);#else   // ( defined(MT6575) || defined(MT6577) || defined(MT6589) )#ifdef TPD_POWER_SOURCE_CUSTOMhwPowerOn(TPD_POWER_SOURCE_CUSTOM, VOL_2800, "TP");#elsehwPowerOn(MT65XX_POWER_LDO_VGP2, VOL_2800, "TP");#endif#ifdef TPD_POWER_SOURCE_1800hwPowerOn(TPD_POWER_SOURCE_1800, VOL_1800, "TP");#endif#endif
关于上电的动作可参考MTK Android Driver:PMIC

2、复位ic

void gtp_reset_guitar(struct i2c_client *client, s32 ms){GTP_INFO("GTP RESET!\n");GTP_GPIO_OUTPUT(GTP_RST_PORT, 0);msleep(ms);GTP_GPIO_OUTPUT(GTP_INT_PORT, client->addr == 0x14);msleep(2);GTP_GPIO_OUTPUT(GTP_RST_PORT, 1);msleep(6);                      //must >= 6ms#if GTP_COMPATIBLE_MODEif (CHIP_TYPE_GT9F == gtp_chip_type){return;}#endifgtp_int_sync(100);  // for dbl-system#if GTP_ESD_PROTECTgtp_init_ext_watchdog(i2c_client_point);#endif}
复位ic就是讲ic上的RST脚设为输出拉低再拉高。MTK的tp驱动程序需要涉及对ic三个引脚的操作:EN(使能或VDD脚)、RST(复位脚)、EINT(外部中断脚)。这三个引脚对应的宏固定为:
GPIO_CTP_EN_PINGPIO_CTP_RST_PINGPIO_CTP_EINT_PIN
123这几个宏在以下路径中的文件进行配置对应的GPIO口 alps\mediatek\dct\DrvGen.exe alps\mediatek\custom\project\kernel\dct\dct\codegen.dws 配置

3、测试I2C是否通

static s8 gtp_i2c_test(struct i2c_client *client);
1测试i2c是否通信成功,需要用到i2c的读写接口,至于接口函数怎么写,可以参照这篇文章待定

3、初始化ic

接下来就是通过i2c读写接口初始化ic了。
s32 gtp_read_version(struct i2c_client *client, u16 *version);static s32 gtp_init_panel(struct i2c_client *client);
12至于初始化的内容会放到一个全局的数组之中,这项工作一般都要FAE来完成。

4、创建内核线程

thread = kthread_run(touch_event_handler, 0, TPD_DEVICE);if (IS_ERR(thread)){err = PTR_ERR(thread);GTP_INFO(TPD_DEVICE " failed to create kernel thread: %d\n", err);goto out;}
创建名为
TPD_DEVICE
线程
thread
是为了处理中断来临之后读取坐标、上报坐标、手势识别、按键等等信息。判断
thread
是否有效需要用
IS_ERR()
来判断,而不是简单的使用
(thread== NULL)
判断,详见Linux内核多线程(一)其主要内容如下:
static int touch_event_handler(void *unused){struct sched_param param = { .sched_priority = RTPM_PRIO_TPD };sched_setscheduler(current, SCHED_RR, ¶m); // 调度策略和调度参数分别设置为param指向的sched_param结构中指定的policy和参数do{set_current_state(TASK_INTERRUPTIBLE); // 设置当前线程可被打断if(tpd_eint_mode)  // 标记采用轮询方式还是中断方式,此处为中断方式{wait_event_interruptible(waiter, tpd_flag != 0); // 此处等待waiter被唤醒,只有当tpd_flag不为1且wake_up waite才会去执行。可知这两个条件都在中断服务子程序去置位了tpd_flag = 0; // 判断是否有中断的标记}else{msleep(tpd_polling_time);}set_current_state(TASK_RUNNING);// 标记当前线程正执行mutex_lock(&i2c_access);// 此处添加你的工作mutex_unlock(&i2c_access);} while (!kthread_should_stop());return 0;}
28对于
wait_event_interruptible()
可以参照wait_event_interruptible使用方法 写这个内容好着急啊,很多知识点都没有很深入的了解,只能参照网上说的来进行解释。

5、申请中断服务子程序

// set INT modemt_set_gpio_mode(GPIO_CTP_EINT_PIN,GPIO_CTP_EINT_PIN_M_EINT);mt_set_gpio_dir(GPIO_CTP_EINT_PIN, GPIO_DIR_IN);mt_set_gpio_pull_enable(GPIO_CTP_EINT_PIN,GPIO_PULL_DISABLE);msleep(50);mt_eint_set_hw_debounce(CUST_EINT_TOUCH_PANEL_NUM, 0);if (!int_type)  //EINTF_TRIGGER{mt_eint_registration(CUST_EINT_TOUCH_PANEL_NUM, EINTF_TRIGGER_RISING, tpd_eint_interrupt_handler, 1);}else{mt_eint_registration(CUST_EINT_TOUCH_PANEL_NUM, EINTF_TRIGGER_FALLING, tpd_eint_interrupt_handler, 1);}mt_eint_unmask(CUST_EINT_TOUCH_PANEL_NUM); // 关闭中断使能,probe完毕之后会打开中断使能
CUST_EINT_TOUCH_PANEL_NUM
为分配给触摸ic的中断号,在alps\mediatek\custom\project\kernel\dct\dct\cust_eint.h中定义; 设置中断的触发方式 为上升沿或者下降沿(需要根据ic的功能设置);GPIO的相关功能可参照MTK6577+Android之GPIO驱动简介 设置中断服务子程序
static void tpd_eint_interrupt_handler(void)
 这个函数的内容很简单,就是置位
tpd_flag
变量和wake_upwaiter.
static void tpd_eint_interrupt_handler(void){TPD_DEBUG_PRINT_INT;tpd_flag = 1;wake_up_interruptible(&waiter);}
至此,
tpd_i2c_probe()
的所有内容都已实现,接下来就是等待ic给中断然后读取坐标等信息了。

tpd_down()和tpd_up()

这两个函数通过input子系统上报坐标以及上报手指抬起的动作。关于input子系统,我根据自己的理解写了待定

tpd_suspend()和tpd_resume()

关于休眠和唤醒的内容根据ic的特性设置。如休眠的时候需要关闭中断、配置进入休眠模式。唤醒的时候唤醒ic,使能中断等。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: