当前位置: 代码迷 >> 综合 >> 2022-04-13 Ambient Light Proximity Sensor 光感和距离传感器 STK3311X调试记录 RK3566 Android11平台
  详细解决方案

2022-04-13 Ambient Light Proximity Sensor 光感和距离传感器 STK3311X调试记录 RK3566 Android11平台

热度:14   发布时间:2023-11-27 10:39:31.0

一、原理图,接口比较简单,就是I2C。

 二、光感用轮询方式,距离用中断方式。代码。

1、dts配置

	ls_stk3x1x: light@48 {compatible = "ls_stk3x1x";status = "okay";reg = <0x48>;type = <SENSOR_TYPE_LIGHT>;irq_enable = <0>;als_threshold_high = <100>;als_threshold_low = <10>;als_ctrl_gain = <2>; /* 0:x1 1:x4 2:x16 3:x64 */poll_delay_ms = <100>;layout = <1>;};ps_stk3x1x: proximity@48 {compatible = "ps_stk3x1x";status = "okay";reg = <0x48>;type = <SENSOR_TYPE_PROXIMITY>;pinctrl-names = "default";pinctrl-0 = <&al_det>;irq-gpio = <&gpio0 RK_PD4 IRQ_TYPE_LEVEL_LOW>;irq_enable = <1>;ps_threshold_high = <0x200>;ps_threshold_low = <0x100>;ps_ctrl_gain = <3>; /* 0:x1 1:x4 2:x16 3:x64 */ps_led_current = <3>; /* 0:12.5mA 1:25mA 2:50mA 3:100mA */poll_delay_ms = <100>;};

2、光感驱动代码 kernel\drivers\input\sensors\lsensor\ls_stk3x1x.c

/**  ls_stk3x1x.c - Linux kernel modules for sensortek stk301x, stk321x and stk331x *  proximity/ambient light sensor**  Copyright (C) 2012~2015 Lex Hsieh / sensortek <lex_hsieh@sensortek.com.tw>**  This program is free software; you can redistribute it and/or modify*  it under the terms of the GNU General Public License as published by*  the Free Software Foundation; either version 2 of the License, or*  (at your option) any later version.**  This program is distributed in the hope that it will be useful,*  but WITHOUT ANY WARRANTY; without even the implied warranty of*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the*  GNU General Public License for more details.**  You should have received a copy of the GNU General Public License*  along with this program; if not, write to the Free Software*  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.*/#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/i2c.h>
#include <linux/mutex.h>
#include <linux/kdev_t.h>
#include <linux/fs.h>
#include <linux/input.h>
#include <linux/workqueue.h>
#include <linux/irq.h>
#include <linux/delay.h>
#include <linux/sched.h>
#include <linux/kthread.h>
#include <linux/errno.h>
#include <linux/wakelock.h>
#include <linux/interrupt.h>
#include <linux/gpio.h>
#include   <linux/fs.h>   
#include  <asm/uaccess.h> 
#include <linux/sensor-dev.h>
#include <linux/of_gpio.h>
#include <linux/regulator/consumer.h>
#ifdef CONFIG_HAS_EARLYSUSPEND
//#include <linux/earlysuspend.h>
#endif
#include "linux/stk3x1x.h"#define DRIVER_VERSION  "3.10.0_0429"/* Driver Settings */
#define STK_POLL_ALS		/* ALS interrupt is valid only when STK_PS_INT_MODE = 1	or 4*/
// #define STK_IRS
#define STK_DEBUG_PRINTF#define PROXIMITY_ID_I2C 2/*****************************************************************************/
/* Define Register Map */
#define STK_STATE_REG 			0x00
#define STK_PSCTRL_REG 			0x01
#define STK_ALSCTRL_REG 			0x02
#define STK_LEDCTRL_REG 			0x03
#define STK_INT_REG 				0x04
#define STK_WAIT_REG 			0x05
#define STK_THDH1_PS_REG 		0x06
#define STK_THDH2_PS_REG 		0x07
#define STK_THDL1_PS_REG 		0x08
#define STK_THDL2_PS_REG 		0x09
#define STK_THDH1_ALS_REG 		0x0A
#define STK_THDH2_ALS_REG 		0x0B
#define STK_THDL1_ALS_REG 		0x0C
#define STK_THDL2_ALS_REG 		0x0D
#define STK_FLAG_REG 			0x10
#define STK_DATA1_PS_REG	 	0x11
#define STK_DATA2_PS_REG 		0x12
#define STK_DATA1_ALS_REG 		0x13
#define STK_DATA2_ALS_REG 		0x14
#define STK_DATA1_OFFSET_REG 	0x15
#define STK_DATA2_OFFSET_REG 	0x16
#define STK_DATA1_IR_REG 		0x17
#define STK_DATA2_IR_REG 		0x18
#define STK_PDT_ID_REG 			0x3E
#define STK_RSRVD_REG 			0x3F
#define STK_SW_RESET_REG		0x80	#define STK_STATE_EN_IRS_MASK	0x80
#define STK_STATE_EN_AK_MASK	0x40
#define STK_STATE_EN_ASO_MASK	0x20
#define STK_STATE_EN_IRO_MASK	0x10
#define STK_STATE_EN_WAIT_MASK	0x04
#define STK_STATE_EN_ALS_MASK	0x02
#define STK_STATE_EN_PS_MASK	0x01#define STK_FLG_ALSDR_MASK		0x80
#define STK_FLG_PSDR_MASK		0x40
#define STK_FLG_ALSINT_MASK		0x20
#define STK_FLG_PSINT_MASK		0x10
#define STK_FLG_OUI_MASK			0x04
#define STK_FLG_IR_RDY_MASK		0x02
#define STK_FLG_NF_MASK			0x01#define STK_INT_ALS				0x08#define STK_IRC_MAX_ALS_CODE		20000
#define STK_IRC_MIN_ALS_CODE		25
#define STK_IRC_MIN_IR_CODE		50
#define STK_IRC_ALS_DENOMI		2		
#define STK_IRC_ALS_NUMERA		5
#define STK_IRC_ALS_CORREC		850#define STK_IRS_IT_REDUCE			2
#define STK_ALS_READ_IRS_IT_REDUCE	5
#define STK_ALS_THRESHOLD			30/*****************************************************************************/
#define STK3310SA_PID		0x17
#define STK3311SA_PID		0x1E
#define STK3311WV_PID	0x1D
/*****************************************************************************/#ifdef STK_ALS_FIR#define STK_FIR_LEN	8#define MAX_FIR_LEN 32struct data_filter {u16 raw[MAX_FIR_LEN];int sum;int number;int idx;
};
#endifstruct stk3x1x_data {uint16_t ir_code;uint16_t als_correct_factor;uint8_t alsctrl_reg;uint8_t psctrl_reg;uint8_t ledctrl_reg;uint8_t state_reg;int		int_pin;uint8_t wait_reg;uint8_t int_reg;
#ifdef CONFIG_HAS_EARLYSUSPEND//struct early_suspend stk_early_suspend;
#endif	uint16_t ps_thd_h;uint16_t ps_thd_l;
#ifdef CALI_PS_EVERY_TIME	uint16_t ps_high_thd_boot;uint16_t ps_low_thd_boot;
#endif	struct mutex io_lock;struct input_dev *ps_input_dev;int32_t ps_distance_last;bool ps_enabled;bool re_enable_ps;struct wake_lock ps_wakelock;	
#ifdef STK_POLL_PS		struct hrtimer ps_timer;	struct work_struct stk_ps_work;struct workqueue_struct *stk_ps_wq;struct wake_lock ps_nosuspend_wl;		
#endifstruct input_dev *als_input_dev;int32_t als_lux_last;uint32_t als_transmittance;	bool als_enabled;bool re_enable_als;ktime_t ps_poll_delay;ktime_t als_poll_delay;
#ifdef STK_POLL_ALS		struct work_struct stk_als_work;struct hrtimer als_timer;	struct workqueue_struct *stk_als_wq;
#endif	bool first_boot;
#ifdef STK_TUNE0uint16_t psa;uint16_t psi;	uint16_t psi_set;	struct hrtimer ps_tune0_timer;	struct workqueue_struct *stk_ps_tune0_wq;struct work_struct stk_ps_tune0_work;ktime_t ps_tune0_delay;bool tune_zero_init_proc;uint32_t ps_stat_data[3];int data_count;int stk_max_min_diff;int stk_lt_n_ct;int stk_ht_n_ct;
#endif	
#ifdef STK_ALS_FIRstruct data_filter      fir;atomic_t                firlength;	
#endifatomic_t	recv_reg;#ifdef STK_GES		struct input_dev *ges_input_dev;int ges_enabled;int re_enable_ges;	atomic_t gesture2;
#endif	
#ifdef STK_IRSint als_data_index;
#endif	
#ifdef STK_QUALCOMM_POWER_CTRLstruct regulator *vdd;struct regulator *vio;bool power_enabled;
#endif	uint8_t pid;uint8_t	p_wv_r_bd_with_co;uint32_t als_code_last;
};static struct stk3x1x_data *ps_data;const int ALS_LEVEL[] = {100, 1600, 2250, 3200, 6400, 12800, 26000};static void set_stk_power(bool flag)
{struct regulator *ldo=NULL;int ret;ldo = regulator_get(NULL, "rk818_ldo2");if(ldo==NULL){printk("set_stk_sensor_power ldo is null\n");return;}if(flag){regulator_set_voltage(ldo, 3300000, 3300000);ret = regulator_enable(ldo);if(ret < 0){printk("----->%s:enable error...\n",__func__);}regulator_put(ldo);}else{regulator_disable(ldo);regulator_put(ldo);}
}static struct stk3x1x_platform_data stk3x1x_pfdata={ .state_reg = 0x0,    /* disable all */ .psctrl_reg = 0x31,    /* ps_persistance=1, ps_gain=64X, PS_IT=0.391ms */ .alsctrl_reg = 0x39, 	/* als_persistance=1, als_gain=64X, ALS_IT=100ms */.ledctrl_reg = 0xFF,   /* 100mA IRDR, 64/64 LED duty */ .wait_reg = 0x07,    /* 50 ms */   .ps_thd_h = 800, .ps_thd_l = 600, //.int_pin = sprd_3rdparty_gpio_pls_irq,  .transmittance = 500, .stk_max_min_diff = 200,.stk_lt_n_ct = 60,.stk_ht_n_ct = 80,   
};/*****************************************************************************/
#ifndef STK_POLL_ALS
static int32_t stk3x1x_set_als_thd_l(struct i2c_client *client, uint16_t thd_l)
{unsigned char val[3];int ret;val[0] = STK_THDL1_ALS_REG;val[1] = (thd_l & 0xFF00) >> 8;val[2] = thd_l & 0x00FF;ret = sensor_tx_data(client, val, 3);// ret = sensor_write_reg(client, STK_THDL1_ALS_REG, );// if(ret)// printk("%s:fail to active sensor\n",__func__);return ret;		
}
static int32_t stk3x1x_set_als_thd_h(struct i2c_client *client, uint16_t thd_h)
{unsigned char val[2];int ret;val[0] = STK_THDH1_ALS_REG;val[1] = (thd_h & 0xFF00) >> 8;val[2] = thd_h & 0x00FF;ret = sensor_tx_data(client, val, 3);	// ret = sensor_write_reg(client, STK_THDL1_ALS_REG, );// if(ret)// printk("%s:fail to active sensor\n",__func__);	return ret;	
}
#endif
static int light_sensor_active(struct i2c_client *client, int enable, int rate)
{struct sensor_private_data *sensor =(struct sensor_private_data *) i2c_get_clientdata(client);	int result = 0;// int status = 0;// char buffer[3] = {0};// int high = 0x80, low = 0x60;
#ifdef STK_IRS	int ret = 0;
#endifsensor->ops->ctrl_data = sensor_read_reg(client, sensor->ops->ctrl_reg);	
#ifndef STK_POLL_ALSif (enable){				stk3x1x_set_als_thd_h(client, 0x0000);stk3x1x_set_als_thd_l(client, 0xFFFF);}	#ifdef STK_IRSif(enable && !(sensor->ops->ctrl_data & STK_STATE_EN_PS_MASK)){ret = stk3x1x_get_ir_reading(ps_data, STK_IRS_IT_REDUCE);if(ret > 0)ps_data->ir_code = ret;}#endif	
#endif	sensor->ops->ctrl_data = (uint8_t)((sensor->ops->ctrl_data) & (~(STK_STATE_EN_ALS_MASK | STK_STATE_EN_WAIT_MASK))); if(enable)sensor->ops->ctrl_data |= STK_STATE_EN_ALS_MASK;	else if (sensor->ops->ctrl_data & STK_STATE_EN_PS_MASK)		sensor->ops->ctrl_data |= STK_STATE_EN_WAIT_MASK;		printk("%s:reg=0x%x,reg_ctrl=0x%x,enable=%d\n",__func__,sensor->ops->ctrl_reg, sensor->ops->ctrl_data, enable);result = sensor_write_reg(client, sensor->ops->ctrl_reg, sensor->ops->ctrl_data);if(result)printk("%s:fail to active sensor\n",__func__);if(enable){
#ifdef STK_IRSps_data->als_data_index = 0;
#endif		// sensor->ops->report(sensor->client);}ps_data->als_enabled = enable?true:false;return result;
}static int32_t stk3x1x_check_pid(struct i2c_client *client)
{char value[2] = {0}, pid_msb;int result;ps_data->p_wv_r_bd_with_co = 0;value[0] = STK_PDT_ID_REG;result = sensor_rx_data(client, value, 2);	if(result){printk("%s:line=%d,error\n",__func__,__LINE__);return result;}	printk(KERN_INFO "%s: PID=0x%x, RID=0x%x\n", __func__, value[0], value[1]);ps_data->pid = value[0];if(value[0] == STK3311WV_PID)ps_data->p_wv_r_bd_with_co |= 0b100;if(value[1] == 0xC3)ps_data->p_wv_r_bd_with_co |= 0b010;// if(stk3x1x_read_otp25(ps_data) == 1)// {// ps_data->p_wv_r_bd_with_co |= 0b001;// }printk(KERN_INFO "%s: p_wv_r_bd_with_co = 0x%x\n", __func__, ps_data->p_wv_r_bd_with_co);	pid_msb = value[0] & 0xF0;switch(pid_msb){case 0x10:case 0x20:case 0x30:return 0;default:printk(KERN_ERR "%s: invalid PID(%#x)\n", __func__, value[0]);	return -1;}return 0;
}static int light_sensor_init(struct i2c_client *client)
{int res = 0;printk("stk %s init ...\n", __func__);set_stk_power(1);ps_data = kzalloc(sizeof(struct stk3x1x_data),GFP_KERNEL);if(!ps_data){printk(KERN_ERR "%s: failed to allocate stk3x1x_data\n", __func__);return -ENOMEM;}	res = sensor_write_reg(client, STK_WAIT_REG, 0x7F);if(res < 0){printk("stk %s i2c test error line:%d\n", __func__,__LINE__);goto EXIT_ERR;}res = sensor_read_reg(client, STK_WAIT_REG);if(res != 0x7F){printk("stk %s i2c test error line:%d\n", __func__,__LINE__);		goto EXIT_ERR;}res = sensor_write_reg(client, STK_SW_RESET_REG, 0x0);if(res < 0){printk("stk %s i2c error line:%d\n", __func__,__LINE__);goto EXIT_ERR;}//usleep_range(13000, 15000);	res = stk3x1x_check_pid(client);if(res < 0){printk("stk %s i2c error line:%d\n", __func__,__LINE__);goto EXIT_ERR;}res = sensor_write_reg(client, STK_STATE_REG, stk3x1x_pfdata.state_reg);if(res < 0){printk("stk %s i2c error line:%d\n", __func__,__LINE__);	goto EXIT_ERR;}res = sensor_write_reg(client, STK_PSCTRL_REG, stk3x1x_pfdata.psctrl_reg);if(res < 0){printk("stk %s i2c error line:%d\n", __func__,__LINE__);goto EXIT_ERR;}res = sensor_write_reg(client, STK_ALSCTRL_REG, stk3x1x_pfdata.alsctrl_reg);if(res < 0){printk("stk %s i2c error line:%d\n", __func__,__LINE__);goto EXIT_ERR;}if(ps_data->pid == STK3310SA_PID || ps_data->pid == STK3311SA_PID)stk3x1x_pfdata.ledctrl_reg &= 0x3F;	res = sensor_write_reg(client, STK_LEDCTRL_REG, stk3x1x_pfdata.ledctrl_reg);if(res < 0){printk("stk %s i2c error line:%d\n", __func__,__LINE__);goto EXIT_ERR;}res = sensor_write_reg(client, STK_WAIT_REG, stk3x1x_pfdata.wait_reg);if(res < 0){printk("stk %s i2c error line:%d\n", __func__,__LINE__);goto EXIT_ERR;	}#ifndef STK_POLL_ALS	value = STK_INT_REG;res = sensor_rx_data(client, value, 1);	if(res){printk("%s:line=%d,error=%d\n",__func__,__LINE__, res);return res;}		value |= STK_INT_ALS;res = sensor_write_reg(client, STK_INT_REG, value);if(res <= 0){printk("stk %s i2c error line:%d\n", __func__,__LINE__);goto EXIT_ERR;	}
#endifps_data->als_code_last = 0;printk("stk %s init successful \n", __func__);return 0;EXIT_ERR:printk(KERN_ERR "stk init fail dev: %d\n", res);return res;}static int light_report_abs_value(struct input_dev *input, int data)
{unsigned char index = 0;if(data <= ALS_LEVEL[0]){index = 0;goto report;}else if(data <= ALS_LEVEL[1]){index = 1;goto report;}else if(data <= ALS_LEVEL[2]){index = 2;goto report;}else if(data <= ALS_LEVEL[3]){index = 3;goto report;}else if(data <= ALS_LEVEL[4]){index = 4;goto report;}else if(data <= ALS_LEVEL[5]){index = 5;goto report;}else if(data <= ALS_LEVEL[6]){index = 6;goto report;}else{index = 7;goto report;}report:input_report_abs(input, ABS_MISC, index);input_sync(input);return index;
}
/*
static int stk_allreg(struct i2c_client *client)
{uint8_t ps_reg[0x22];int cnt = 0;	for(cnt=0;cnt<0x20;cnt++){ps_reg[cnt] = sensor_read_reg(client, cnt);if(ps_reg[cnt] < 0){printk("%s fail \n", __func__);	return -EINVAL;}printk(KERN_INFO "reg[0x%2X]=0x%2X\n", cnt, ps_reg[cnt]);}	return 0;
}
*/
static int32_t stk3x1x_set_irs_it_slp(struct i2c_client *client, uint16_t *slp_time, int32_t ials_it_reduce)
{int irs_alsctrl;int32_t ret;irs_alsctrl = (stk3x1x_pfdata.alsctrl_reg & 0x0F) - ials_it_reduce;switch(irs_alsctrl){case 2:*slp_time = 1;break;			case 3:*slp_time = 2;break;	case 4:*slp_time = 3;break;	case 5:*slp_time = 6;break;case 6:*slp_time = 12;break;case 7:*slp_time = 24;			break;case 8:*slp_time = 48;			break;case 9:*slp_time = 96;			break;				case 10:*slp_time = 192;break;				default:printk(KERN_ERR "%s: unknown ALS IT=0x%x\n", __func__, irs_alsctrl);ret = -EINVAL;	return ret;}irs_alsctrl |= (stk3x1x_pfdata.alsctrl_reg & 0xF0);ret = sensor_write_reg(client, STK_ALSCTRL_REG, irs_alsctrl);if(ret <= 0)return ret;return 0;
}static int stk3x1x_get_ir_reading(struct i2c_client *client, int32_t als_it_reduce)
{int res = 0;	int32_t word_data, ret;int w_reg, retry = 0;	uint16_t irs_slp_time = 100;char buffer[2] = {0};ret = stk3x1x_set_irs_it_slp(client, &irs_slp_time, als_it_reduce);if(ret < 0)return ret;w_reg = sensor_read_reg(client, STK_STATE_REG);if(w_reg <= 0){printk("stk %s i2c error(%d)\n", __func__, w_reg);return ret;}	w_reg |= STK_STATE_EN_IRS_MASK;		res = sensor_write_reg(client, STK_STATE_REG, w_reg);if(res <= 0)return res;msleep(irs_slp_time);		do{usleep_range(3000, 4000);w_reg = sensor_read_reg(client, STK_FLAG_REG);if(w_reg <= 0)return w_reg;retry++;}while(retry < 10 && ((w_reg & STK_FLG_IR_RDY_MASK) == 0));if(retry == 10){printk(KERN_ERR "%s: ir data is not ready for a long time\n", __func__);return -EINVAL;}w_reg &= (~STK_FLG_IR_RDY_MASK);res = sensor_write_reg(client, STK_FLAG_REG, w_reg);if(res <= 0)return res;buffer[0] = STK_DATA1_IR_REG;res = sensor_rx_data(client, buffer, 2);	if(res){printk("%s:line=%d,error\n",__func__,__LINE__);return res;}word_data = ((buffer[0]<<8) | buffer[1]);	printk(KERN_INFO "%s: ir=%d\n", __func__, word_data);res = sensor_write_reg(client, STK_ALSCTRL_REG, stk3x1x_pfdata.alsctrl_reg);if(res <= 0)return res;return word_data;
}
#ifdef STK_IRS	
static int stk_als_ir_skip_als(struct i2c_client *client, struct sensor_private_data *sensor)
{int ret;unsigned char buffer[2] = {0};	if(ps_data->als_data_index < 60000)ps_data->als_data_index++;elseps_data->als_data_index = 0;if(	ps_data->als_data_index % 10 == 1){buffer[0] = STK_DATA1_ALS_REG;ret = sensor_rx_data(client, buffer, 2);	if(ret){printk("%s:line=%d,error=%d\n",__func__,__LINE__, ret);return ret;}return 1;}return 0;
}
#endif
static int stk_als_cal(struct i2c_client *client, int *als_data)
{int32_t ir_data = 0;
#ifdef STK_ALS_FIRint index;   int firlen = atomic_read(&ps_data->firlength);   
#endif
#ifdef STK_IRS	const int ir_enlarge = 1 << (STK_ALS_READ_IRS_IT_REDUCE - STK_IRS_IT_REDUCE);
#endifif(ps_data->p_wv_r_bd_with_co & 0b010){if(*als_data < STK_ALS_THRESHOLD && ps_data->als_code_last > 10000){ir_data = stk3x1x_get_ir_reading(client, STK_ALS_READ_IRS_IT_REDUCE);
#ifdef STK_IRS				if(ir_data > 0)ps_data->ir_code = ir_data * ir_enlarge;
#endif			// printk(KERN_INFO "%s: *als_data=%d, als_code_last=%d,ir_data=%d\n", // __func__, *als_data, ps_data->als_code_last, ir_data);	if(ir_data > (STK_ALS_THRESHOLD*3)){*als_data = ps_data->als_code_last;}}
#ifdef STK_IRS			else{ps_data->ir_code = 0;}
#endif		}ps_data->als_code_last = *als_data;	
#ifdef STK_ALS_FIRif(ps_data->fir.number < firlen){                ps_data->fir.raw[ps_data->fir.number] = *als_data;ps_data->fir.sum += *als_data;ps_data->fir.number++;ps_data->fir.idx++;}else{index = ps_data->fir.idx % firlen;ps_data->fir.sum -= ps_data->fir.raw[index];ps_data->fir.raw[index] = *als_data;ps_data->fir.sum += *als_data;ps_data->fir.idx++;*als_data = ps_data->fir.sum/firlen;}	
#endif		return 0;
}#ifdef STK_IRS
static void stk_als_ir_get_corr(int32_t als)
{int32_t als_comperator;if(ps_data->ir_code){ps_data->als_correct_factor = 1000;if(als < STK_IRC_MAX_ALS_CODE && als > STK_IRC_MIN_ALS_CODE && ps_data->ir_code > STK_IRC_MIN_IR_CODE){als_comperator = als * STK_IRC_ALS_NUMERA / STK_IRC_ALS_DENOMI;if(ps_data->ir_code > als_comperator)ps_data->als_correct_factor = STK_IRC_ALS_CORREC;}
#ifdef STK_DEBUG_PRINTF				printk(KERN_INFO "%s: als=%d, ir=%d, als_correct_factor=%d", __func__, als, ps_data->ir_code, ps_data->als_correct_factor);
#endif		ps_data->ir_code = 0;}	return;
}static int stk_als_ir_run(struct i2c_client *client)
{int ret;if(ps_data->als_data_index % 10 == 0){if(ps_data->ps_distance_last != 0 && ps_data->ir_code == 0){ret = stk3x1x_get_ir_reading(client, STK_IRS_IT_REDUCE);if(ret > 0)ps_data->ir_code = ret;}		return ret;}	return 0;
}
#endifstatic int light_sensor_report_value(struct i2c_client *client)
{struct sensor_private_data *sensor =(struct sensor_private_data *) i2c_get_clientdata(client);	int result = 0;uint32_t value = 0;unsigned char buffer[2] = {0};	char index = 0;if(sensor->ops->read_len < 2)	//sensor->ops->read_len = 1{printk("%s:lenth is error,len=%d\n",__func__,sensor->ops->read_len);return -1;}value = sensor_read_reg(client, STK_FLAG_REG);if(value < 0){printk("stk %s read STK_FLAG_REG, ret=%d\n", __func__, value);return value;}if(!(value & STK_FLG_ALSDR_MASK))return 0;#ifdef STK_IRSresult = stk_als_ir_skip_als(client, sensor);if(result == 1)return 0;
#endif		buffer[0] = sensor->ops->read_reg;result = sensor_rx_data(client, buffer, sensor->ops->read_len);	if(result){printk("%s:line=%d,error\n",__func__,__LINE__);return result;}value = (buffer[0] << 8) | buffer[1];
#ifdef STK_DEBUG_PRINTFprintk("%s: value == %d \n",__func__,value);
#endif	stk_als_cal(client, &value);
#ifdef STK_IRSstk_als_ir_get_corr(value);value = value * ps_data->als_correct_factor / 1000;
#endif	index = light_report_abs_value(sensor->input_dev, value);	/*if(sensor->pdata->irq_enable){if(sensor->ops->int_status_reg){	value = sensor_read_reg(client, sensor->ops->int_status_reg);}if(value & STA_PS_INT){value &= ~STA_PS_INT;result = sensor_write_reg(client, sensor->ops->int_status_reg,value);	//clear intif(result){printk("%s:line=%d,error\n",__func__,__LINE__);return result;}}}*/
#ifdef STK_IRSstk_als_ir_run(client);
#endif	return result;
}struct sensor_operate light_stk3x1x_ops = {.name				= "ls_stk3x1x",.type				= SENSOR_TYPE_LIGHT,	//sensor type and it should be correct.id_i2c				= LIGHT_ID_STK3X1X,		//i2c id number.read_reg			= STK_DATA1_ALS_REG,			//read data.read_len			= 2,				//data length.id_reg				= SENSOR_UNKNOW_DATA,		//read device id from this register.id_data 			= SENSOR_UNKNOW_DATA,		//device id.precision			= 16,				//16 bits.ctrl_reg 			= STK_STATE_REG,			//enable or disable .int_status_reg 	= SENSOR_UNKNOW_DATA,			//intterupt status register.range				= {100,65535},		//range.brightness         ={10,255},     //brightness	.trig				= IRQF_TRIGGER_LOW | IRQF_ONESHOT | IRQF_SHARED,		.active				= light_sensor_active,	.init				= light_sensor_init,.report				= light_sensor_report_value,
};static int light_stk3x1x_probe(struct i2c_client *client,const struct i2c_device_id *devid)
{return sensor_register_device(client, NULL, devid, &light_stk3x1x_ops);
}static int light_stk3x1x_remove(struct i2c_client *client)
{return sensor_unregister_device(client, NULL, &light_stk3x1x_ops);
}static const struct i2c_device_id light_stk3x1x_id[] = {{"ls_stk3x1x", LIGHT_ID_STK3X1X},{}
};static struct i2c_driver light_stk3x1x_driver = {.probe = light_stk3x1x_probe,.remove = light_stk3x1x_remove,.shutdown = sensor_shutdown,.id_table = light_stk3x1x_id,.driver = {.name = "light_stk3x1x",#ifdef CONFIG_PM.pm = &sensor_pm_ops,#endif},
};module_i2c_driver(light_stk3x1x_driver);MODULE_AUTHOR("Lex Hsieh <lex_hsieh@sensortek.com.tw>");
MODULE_DESCRIPTION("Sensortek stk3x1x Proximity Sensor driver");
MODULE_LICENSE("GPL");
MODULE_VERSION(DRIVER_VERSION);

二、距离传感驱动代码 kernel\drivers\input\sensors\psensor\ps_stk3x1x.c,代码里面带sensor->pdata->irq_enable部分的是我自己添加来根据dts里面的配置irq_enable来处理中断的模式,默认是轮询模式。

/**  ps_stk3x1x.c - Linux kernel modules for sensortek stk301x, stk321x and stk331x *  proximity/ambient light sensor**  Copyright (C) 2012~2015 Lex Hsieh / sensortek <lex_hsieh@sensortek.com.tw>**  This program is free software; you can redistribute it and/or modify*  it under the terms of the GNU General Public License as published by*  the Free Software Foundation; either version 2 of the License, or*  (at your option) any later version.**  This program is distributed in the hope that it will be useful,*  but WITHOUT ANY WARRANTY; without even the implied warranty of*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the*  GNU General Public License for more details.**  You should have received a copy of the GNU General Public License*  along with this program; if not, write to the Free Software*  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.*/#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/i2c.h>
#include <linux/mutex.h>
#include <linux/kdev_t.h>
#include <linux/fs.h>
#include <linux/input.h>
#include <linux/workqueue.h>
#include <linux/irq.h>
#include <linux/delay.h>
#include <linux/sched.h>
#include <linux/kthread.h>
#include <linux/errno.h>
#include <linux/wakelock.h>
#include <linux/interrupt.h>
#include <linux/gpio.h>
#include   <linux/fs.h>   
#include  <asm/uaccess.h> 
#include <linux/sensor-dev.h>
#include <linux/of_gpio.h>
#ifdef CONFIG_HAS_EARLYSUSPEND
//#include <linux/earlysuspend.h>
#endif#define DRIVER_VERSION  "3.10.0_0429"//#define STK_POLL_PS
#define STK_TUNE0
#define STK_DEBUG_PRINTF#include "linux/stk3x1x.h"/* Define Register Map */
#define STK_STATE_REG 			0x00
#define STK_PSCTRL_REG 			0x01
#define STK_ALSCTRL_REG 			0x02
#define STK_LEDCTRL_REG 			0x03
#define STK_INT_REG 				0x04
#define STK_WAIT_REG 			0x05
#define STK_THDH1_PS_REG 		0x06
#define STK_THDH2_PS_REG 		0x07
#define STK_THDL1_PS_REG 		0x08
#define STK_THDL2_PS_REG 		0x09
#define STK_THDH1_ALS_REG 		0x0A
#define STK_THDH2_ALS_REG 		0x0B
#define STK_THDL1_ALS_REG 		0x0C
#define STK_THDL2_ALS_REG 		0x0D
#define STK_FLAG_REG 			0x10
#define STK_DATA1_PS_REG	 	0x11
#define STK_DATA2_PS_REG 		0x12
#define STK_DATA1_ALS_REG 		0x13
#define STK_DATA2_ALS_REG 		0x14
#define STK_DATA1_OFFSET_REG 	0x15
#define STK_DATA2_OFFSET_REG 	0x16
#define STK_DATA1_IR_REG 		0x17
#define STK_DATA2_IR_REG 		0x18
#define STK_PDT_ID_REG 			0x3E
#define STK_RSRVD_REG 			0x3F
#define STK_SW_RESET_REG		0x80	#define STK_STATE_EN_IRS_MASK	0x80
#define STK_STATE_EN_AK_MASK	0x40
#define STK_STATE_EN_ASO_MASK	0x20
#define STK_STATE_EN_IRO_MASK	0x10
#define STK_STATE_EN_WAIT_MASK	0x04
#define STK_STATE_EN_ALS_MASK	0x02
#define STK_STATE_EN_PS_MASK	0x01#define STK_FLG_ALSDR_MASK		0x80
#define STK_FLG_PSDR_MASK		0x40
#define STK_FLG_ALSINT_MASK		0x20
#define STK_FLG_PSINT_MASK		0x10
#define STK_FLG_OUI_MASK			0x04
#define STK_FLG_IR_RDY_MASK		0x02
#define STK_FLG_NF_MASK			0x01#define STK_INT_ALS				0x08/*****************************************************************************/
#define STK_MAX_MIN_DIFF	200
#define STK_LT_N_CT	100
#define STK_HT_N_CT	150
/*****************************************************************************/
#define STK3310SA_PID		0x17
#define STK3311SA_PID		0x1E
#define STK3311WV_PID	0x1D
/*****************************************************************************//* INT 0x04 */
#define	PS_INT_DISABLE		0xF8
#define	PS_INT_ENABLE		(1 << 0)
#define	PS_INT_ENABLE_FLGNFH	(2 << 0)
#define	PS_INT_ENABLE_FLGNFL	(3 << 0)
#define	PS_INT_MODE_ENABLE	(4 << 0)
#define	PS_INT_ENABLE_THL	(5 << 0)
#define	PS_INT_ENABLE_THH	(6 << 0)
#define	PS_INT_ENABLE_THHL	(7 << 0)
#define	ALS_INT_DISABLE		(0 << 3)
#define	ALS_INT_ENABLE		(1 << 3)
#define	INT_CTRL_PS_OR_LS	(0 << 7)
#define	INT_CTRL_PS_AND_LS	(1 << 7)/* FLAG 0x10 */
/* FLAG 0x10 */
#define	STK_FLAG_NF	(1 << 0)
#define	STK_FLAG_IR_RDY	(1 << 1)
#define	STK_FLAG_OUI	(1 << 2)
#define	STK_FLAG_PSINT	(1 << 4)
#define	STK_FLAG_ALSINT	(1 << 5)
#define	STK_FLAG_PSDR	(1 << 6)
#define	STK_FLAG_ALSDR	(1 << 7)#ifdef STK_ALS_FIR#define STK_FIR_LEN	8#define MAX_FIR_LEN 32struct data_filter {u16 raw[MAX_FIR_LEN];int sum;int number;int idx;
};
#endifstruct stk3x1x_data {int		int_pin;uint16_t ps_thd_h;uint16_t ps_thd_l;
#ifdef CALI_PS_EVERY_TIME	uint16_t ps_high_thd_boot;uint16_t ps_low_thd_boot;
#endif	int32_t ps_distance_last;bool ps_enabled;// bool re_enable_ps;bool first_boot;
#ifdef STK_TUNE0uint16_t psa;uint16_t psi;	uint16_t psi_set;	struct hrtimer ps_tune0_timer;	struct workqueue_struct *stk_ps_tune0_wq;struct work_struct stk_ps_tune0_work;ktime_t ps_tune0_delay;bool tune_zero_init_proc;uint32_t ps_stat_data[3];int data_count;int stk_max_min_diff;int stk_lt_n_ct;int stk_ht_n_ct;
#endif	atomic_t	recv_reg;uint8_t pid;uint8_t	p_wv_r_bd_with_co;
};struct stk3x1x_data *ps_data;/*****************************************************************************/static struct stk3x1x_platform_data stk3x1x_pfdata={ .state_reg = 0x0,    /* disable all */ .psctrl_reg = 0x31,    /* ps_persistance=1, ps_gain=64X, PS_IT=0.391ms */ .alsctrl_reg = 0x39, 	/* als_persistance=1, als_gain=64X, ALS_IT=100ms */.ledctrl_reg = 0xFF,   /* 100mA IRDR, 64/64 LED duty */ .wait_reg = 0x07,    /* 50 ms */   .ps_thd_h = 1700, .ps_thd_l = 1500, //.int_pin = sprd_3rdparty_gpio_pls_irq,  .transmittance = 500, 
#if defined(CONFIG_SOFIA_3GR_BND_I706).stk_max_min_diff = 15,.stk_lt_n_ct = 50,.stk_ht_n_ct = 75, 
#else.stk_max_min_diff = 10,.stk_lt_n_ct = 45,.stk_ht_n_ct = 60,
#endif
};static int32_t stk3x1x_check_pid(struct i2c_client *client);
static int stk_ps_tune_zero_init(struct i2c_client *client);/*****************************************************************************/static int32_t stk3x1x_set_ps_thd_h(struct i2c_client *client, uint16_t thd_h)
{	unsigned char val[2];int ret;val[0] = (thd_h & 0xFF00) >> 8;val[1] = thd_h & 0x00FF;ret = sensor_write_reg(client, STK_THDH1_PS_REG, val[0]);if(ret < 0){printk("%s: fail, ret=%d\n", __func__, ret);	}ret = sensor_write_reg(client, STK_THDH2_PS_REG, val[1]);if(ret < 0){printk("%s: fail, ret=%d\n", __func__, ret);	}return ret;
}static int32_t stk3x1x_set_ps_thd_l(struct i2c_client *client, uint16_t thd_l)
{	unsigned char val[2];int ret;val[0] = (thd_l & 0xFF00) >> 8;val[1] = thd_l & 0x00FF;	ret = sensor_write_reg(client, STK_THDL1_PS_REG, val[0]);if(ret < 0){printk("%s: fail, ret=%d\n", __func__, ret);	}ret = sensor_write_reg(client, STK_THDL2_PS_REG, val[1]);if(ret < 0){printk("%s: fail, ret=%d\n", __func__, ret);	}return ret;
}
/* 
static uint32_t stk3x1x_get_ps_reading(struct i2c_client *client, u16 *data){	 unsigned char value[2];int err = 0;value[0] = sensor_read_reg(client, STK_DATA1_PS_REG);if(value[0] < 0){goto EXIT_ERR;}value[1] = sensor_read_reg(client, STK_DATA2_PS_REG);if(value[1] < 0){goto EXIT_ERR;}*data = ((value[0]<<8) | value[1]);return 0; EXIT_ERR:printk("stk3x1x_read_ps fail\n");return err;}*/static int proximity_sensor_active(struct i2c_client *client, int enable, int rate)
{struct sensor_private_data *sensor =(struct sensor_private_data *) i2c_get_clientdata(client);	int result = 0;// u16 ps_code;
#ifdef STK_DEBUG_PRINTF	printk("%s init proc = %d\n", __func__, (ps_data->tune_zero_init_proc ? 1 : 0));
#endif	sensor->ops->ctrl_data = sensor_read_reg(client, sensor->ops->ctrl_reg);sensor->ops->ctrl_data &= ~(STK_STATE_EN_PS_MASK | STK_STATE_EN_WAIT_MASK); if(enable){sensor->ops->ctrl_data |= STK_STATE_EN_PS_MASK;	if(!(sensor->ops->ctrl_data & STK_STATE_EN_ALS_MASK))sensor->ops->ctrl_data |= STK_STATE_EN_WAIT_MASK;			}
#ifdef STK_DEBUG_PRINTF		printk("%s:reg=0x%x,reg_ctrl=0x%x,enable=%d\n",__func__,sensor->ops->ctrl_reg, sensor->ops->ctrl_data, enable);
#endifresult = sensor_write_reg(client, sensor->ops->ctrl_reg, sensor->ops->ctrl_data);if(result)printk("%s:fail to active sensor\n",__func__);if(enable){usleep_range(4000, 5000);sensor->ops->report(sensor->client);// stk3x1x_get_ps_reading(client, &ps_code);// stk3x1x_set_ps_thd_h(client, ps_code + STK_HT_N_CT);// stk3x1x_set_ps_thd_l(client, ps_code + STK_LT_N_CT);
#ifdef STK_DEBUG_PRINTF				printk(KERN_INFO "%s: thdh:%d, thdl:%d\n", __func__, ps_data->ps_thd_h, ps_data->ps_thd_l);
#endif	stk3x1x_set_ps_thd_h(client, ps_data->ps_thd_h);stk3x1x_set_ps_thd_l(client, ps_data->ps_thd_l);		}ps_data->ps_enabled = enable?true:false;ps_data->ps_distance_last = 1;	ps_data->psa = 0x0;ps_data->psi = 0xFFFF;	ps_data->psi_set = 0;ps_data->stk_max_min_diff = stk3x1x_pfdata.stk_max_min_diff;ps_data->stk_lt_n_ct = stk3x1x_pfdata.stk_lt_n_ct;ps_data->stk_ht_n_ct = stk3x1x_pfdata.stk_ht_n_ct;#ifdef STK_DEBUG_PRINTF				printk(KERN_INFO "%s: lt:%d ht:%d max diff:%d\n", __func__, ps_data->stk_lt_n_ct, ps_data->stk_ht_n_ct, ps_data->stk_max_min_diff);
#endif	return result;}static int32_t stk3x1x_check_pid(struct i2c_client *client)
{char value[2] = {0}, pid_msb;int result;ps_data->p_wv_r_bd_with_co = 0;value[0] = STK_PDT_ID_REG;result = sensor_rx_data(client, value, 2);	if(result){printk("%s:line=%d,error\n",__func__,__LINE__);return result;}
#ifdef STK_DEBUG_PRINTF		printk(KERN_INFO "%s: PID=0x%x, RID=0x%x\n", __func__, value[0], value[1]);
#endifps_data->pid = value[0];if(value[0] == STK3311WV_PID)ps_data->p_wv_r_bd_with_co |= 0b100;if(value[1] == 0xC3)ps_data->p_wv_r_bd_with_co |= 0b010;// if(stk3x1x_read_otp25(ps_data) == 1)// {// ps_data->p_wv_r_bd_with_co |= 0b001;// }
#ifdef STK_DEBUG_PRINTF		printk(KERN_INFO "%s: p_wv_r_bd_with_co = 0x%x\n", __func__, ps_data->p_wv_r_bd_with_co);	
#endifpid_msb = value[0] & 0xF0;switch(pid_msb){case 0x10:case 0x20:case 0x30:return 0;default:printk(KERN_ERR "%s: invalid PID(%#x)\n", __func__, value[0]);	return -1;}return 0;
}/*
static int stk_allreg(struct i2c_client *client)
{uint8_t ps_reg[0x22];int cnt = 0;	for(cnt=0;cnt<0x20;cnt++){ps_reg[cnt] = sensor_read_reg(client, cnt);if(ps_reg[cnt] < 0){printk("%s fail \n", __func__);	return -EINVAL;}
#ifdef STK_DEBUG_PRINTF			printk(KERN_INFO "reg[0x%2X]=0x%2X\n", cnt, ps_reg[cnt]);
#endif}	return 0;
}
*/
#ifdef STK_TUNE0	
static int stk_ps_val(struct i2c_client *client)
{int mode;int32_t word_data, lii;	unsigned char value[4];int ret;value[0] = 0x20;ret = sensor_rx_data(client, value, 4);	if(ret){printk("%s:line=%d,error=%d\n",__func__,__LINE__, ret);return ret;}word_data = (value[0]<<8) | value[1];	word_data += ((value[2]<<8) | value[3]);	mode = (stk3x1x_pfdata.psctrl_reg) & 0x3F;if(mode == 0x30)	lii = 100;	else if (mode == 0x31)lii = 200;		else if (mode == 0x32)lii = 400;		else if (mode == 0x33)lii = 800;	else{printk(KERN_ERR "%s: unsupported PS_IT(0x%x)\n", __func__, mode);return -1;}if(word_data > lii){printk(KERN_INFO "%s: word_data=%d, lii=%d\n", __func__, word_data, lii);	return 0xFFFF;	}return 0;
}	static int stk_ps_tune_zero_final(struct i2c_client *client)
{int ret;int value;value = 0;
#ifndef STK_POLL_PS	value |= 0x01;		
#endif
#ifndef STK_POLL_ALSvalue |= STK_INT_ALS;
#endifret = sensor_write_reg(client, STK_INT_REG, value);if(ret <= 0)return ret;	value = sensor_read_reg(client, STK_STATE_REG);if(!(value & STK_STATE_EN_ALS_MASK))value |= STK_STATE_EN_WAIT_MASK;if(ps_data->ps_enabled)value |= STK_STATE_EN_PS_MASK;ret = sensor_write_reg(client, STK_STATE_REG, value);if (ret < 0){printk(KERN_ERR "%s: write i2c error\n", __func__);return ret;}if(ps_data->data_count == -1){printk(KERN_INFO "%s: exceed limit\n", __func__);ps_data->tune_zero_init_proc = false;return 0;}ps_data->psa = ps_data->ps_stat_data[0];ps_data->psi = ps_data->ps_stat_data[2];	ps_data->ps_thd_h = ps_data->ps_stat_data[1] + ps_data->stk_ht_n_ct;ps_data->ps_thd_l = ps_data->ps_stat_data[1] + ps_data->stk_lt_n_ct;			stk3x1x_set_ps_thd_h(client, ps_data->ps_thd_h);stk3x1x_set_ps_thd_l(client, ps_data->ps_thd_l);	
#ifdef STK_DEBUG_PRINTF		printk(KERN_INFO "stk %s: set HT=%d,LT=%d\n", __func__, ps_data->ps_thd_h,  ps_data->ps_thd_l);		
#endifps_data->tune_zero_init_proc = false;return 0;
}static int32_t stk_tune_zero_get_ps_data(struct i2c_client *client, int ps_adc)
{int ret;ret = stk_ps_val(client);	if(ret == 0xFFFF){ps_data->data_count = -1;stk_ps_tune_zero_final(client);return 0;}
#ifdef STK_DEBUG_PRINTF		printk(KERN_INFO "%s: ps_adc #%d=%d\n", __func__, ps_data->data_count, ps_adc);
#endifps_data->ps_stat_data[1] +=  ps_adc;			if(ps_adc > ps_data->ps_stat_data[0])ps_data->ps_stat_data[0] = ps_adc;if(ps_adc < ps_data->ps_stat_data[2])ps_data->ps_stat_data[2] = ps_adc;						ps_data->data_count++;	if(ps_data->data_count == 5){ps_data->ps_stat_data[1]  /= ps_data->data_count;			stk_ps_tune_zero_final(client);}		return 0;
}static int stk_ps_tune_zero_init(struct i2c_client *client)
{//struct sensor_private_data *sensor =//    (struct sensor_private_data *) i2c_get_clientdata(client);		ps_data->psa = 0x0;ps_data->psi = 0xFFFF;	ps_data->psi_set = 0;	ps_data->ps_stat_data[0] = 0;ps_data->ps_stat_data[2] = 9999;ps_data->ps_stat_data[1] = 0;ps_data->data_count = 0;ps_data->tune_zero_init_proc = false;	/*sensor->ops->ctrl_data = sensor_read_reg(client, sensor->ops->ctrl_reg);sensor->ops->ctrl_data &= ~(STK_STATE_EN_PS_MASK | STK_STATE_EN_WAIT_MASK); sensor->ops->ctrl_data |= STK_STATE_EN_PS_MASK;	if(!(sensor->ops->ctrl_data & STK_STATE_EN_ALS_MASK))sensor->ops->ctrl_data |= STK_STATE_EN_WAIT_MASK;			result = sensor_write_reg(client, sensor->ops->ctrl_reg, sensor->ops->ctrl_data);if(result)printk("%s:fail to active sensor\n",__func__);
#ifdef STK_DEBUG_PRINTF		printk("%s:reg=0x%x,reg_ctrl=0x%x\n",__func__,sensor->ops->ctrl_reg, sensor->ops->ctrl_data);
#endifresult = sensor_write_reg(client, STK_INT_REG, 0);if(result)printk("%s:fail to active sensor\n",__func__);*/return 0;	
}static int stk_ps_tune_zero_func_fae(struct i2c_client *client, int word_data)
{int ret, diff;
#ifdef STK_DEBUG_PRINTF	//int cnt = 0;//int ps_reg[0x22];
#endifif(ps_data->psi_set || !(ps_data->ps_enabled))return 0;ret = stk_ps_val(client);	if(ret == 0){				if(word_data == 0){//printk(KERN_ERR "%s: incorrect word data (0)\n", __func__);return 0xFFFF;}if(word_data > ps_data->psa){ps_data->psa = word_data;
#ifdef STK_DEBUG_PRINTF				printk(KERN_INFO "%s: update psa: psa=%d,psi=%d\n", __func__, ps_data->psa, ps_data->psi);
#endif}if(word_data < ps_data->psi){ps_data->psi = word_data;	
#ifdef STK_DEBUG_PRINTF				printk(KERN_INFO "%s: update psi: psa=%d,psi=%d\n", __func__, ps_data->psa, ps_data->psi);	
#endif}	}	diff = ps_data->psa - ps_data->psi;
#ifdef STK_DEBUG_PRINTF				printk(KERN_INFO "%s: diff:%d  psa:%d, psi:%d max diff:%d\n", __func__, diff, ps_data->psa, ps_data->psi, ps_data->stk_max_min_diff);
#endif	if(diff > ps_data->stk_max_min_diff){ps_data->psi_set = ps_data->psi;ps_data->ps_thd_h = ps_data->psi + ps_data->stk_ht_n_ct;ps_data->ps_thd_l = ps_data->psi + ps_data->stk_lt_n_ct;
#ifdef STK_DEBUG_PRINTF				printk(KERN_INFO "%s: tune0 thd_h:%d	thd_l:%d\n", __func__, ps_data->ps_thd_h, ps_data->ps_thd_l);
#endif#if 0 //def STK_DEBUG_PRINTF	cnt = 0x6;ps_reg[cnt] = sensor_read_reg(client, cnt);cnt = 0x7;ps_reg[cnt] = sensor_read_reg(client, cnt);cnt = 0x8;ps_reg[cnt] = sensor_read_reg(client, cnt);cnt = 0x9;ps_reg[cnt] = sensor_read_reg(client, cnt); printk(KERN_INFO "%s: befor [0x06/0x07]%d, %d  [0x08/0x09]%d, %d	\n", __func__, ps_reg[0x6], ps_reg[0x7], ps_reg[0x8], ps_reg[0x9]);
#endifstk3x1x_set_ps_thd_h(client, ps_data->ps_thd_h);stk3x1x_set_ps_thd_l(client, ps_data->ps_thd_l);#if 0 //def STK_DEBUG_PRINTF	cnt = 0x6;ps_reg[cnt] = sensor_read_reg(client, cnt);cnt = 0x7;ps_reg[cnt] = sensor_read_reg(client, cnt);cnt = 0x8;ps_reg[cnt] = sensor_read_reg(client, cnt);cnt = 0x9;ps_reg[cnt] = sensor_read_reg(client, cnt);	printk(KERN_INFO "%s: after [0x06/0x07]%d, %d  [0x08/0x09]%d, %d  \n", __func__, ps_reg[0x6], ps_reg[0x7], ps_reg[0x8], ps_reg[0x9]);
#endif#ifdef STK_DEBUG_PRINTF				printk(KERN_INFO "%s: FAE tune0 found thd_h:%d  thd_l:%d\n", __func__, ps_data->ps_thd_h, ps_data->ps_thd_l);
#endif}return 0;
}	
#endifstatic int stk_ps_report(struct i2c_client *client, int ps)
{struct sensor_private_data *sensor =(struct sensor_private_data *) i2c_get_clientdata(client);	int result = 0;char buffer[2] = {0};	int reg_flag = 0;#if 0 //def STK_DEBUG_PRINTF	int cnt = 0;int ps_reg[0x22];	
#endifbuffer[0] = STK_FLAG_REG;result = sensor_rx_data(client, buffer, 1);	if(result){printk("%s:line=%d,error\n",__func__,__LINE__);return result;}reg_flag = buffer[0];reg_flag = (reg_flag & 0x1);ps_data->ps_distance_last = reg_flag ? 1:0;#if 0 //def STK_DEBUG_PRINTF	cnt = 0x6;ps_reg[cnt] = sensor_read_reg(client, cnt);cnt = 0x7;ps_reg[cnt] = sensor_read_reg(client, cnt);cnt = 0x8;ps_reg[cnt] = sensor_read_reg(client, cnt);cnt = 0x9;ps_reg[cnt] = sensor_read_reg(client, cnt);	printk(KERN_INFO "%s: [0x06/0x07]%d, %d  [0x08/0x09]%d, %d  \n", __func__, ps_reg[0x6], ps_reg[0x7], ps_reg[0x8], ps_reg[0x9]);
#endifif(ps > ps_data->ps_thd_h){ps_data->ps_distance_last = 0;}else if(ps < ps_data->ps_thd_l){ps_data->ps_distance_last = 1;}input_report_abs(sensor->input_dev, ABS_DISTANCE, ps_data->ps_distance_last);input_sync(sensor->input_dev);
#ifdef STK_DEBUG_PRINTF		printk("%s:ps=0x%x,flag=%d, dis=%d\n",__func__, ps,reg_flag, ps_data->ps_distance_last);
#endifreturn 0;
}static int proximity_sensor_init(struct i2c_client *client)
{struct sensor_private_data *sensor =(struct sensor_private_data *)i2c_get_clientdata(client);int res = 0;char value;int val = 0;printk("stk %s init ...\n", __func__);ps_data = kzalloc(sizeof(struct stk3x1x_data),GFP_KERNEL);if(!ps_data){printk(KERN_ERR "%s: failed to allocate stk3x1x_data\n", __func__);return -ENOMEM;}res = sensor_write_reg(client, STK_WAIT_REG, 0x7F);if(res < 0){printk("stk %s int error 1\n", __func__);	goto EXIT_ERR;}value = sensor_read_reg(client, STK_WAIT_REG);if(value != 0x7F){printk("stk %s i2c test error\n", __func__);		goto EXIT_ERR;}res = sensor_write_reg(client, STK_SW_RESET_REG, 0x0);if(res < 0){printk("stk %s int error 2\n", __func__);	goto EXIT_ERR;}//usleep_range(13000, 15000);	res = stk3x1x_check_pid(client);if(res < 0){printk("stk %s int error 3\n", __func__);	goto EXIT_ERR;}res = sensor_write_reg(client, STK_STATE_REG, stk3x1x_pfdata.state_reg);if(res < 0){printk("stk %s int error 4\n", __func__);	goto EXIT_ERR;}res = sensor_write_reg(client, STK_PSCTRL_REG, stk3x1x_pfdata.psctrl_reg);if(res < 0){printk("stk %s int error 5\n", __func__);	goto EXIT_ERR;}res = sensor_write_reg(client, STK_ALSCTRL_REG, stk3x1x_pfdata.alsctrl_reg);if(res < 0){printk("stk %s int error 6\n", __func__);	goto EXIT_ERR;}if(ps_data->pid == STK3310SA_PID || ps_data->pid == STK3311SA_PID)stk3x1x_pfdata.ledctrl_reg &= 0x3F;	res = sensor_write_reg(client, STK_LEDCTRL_REG, stk3x1x_pfdata.ledctrl_reg);if(res < 0){printk("stk %s int error 7\n", __func__);	goto EXIT_ERR;}res = sensor_write_reg(client, STK_WAIT_REG, stk3x1x_pfdata.wait_reg);if(res < 0){printk("stk %s int error 8\n", __func__);	goto EXIT_ERR;}	value = 0x0;res = sensor_write_reg(client, STK_INT_REG, value);if(res < 0){printk("stk %s int error 10\n", __func__);	goto EXIT_ERR;}stk3x1x_set_ps_thd_h(client, stk3x1x_pfdata.ps_thd_h);	stk3x1x_set_ps_thd_l(client, stk3x1x_pfdata.ps_thd_l);	printk("stk %s initing \n", __func__);		
#ifdef STK_TUNE0stk_ps_tune_zero_init(client);
#endif	#ifdef STK_ALS_FIRmemset(&ps_data->fir, 0x00, sizeof(ps_data->fir));  atomic_set(&ps_data->firlength, STK_FIR_LEN);	
#endifatomic_set(&ps_data->recv_reg, 0);  	ps_data->ps_enabled = false;ps_data->ps_distance_last = 1;	ps_data->stk_max_min_diff = stk3x1x_pfdata.stk_max_min_diff;ps_data->stk_lt_n_ct = stk3x1x_pfdata.stk_lt_n_ct;ps_data->stk_ht_n_ct = stk3x1x_pfdata.stk_ht_n_ct;ps_data->ps_thd_h = stk3x1x_pfdata.ps_thd_h;ps_data->ps_thd_l = stk3x1x_pfdata.ps_thd_l;printk("stk %s init successful \n", __func__);val = sensor_read_reg(client, STK_INT_REG);val &= ~INT_CTRL_PS_AND_LS;if (sensor->pdata->irq_enable)val |= PS_INT_ENABLE;elseval &= ~PS_INT_ENABLE;res = sensor_write_reg(client, STK_INT_REG, val);if (res) {dev_err(&client->dev, "%s:write INT_CTRL fail\n", __func__);return res;}return 0;EXIT_ERR:printk(KERN_ERR "stk init fail dev: %d\n", res);return res;}static int proximity_sensor_report_value(struct i2c_client *client)
{struct sensor_private_data *sensor =(struct sensor_private_data *) i2c_get_clientdata(client);	int result = 0;int value = 0;char buffer[2] = {0};	//printk("stk %s\n", __func__);if(sensor->ops->read_len < 2)	//sensor->ops->read_len = 1{printk("%s:lenth is error,len=%d\n",__func__,sensor->ops->read_len);return -1;}value = sensor_read_reg(client, STK_FLAG_REG);if(value < 0){printk("stk %s read STK_FLAG_REG, ret=%d\n", __func__, value);return value;}if(!(value & STK_FLG_PSDR_MASK))return 0;memset(buffer, 0, 2);buffer[0] = sensor->ops->read_reg;result = sensor_rx_data(client, buffer, sensor->ops->read_len);	if(result){printk("%s:line=%d,error\n",__func__,__LINE__);return result;}value = (buffer[0] << 8) | buffer[1];if(value < 0) {
#ifdef STK_DEBUG_PRINTFprintk("stk %s: value == %d return \n",__func__,value);
#endif				return result;}#ifdef STK_DEBUG_PRINTFprintk("stk %s: value == %d \n",__func__,value);
#endif		
#ifdef STK_TUNE0	if(ps_data->tune_zero_init_proc)stk_tune_zero_get_ps_data(client, value);elsestk_ps_tune_zero_func_fae(client, value);	
#endif	stk_ps_report(client, value);if (sensor->pdata->irq_enable && sensor->ops->int_status_reg) {value = sensor_read_reg(client, sensor->ops->int_status_reg);if (value & STK_FLAG_PSINT) {value &= ~STK_FLAG_PSINT;result = sensor_write_reg(client, sensor->ops->int_status_reg,value);if (result) {dev_err(&client->dev, "%s:write status reg error\n",__func__);return result;}}}return result;
}struct sensor_operate proximity_stk3x1x_ops = {.name				= "ps_stk3x1x",.type				= SENSOR_TYPE_PROXIMITY,	//sensor type and it should be correct.id_i2c				= PROXIMITY_ID_STK3X1X,		//i2c id number.read_reg			= STK_DATA1_PS_REG,			//read data.read_len			= 2,				//data length.id_reg				= SENSOR_UNKNOW_DATA,		//read device id from this register.id_data 			= SENSOR_UNKNOW_DATA,		//device id.precision			= 16,				//16 bits.ctrl_reg 			= STK_STATE_REG,			//enable or disable .int_status_reg 	= STK_FLAG_REG,			//intterupt status register.range				= {0,1},			//range.trig				= IRQF_TRIGGER_LOW | IRQF_ONESHOT | IRQF_SHARED,		.active				= proximity_sensor_active,	.init				= proximity_sensor_init,.report				= proximity_sensor_report_value,// int 	brightness[2];//backlight min_brightness max_brightness // int int_ctrl_reg;// int (*suspend)(struct i2c_client *client);// int (*resume)(struct i2c_client *client);// struct miscdevice *misc_dev;	
};/****************operate according to sensor chip:end************/
static int psensor_stk3x1x_probe(struct i2c_client *client,const struct i2c_device_id *devid)
{return sensor_register_device(client, NULL, devid, &proximity_stk3x1x_ops);
}static int psensor_stk3x1x_remove(struct i2c_client *client)
{return sensor_unregister_device(client, NULL, &proximity_stk3x1x_ops);
}static const struct i2c_device_id psensor_stk3x1x_id[] = {{"ps_stk3x1x", PROXIMITY_ID_STK3X1X},{}
};MODULE_DEVICE_TABLE(i2c, psensor_stk3x1x_id);static struct i2c_driver psensor_stk3x1x_driver = {.probe = psensor_stk3x1x_probe,.remove = psensor_stk3x1x_remove,.shutdown = sensor_shutdown,.id_table = psensor_stk3x1x_id,.driver = {.name = "psensor_stk3x1x",#ifdef CONFIG_PM.pm = &sensor_pm_ops,#endif},
};module_i2c_driver(psensor_stk3x1x_driver);MODULE_AUTHOR("Lex Hsieh <lex_hsieh@sensortek.com.tw>");
MODULE_DESCRIPTION("Sensortek stk3x1x Proximity Sensor driver");
MODULE_LICENSE("GPL");
MODULE_VERSION(DRIVER_VERSION);

3、stk3x1x.h

/*** $Id: stk3x1x.h** Copyright (C) 2012~2013 Lex Hsieh     <lex_hsieh@sensortek.com.tw> ** This file is subject to the terms and conditions of the GNU General Public* License.  See the file COPYING in the main directory of this archive for* more details.**/
#ifndef __STK3X1X_H__
#define __STK3X1X_H__/* platform data */
struct stk3x1x_platform_data
{uint8_t state_reg;uint8_t psctrl_reg;uint8_t alsctrl_reg;uint8_t ledctrl_reg;uint8_t	wait_reg;	uint16_t ps_thd_h;uint16_t ps_thd_l;//int int_pin;uint32_t transmittance;uint16_t stk_max_min_diff;uint16_t stk_lt_n_ct;uint16_t stk_ht_n_ct;	
};#endif // __STK3X1X_H__

4、在device 添加两个宏,编译hardware下相关的代码。 

三、打开settings下面的自动调光选项,驱动会轮询环境光的亮度。

 四、测试距离传感器。

 1、需要搞个小app打开这个服务,app的代码。

package com.giada.proximity;import androidx.appcompat.app.AppCompatActivity;import android.content.Context;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.Bundle;
import android.os.PowerManager;
import android.util.Log;public class MainActivity extends AppCompatActivity {private Sensor sensor;private SensorManager sm;private SensorEventListener listener;private String TAG = "TYPE_PROXIMITY";private PowerManager localPowerManager = null;// 电源管理对象private PowerManager.WakeLock localWakeLock = null;// 电源锁@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);sm=(SensorManager) getSystemService(Context.SENSOR_SERVICE);sensor=sm.getDefaultSensor(Sensor.TYPE_PROXIMITY);localPowerManager = (PowerManager) getSystemService(POWER_SERVICE);listener=new SensorEventListener() {@Overridepublic void onSensorChanged(SensorEvent event) {// TODO Auto-generated method stub//获得距离传感器中的数值,这里只有一个距离float[] values = event.values;Log.i(TAG,"onSensorChanged values[0]="+values[0]+" maxrange="+sensor.getMaximumRange());if (values[0] == 0.0) {// 贴近手机Log.d(TAG, "The object is near to sensor!");} else {// 远离手机Log.d(TAG, "The object is far to sensor!");}}@Overridepublic void onAccuracyChanged(Sensor sensor, int accuracy) {// TODO Auto-generated method stubLog.i(TAG,"onAccuracyChanged");}};sm.registerListener(listener, sensor, SensorManager.SENSOR_DELAY_NORMAL);}
}

2、app界面,打开就可以了

3、当有物体靠近和远离传感器的时候会产生中断,上层可以用getevent  -l 看到上报的信息,有ABS_DISTANCE的信息,这个就是距离传感器上报上来的信息。

4、adb logcat看上层的log,物体接近的时候onSensorChanged values[0]=0.0,物体远离的时候onSensorChanged values[0]=9.3,有一个问题9.0这个数在哪里设置呢?答案是hardware\rockchip\sensor\st\nusensors.h

 

 

五、参考文章

https://www.jb51.net/article/127408.htm (Android编程基于距离传感器控制手机屏幕熄灭的方法详解)

STK3311-X传感器调试_晓风凌殇的博客-CSDN博客_stk3311

Android——距离传感器(PROXIMITY)的应用_Li_peilun的博客-CSDN博客

  相关解决方案