3 PS sensor driver
static int ltr559_i2c_probe(struct i2c_client*client, const struct i2c_device_id *id)
{
structltr559_priv *obj;
structhwmsen_object obj_ps, obj_als;
interr = 0;
if(!(obj= kzalloc(sizeof(*obj), GFP_KERNEL)))
{
err= -ENOMEM;
gotoexit;
}
memset(obj,0, sizeof(*obj));
ltr559_obj= obj;
obj->hw= get_cust_alsps_hw();
//ltr559_get_addr(obj->hw,&obj->addr);
INIT_WORK(&obj->eint_work,ltr559_eint_work); //初始化ps eintwork
obj->client= client;
i2c_set_clientdata(client,obj);
atomic_set(&obj->als_debounce,300);
atomic_set(&obj->als_deb_on,0);
atomic_set(&obj->als_deb_end,0);
atomic_set(&obj->ps_debounce,300);
atomic_set(&obj->ps_deb_on,0);
atomic_set(&obj->ps_deb_end,0);
atomic_set(&obj->ps_mask,0);
atomic_set(&obj->als_suspend,0);
atomic_set(&obj->ps_thd_val_high, obj->hw->ps_threshold_high);
atomic_set(&obj->ps_thd_val_low, obj->hw->ps_threshold_low);
atomic_set(&obj->ps_thd_val, obj->hw->ps_threshold);
obj->enable= 0;
obj->pending_intr= 0;
obj->als_level_num= sizeof(obj->hw->als_level)/sizeof(obj->hw->als_level[0]);
obj->als_value_num= sizeof(obj->hw->als_value)/sizeof(obj->hw->als_value[0]);
obj->als_modulus= (400*100)/(16*150);
BUG_ON(sizeof(obj->als_level)!= sizeof(obj->hw->als_level));
memcpy(obj->als_level,obj->hw->als_level, sizeof(obj->als_level));
BUG_ON(sizeof(obj->als_value)!= sizeof(obj->hw->als_value));
memcpy(obj->als_value,obj->hw->als_value, sizeof(obj->als_value));
atomic_set(&obj->i2c_retry,3);
set_bit(CMC_BIT_ALS,&obj->enable);
set_bit(CMC_BIT_PS,&obj->enable);
APS_LOG("ltr559_devinit()start...!\n");
ltr559_i2c_client= client;
if(ltr559_check_alive()< 0) //check ps sensorid ,verify i2c communication
return-1;
if(err= ltr559_devinit()) //pssensor 初始化,注册中断函数
{
gotoexit_init_failed;
}
APS_LOG("ltr559_devinit()...OK!\n");
obj_ps.self= ltr559_obj;
if(1== obj->hw->polling_mode_ps)
{
obj_ps.polling= 1;
}
else
{
obj_ps.polling= 0;
}
obj_ps.sensor_operate= ltr559_ps_operate; //ops
if(err= hwmsen_attach(ID_PROXIMITY, &obj_ps)) //ps sensor 注册到sensor系统
{
APS_ERR("attachfail = %d\n", err);
gotoexit_create_attr_failed;
}
obj_als.self= ltr559_obj;
obj_als.polling= 1;
obj_als.sensor_operate= ltr559_als_operate;
if(err= hwmsen_attach(ID_LIGHT, &obj_als))// //als sensor 注册到sensor系统
{
APS_ERR("attachfail = %d\n", err);
gotoexit_create_attr_failed;
}
#if defined(CONFIG_HAS_EARLYSUSPEND)
obj->early_drv.level = EARLY_SUSPEND_LEVEL_DISABLE_FB - 1,
obj->early_drv.suspend = ltr559_early_suspend,
obj->early_drv.resume = ltr559_late_resume,
register_early_suspend(&obj->early_drv);
#endif
APS_LOG("%s:OK\n", __func__);
return0;
exit_create_attr_failed:
exit_misc_device_register_failed:
exit_init_failed:
exit_kfree:
kfree(obj);
exit:
ltr559_i2c_client= NULL;
APS_ERR("%s:err = %d\n", __func__, err);
returnerr;
}
/*中断函数*/
void ltr559_eint_func(void)
{
APS_FUN();
structltr559_priv *obj = ltr559_obj;
if(!obj)
{
return;
}
schedule_work(&obj->eint_work);
//schedule_delayed_work(&obj->eint_work);
}
/*ps eint work*/
static void ltr559_eint_work(structwork_struct *work)
{
structltr559_priv *obj = (struct ltr559_priv *)container_of(work, struct ltr559_priv,eint_work);
interr;
hwm_sensor_datasensor_data;
inttemp_noise;
// u8buffer[1];
// u8reg_value[1];
u8databuf[2];
intres = 0;
APS_FUN();
err= ltr559_check_intr(obj->client); //中断状态
if(err< 0)
{
APS_ERR("ltr559_eint_workcheck intrs: %d\n", err);
}
else
{
//getraw data
obj->ps= ltr559_ps_read();
APS_DBG("ltr559_eint_workrawdata ps=%d als_ch0=%d!\n",obj->ps,obj->als);
APS_DBG("ltr559_eint_workobj->ps_thd_val_low = %d\n",obj->ps_thd_val_low);
APS_DBG("ltr559_eint_workobj->ps_thd_val_high = %d\n",obj->ps_thd_val_high);
sensor_data.values[0]= ltr559_get_ps_value(obj, obj->ps);
sensor_data.value_divide= 1;
sensor_data.status= SENSOR_STATUS_ACCURACY_MEDIUM;
/*singal interrupt function add*/
APS_DBG("intr_flag_value=%d\n",intr_flag_value);
if(intr_flag_value){//close
APS_DBG("interrupt value ps will < ps_threshold_low");
databuf[0]= LTR559_PS_THRES_LOW_0;
databuf[1]= (u8)((atomic_read(&obj->ps_thd_val_low)) & 0x00FF);
res= i2c_master_send(obj->client, databuf, 0x2);
if(res<= 0)
{
return;
}
databuf[0]= LTR559_PS_THRES_LOW_1;
databuf[1]= (u8)(((atomic_read(&obj->ps_thd_val_low)) & 0xFF00) >> 8);
res= i2c_master_send(obj->client, databuf, 0x2);
if(res<= 0)
{
return;
}
databuf[0]= LTR559_PS_THRES_UP_0;
databuf[1]= (u8)(0x00FF);
res= i2c_master_send(obj->client, databuf, 0x2);
if(res<= 0)
{
return;
}
databuf[0]= LTR559_PS_THRES_UP_1;
databuf[1]= (u8)((0xFF00) >> 8);;
res= i2c_master_send(obj->client, databuf, 0x2);
if(res<= 0)
{
return;
}
}
else{ //faraway
APS_DBG("interrupt value ps will > ps_threshold_high");
databuf[0] = LTR559_PS_THRES_LOW_0;
databuf[1]= (u8)(0x00 & 0x00FF);
res= i2c_master_send(obj->client, databuf, 0x2);
if(res<= 0)
{
return;
}
databuf[0]= LTR559_PS_THRES_LOW_1;
databuf[1]= (u8)((0x00 & 0xFF00) >> 8);
res= i2c_master_send(obj->client, databuf, 0x2);
if(res<= 0)
{
return;
}
databuf[0]= LTR559_PS_THRES_UP_0;
databuf[1]= (u8)((atomic_read(&obj->ps_thd_val_high)) & 0x00FF);
res= i2c_master_send(obj->client, databuf, 0x2);
if(res<= 0)
{
return;
}
databuf[0]= LTR559_PS_THRES_UP_1;
databuf[1]= (u8)(((atomic_read(&obj->ps_thd_val_high)) & 0xFF00) >> 8);;
res= i2c_master_send(obj->client, databuf, 0x2);
if(res<= 0)
{
return;
}
}
//letup layer to know
if((err= hwmsen_get_interrupt_data(ID_PROXIMITY, &sensor_data)))
{
APS_ERR("call hwmsen_get_interrupt_datafail = %d\n", err);
}
}
ltr559_clear_intr(obj->client);
mt_eint_unmask(CUST_EINT_ALS_NUM);
}
static int ltr559_get_ps_value(structltr559_priv *obj, u16 ps)
{
intval, mask =atomic_read(&obj->ps_mask);
intinvalid = 0;
staticint val_temp = 1;
if((ps> atomic_read(&obj->ps_thd_val_high)) && ps < 2048) //ps 和 高门限比较
{
val= 0; /*close*/
val_temp = 0;
intr_flag_value= 1;
}
elseif((ps < atomic_read(&obj->ps_thd_val_low))) //ps 和 高门限比较
{
val= 1; /*far away*/
val_temp= 1;
intr_flag_value= 0;
}
else
val= val_temp;
if(atomic_read(&obj->ps_suspend))
{
invalid= 1;
}
elseif(1 == atomic_read(&obj->ps_deb_on))
{
unsignedlong endt = atomic_read(&obj->ps_deb_end);
if(time_after(jiffies,endt))
{
atomic_set(&obj->ps_deb_on,0);
}
if(1 == atomic_read(&obj->ps_deb_on))
{
invalid= 1;
}
}
elseif (obj->als > 50000)
{
//invalid= 1;
APS_DBG("lightoo high will result to failt proximiy\n");
return1; /*far away*/
}
if(!invalid)
{
APS_DBG("PS: %05d => %05d\n", ps, val);
returnval; //返回上层ps信息 0 接近 ,1 远离
}
else
{
return-1;
}
}
Ops介绍:
static struct file_operations ltr559_fops ={
//.owner= THIS_MODULE,
.open= ltr559_open,
.release= ltr559_release,
.unlocked_ioctl= ltr559_unlocked_ioctl,
};
重点看下ioctl
static int ltr559_unlocked_ioctl(structfile *file, unsigned int cmd,
unsigned long arg)
{
structi2c_client *client = (struct i2c_client*)file->private_data;
structltr559_priv *obj = i2c_get_clientdata(client);
interr = 0;
void__user *ptr = (void __user*) arg;
intdat;
uint32_tenable;
structPS_CALI_DATA_STRUCT ps_cali_temp;// added for ps nvram
intps_result;
intps_cali_result;
char*driver_name = ALSPS_DRIVER_NAME_LTR559;
APS_DBG("cmd=%d\n", cmd);
switch(cmd)
{
caseALSPS_SET_PS_MODE: //打开、关闭proximitysensor
if(copy_from_user(&enable,ptr, sizeof(enable)))
{
err= -EFAULT;
gotoerr_out;
}
if(enable)
{
err = ltr559_ps_enable(ps_gainrange); //打开
if(err< 0)
{
APS_ERR("enableps fail: %d\n", err);
gotoerr_out;
}
set_bit(CMC_BIT_PS,&obj->enable);
}
else
{
err = ltr559_ps_disable(); //关闭
if(err< 0)
{
APS_ERR("disableps fail: %d\n", err);
gotoerr_out;
}
clear_bit(CMC_BIT_PS,&obj->enable);
}
break;
caseALSPS_GET_PS_MODE: // proximitysensor状态:打开 or 关闭
enable= test_bit(CMC_BIT_PS, &obj->enable) ? (1) : (0);
if(copy_to_user(ptr,&enable, sizeof(enable)))
{
err= -EFAULT;
gotoerr_out;
}
break;
caseALSPS_GET_PS_DATA: //获取ps值,0 close,1 far away
APS_DBG("ALSPS_GET_PS_DATA\n");
obj->ps = ltr559_ps_read();
if(obj->ps< 0)
{
gotoerr_out;
}
dat= ltr559_get_ps_value(obj, obj->ps);
if(copy_to_user(ptr,&dat, sizeof(dat)))
{
err= -EFAULT;
gotoerr_out;
}
break;
caseALSPS_GET_PS_RAW_DATA: //获取ps raw data值
obj->ps= ltr559_ps_read();
if(obj->ps< 0)
{
gotoerr_out;
}
dat= obj->ps;
if(copy_to_user(ptr,&dat, sizeof(dat)))
{
err= -EFAULT;
gotoerr_out;
}
break;
/*PS 校准相关*/
caseALSPS_GET_PS_TEST_RESULT:
break;
caseALSPS_IOCTL_CLR_CALI:
break;
caseALSPS_CALIBRATE_PS:
break;
caseALSPS_WRITE_CALIBRATE:
break;
/*PS 校准相关*/
default:
APS_ERR("%snot supported = 0x%04x", __FUNCTION__, cmd);
err= -ENOIOCTLCMD;
break;
}
err_out:
returnerr;
}
proximity sensor 状态图:
相关log:
<6>[ 248.771238].(2)[5:kworker/u:0][ALS/PS] ltr559_late_resume
<6>[ 252.594142].(3)[76:kworker/u:2][ALS/PS] ltr559_early_suspend
<6>[ 252.595203].(0)[76:kworker/u:2][ALS/PS] ltr559_als_disable ...OK
<6>[ 253.801641].(0)[76:kworker/u:2][ALS/PS] ltr559_late_resume
//call enanle ps sensor
<6>[ 261.246562].(0)[718:PowerManagerSer][ALS/PS] ltr559_ps_enable()...start!
<6>[ 261.246576].(0)[718:PowerManagerSer][ALS/PS] LTR559_PS setgain = 11!
<6>[ 261.286090].(3)[718:PowerManagerSer][ALS/PS] ltr559_ps_enable ...OK!
//faraway
<6>[ 261.414876]-(0)[54:ion_mm_heap][ALS/PS] ltr559_eint_func
<6>[ 261.415037].(0)[69:kworker/0:1][ALS/PS] ltr559_eint_work
<6>[ 261.415064].(0)[69:kworker/0:1][ALS/PS] ltr559_check_intr
<6>[ 261.422073].(0)[69:kworker/0:1][ALS/PS] ltr559_eint_work rawdata ps=59als_ch0=0!
<6>[ 261.422094].(0)[69:kworker/0:1][ALS/PS] ltr559_eint_workobj->ps_thd_val_low = 272
<6>[ 261.422107].(0)[69:kworker/0:1][ALS/PS] ltr559_eint_workobj->ps_thd_val_high = 312
<6>[ 261.422122].(0)[69:kworker/0:1][ALS/PS] PS: 00059 => 00001
<6>[ 261.422134].(0)[69:kworker/0:1][ALS/PS] intr_flag_value=0
<6>[ 261.422146].(0)[69:kworker/0:1][ALS/PS] interrupt value ps will > ps_threshold_high
<6>[ 261.425323].(0)[69:kworker/0:1][ALS/PS] ltr559_clear_intr
<6>[ 261.431236].(0)[69:kworker/0:1][ALS/PS] buffer[0] = 0
//close
<6>[ 266.669282]-(0)[0:swapper/0][ALS/PS] ltr559_eint_func
<6>[ 266.669499].(0)[69:kworker/0:1][ALS/PS] ltr559_eint_work
<6>[ 266.669540].(0)[69:kworker/0:1][ALS/PS] ltr559_check_intr
<6>[ 266.671995].(0)[69:kworker/0:1][ALS/PS] ltr559_eint_work rawdata ps=943als_ch0=0!
<6>[ 266.672027].(0)[69:kworker/0:1][ALS/PS] ltr559_eint_workobj->ps_thd_val_low = 272
<6>[ 266.672056].(0)[69:kworker/0:1][ALS/PS] ltr559_eint_workobj->ps_thd_val_high = 312
<6>[ 266.672086].(0)[69:kworker/0:1][ALS/PS] PS: 00943 => 00000
<6>[ 266.672112].(0)[69:kworker/0:1][ALS/PS] intr_flag_value=1
<6>[ 266.672135].(0)[69:kworker/0:1][ALS/PS] interrupt value ps will < ps_threshold_low
<6>[ 266.676037].(0)[69:kworker/0:1][ALS/PS] ltr559_clear_intr
<6>[ 266.676888].(0)[69:kworker/0:1][ALS/PS] buffer[0] = 0
<6>[ 266.815520].(2)[76:kworker/u:2][ALS/PS] ltr559_early_suspend
<6>[ 266.816473].(1)[76:kworker/u:2][ALS/PS] ltr559_als_disable ...OK
//faraway
<6>[ 269.241498]-(0)[0:swapper/0][ALS/PS] ltr559_eint_func
<6>[ 269.241618].(0)[69:kworker/0:1][ALS/PS] ltr559_eint_work
<6>[ 269.241641].(0)[69:kworker/0:1][ALS/PS] ltr559_check_intr
<6>[ 269.243660].(0)[69:kworker/0:1][ALS/PS] ltr559_eint_work rawdata ps=59als_ch0=0!
<6>[ 269.243678].(0)[69:kworker/0:1][ALS/PS] ltr559_eint_workobj->ps_thd_val_low = 272
<6>[ 269.243695].(0)[69:kworker/0:1][ALS/PS] ltr559_eint_work obj->ps_thd_val_high= 312
<6>[ 269.243712].(0)[69:kworker/0:1][ALS/PS] PS: 00059 => 00001
<6>[ 269.243727].(0)[69:kworker/0:1][ALS/PS] intr_flag_value=0
<6>[ 269.243741].(0)[69:kworker/0:1][ALS/PS] interrupt value ps will > ps_threshold_high
<6>[ 269.246877].(0)[69:kworker/0:1][ALS/PS] ltr559_clear_intr
<6>[ 269.247573].(0)[69:kworker/0:1][ALS/PS] buffer[0] = 0
<6>[ 269.651832].(0)[76:kworker/u:2][ALS/PS] ltr559_late_resume
//close
<6>[ 271.760016]-(0)[0:swapper/0][ALS/PS] ltr559_eint_func
<6>[ 271.760192].(0)[69:kworker/0:1][ALS/PS]ltr559_eint_work
<6>[ 271.760231].(0)[69:kworker/0:1][ALS/PS] ltr559_check_intr
<6>[ 271.762742].(0)[69:kworker/0:1][ALS/PS] ltr559_eint_work rawdata ps=1195als_ch0=0!
<6>[ 271.762773].(0)[69:kworker/0:1][ALS/PS] ltr559_eint_workobj->ps_thd_val_low = 272
<6>[ 271.762802].(0)[69:kworker/0:1][ALS/PS] ltr559_eint_workobj->ps_thd_val_high = 312
<6>[ 271.762832].(0)[69:kworker/0:1][ALS/PS] PS: 01195 => 00000
<6>[ 271.762858].(0)[69:kworker/0:1][ALS/PS] intr_flag_value=1
<6>[ 271.762881].(0)[69:kworker/0:1][ALS/PS] interrupt value ps will < ps_threshold_low
<6>[ 271.766958].(0)[69:kworker/0:1][ALS/PS] ltr559_clear_intr
<6>[ 271.767815].(0)[69:kworker/0:1][ALS/PS] buffer[0] = 0
//sleep
<6>[ 271.952675].(1)[5:kworker/u:0][ALS/PS] ltr559_early_suspend