From 844ba815a5c432ceafb31579b023f1822dcd4ea6 Mon Sep 17 00:00:00 2001 From: Wu Liangqing Date: Fri, 8 May 2020 09:26:55 +0800 Subject: [PATCH] intput: sensors: accel: add sc7a30 support Signed-off-by: Wu Liangqing Change-Id: I7727b6bf642b9f2f2a1ee53e7de283c4f818d7f9 --- drivers/input/sensors/accel/Kconfig | 6 + drivers/input/sensors/accel/Makefile | 1 + drivers/input/sensors/accel/sc7a30.c | 1206 ++++++++++++++++++++++++++ drivers/input/sensors/sensor-dev.c | 3 + include/linux/sensor-dev.h | 1 + 5 files changed, 1217 insertions(+) create mode 100644 drivers/input/sensors/accel/sc7a30.c diff --git a/drivers/input/sensors/accel/Kconfig b/drivers/input/sensors/accel/Kconfig index 248c2e8e3ba9..e328a2a11cec 100644 --- a/drivers/input/sensors/accel/Kconfig +++ b/drivers/input/sensors/accel/Kconfig @@ -71,6 +71,12 @@ config GS_MC3230 To have support for your specific gsesnor you will have to select the proper drivers which depend on this option. +config GS_SC7A30 + bool "gsensor sc7a30" + help + To have support for your specific gsesnor you will have to + select the proper drivers which depend on this option. + config GS_MXC6225 bool "gsensor mxc6225" help diff --git a/drivers/input/sensors/accel/Makefile b/drivers/input/sensors/accel/Makefile index 1628b8058131..b4fe3fb624c6 100644 --- a/drivers/input/sensors/accel/Makefile +++ b/drivers/input/sensors/accel/Makefile @@ -10,6 +10,7 @@ obj-$(CONFIG_GS_DMT10) += dmard10.o obj-$(CONFIG_GS_LSM303D) += lsm303d.o obj-$(CONFIG_GS_MC3230) += mc3230.o obj-$(CONFIG_MPU6880_ACC) += mpu6880_acc.o +obj-$(CONFIG_GS_SC7A30) += sc7a30.o obj-$(CONFIG_MPU6500_ACC) += mpu6500_acc.o obj-$(CONFIG_LSM330_ACC) += lsm330_acc.o obj-$(CONFIG_BMA2XX_ACC) += bma2xx.o diff --git a/drivers/input/sensors/accel/sc7a30.c b/drivers/input/sensors/accel/sc7a30.c new file mode 100644 index 000000000000..6bfe353a562c --- /dev/null +++ b/drivers/input/sensors/accel/sc7a30.c @@ -0,0 +1,1206 @@ +/* drivers/input/sensors/access/sc7a30.c + * + * Copyright (C) 2012-2015 ROCKCHIP. + * Author: luowei + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + * + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_HAS_EARLYSUSPEND +#include +#endif +#include +#include +#include + +#define SC7A30_ENABLE 1 +#define SC7A30_XOUT_L 0x28 +#define SC7A30_XOUT_H 0x29 +#define SC7A30_YOUT_L 0x2A +#define SC7A30_YOUT_H 0x2B +#define SC7A30_ZOUT_L 0x2C +#define SC7A30_ZOUT_H 0x2D +#define SC7A30_MODE 0x20 +#define SC7A30_MODE1 0x21 +#define SC7A30_MODE2 0x22 +#define SC7A30_MODE3 0x23 +#define SC7A30_BOOT 0x24 +#define SC7A30_STATUS 0x27 +#define SC7A30_50HZ 0x40 +#define SC7A30_100HZ 0x50 +#define SC7A30_200HZ 0x60 +#define SC7A30_400HZ 0x70 +#define SC7A30_RANGE 32768 + +#define CALIBRATION_NUM 20//40 +#define AXIS_X_Y_RANGE_LIMIT 200 +#define AXIS_X_Y_AVG_LIMIT 400 +#define AXIS_Z_RANGE 200 +#define AXIS_Z_DFT_G 1000 +#define GOTO_CALI 100 +#define FAILTO_CALI 101 +/* LIS3DH */ +#define SC7A30_PRECISION 12 +#define SC7A30_BOUNDARY (0x1 << (SC7A30_PRECISION - 1)) +#define SC7A30_GRAVITY_STEP (SC7A30_RANGE / SC7A30_BOUNDARY) + +#define SC7A30_COUNT_AVERAGE 2 + +#define CFG_GSENSOR_CALIBFILE "/data/data/com.actions.sensor.calib/files/gsensor_calib.txt" + +struct SC7A30_acc { + int x; + int y; + int z; +}; + +static struct SC7A30_acc offset; +static int calibrated; +static struct i2c_client *sc7a30_client; + +struct sensor_axis_average { + long x_average; + long y_average; + long z_average; + int count; +}; + +struct Cali_Data { + //mis p and n + unsigned char xpmis; //x axis positive mismatch to write + unsigned char xnmis; //x axis negtive mismatch to write + unsigned char ypmis; + unsigned char ynmis; + unsigned char zpmis; + unsigned char znmis; + //off p and n + unsigned char xpoff; //x axis positive offset to write + unsigned char xnoff; //x axis negtive offset to write + unsigned char ypoff; + unsigned char ynoff; + unsigned char zpoff; + unsigned char znoff; + //mid mis and off + unsigned char xmmis; //x axis middle mismatch to write + unsigned char ymmis; //y axis middle mismatch to write + unsigned char zmmis; //z axis middle mismatch to write + unsigned char xmoff; //x axis middle offset to write + unsigned char ymoff; //y axis middle offset to write + unsigned char zmoff; //z axis middle offset to write + //output p and n + signed int xpoutput; //x axis output of positive mismatch + signed int xnoutput; //x axis output of negtive mismatch + signed int ypoutput; + signed int ynoutput; + signed int zpoutput; + signed int znoutput; + //output + signed int xfoutput; //x axis the best or the temporary output + signed int yfoutput; //y axis the best or the temporary output + signed int zfoutput; //z axis the best or the temporary output + //final and temp flag + unsigned char xfinalf; //x axis final flag:if 1,calibration finished + unsigned char yfinalf; //y axis final flag:if 1,calibration finished + unsigned char zfinalf; //z axis final flag:if 1,calibration finished + unsigned char xtempf; //x axis temp flag:if 1,the step calibration finished + unsigned char ytempf; //y axis temp flag:if 1,the step calibration finished + unsigned char ztempf; //z axis temp flag:if 1,the step calibration finished + + unsigned char xaddmis; //x axis mismtach register address + unsigned char yaddmis; //y axis mismtach register address + unsigned char zaddmis; //z axis mismtach register address + unsigned char xaddoff; //x axis offset register address + unsigned char yaddoff; //y axis offset register address + unsigned char zaddoff; //z axis offset register address + + unsigned char (*MisDataSpaceConvert)(unsigned char continuous); //mismatch space convert function pointer + unsigned char (*OffDataSpaceConvert)(unsigned char continuous); //offset space convert function pointer +}; + +static struct sensor_axis_average axis_average; + +static unsigned char Read_Reg(unsigned char reg) +{ + char buffer[3] = {0}; + *buffer = reg; + sensor_rx_data(sc7a30_client, buffer, 1); + return buffer[0]; +} + +static void Read_Output_3axis(unsigned char *acc_buf) +{ + char buffer[3] = {0}; + int index = 0; + int ret = 0; + while(1){ + msleep(20); + *buffer = SC7A30_STATUS; + //ret = sensor_rx_data(sc7a30_client, buffer,1); + buffer[0] = Read_Reg(0x27); + if( (buffer[0] & 0x08) != 0 ) {break;} + index++; + if(index > 40)break; + } + //6 register data be read out + *buffer = SC7A30_XOUT_L; + ret = sensor_rx_data(sc7a30_client, buffer, 1); + acc_buf[0] = buffer[0]; + *buffer = SC7A30_XOUT_H; + ret = sensor_rx_data(sc7a30_client, buffer, 1); + acc_buf[1] = buffer[0]; + + *buffer = SC7A30_YOUT_L; + ret = sensor_rx_data(sc7a30_client, buffer, 1); + acc_buf[2] = buffer[0]; + *buffer = SC7A30_YOUT_H; + ret = sensor_rx_data(sc7a30_client, buffer, 1); + acc_buf[3] = buffer[0]; + + *buffer = SC7A30_ZOUT_L; + ret = sensor_rx_data(sc7a30_client, buffer,1); + acc_buf[4] = buffer[0]; + *buffer = SC7A30_ZOUT_H; + ret = sensor_rx_data(sc7a30_client, buffer, 1); + acc_buf[5] = buffer[0]; +} + +static void Write_Input(char addr, char thedata) +{ + int result; + result = sensor_write_reg(sc7a30_client, addr, thedata); +} + +static void tilt_3axis_mtp(signed int x, signed int y, signed int z) +{ + char buffer[6] = {0}; + unsigned char buffer0[6] = {0}; + unsigned char buffer1[6] = {0}; + signed char mtpread[3]={0}; + signed int xoutp, youtp, zoutp; + signed int xoutpt, youtpt, zoutpt; + signed char xtilt, ytilt, ztilt; + xoutp = youtp = zoutp = 0; + xoutpt = youtpt = zoutpt = 0; + xtilt = ytilt = ztilt = 0; + Read_Output_3axis(buffer0); + Read_Output_3axis(buffer1); + + xoutpt = ((signed int)((buffer1[1]<<8)|buffer1[0]))>>4; + youtpt = ((signed int)((buffer1[3]<<8)|buffer1[2]))>>4; + zoutpt = ((signed int)((buffer1[5]<<8)|buffer1[4]))>>4; + + xoutp = xoutpt-x*16; + youtp = youtpt-y*16; + zoutp = zoutpt-z*16; + + *buffer = 0x10; + sensor_rx_data(sc7a30_client, buffer, 1); + mtpread[0]=(signed char)buffer[0]; + + *buffer = 0x11; + sensor_rx_data(sc7a30_client, buffer, 1); + mtpread[1]=(signed char)buffer[0]; + + *buffer = 0x12; + sensor_rx_data(sc7a30_client, buffer, 1); + mtpread[2]=(signed char)buffer[0]; + + xtilt=(signed char)(xoutp/8)+ mtpread[0]; + ytilt=(signed char)(youtp/8)+ mtpread[1]; + ztilt=(signed char)(zoutp/8)+ mtpread[2]; + + Write_Input(0x10, xtilt); + Write_Input(0x11, ytilt); + Write_Input(0x12, ztilt); + +} + +static unsigned char forword_MisDataSpaceConvert(unsigned char continuous) +{ + if (continuous >= 128) + return continuous - 128; + else + return 255 - continuous; +} + +static unsigned char reverse_MisDataSpaceConvert(unsigned char continuous) +{ + if (continuous >= 128) + return continuous; + else + return 127 - continuous; +} + +static unsigned char reverse_OffDataSpaceConvert(unsigned char continuous) +{ + return 127 - continuous; +} + + +static unsigned char forword_OffDataSpaceConvert(unsigned char continuous) +{ + return continuous; +} + +static void check_output_set_finalflag(struct Cali_Data *pcalidata,unsigned char err) +{ + + if (abs(pcalidata->xfoutput) < err) { + //printk("line:%d Xcali finish!Final=%d\n",__LINE__,pcalidata->xfoutput); + pcalidata->xfinalf=1; + } + if (abs(pcalidata->yfoutput) < err) { + //printk("line:%d Xcali finish!Final=%d\n",__LINE__,pcalidata->yfoutput); + pcalidata->yfinalf=1; + } + if (abs(pcalidata->zfoutput) < err) { + //printk("line:%d Xcali finish!Final=%d\n",__LINE__,pcalidata->zfoutput); + pcalidata->zfinalf=1; + } + +} + +static void check_finalflag_set_tempflag(struct Cali_Data *pcalidata) +{ + if (pcalidata->xfinalf) { pcalidata->xtempf=1; } + if (pcalidata->yfinalf) { pcalidata->ytempf=1; } + if (pcalidata->zfinalf) { pcalidata->ztempf=1; } +} + +static unsigned char check_flag_is_return(struct Cali_Data *pcalidata) +{ + if ((pcalidata->xfinalf) && (pcalidata->yfinalf) && (pcalidata->zfinalf)) + { + //printk("line:%d Allcali finish!\n",__LINE__); + return 1;//xyz cali ok + } else + return 0; +} + +static void updata_midmis_address(struct Cali_Data *pcalidata) +{ + if(pcalidata->xtempf == 0) { + pcalidata->xmmis = (unsigned char)(((unsigned int)(pcalidata->xpmis) + (unsigned int)(pcalidata->xnmis))/2); + pcalidata->MisDataSpaceConvert = reverse_MisDataSpaceConvert; + Write_Input(pcalidata->xaddmis, (*(pcalidata->MisDataSpaceConvert))(pcalidata->xmmis)); + } + if(pcalidata->ytempf == 0) { + pcalidata->ymmis = (unsigned char)(((unsigned int)(pcalidata->ypmis) + (unsigned int)(pcalidata->ynmis))/2); + pcalidata->MisDataSpaceConvert = forword_MisDataSpaceConvert; + Write_Input(pcalidata->yaddmis, (*(pcalidata->MisDataSpaceConvert))(pcalidata->ymmis)); + } + if(pcalidata->ztempf == 0) { + pcalidata->zmmis = (unsigned char)(((unsigned int)(pcalidata->zpmis) + (unsigned int)(pcalidata->znmis))/2); + pcalidata->MisDataSpaceConvert = reverse_MisDataSpaceConvert; + Write_Input(pcalidata->zaddmis, (*(pcalidata->MisDataSpaceConvert))(pcalidata->zmmis)); + } +} + +static void updata_midoff_address(struct Cali_Data *pcalidata) +{ + if (pcalidata->xtempf == 0) { + pcalidata->xmoff = (unsigned char)(((unsigned int)(pcalidata->xpoff) + (unsigned int)(pcalidata->xnoff))/2); + pcalidata->OffDataSpaceConvert = reverse_OffDataSpaceConvert; + Write_Input(pcalidata->xaddoff, (*(pcalidata->OffDataSpaceConvert))(pcalidata->xmoff)); + } + if (pcalidata->ytempf == 0) { + pcalidata->ymoff = (unsigned char)(((unsigned int)(pcalidata->ypoff) + (unsigned int)(pcalidata->ynoff))/2); + pcalidata->OffDataSpaceConvert = forword_OffDataSpaceConvert; + Write_Input(pcalidata->yaddoff, (*(pcalidata->OffDataSpaceConvert))(pcalidata->ymoff)); + } + if (pcalidata->ztempf == 0) { + pcalidata->zmoff = (unsigned char)(((unsigned int)(pcalidata->zpoff) + (unsigned int)(pcalidata->znoff))/2); + pcalidata->OffDataSpaceConvert = forword_OffDataSpaceConvert; + Write_Input(pcalidata->zaddoff, (*(pcalidata->OffDataSpaceConvert))(pcalidata->zmoff)); + } +} + +static void updata_mmis_pnfoutput_set_tempflag( struct Cali_Data *pcalidata, + unsigned char *buf, + signed int xrel, + signed int yrel, + signed int zrel) +{ + + pcalidata->xfoutput = (signed int)((signed char)buf[1])-xrel; + pcalidata->yfoutput = (signed int)((signed char)buf[3])-yrel; + pcalidata->zfoutput =(signed int)((signed char)buf[5])-zrel; + + if (abs(pcalidata->xfoutput)<25)pcalidata->xtempf=1; + if (abs(pcalidata->yfoutput)<25)pcalidata->ytempf=1; + if (abs(pcalidata->zfoutput)<25)pcalidata->ztempf=1; + + if (pcalidata->xtempf == 0) + { + if (pcalidata->xfoutput>0) { + pcalidata->xpoutput = pcalidata->xfoutput; + pcalidata->xpmis = pcalidata->xmmis; + } + else { + pcalidata->xnoutput = pcalidata->xfoutput; + pcalidata->xnmis = pcalidata->xmmis; + } + } + + if (pcalidata->ytempf == 0) + { + if (pcalidata->yfoutput>0){ + pcalidata->ypoutput = pcalidata->yfoutput; + pcalidata->ypmis = pcalidata->ymmis; + } + else{ + pcalidata->ynoutput = pcalidata->yfoutput; + pcalidata->ynmis = pcalidata->ymmis; + } + } + + if(pcalidata->ztempf==0) + { + if(pcalidata->zfoutput>0){ + pcalidata->zpoutput = pcalidata->zfoutput; + pcalidata->zpmis = pcalidata->zmmis; + } + else{ + pcalidata->znoutput = pcalidata->zfoutput; + pcalidata->znmis = pcalidata->zmmis; + } + } +} + +static void updata_moff_pnfoutput_set_tempflag( struct Cali_Data *pcalidata, + unsigned char *buf, + signed int xrel, + signed int yrel, + signed int zrel) +{ + + pcalidata->xfoutput = (signed int)((signed char)buf[1])-xrel; + pcalidata->yfoutput = (signed int)((signed char)buf[3])-yrel; + pcalidata->zfoutput = (signed int)((signed char)buf[5])-zrel; + + if (abs(pcalidata->xfoutput)<3)pcalidata->xtempf = 1; + if (abs(pcalidata->yfoutput)<3)pcalidata->ytempf = 1; + if (abs(pcalidata->zfoutput)<3)pcalidata->ztempf = 1; + + if (pcalidata->xtempf == 0) + { + if(pcalidata->xfoutput>0){ + pcalidata->xpoutput = pcalidata->xfoutput; + pcalidata->xpoff = pcalidata->xmoff; + } else { + pcalidata->xnoutput = pcalidata->xfoutput; + pcalidata->xnoff = pcalidata->xmoff; + } + } + + if (pcalidata->ytempf == 0) + { + if(pcalidata->yfoutput>0){ + pcalidata->ypoutput = pcalidata->yfoutput; + pcalidata->ypoff = pcalidata->ymoff; + } else { + pcalidata->ynoutput = pcalidata->yfoutput; + pcalidata->ynoff = pcalidata->ymoff; + } + } + + if (pcalidata->ztempf == 0) + { + if (pcalidata->zfoutput > 0) { + pcalidata->zpoutput = pcalidata->zfoutput; + pcalidata->zpoff = pcalidata->zmoff; + } else { + pcalidata->znoutput = pcalidata->zfoutput; + pcalidata->znoff = pcalidata->zmoff; + } + } +} + +static int auto_calibration_instant(signed int x, signed int y, signed int z) +{ + + unsigned char count=0,cyclecount=0; + unsigned char acc_buf[6]; + + struct Cali_Data calidata={0}; + + calidata.xaddmis = 0x40; + calidata.yaddmis = 0x41; + calidata.zaddmis = 0x42; + calidata.xaddoff = 0x47; + calidata.yaddoff = 0x48; + calidata.zaddoff = 0x49; +#ifdef PRINT + printf("L%4d:xff=%4d,xtf=%4d,yff=%4d,ytf=%4d,zff=%4d,ztf=%4d\n\r",__LINE__, + (UINT)calidata.xfinalf,(UINT)calidata.xtempf, + (UINT)calidata.yfinalf,(UINT)calidata.ytempf, + (UINT)calidata.zfinalf,(UINT)calidata.ztempf + ); +#endif + + Read_Output_3axis(acc_buf); + calidata.xfoutput=(signed int)((signed char)acc_buf[1])-x; + calidata.yfoutput=(signed int)((signed char)acc_buf[3])-y; + calidata.zfoutput=(signed int)((signed char)acc_buf[5])-z; + check_output_set_finalflag(&calidata,2); + if(check_flag_is_return(&calidata)){ + printk("step1:=file=%s,line=%d\n",__FILE__,__LINE__); + return 1; + } +#ifdef PRINT + printf("L%4d:xff=%4d,xtf=%4d,yff=%4d,ytf=%4d,zff=%4d,ztf=%4d\n\r",__LINE__, + (UINT)calidata.xfinalf,(UINT)calidata.xtempf, + (UINT)calidata.yfinalf,(UINT)calidata.ytempf, + (UINT)calidata.zfinalf,(UINT)calidata.ztempf + ); +#endif + + if (calidata.xfinalf == 0) { + Write_Input(calidata.xaddoff, 0x3f);//cali mis under off=0x3f + Write_Input(0x10, 0); //tilt clear + calidata.MisDataSpaceConvert = reverse_MisDataSpaceConvert; + Write_Input(calidata.xaddmis, (*(calidata.MisDataSpaceConvert))(255)); // x mis to max + } + if (calidata.yfinalf == 0) { + Write_Input(calidata.yaddoff, 0x3f);//cali mis under off=0x3f + Write_Input(0x11, 0); //tilt clear + calidata.MisDataSpaceConvert = forword_MisDataSpaceConvert; + Write_Input(calidata.yaddmis, (*(calidata.MisDataSpaceConvert))(255)); // y mis to max + } + if (calidata.zfinalf == 0){ + Write_Input(calidata.zaddoff, 0x3f);//cali mis under off=0x3f + Write_Input(0x12, 0); //tilt clear + calidata.MisDataSpaceConvert = reverse_MisDataSpaceConvert; + Write_Input(calidata.zaddmis, (*(calidata.MisDataSpaceConvert))(255)); // z mis to max + } + + Read_Output_3axis(acc_buf); + calidata.xpoutput=calidata.xfoutput=(signed int)((signed char)acc_buf[1])-x; + calidata.ypoutput=calidata.yfoutput=(signed int)((signed char)acc_buf[3])-y; + calidata.zpoutput=calidata.zfoutput=(signed int)((signed char)acc_buf[5])-z; + printk("step 2 xnoutput = %d ynoutput = %d znoutput = %d \n",calidata.xnoutput,calidata.ynoutput,calidata.znoutput); + if ((calidata.xpoutput<-25) || (calidata.ypoutput<-25) || (calidata.zpoutput<-25)){ + printk("step2:=file=%s,line=%d\n",__FILE__,__LINE__); + sensor_write_reg(sc7a30_client,0x13,0x01);//allen + Write_Input(0x1e, 0x15); //保存校准寄存器的修改 + mdelay(300); + // Write_Input(0x1e, 0); + return 0; + } + + if (calidata.xfinalf == 0) { + calidata.MisDataSpaceConvert = reverse_MisDataSpaceConvert; + Write_Input(calidata.xaddmis, (*(calidata.MisDataSpaceConvert))(0)); // x mis to min + } + if (calidata.yfinalf == 0) { + calidata.MisDataSpaceConvert = forword_MisDataSpaceConvert; + Write_Input(calidata.yaddmis, (*(calidata.MisDataSpaceConvert))(0)); // y mis to min + } + if (calidata.zfinalf == 0) { + calidata.MisDataSpaceConvert = reverse_MisDataSpaceConvert; + Write_Input(calidata.zaddmis, (*(calidata.MisDataSpaceConvert))(0)); // z mis to min + } + Read_Output_3axis(acc_buf); + calidata.xnoutput=calidata.xfoutput=(signed int)((signed char)acc_buf[1])-x; + calidata.ynoutput=calidata.yfoutput=(signed int)((signed char)acc_buf[3])-y; + calidata.znoutput=calidata.zfoutput=(signed int)((signed char)acc_buf[5])-z; + printk("step 2 xnoutput = %d ynoutput = %d znoutput = %d \n",calidata.xnoutput,calidata.ynoutput,calidata.znoutput); + if ((calidata.xnoutput>25) || (calidata.ynoutput>25) || (calidata.znoutput>25)) { + printk("step2:=file=%s,line=%d\n",__FILE__,__LINE__); + sensor_write_reg(sc7a30_client,0x13,0x01); + Write_Input(0x1e, 0x15); + mdelay(300); + + return 0; + } + + if (abs(calidata.xpoutput)<=abs(calidata.xnoutput)) { + calidata.xfoutput=calidata.xpoutput; + calidata.xmmis=255; + } else { + calidata.xfoutput=calidata.xnoutput; + calidata.xmmis=0; + } + if (abs(calidata.ypoutput)<=abs(calidata.ynoutput)) { + calidata.yfoutput=calidata.ypoutput; + calidata.ymmis=255; + } else { + calidata.yfoutput=calidata.ynoutput; + calidata.ymmis=0; + } + if (abs(calidata.zpoutput)<=abs(calidata.znoutput)) { + calidata.zfoutput=calidata.zpoutput; + calidata.zmmis=255; + } else { + calidata.zfoutput=calidata.znoutput; + calidata.zmmis=0; + } + + if (calidata.xfinalf == 0) { + calidata.MisDataSpaceConvert = reverse_MisDataSpaceConvert; + Write_Input(calidata.xaddmis, (*(calidata.MisDataSpaceConvert))(calidata.xmmis)); + } + if (calidata.yfinalf == 0) { + calidata.MisDataSpaceConvert = forword_MisDataSpaceConvert; + Write_Input(calidata.yaddmis, (*(calidata.MisDataSpaceConvert))(calidata.ymmis)); + } + if (calidata.zfinalf == 0) { + calidata.MisDataSpaceConvert = reverse_MisDataSpaceConvert; + Write_Input(calidata.zaddmis, (*(calidata.MisDataSpaceConvert))(calidata.zmmis)); + } + check_output_set_finalflag(&calidata,2); + + if(abs(calidata.xfoutput)<25) calidata.xtempf=1; + if(abs(calidata.yfoutput)<25) calidata.ytempf=1; + if(abs(calidata.zfoutput)<25) calidata.ztempf=1; + + calidata.xpmis=calidata.ypmis=calidata.zpmis=255; + calidata.xnmis=calidata.ynmis=calidata.znmis=0; + check_finalflag_set_tempflag(&calidata); +#ifdef PRINT + printk("L%4d:xff=%4d,xtf=%4d,yff=%4d,ytf=%4d,zff=%4d,ztf=%4d\n\r",__LINE__, + (unsigned int)calidata.xfinalf,(unsigned int)calidata.xtempf, + (unsigned int)calidata.yfinalf,(unsigned int)calidata.ytempf, + (unsigned int)calidata.zfinalf,(unsigned int)calidata.ztempf + ); +#endif + cyclecount=0; + while(1){ + if (++cyclecount > 20) + break; + + if((calidata.xtempf)&&(calidata.ytempf)&&(calidata.ztempf))break; + updata_midmis_address(&calidata); + Read_Output_3axis(acc_buf); + calidata.xfoutput=(signed int)((signed char)acc_buf[1])-x; + calidata.yfoutput=(signed int)((signed char)acc_buf[3])-y; + calidata.zfoutput=(signed int)((signed char)acc_buf[5])-z; +#ifdef PRINT + printk("xp%4d=%4d,xm%4d=%4d,xn%4d=%4d, yp%4d=%4d,ym%4d=%4d,yn%4d=%4d, zp%4d=%4d,zm%4d=%4d,zn%4d=%4d\n\r", + calidata.xpoutput,(unsigned int)calidata.xpmis, + calidata.xfoutput,(unsigned int)calidata.xmmis, + calidata.xnoutput,(unsigned int)calidata.xnmis, + calidata.ypoutput,(unsigned int)calidata.ypmis, + calidata.yfoutput,(unsigned int)calidata.ymmis, + calidata.ynoutput,(unsigned int)calidata.ynmis, + calidata.zpoutput,(unsigned int)calidata.zpmis, + calidata.zfoutput,(unsigned int)calidata.zmmis, + calidata.znoutput,(unsigned int)calidata.znmis + ); +#endif + updata_mmis_pnfoutput_set_tempflag(&calidata,acc_buf,x,y,z); + check_output_set_finalflag(&calidata,2); + if(check_flag_is_return(&calidata))return 1; + } +#ifdef PRINT + printk("L%4d:xff=%4d,xtf=%4d,yff=%4d,ytf=%4d,zff=%4d,ztf=%4d\n\r",__LINE__, + (unsigned int)calidata.xfinalf,(unsigned int)calidata.xtempf, + (unsigned int)calidata.yfinalf,(unsigned int)calidata.ytempf, + (unsigned int)calidata.zfinalf,(unsigned int)calidata.ztempf + ); +#endif + + calidata.xtempf=calidata.ytempf=calidata.ztempf=1; + if((calidata.xmmis>0)&&(calidata.xmmis<255))calidata.xtempf=0; + if((calidata.ymmis>0)&&(calidata.ymmis<255))calidata.ytempf=0; + if((calidata.zmmis>0)&&(calidata.zmmis<255))calidata.ztempf=0; + calidata.xpmis=calidata.xnmis=calidata.xmmis; + calidata.ypmis=calidata.ynmis=calidata.ymmis; + calidata.zpmis=calidata.znmis=calidata.zmmis; + for(count = 0; count < 3; count++) + { + if(calidata.xtempf==0){ + calidata.xpmis = calidata.xmmis + count - 1; + if((calidata.xpmis>calidata.xmmis)&&(calidata.xpmis==128))calidata.xpmis = calidata.xmmis + count-1 + 1; + if((calidata.xpmiscalidata.ymmis)&&(calidata.ypmis==128))calidata.ypmis = calidata.ymmis + count-1 + 1; + if((calidata.ypmiscalidata.zmmis)&&(calidata.zpmis==128))calidata.zpmis = calidata.zmmis + count-1 + 1; + if((calidata.zpmis0 && calidata.xnoutput>0)||(calidata.xpoutput<0 && calidata.xnoutput<0)) { + calidata.xfinalf=1; + } + + if((calidata.ypoutput>0 && calidata.ynoutput>0)||(calidata.ypoutput<0 && calidata.ynoutput<0)){ + calidata.yfinalf=1; + } + + if((calidata.zpoutput>0 && calidata.znoutput>0)||(calidata.zpoutput<0 && calidata.znoutput<0)){ + calidata.zfinalf=1; + } + + check_finalflag_set_tempflag(&calidata); +#ifdef PRINT + printk("L%4d:xff=%4d,xtf=%4d,yff=%4d,ytf=%4d,zff=%4d,ztf=%4d\n\r",__LINE__, + (unsigned int)calidata.xfinalf,(unsigned int)calidata.xtempf, + (unsigned int)calidata.yfinalf,(unsigned int)calidata.ytempf, + (unsigned int)calidata.zfinalf,(unsigned int)calidata.ztempf + ); +#endif + cyclecount=0; + while(1){ + if(++cyclecount>20)break; + + if((calidata.xtempf)&&(calidata.ytempf)&&(calidata.ztempf))break; + updata_midoff_address(&calidata); + Read_Output_3axis(acc_buf); + calidata.xfoutput=(signed int)((signed char)acc_buf[1])-x; + calidata.yfoutput=(signed int)((signed char)acc_buf[3])-y; + calidata.zfoutput=(signed int)((signed char)acc_buf[5])-z; +#ifdef PRINT + printk("xp%4d=%4d,xm%4d=%4d,xn%4d=%4d, yp%4d=%4d,ym%4d=%4d,yn%4d=%4d, zp%4d=%4d,zm%4d=%4d,zn%4d=%4d\n\r", + calidata.xpoutput,(unsigned int)calidata.xpoff, + calidata.xfoutput,(unsigned int)calidata.xmoff, + calidata.xnoutput,(unsigned int)calidata.xnoff, + calidata.ypoutput,(unsigned int)calidata.ypoff, + calidata.yfoutput,(unsigned int)calidata.ymoff, + calidata.ynoutput,(unsigned int)calidata.ynoff, + calidata.zpoutput,(unsigned int)calidata.zpoff, + calidata.zfoutput,(unsigned int)calidata.zmoff, + calidata.znoutput,(unsigned int)calidata.znoff + ); +#endif + updata_moff_pnfoutput_set_tempflag(&calidata,acc_buf,x,y,z); + check_output_set_finalflag(&calidata,2); + if(check_flag_is_return(&calidata))return 1; + } +#ifdef PRINT + printk("L%4d:xff=%4d,xtf=%4d,yff=%4d,ytf=%4d,zff=%4d,ztf=%4d\n\r",__LINE__, + (unsigned int)calidata.xfinalf,(unsigned int)calidata.xtempf, + (unsigned int)calidata.yfinalf,(unsigned int)calidata.ytempf, + (unsigned int)calidata.zfinalf,(unsigned int)calidata.ztempf + ); +#endif + + return 1; +} + +static __maybe_unused int auto_calibration_instant_mtp(signed int x, signed int y, signed int z) +{ + unsigned char readbuf[3]={0}; + unsigned char buffer[6] = {0}; + + signed int xoutp,youtp,zoutp; + unsigned char xfinalf,yfinalf,zfinalf; + int reg_13 = 0; + + xoutp=youtp=zoutp=0; + xfinalf=yfinalf=zfinalf=0; + if (auto_calibration_instant(x,y,z) == 0) + { + printk("auto_calibration_instant ==0 \n"); + sensor_write_reg(sc7a30_client, 0x1e,0x05); + mdelay(100); + sensor_write_reg(sc7a30_client, 0x13,0x01); + + sensor_write_reg(sc7a30_client, 0x1e,0x15); + mdelay(300); + return 0; + } + + //msleep(20); + tilt_3axis_mtp(x,y,z); + Read_Output_3axis(buffer); + xoutp=(signed int)((signed char)buffer[1])-x; + youtp=(signed int)((signed char)buffer[3])-y; + zoutp=(signed int)((signed char)buffer[5])-z; + + if(abs(xoutp) < 2){xfinalf=1;} + if(abs(youtp) < 2){yfinalf=1;} + if(abs(zoutp) < 2){zfinalf=1;} + + //*tbuffer = 0x10; + //sensor_rx_data(sc7a30_client, tbuffer,1); + readbuf[0]= Read_Reg(0x10); + //*tbuffer = 0x40; + //sensor_rx_data(sc7a30_client, tbuffer,1); + readbuf[1]= Read_Reg(0x40); + //*tbuffer = 0x47; + //sensor_rx_data(sc7a30_client, tbuffer,1); + readbuf[2]= Read_Reg(0x47); + printk("L%4d:xtilt=%4d,xmis=%4d,xoff=%4d\n\r",__LINE__, + (unsigned int)readbuf[0], + (unsigned int)readbuf[1], + (unsigned int)readbuf[2] + ); + + readbuf[0]= Read_Reg(0x11); + readbuf[1]= Read_Reg(0x41); + readbuf[2]= Read_Reg(0x48); + printk("L%4d:ytilt=%4d,ymis=%4d,yoff=%4d\n\r",__LINE__, + (unsigned int)readbuf[0], + (unsigned int)readbuf[1], + (unsigned int)readbuf[2] + ); + readbuf[0]= Read_Reg(0x12); + readbuf[1]= Read_Reg(0x42); + readbuf[2]= Read_Reg(0x49); + printk("L%4d:ztilt=%4d,zmis=%4d,zoff=%4d\n\r",__LINE__, + (unsigned int)readbuf[0], + (unsigned int)readbuf[1], + (unsigned int)readbuf[2] + ); + + if(xfinalf && yfinalf && zfinalf) + { + sensor_write_reg(sc7a30_client,0x13,0x01); + reg_13 = sensor_read_reg(sc7a30_client,0x13); + printk("line %d reg_13 = %x\n",__LINE__,reg_13); + Write_Input(0x1e, 0x15); + mdelay(300); + printk(KERN_INFO "run calibration finished\n"); + + return 1; + } else { + sensor_write_reg(sc7a30_client,0x13,0x01);//allen MTP + reg_13 = sensor_read_reg(sc7a30_client,0x13); + printk("line %d reg_13 = %x\n",__LINE__,reg_13); + Write_Input(0x1e, 0x15); + mdelay(300); + + return 0; + } +} + +/****************operate according to sensor chip:start************/ + +static int 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; + + sensor->ops->ctrl_data = 0x07; + + if (enable) + { + status = SC7A30_ENABLE; //sc7a30 + sensor->ops->ctrl_data |= SC7A30_400HZ; + } else + status = ~SC7A30_ENABLE; //sc7a30 + + 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__); + + return result; +} + +static int sensor_init(struct i2c_client *client) +{ + struct sensor_private_data *sensor = + (struct sensor_private_data *) i2c_get_clientdata(client); + int result = 0; + + //mutex_lock(&(sensor->allen_mutex) );//allen + + printk("aaaaa %s:line=%d\n",__func__,__LINE__); + + result = sensor->ops->active(client,0,0); + if (result) + { + printk("%s:line=%d,error\n",__func__,__LINE__); + return result; + } + calibrated = 0; + sc7a30_client = client; + sensor->status_cur = SENSOR_OFF; + //sensor->time_of_cali =0;//allen + offset.x=offset.y=offset.z=0; + sensor_write_reg(client, SC7A30_BOOT, 0x80); + mdelay(20); + result = sensor_write_reg(client, SC7A30_MODE, 0x07); + + sensor_write_reg(client, SC7A30_MODE3, 0x88); +// result = sensor_write_reg(client, SC7A30_MODE, 0x77); + + //register_test(); + if(result) + { + printk("aaaaa %s:line=%d,error\n",__func__,__LINE__); + return result; + } + + if(sensor->pdata->irq_enable) //open interrupt + { + result = sensor_write_reg(client, SC7A30_MODE2, 0x10); + result = sensor_write_reg(client, 0x25, 0x02); + + if(result) + { + printk("%s:line=%d,error\n",__func__,__LINE__); + return result; + } + } + memset(&axis_average, 0, sizeof(struct sensor_axis_average)); + + return result; +} + +static int sensor_convert_data(struct i2c_client *client, char high_byte, char low_byte ,s16 off) +{ + s64 result; + result = (((s16)((high_byte << 8) + low_byte)) >>4); + result -= off; + result = result* SC7A30_GRAVITY_STEP; + + return (int)result; +} + +static int gsensor_report_value(struct i2c_client *client, struct sensor_axis *axis) +{ + struct sensor_private_data *sensor = + (struct sensor_private_data *) i2c_get_clientdata(client); + if (sensor->status_cur == SENSOR_ON) { + /* Report acceleration sensor information */ + input_report_abs(sensor->input_dev, ABS_X, axis->x); + input_report_abs(sensor->input_dev, ABS_Y, axis->y); + input_report_abs(sensor->input_dev, ABS_Z, axis->z); + input_sync(sensor->input_dev); + //printk("Gsensor x==%d y==%d z==%d\n",axis->x,axis->y,axis->z); + } + return 0; +} + +#define GSENSOR_MIN 2 +static int sensor_report_value(struct i2c_client *client) +{ + + struct sensor_private_data *sensor = + (struct sensor_private_data *) i2c_get_clientdata(client); + struct sensor_platform_data *pdata = sensor->pdata; + int ret = 0; + int x,y,z; + struct sensor_axis axis; + char value = 0; + //SC7A30_load_user_calibration(client); + //printk("---------------in--------------------\n"); +#if 0 + memset(buffer1, 0, 3); + memset(buffer2, 0, 3); + + *buffer1 = SC7A30_STATUS; + ret = sensor_rx_data(sc7a30_client, buffer1,1); + buffer1[0] &= 0x08; + if(!buffer1[0]) + return ret; + + *buffer1 = SC7A30_XOUT_L; + ret = sensor_rx_data(sc7a30_client, buffer1,1); + *buffer2 = SC7A30_XOUT_H; + ret = sensor_rx_data(client, buffer2,1); + if (ret < 0) + return ret; + x = sensor_convert_data(sensor->client, buffer2[0], buffer1[0],0); //buffer[1]:high bit + + *buffer1 = SC7A30_YOUT_L; + ret = sensor_rx_data(sc7a30_client, buffer1,1); + *buffer2 = SC7A30_YOUT_H; + ret = sensor_rx_data(client, buffer2,1); + if (ret < 0) + return ret; + y = sensor_convert_data(sensor->client, buffer2[0], buffer1[0],0); + *buffer1 = SC7A30_ZOUT_L; + ret = sensor_rx_data(sc7a30_client, buffer1,1); + *buffer2 = SC7A30_ZOUT_H; + ret = sensor_rx_data(client, buffer2,1); + if (ret < 0) + return ret; + z = sensor_convert_data(sensor->client, buffer2[0], buffer1[0],0); +#else + char buffer[6] = {0}; + memset(buffer, 0, 6); + + /* Data bytes from hardware xL, xH, yL, yH, zL, zH */ + *buffer = SC7A30_XOUT_L | 0x80; + ret = sensor_rx_data(sc7a30_client, buffer, 6); + if (ret < 0) { + printk("%s, %d, sensor rx data failed\n", __func__, __LINE__); + return ret; + } + + //this gsensor need 6 bytes buffer + x = sensor_convert_data(sensor->client, buffer[1], buffer[0], 0); //buffer[1]:high bit + y = sensor_convert_data(sensor->client, buffer[3], buffer[2], 0); + z = sensor_convert_data(sensor->client, buffer[5], buffer[4], 0); +#endif + + axis.x = (pdata->orientation[0])*x + (pdata->orientation[1])*y + (pdata->orientation[2])*z; + axis.y = (pdata->orientation[3])*x + (pdata->orientation[4])*y + (pdata->orientation[5])*z; + axis.z = (pdata->orientation[6])*x + (pdata->orientation[7])*y + (pdata->orientation[8])*z; + +#if 0 + axis_average.x_average += axis.x; + axis_average.y_average += axis.y; + axis_average.z_average += axis.z; + axis_average.count++; + + if(axis_average.count >= SC7A30_COUNT_AVERAGE) + { + axis.x = axis_average.x_average / axis_average.count; + axis.y = axis_average.y_average / axis_average.count; + axis.z = axis_average.z_average / axis_average.count; + + printk( "%s: axis = %d %d %d \n", __func__, axis.x, axis.y, axis.z); + + memset(&axis_average, 0, sizeof(struct sensor_axis_average)); + + //Report event only while value is changed to save some power + if((abs(sensor->axis.x - axis.x) > GSENSOR_MIN) || (abs(sensor->axis.y - axis.y) > GSENSOR_MIN) || (abs(sensor->axis.z - axis.z) > GSENSOR_MIN)) + { + gsensor_report_value(client, &axis); + + /* \BB\A5\B3\E2\B5ػ\BA\B4\E6\CA\FD\BE\DD. */ + mutex_lock(&(sensor->data_mutex) ); + sensor->axis = axis; + mutex_unlock(&(sensor->data_mutex) ); + } + } +#else + gsensor_report_value(client, &axis); + + /* \BB\A5\B3\E2\B5ػ\BA\B4\E6\CA\FD\BE\DD. */ + mutex_lock(&(sensor->data_mutex) ); + sensor->axis = axis; + mutex_unlock(&(sensor->data_mutex) ); +#endif + if((sensor->pdata->irq_enable)&& (sensor->ops->int_status_reg >= 0)) //read sensor intterupt status register + { + + value = sensor_read_reg(client, sensor->ops->int_status_reg); + printk("%s:sensor int status :0x%x\n",__func__,value); + } + return ret; +} + +struct sensor_operate gsensor_sc7a30_ops = { + .name = "gs_sc7a30", + .type = SENSOR_TYPE_ACCEL, //sensor type and it should be correct + .id_i2c = ACCEL_ID_SC7A30, //i2c id number + .read_reg = SC7A30_XOUT_H, //read data + .read_len = 1, //data length + .id_reg = SENSOR_UNKNOW_DATA, //read device id from this register + .id_data = SENSOR_UNKNOW_DATA, //device id + .precision = SC7A30_PRECISION, //12 bit + .ctrl_reg = SC7A30_MODE, //enable or disable SC7A30_MODE + .int_status_reg = SENSOR_UNKNOW_DATA, //intterupt status register + .range = {-SC7A30_RANGE,SC7A30_RANGE}, //range + .trig = IRQF_TRIGGER_HIGH|IRQF_ONESHOT, + .active = sensor_active, + .init = sensor_init, + .report = sensor_report_value, +}; + +/****************operate according to sensor chip:end************/ + +//function name should not be changed +static struct sensor_operate *gsensor_get_ops(void) +{ + return &gsensor_sc7a30_ops; +} + +static int __init gsensor_sc7a30_init(void) +{ + struct sensor_operate *ops = gsensor_get_ops(); + int result = 0; + int type = ops->type; + result = sensor_register_slave(type, NULL, NULL, gsensor_get_ops); + return result; +} + +static void __exit gsensor_sc7a30_exit(void) +{ + struct sensor_operate *ops = gsensor_get_ops(); + int type = ops->type; + sensor_unregister_slave(type, NULL, NULL, gsensor_get_ops); +} + +module_init(gsensor_sc7a30_init); +module_exit(gsensor_sc7a30_exit); diff --git a/drivers/input/sensors/sensor-dev.c b/drivers/input/sensors/sensor-dev.c index 823d8a46862a..22411ae98509 100644 --- a/drivers/input/sensors/sensor-dev.c +++ b/drivers/input/sensors/sensor-dev.c @@ -2016,6 +2016,7 @@ static const struct i2c_device_id sensor_id[] = { {"gs_mxc6655xa", ACCEL_ID_MXC6655XA}, {"gs_dmard10", ACCEL_ID_DMARD10}, {"gs_lsm303d", ACCEL_ID_LSM303D}, + {"gs_sc7a30",ACCEL_ID_SC7A30}, {"gs_mc3230", ACCEL_ID_MC3230}, {"mpu6880_acc", ACCEL_ID_MPU6880}, {"mpu6500_acc", ACCEL_ID_MPU6500}, @@ -2074,10 +2075,12 @@ static struct of_device_id sensor_dt_ids[] = { { .compatible = "gs_mma7660" }, { .compatible = "gs_mxc6225" }, { .compatible = "gs_mc3230" }, + { .compatible = "gs_sc7a30" }, { .compatible = "lsm330_acc" }, { .compatible = "bma2xx_acc" }, { .compatible = "gs_stk8baxx" }, { .compatible = "gs_mxc6655xa"}, + /*compass*/ { .compatible = "ak8975" }, { .compatible = "ak8963" }, diff --git a/include/linux/sensor-dev.h b/include/linux/sensor-dev.h index 5c7b589aa5cb..81074d69b61e 100644 --- a/include/linux/sensor-dev.h +++ b/include/linux/sensor-dev.h @@ -51,6 +51,7 @@ enum sensor_id { ACCEL_ID_MMA8450, ACCEL_ID_MMA845X, ACCEL_ID_MMA7660, + ACCEL_ID_SC7A30, ACCEL_ID_MPU6050, ACCEL_ID_MXC6225, ACCEL_ID_MXC6655XA,