一、原理图,接口比较简单,就是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博客