/* 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; } static 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************/ static int gsensor_sc7a30_probe(struct i2c_client *client, const struct i2c_device_id *devid) { return sensor_register_device(client, NULL, devid, &gsensor_sc7a30_ops); } static int gsensor_sc7a30_remove(struct i2c_client *client) { return sensor_unregister_device(client, NULL, &gsensor_sc7a30_ops); } static const struct i2c_device_id gsensor_sc7a30_id[] = { {"gs_sc7a30", ACCEL_ID_SC7A30}, {} }; static struct i2c_driver gsensor_sc7a30_driver = { .probe = gsensor_sc7a30_probe, .remove = gsensor_sc7a30_remove, .shutdown = sensor_shutdown, .id_table = gsensor_sc7a30_id, .driver = { .name = "gsensor_sc7a30", #ifdef CONFIG_PM .pm = &sensor_pm_ops, #endif }, }; module_i2c_driver(gsensor_sc7a30_driver); MODULE_AUTHOR("luowei "); MODULE_DESCRIPTION("sc7a30 3-Axis accelerometer driver"); MODULE_LICENSE("GPL");