用触摸屏来实现距离传感器的功能

来源:互联网 发布:淘宝设备管理怎么没了 编辑:程序博客网 时间:2024/05/18 00:10

需求:某些客户为了节约成本吧,将距离传感器拿掉,相应的功能用TP触摸屏来模拟实现。流程图如下
 

移植原理:去掉手机上的感光Sensor,用TP来模拟实现感光sensor在通话时亮屏和灭屏的功能。
当然了TP本身是需要支持相应的功能的。可以联系模组厂进行调试,导入firmware,然后才在代码中进行相应的修改。
1. 首先在目录/sys/bus/i2c/devices下添加相应的I2C设备,在ProximitySensor.cpp中添加:
//the below characters is the origin codes,modified to make the JNI work corretly
#define ENALBE_PS_SENSOR  "/sys/bus/i2c/devices/i2c-2/2-0038/enable_ps_sensor"
 
2. 在sensor.cpp中取代感光sensor
修改原则是用模拟距离传感器的代码替换原先感光sensor的代码。
在sensor列表中添加支持模拟距离传感器的模块代码,以敦太的ft5306为例。
static const struct sensor_t sSensorList[] ={
。。。 
 
。。。};
接下来是声明,替换感光sensor的相关部分。
 
 
 
3. 加入编译选项,在Android.mk.3rdparty
     sensors.cpp  \
4. 在tp驱动里加入代码
先在代码里声明个宏开关吧
#define TP_PROXIMITY_SENSOR
在结构体中添加必要的成员变量
struct pixcir_i2c_ts_data {
 struct i2c_client *client;
 struct input_dev *input;
 struct ts_event  event;
 //const struct pixcir_ts_platform_data *chip;
 bool exiting;
#ifdef TP_PROXIMITY_SENSOR
 //struct mutex update_lock;
 //struct delayed_work dwork; /* for PS interrupt */
 struct input_dev *input_dev_ps;

 unsigned int enable;
 unsigned int control;

 /* control flag from HAL */
 unsigned int enable_ps_sensor;

 unsigned int ps_detection;  /* 0 = near-to-far; 1 = far-to-near */
 //unsigned int ps_data;   /* to store PS data */
#endif
};
创建sysfs接口,用于hal层调用
static DEVICE_ATTR(enable_ps_sensor, S_IWUGO | S_IRUGO,
       ft5306_show_enable_ps_sensor, ft5306_store_enable_ps_sensor);

static struct attribute *ft5306_attributes[] = {
 &dev_attr_enable_ps_sensor.attr,
 NULL
};
当你想要实现的接口名字是enable_ps_sensor的时候,需要实现结构体struct attribute *dev_attrs[]
其中成员变量的名字必须是&dev_attr_enable_ps_sensor.attr,然后再封装
static const struct attribute_group ft5306_attr_group = {
 .attrs = ft5306_attributes,
};
最后就可以创建接口了,这个是在probe里面创建的哦
#ifdef TP_PROXIMITY_SENSOR
 error = sysfs_create_group(&client->dev.kobj, &ft5306_attr_group); 
 if (error)
  input_unregister_device(ps_input);
#endif
这里只是建立了android到kernel的桥梁,真正实现对硬件操作的还是show和store两个函数。
#ifdef TP_PROXIMITY_SENSOR
static ssize_t ft5306_show_enable_ps_sensor(struct device *dev,
    struct device_attribute *attr, char *buf)
{
 struct i2c_client *client = to_i2c_client(dev);
 struct pixcir_i2c_ts_data *data = i2c_get_clientdata(client);

 return sprintf(buf, "%d\n", data->enable_ps_sensor);
}

static ssize_t ft5306_store_enable_ps_sensor(struct device *dev,
    struct device_attribute *attr, const char *buf, size_t count)
{
 struct i2c_client *client = to_i2c_client(dev);
 struct pixcir_i2c_ts_data *data = i2c_get_clientdata(client);
 
 unsigned long val = simple_strtoul(buf, NULL, 10);
  unsigned long flags;
 int err;
 char data_cmd[2]={0, 0};

 
 printk("%s: enable ps senosr ( %ld)\n", __func__, val);
 
 if ((val != 0) && (val != 1)) {
  printk("%s:store unvalid value=%ld\n", __func__, val);
  return count;
 }
 
 if(val == 1) {
  rgt_ps_mode = true;
  //turn on p sensor
  if (data->enable_ps_sensor==0) {
   data->enable_ps_sensor= 1;
   err = pixcir_i2c_write_data(0xB0, 0x01);

   if(err==0)
    printk("tp_ps: i2c write sucess, err:%d\n", err); 
   //}
   else
    printk("tp_ps: i2c write fail, err:%d\n", err);
  }
 }
 else {
  //turn off p sensor - kk 25 Apr 2011 we can't turn off the entire sensor, the light sensor may be needed by HAL
  rgt_ps_mode=false;
  data->enable_ps_sensor = 0;
  err=pixcir_i2c_txdata(0xB0, 0x00);//out ps mode
  if(err==0)
  //{
   printk("tp_ps: i2c write sucess\n");
  //}
  else
   printk("tp_ps: i2c write fail\n");
 } 
 return count;
}
接下来在probe里各种添加了

static int __devinit pixcir_i2c_ts_probe(struct i2c_client *client,
      const struct i2c_device_id *id)
{
 //const struct pixcir_ts_platform_data *pdata = client->dev.platform_data;
 struct pixcir_i2c_ts_data *tsdata;
 struct input_dev *input;
 struct input_dev *ps_input;
 struct device *dev;
 struct i2c_dev *i2c_dev;
 int i, error;
 
 this_client = client;
 client->irq = pixcir_ts_config_pins(); //reset pin set to 0 or 1 and platform init
 
 for(i=0; i<MAX_FINGER_NUM*2; i++) {
  point_slot[i].active = 0;
 }

 tsdata = kzalloc(sizeof(*tsdata), GFP_KERNEL);
 input = input_allocate_device();
#ifdef TP_PROXIMITY_SENSOR
 ps_input = input_allocate_device();
#endif
 if (!tsdata || !input || !ps_input) {
  dev_err(&client->dev, "Failed to allocate driver data!\n");
  error = -ENOMEM;
  goto err_free_mem;
 }
#ifdef TOUCH_VIRTUAL_KEYS
 pixcir_ts_virtual_keys_init();
#endif

 tsdata->client = client;
 tsdata->input = input;
#ifdef TP_PROXIMITY_SENSOR
 tsdata->input_dev_ps = ps_input;
#endif
 //tsdata->chip = pdata;
 global_irq = client->irq;

 input->name = client->name;
 input->id.bustype = BUS_I2C;
 input->dev.parent = &client->dev;
#ifdef TP_PROXIMITY_SENSOR
 ps_input->name = "FTPS";
 ps_input->id.bustype = BUS_I2C;
#endif

 __set_bit(EV_KEY, input->evbit);
 __set_bit(EV_ABS, input->evbit);
 __set_bit(EV_SYN, input->evbit);
 __set_bit(BTN_TOUCH, input->keybit);
#ifdef TP_PROXIMITY_SENSOR
 __set_bit(EV_ABS, ps_input->evbit);
#endif
 __set_bit(ABS_MT_TOUCH_MAJOR, input->absbit);
 __set_bit(ABS_MT_POSITION_X, input->absbit);
 __set_bit(ABS_MT_POSITION_Y, input->absbit);
 __set_bit(ABS_MT_WIDTH_MAJOR, input->absbit);

 __set_bit(KEY_MENU,  input->keybit);
 __set_bit(KEY_BACK,  input->keybit);
 //__set_bit(KEY_HOME,  input->keybit);
 //__set_bit(KEY_SEARCH,  input->keybit);
 
 input_set_abs_params(input, ABS_MT_TOUCH_MAJOR, 0, 255, 0, 0);
 input_set_abs_params(input, ABS_MT_POSITION_X, 0, X_MAX, 0, 0);
 input_set_abs_params(input, ABS_MT_POSITION_Y, 0, Y_MAX, 0, 0);
 input_set_abs_params(input, ABS_MT_WIDTH_MAJOR, 0, 200, 0, 0);
#ifdef TP_PROXIMITY_SENSOR
 input_set_abs_params(ps_input, ABS_DISTANCE, 0, 1, 0, 0);
#endif


 input_set_drvdata(input, tsdata);

 error = request_threaded_irq(client->irq, NULL, pixcir_ts_isr,
         IRQF_TRIGGER_FALLING,
         client->name, tsdata);
 if (error) {
  dev_err(&client->dev, "Unable to request touchscreen IRQ.\n");
  goto err_free_mem;
 }
 disable_irq_nosync(client->irq);

 error = input_register_device(input);
 if (error)
  goto err_free_irq;
 
#ifdef TP_PROXIMITY_SENSOR
 error = input_register_device(ps_input);
 if (error)
  goto err_free_irq;
#endif
 i2c_set_clientdata(client, tsdata);
 device_init_wakeup(&client->dev, 1);

 /*********************************Bee-0928-TOP****************************************/
 i2c_dev = get_free_i2c_dev(client->adapter);
 if (IS_ERR(i2c_dev)) {
  error = PTR_ERR(i2c_dev);
  return error;
 }

//hong 找到了,上述说的就是在这里的。
#ifdef TP_PROXIMITY_SENSOR
 error = sysfs_create_group(&client->dev.kobj, &ft5306_attr_group); 
 if (error)
  input_unregister_device(ps_input);
#endif

 dev = device_create(i2c_dev_class, &client->adapter->dev, MKDEV(I2C_MAJOR,
   client->adapter->nr), NULL, "ft5206_ts%d", 0);
 if (IS_ERR(dev)) {
  error = PTR_ERR(dev);
  return error;
 }
 /*********************************Bee-0928-BOTTOM****************************************/

 pixcir_early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1;
 pixcir_early_suspend.suspend = pixcir_ts_suspend;
 pixcir_early_suspend.resume = pixcir_ts_resume;
 register_early_suspend(&pixcir_early_suspend);

 if(pixcir_config_intmode()<0) {
#ifdef PIXCIR_DEBUG
  printk("%s: I2C error\n",__func__);
#endif
  goto err_free_irq;
 }
 pixcir_create_sysfs(client);

#ifdef PIXCIR_DEBUG
 dev_err(&tsdata->client->dev, "insmod successfully!\n");
#endif 
 enable_irq(client->irq);
 msleep(100);
 pixcir_i2c_write_data(0x80, 0x10);

#if 0//def TP_PROXIMITY_SENSOR
 //struct ft5306_ps_data ps_data;
 int err;
 ps_data->enable = 0;
 ps_data->detection= 0;
 ps_data->enable_ps_sensor = 0;
 if(err = hwmsen_attach(ID_PROXIMITY, &tp_ps))
 {
  printk("tp_ps:attach fail = %d\n", err);
  //goto exit_create_attr_failed;
 }
 data->enable_ps_sensor = 0;
#endif
 return 0;

err_free_irq:
 free_irq(client->irq, tsdata);
 sprd_free_gpio_irq(pixcir_irq);
err_free_mem:
 input_free_device(input);
 kfree(tsdata);
 return error;
}


中断read数据,打电话时模拟距离控制屏的休眠和唤醒
static irqreturn_t pixcir_ts_isr(int irq, void *dev_id)
{
 struct pixcir_i2c_ts_data *tsdata = dev_id;
 int ret;
 
 disable_irq_nosync(irq);

 ret = ft5x0x_read_data(tsdata); 
 if (ret == 0) { 
  ft5x0x_report_value(tsdata);
 }

 enable_irq(irq);
 
 return IRQ_HANDLED;
}

static int ft5x0x_read_data(struct pixcir_i2c_ts_data *data)
{
// struct pixcir_i2c_ts_data *data = i2c_get_clientdata(this_client);
 struct ts_event *event = &data->event;
// u8 buf[14] = {0};
 u8 buf[32] = {0};
 int ret = -1;
 int touch_point = 0;
//add detect function by liuhui 20120530. start
#ifdef TP_PROXIMITY_SENSOR
 int err;
 u8 buf_ps[2] = {0};

 if(rgt_ps_mode == true)
 {
  err=pixcir_i2c_rxdata(&buf_ps, 2);
  if(err==1)
   printk("tp_ps: i2c read sucess\n");
  else
   printk("tp_ps: i2c read fail, err = %d\n", err);
  printk("tp_ps:ps data:%d\n", buf_ps[1]);
  if(buf_ps[1]==0xc0)//close
  {
   data->ps_detection = 1;
   input_report_abs(data->input_dev_ps, ABS_DISTANCE, 1);
   input_sync(data->input_dev_ps);
   return 0;
  }
  else if(buf_ps[1]==0xe0)//far away
  {
   data->ps_detection = 0;
   input_report_abs(data->input_dev_ps, ABS_DISTANCE, 0);
   input_sync(data->input_dev_ps);
   //return 0;
  }
 }
#endif
。。。

suspend休眠
static void pixcir_ts_suspend(struct early_suspend *handler)
{
 if(rgt_ps_mode==true)
  return -1;
 disable_irq_nosync(global_irq);
    pixcir_ts_pwroff();
}

resume唤醒
static void pixcir_ts_resume(struct early_suspend *handler)

 int ret = 0; 
 unsigned char reg_val[8] = {0};
 struct i2c_client *client = this_client;
 if(rgt_ps_mode==true)
  return -1;
 pixcir_ts_pwron();
 pixcir_reset();
 
 msleep(50);
 pixcir_i2c_write_data(0x80, 0x12);
 enable_irq(global_irq);

到此,整个移植也算结束了。
5.关于bug
    这个在调试的过程中还得和模组厂的FAE们,一起掌控TP的灵敏度,这个要多次反复的实验才行。
    做了很多专项测试,依照上面的代码来看,当打电话的时候离开人脸,有时会出现唤不醒屏幕的问题,手动唤醒后,GOD,TP居然失效了,
这是难以接受的。这就是模拟的缺陷了,经过很多调试才避免了这种TP失效的发生,当然了偶尔还是出现自动唤不醒的情况。具体的优化,在
下一章中会详细讲到,ps 解决这个bug,我搞了两天。。。
    事情到此结束了?有兴趣的话,可以考虑下为什么在pixcir_ts_resume中加入rgt_ps_mode==true的判断,当时偶也是很迷惑的。
    最终,还是有别的隐性bug的,但目前就优化到这里。可能在你看来还是有很多问题,不妨给点建议。

ps:第一次在csdn上些东西,排版好难整啊。。

 

 


 

原创粉丝点击