Psensor driver 二(重要函数)

文章详细介绍了LTR559接近传感器在Linux内核中的驱动实现,包括I2C通信、设备初始化、中断函数`ltr559_eint_func`、工作队列`ltr559_eint_work`以及如何根据中断事件调整传感器阈值。同时,展示了如何处理传感器的开启、关闭、数据获取以及中断触发时的逻辑。
摘要由CSDN通过智能技术生成

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

 

</article>

转自:https://blog.csdn.net/u013531497/article/details/38400375

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值