手机上一般都用距离感应器来做通话时的贴脸熄屏,而现在的TP芯片一般也都具有了这个功能,所以如果TP能够实现贴脸熄屏的话,将可以省下距离感应器的成本。其原理就是通话时打开TP的电容感应,通过脸的靠近和移动来检测TP电容的变化,从而判断人脸跟听筒的距离,调整LCD背光的亮灭,在通话断开时关闭TP的此功能即可。
MELFAS的芯片此项功能做法如下:
(1)首先定义两个全局变量:
unsigned char ps_data_state_value; //从TP的PS寄存器读出的当前是否贴脸的判断值,只可读
unsigned char ps_onoff_state_control; //使能TP做PS功能的开关,可读可写
(2)在TP的probe函数中用device_create_file分别创建两个设备属性,名字分别是:“/sys/class/mtk-tpd/device/proximity_sensor”和“/sys/class/mtk-tpd/device/proximity_sensor_state”,这两个变量只需上层open即可用来跟上层进行控制通讯,前者可读可写,上层用来对TP的PS功能的使能和禁止进行控制,通话时写1,通话断开时写0;后者仅可读,当通话时TP的PS功能打开时,该值为1表明贴脸了要关掉LCD背光,该值为0表明脸移开要打开LCD背光。
上面两个属性对应的show/store函数如下,分别在read/write时被调用,需要用到的寄存器是0x01和0x17。
static ssize_t show_proximity_sensor(struct device *dev, struct device_attribute *attr, char *buf) //显示TP PS功能是否打开
{
static unsigned char temp = 2;
if(temp != ps_onoff_state_control){
printk("proximity_sensor_show: ps_onoff_state_control=%d\r\n", ps_onoff_state_control);
temp = ps_onoff_state_control;
}
return sprintf(buf, "%d\n", ps_onoff_state_control);
}
static ssize_t store_proximity_sensor(struct device *dev, struct device_attribute *attr, const char *buf, size_t size)
{
printk("store_proximity_sensor ,*buf is %s \r\n",buf); //上层对TP PS的使能控制
U8 RegValue;
if(buf != NULL && size != 0)
{
printk("store_proximity_sensor no null \r\n");
if('0' == *buf) { //通话断开禁止功能
printk("DISABLE_CTP_PS buf=%d,size=%d\n", *buf, size);
mfs_i2c_read_single_reg(0x01,&RegValue);
msleep(200);
RegValue &= 0xdf;
mfs_i2c_write_single_reg(0x01,RegValue); //该功能的寄存器位置0
msleep(500);
ps_onoff_state_control = 0; //该功能开关状态置0
ps_data_state_value = 0; //该功能只是状态置0
}
else if('1' == *buf){ //通话使能该功能时
printk("ENABLE_CTP_PS buf=%d,size=%d\n", *buf, size);
mfs_i2c_read_single_reg(0x01,&RegValue);
msleep(200);
RegValue |= 0x20;
mfs_i2c_write_single_reg(0x01,RegValue); //该功能的寄存器位置1
msleep(500);
ps_onoff_state_control = 1; //该功能开关状态置1
}
}
return size;
}
static ssize_t show_proximity_sensor_state(struct device *dev, struct device_attribute *attr, char *buf) //显示TP PS的工作指示状态
{
static unsigned char temp = 2;
if(temp != ps_data_state_value){
printk("show_proximity_sensor_state: ps_data_state_value=%d\n\n", ps_data_state_value);
temp = ps_data_state_value;
}
return sprintf(buf, "%d\n", ps_data_state_value);
}
(3)上面着重使能的控制,下面讲述TP PS状态的指示。当通话时TP的该功能激活后,TP也处于一种中断状态,屏表面电容的变化都会触发中断,让TP进行相应的处理,所以在TP的中断处理函数中,加上如下处理:
uint8_t ProximityEn; //读TP工作状态的PS位是否激活
uint8_t ProximityDecetVal; //读TP的PS反馈值
mfs_i2c_read_single_reg(0x01,&ProximityEn);
if((ProximityEn&0x20)!=0) //只有PS功能激活后,才去读反馈值
{
mfs_i2c_read_single_reg(0x17,&ProximityDecetVal);
if(ProximityDecetVal == 1) // close to
{
printk("TP_PROXIMITY_SENSOR_DEFINE '1' close to by zhangcheng\n");
ps_data_state_value = 1; //人脸接近LCD,置1
}
else if(ProximityDecetVal == 0) // leave
{
printk("TP_PROXIMITY_SENSOR_DEFINE '0' leave by zhangcheng\n");
ps_data_state_value = 0; //人脸离开LCD,置0
}
}
完毕。
需要注意的是:偶尔会出现贴脸通话一段时间,移开手机后,LCD不会重亮,原因是手机睡眠后导致TP也会睡眠,这样就算拿开手机后TP也不会相应外部的电容变化。所以解决方法是:通话过程中贴脸熄屏激活后,睡眠时不要走正常的睡眠处理,PASS掉就行了。
另外一个需要注意的是:操作手机的睡眠和唤醒时,偶尔会出现TP不能使用,要睡眠再唤醒后才可以使用。此时一个可能的原因是LCD跟TP的上电先后顺序可能会影响到。
==================如何计算TP中断触发的频率===================
如何发现TP报点慢,画线卡顿,原因有很多。中断触发的频率值的大小是其中一个因素,可以通过测试INT的波形来获得,也可以通过软件计算获得,因为每次中断触发都会跑到中断处理Handler中,只需要在Handler的开头加上如下语句,即可获知
static void goodix_ts_work_func(struct work_struct *work)
{
static unsigned long lastjiffies = 0;
unsigned long currentjiffies = jiffies;
unsigned int tamp = jiffies_to_msecs(jiffies-lastjiffies);
printk("TP int freq is %d \r\n",1000/tamp);
lastjiffies = currentjiffies;
每次最新的jiffies减去上次触发时的jiffies得到差值,tamp /1000得到的s时间即为触发周期,倒一下就变成频率值了。经测算,我的INT触发频率是100,还是较高的。所以问题不在这里,在中断处理handler中,读出XY座标的处理有问题。
==================notifier机制做TP休眠唤醒处理===================
如果TP驱动中没有做suspend和resume的接口,如何处理TP的休眠唤醒呢?采用notifier机制是种思路,因为注册它以后,可以捕获亮屏和熄屏的时机,可以家对应的代码。比如下:
if (*blank == FB_BLANK_UNBLANK)//亮屏
msg21xx_ts_resume(&msg21xx_data->client->dev);
else if (*blank == FB_BLANK_POWERDOWN)//灭屏
msg21xx_ts_suspend(&msg21xx_data->client->dev);
完整注册和应用参见:https://www.cnblogs.com/linhaostudy/p/9909267.html