【TP】【P-sensor】TP模拟P-sensor

Touchpanel模拟P-sensor功能简述


1.功能概述

该功能用于低端机上为降低成本而设计,利用触摸屏的感应功能,模拟p-sensor在通话时候能根据距离远近来灭屏亮屏的一种功能,从功能性角度上来说可以替代p-sensor在通话过程中防止误触的操作。但从实际意义上说,该种功能是无法代替真实的物理sensor的,无论是灵敏度还是准确性。并且会需要touchpanel牺牲灵敏度去增强感应量来达到该功能的目的。

2.实现原理

 感应距离:

l目前FAE反馈能调试的距离为5mm-10mm,一般在6mm-8mm之间。感应距离主要跟CTP灵敏度有关。我们首先需要确保电容屏的性能能满足公司的测试标准,然后再优化模拟P-Sensor的功能。
l通过跟FAE沟通,对感应距离的测试,可以用铜片进行。铜片大小需要满足1/2的屏幕,且需要接地。测试的时候要保持铜片与屏幕平行。
l

固件软件支持的功能:

l需要支持模拟P-Sensor接近功能,可实现5mm-10mm不接触CTP的情况下,模拟P-Sensor接近效果。
l需要支持大面积触摸感应功能。当手或脸紧贴着CTP的上半部分,CTP固件软件仍然能识别并模拟P-Sensor的接近效果.。
l当CTP模拟P-Sensor功能开启后,CTP除了能正常获取模拟P-Sensor的状态外,还能同时支持正常的触摸坐标报点,及触摸屏虚拟按键的报点功能。

2.框架理解

从框架角度来讲,该功能也是利用平台本身的框架去完成的。在touchpanel的driver中新建一个虚拟的sensor,在suspend/resume和interrupt等情况下完成sensor该做的操作,利用一个变量来标志在各个阶段下是应该灭屏还是亮屏,然后上报事件到对应sensor上层接口。整体来说,上层的框架都没有改变,只是需要在touchpanel的driver中新建虚拟设备,完成特殊的上报,并去上层对接。

虽然对上层的框架没有做调整或者优化,但对上层的一些处理和流程,对该功能的开发也是十分有帮助的。尤其是在和driver层交接数据的接口等。

3.Sensor的上层以及HAL

Sensor关灭屏的应用层及client,server等基本都是android原生的,高通和MTK没有多大差别。主要的区别在与hal层的不同。高通的sensor架构 方面,没有MTK的hwm或者alsps在驱动层去管理各个sensor。而是由hal层直接访问驱动层的enable节点。MTK会有一个hwmsen的软件设备创建,然后用它去连接新增的虚拟sensor的接口,下面软件向上报enable或者disable,上层继续沿用以前的框架。

Qcom是新建一个节点enable,在其节点中写1和0来表示是否需要灭屏,在sys/device/event下回有设备enable/disable来表示有无元使能。

4.HAL层大体流程如下:

   1.sensors.cpp创建NativeSensorManager,NativeSensorManager维护一个list并通过getDataInfo找到驱动的设备,并创建各个sensor的driver对象,如:new ProximitySensor(list);。

   2.其中,getDataInfo通过getSensorListInner扫描获取/sys/class/sensors/下 面的sensor节点等信息添加到list。在上层enable时,通过list调用各个sensor的driver对象的方法进行 enable,在sensor driver对象的enable方法里,会在找到的sensor节点后面的enable等节点进行写来调用驱动的enable。

    3.而input节点在getSensorListInner中通过getEventPathOld扫描/dev/input下 面的节点,并通过name匹配获取各个sensor对应的input节点路径。这样上层读取数据时就可以通过各自的方法,访问各自的input节 点,获取数据。

    4.这样的话,驱动会比较乱,没有统一的方法与hal层链接,因此高通提供了sensors_classdev_register函 数来供驱动调用创建固定的enable等节点,供hal层访问。而input和MTK 相同,采用linux的input_register_device进行注册即可在/dev/input下面创建对应的input节点供hal层访问。

5.因此,主要的驱动修改可以参考平台里面的例子,主要在probe里面通过sensors_classdev_register创 建/sys/class/sensors/下面的sensor节点,及input_register_device进行/dev/input下面的input创建。

6.MTK的话就还需要再依附alsps和hwm来进行sensor的注册和管理

5.底层驱动原理

在驱动层方面,首先要注册一个虚拟sensor的时候首先是需要一个cdev的结构体来列举在该sensor节点下面所有的属性和参数,该结构标准最好按照物理真实sensor来操作,这样的话,以便HAL的调用和管理。如下

struct virtualpsensor {

char const *name;

// struct i2c_client *client;

struct input_dev *virtualdevice;

bool vps_enabled;

struct sensors_classdev vps_cdev;

bool virtual_proximity_data;

};

 struct sensors_classdev virtual_sensors_proximity_cdev = {

.name = VPS_NAME,

.vendor = "NULL",

.version = 1,

.handle = SENSORS_PROXIMITY_HANDLE,

.type = SENSOR_TYPE_PROXIMITY,

.max_range = "5",

.resolution = "5.0",

.sensor_power = "3",

.min_delay = 0, /* in microseconds */

.fifo_reserved_event_count = 0,

.fifo_max_event_count = 0,

.enabled = 0,

.delay_msec = 100,

.sensors_enable = NULL,

.sensors_poll_delay = NULL,

};

然后是将其enable,详细代码不再赘述,如有兴趣请参考pixi4-4.5 TF ATT的两块TP driver中vps_set_enable()。下一步是分析register,首先需要明白是需要register一个虚拟sensor和一个input_device。那么需要分配输入设备的内存,且先register input device。再声明上报事件和事件上报的范围。调用cdev和enable,同理还可以设置cdev中其余参数,如sensors_poll_delay = NULL。然后使用<linux/sensors>中的sensors_classdev_register()来注册虚拟sensor。如下:

int virtual_psensor_input_register(struct i2c_client *pClient)

{

s32 nRetVal = 0;

 

pr_err("*** %s() ***\n", __func__);

 

vps = kzalloc(sizeof(struct virtualpsensor), GFP_KERNEL);

// vps->client = pClient;

// i2c_set_clientdata(pClient, vps);

 

vps->virtualdevice= input_allocate_device();

if (vps->virtualdevice == NULL)

{

pr_err("*** input device allocation failed ***\n");

return -ENOMEM;

}

 

vps->virtualdevice->name = "proximity";

vps->virtualdevice->id.bustype = BUS_I2C;

 

/* set the supported event type for input device */

set_bit(EV_ABS, vps->virtualdevice->evbit);

set_bit(ABS_DISTANCE, vps->virtualdevice->absbit);

input_set_abs_params(vps->virtualdevice, ABS_DISTANCE, 0, 1, 0, 0);

 

nRetVal = input_register_device(vps->virtualdevice);

if (nRetVal < 0)

{

pr_err("*** Unable to register virtual P-sensor input device ***\n");

return nRetVal;

}

 

vps->vps_cdev = virtual_sensors_proximity_cdev;

vps->vps_cdev.sensors_enable = vps_set_enable;

vps->vps_cdev.sensors_poll_delay = NULL;

 

nRetVal = sensors_classdev_register(&pClient->dev, &vps->vps_cdev);

if (nRetVal) {

pr_err("%s: Unable to register to sensors class: %d\n",__func__, nRetVal);

return nRetVal;

}

 

return 0;

}

该段register的函数放在probe中,建议register device后面,并按照register的顺序,在remove()中也相应的添加unregister以便注销。至此,虚拟的sensor设备就应该能在对应的input设备和节点中能够生成。那么接下来需要具体对该sensor的功能做设计。首先必须将有一个变量(tpd_proximity_ft6336_far)来辨别fay away 和close to两种状态。并在interrupt中添加相应的事件和上报值。以便hal接收。如下:

if(tpd_proximity_ft6336_enable)

{

reg_addr = FT_FACE_DETECT_REG;

 

if( ft6x06_read_reg(data->client, reg_addr, ®_value) < 0)

{

dev_err(&data->client->dev, "%s get face detect enable information failed.\n",

__func__);

}

else

{

if(!(reg_value&0x01))

{

vps_set_enable(&virtual_sensors_proximity_cdev,1);

}

 

 

is_face_detect = buf[FT_FACE_DETECT_POS] & 0xE0;

 

if(is_face_detect==0xC0)

{

tpd_proximity_ft6336_far = 0;

}

else if(is_face_detect==0xE0)

{

tpd_proximity_ft6336_far = 1;

 

}

 

if(tpd_proximity_ft6336_last_far != tpd_proximity_ft6336_far)

{

printk("tpd_virtual_sensors_proximity = %d (0:near / 1:far) \n",tpd_proximity_ft6336_far);

}

 

input_report_abs(vps->virtualdevice, ABS_DISTANCE, tpd_proximity_ft6336_far);

    input_sync(vps->virtualdevice);

 

tpd_proximity_ft6336_last_far =  tpd_proximity_ft6336_far;

}

对变量tpd_proximity_ft6336_far的操作,存在几个函数之前,如suspend,resume。

例如在suspend的时候,将判断是否enable该功能,然后enable中断,将suspend作为一个特殊的变量来标志。因为在resume的时候再判断是否处于这种特殊状态进入suspend的情况。如下例代码:

if(tpd_proximity_ft6336_enable)

{

err = enable_irq_wake(ft_g_client->irq);  

if (err) {  

        pr_err("[ft6xx6] enable_irq_wake failed.\n");   

    }  

if (device_may_wakeup(&ft_g_client->dev))

{

err = enable_irq_wake(data->client->irq);

if (err)

{

printk("%s: enable_irq_wake(%d) failed, err=(%d)\n", __func__, data->client->irq, err);

}

else

{

printk("%s: not support wakeup source", __func__);

}

}

tpd_proximity_ft6336_suspend= 1;

printk("== virtual proximity %s() ==\n",__func__);

return 0;

if(tpd_proximity_ft6336_enable)

{

err = disable_irq_wake(ft_g_client->irq);  

if (err) {  

        pr_err("[ft6xx6] disable_irq_wake failed.\n");   

    }  

if (device_may_wakeup(&ft_g_client->dev))

{

err = disable_irq_wake(data->client->irq);

if (err)

{

printk("%s: disable_irq_wake(%d) failed, err=(%d)\n", __func__, data->client->irq, err);

}

else

{

printk("%s: not support wakeup source", __func__);

}

}

if(tpd_proximity_ft6336_suspend == 1)

{

tpd_proximity_ft6336_suspend = 0;

printk("== virtual proximity %s() ==\n",__func__);

return 0;

另外,因上层会有特定的server,在通话等界面会讲enable节点写1,即开始enable虚拟sensor的这套判定机制。那么就存在着对enable节点权限的关系,如果权限不适配的话也可以能导致功能无法ok。正常情况可设置为system root 0664,详细情况可以检查enable没变值之后手动改变节点尝试。

该功能软件设计建议

如果要自行实现该方案,如下的SW建议可以重点参考:
l模拟P-Sensor启动时,需要确保CTP已经被唤醒:

  由于模拟P-Sensor是需要CTP来提供接近或远离的状态,因此在启动模拟P-Sensor功能前,需要确保CTP已经被唤醒。否则模拟P-Sensor将由于获取不到CTP的数据而失效:

   if(enable){

                       TPD_DEBUG("[MSG2133A]Beforethe PS enable wake up the CTP\n");

                        mt_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);

                        mt_set_gpio_out(GPIO_CTP_EN_PIN,GPIO_OUT_ZERO);

                        msleep(10);

                        mt_set_gpio_out(GPIO_CTP_EN_PIN,GPIO_OUT_ONE);

                        msleep(300);

                       mt65xx_eint_unmask(CUST_EINT_TOUCH_PANEL_NUM); 

 

                        dbbus_tx_data[0] =0x52;   dbbus_tx_data[1] =0x00;

                        dbbus_tx_data[2] =0x4A;   dbbus_tx_data[3] =0xA0;

                         err =i2c_master_send(i2c_clientma, &dbbus_tx_data[0],4);

                         if(err>=0){

         TPD_DMESG(“ ctppsopen OK\n");


l模拟P-sensor开启后,CTP需要保持在唤醒状态:

   模拟P-Sensor是需要CTP来提供接近或远离状态的,因此在启动模拟P-Sensor功能后,CTP需要一直 

   处于唤醒状态:

     static int mstar2133_pls_open(struct inode *inode, struct file*file)

     {

        mstar2133_pls_opened = 1;

        …

     }

     static int mstar2133_pls_release(struct inode *inode, struct file*file)

     {

         mstar2133_pls_opened = 0;

         …

     }

 

     static int tpd_suspend(structi2c_client *client, pm_message_tmessage)

     {

        if(mstar2133_pls_opened)

        {

                  printk("==%s==mstar2133_pls_opened ! return \n", __func__);

                  return;

        }

        …

     } 

l模拟Psensor从轮询方式改为中断方式,可有效改善模拟P-Sensor的响应速度:

   if(ret>=0)  {

         if((ps_data&0xf0)==FACE_DETECT_NEAR)

          {

  fps_state=0;

  sensor_data.values[0] =fps_state;

          }

          elseif((ps_data&0xf0)==FACE_DETECT_FAR)

          {

  fps_state=1;

  sensor_data.values[0] =fps_state;

          }

          else //phone closed

  fps_state=-1;

         sensor_data.value_divide = 1;

         sensor_data.status =SENSOR_STATUS_ACCURACY_MEDIUM;

                         if((ret=hwmsen_get_interrupt_data(ID_PROXIMITY,&sensor_data)))

        {

  TPD_DMESG("callhwmsen_get_interrupt_data fail= %d\n", ret);

        }

    }

  如此,每当启动模拟Psensor功能时,状态改变量直接由中断途径通知上层。

l模拟Psensor使能函数和CTP的reset函数必须加上互斥锁,避免CTP在reset的时候使能Psensor功能失败导致模拟Psensor功能失效:

   static void _HalTscrHWReset(void)

{

       printk("%s\n",__func__);

       mutex_lock(&i2c_transfer_mutex);//------------在进行resetCTP之前进行加锁操作

       mt_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);

       mdelay(2);

       mt_set_gpio_out(GPIO_CTP_EN_PIN,GPIO_OUT_ZERO);

       mdelay(10);

       mt_set_gpio_out(GPIO_CTP_EN_PIN,GPIO_OUT_ONE);

       mdelay(300);

#ifdefCTP_PSENSOR_SUPPORT      

       msg2133_tp_resume_flag=0;

#endif

       mutex_unlock(&i2c_transfer_mutex);------------resetCTP完成之后释放锁

}

static int  msg2133_ps_mode_enable(boolenable)

{

        mutex_lock(&i2c_transfer_mutex);//--------------------------在进行psenable之前加锁

       msg2133_tp_resume_flag=0;

       if(enable)

       {

              …..

              err =i2c_master_send(i2c_clientma, &dbbus_tx_data[0],4);//打开模拟Psensor的功能操作

        }

        mutex_unlock(&i2c_transfer_mutex);//---------------------psenable结束之后释放锁

        return 0;

}

  如此,每当启动模拟Psensor功能都必定会成功,就不会出现模拟Psensor失效的情况了。

l模拟Psensor使能函数中需加入CTP  I2C 传输检测,避免长时间通话(1小时或以上)后,CTP连续工作后状态异常造成I2C通讯失败,从而时造成CTP整个功能失效:

static void  FT3407_ps_mode_enable(boolenable){

          int err= 0; 

                  unsigned char rx_data;  mutex_lock(&i2c_transfer_mutex

      if(enable)  //enter phone open

  { 

                   err=ft3407_write_reg(0xB0,0x01); 

                 err=ft3407_read_reg(0xB0,&rx_data);

  if(!(err>=0&& ((rx_data&0x01)==0x01)))

  {

  mutex_unlock(&i2c_transfer_mutex);

  Ft3407_tp_reset();      mutex_lock(&i2c_transfer_mutex); 

  err= ft3407_write_reg(0xB0,0x01);  err=ft3407_read_reg(0xB0,&rx_data);  
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值