天天看點

用觸摸屏來實作距離傳感器的功能

需求:某些客戶為了節約成本吧,将距離傳感器拿掉,相應的功能用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; 

 struct input_dev *input_dev_ps;

 unsigned int enable;

 unsigned int control;

 unsigned int enable_ps_sensor;

 unsigned int ps_detection;  

 //unsigned int 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);

 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;

 }

 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上些東西,排版好難整啊。。

繼續閱讀