用触摸屏来实现距离传感器的功能
Posted Jarry_le
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了用触摸屏来实现距离传感器的功能相关的知识,希望对你有一定的参考价值。
需求:某些客户为了节约成本吧,将距离传感器拿掉,相应的功能用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上些东西,排版好难整啊。。
以上是关于用触摸屏来实现距离传感器的功能的主要内容,如果未能解决你的问题,请参考以下文章
开发者方案 · 用涂鸦Wi-Fi+蓝牙模组SDK完成复合物联网产品的控制