Orange Pi5 kernel

Deprecated Linux kernel 5.10.110 for OrangePi 5/5B/5+ boards

3 Commits   0 Branches   0 Tags
/* drivers/input/sensors/access/sc7660.c
 *
 * Copyright (C) 2012-2015 ROCKCHIP.
 * Author: luowei <lw@rock-chips.com>
 *
 * 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 <linux/interrupt.h>
#include <linux/i2c.h>
#include <linux/slab.h>
#include <linux/irq.h>
#include <linux/miscdevice.h>
#include <linux/gpio.h>
#include <linux/uaccess.h>
#include <asm/atomic.h>
#include <linux/delay.h>
#include <linux/input.h>
#include <linux/workqueue.h>
#include <linux/freezer.h>
#ifdef CONFIG_HAS_EARLYSUSPEND
#include <linux/earlysuspend.h>
#endif
#include <linux/sensor-dev.h>

#define SC7660_ENABLE			1
#define SC7660_XOUT_L			0x28
#define SC7660_XOUT_H			0x29
#define SC7660_YOUT_L			0x2A
#define SC7660_YOUT_H			0x2B
#define SC7660_ZOUT_L			0x2C
#define SC7660_ZOUT_H			0x2D
#define SC7660_MODE			0x20
#define SC7660_MODE1			0x21
#define SC7660_MODE2			0x22
#define SC7660_MODE3			0x23
#define SC7660_BOOT			0x24
#define SC7660_STATUS			0x27
#define SC7660_50HZ			0x40
#define SC7660_100HZ			0x50
#define SC7660_200HZ			0x60
#define SC7660_400HZ			0x70
#define SC7660_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 SC7660_PRECISION        12
#define SC7660_BOUNDARY		(0x1 << (SC7660_PRECISION - 1))
#define SC7660_GRAVITY_STEP	(SC7660_RANGE / SC7660_BOUNDARY)

#define SC7660_COUNT_AVERAGE	2

//#define CFG_GSENSOR_CALIBFILE   "/data/data/com.actions.sensor.calib/files/gsensor_calib.txt"
/*noCreateAttr:the initial is 1-->no create attr. if created, change noCreateAttr to 0.*/
static int noCreateAttr = 1;




//static int sc7660_acc_get_data( int *xyz);

struct SC7660_acc{
    int    x;
    int    y;
    int    z;
} ;

static struct SC7660_acc offset;
//static int calibrated;
struct i2c_client *sc7660_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(sc7660_client, buffer,1);
	return buffer[0];
}


static signed char Read_Output(char reg)
{

	char buffer[3] = {0};
	signed char acc_buf[6];
        int index = 0;
        int ret   = 0;


         while(1)
	 {
			msleep(15);			
			*buffer = SC7660_STATUS;
			ret = sensor_rx_data(sc7660_client, buffer,1);

			if( (buffer[0] & 0x08) != 0 )
			{
				break;
			}
			//msleep(1);

                        index++;

                        if(index > 40)
                                break;		
	}

	*buffer = SC7660_XOUT_L;
	ret = sensor_rx_data(sc7660_client, buffer,1);
	*buffer = SC7660_XOUT_H;
	ret = sensor_rx_data(sc7660_client, buffer,1);
	acc_buf[1] = buffer[0];

	*buffer = SC7660_YOUT_L;
	ret = sensor_rx_data(sc7660_client, buffer,1);
	*buffer = SC7660_YOUT_H;
	ret = sensor_rx_data(sc7660_client, buffer,1);
	acc_buf[3] = buffer[0];

	*buffer = SC7660_ZOUT_L;
	ret = sensor_rx_data(sc7660_client, buffer,1);
	*buffer = SC7660_ZOUT_H;
	ret = sensor_rx_data(sc7660_client, buffer,1);
	acc_buf[5] = buffer[0];

	if(reg == 0x29)
	{
		return acc_buf[1];	
	}
	else if(reg == 0x2b)
	{
		return acc_buf[3];
	}
	else if(reg == 0x2d)
	{
		return acc_buf[5];
	}
	else
		return 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 = SC7660_STATUS;
			//ret = sensor_rx_data(sc7660_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 = SC7660_XOUT_L;
	ret = sensor_rx_data(sc7660_client, buffer,1);
	acc_buf[0] = buffer[0];
	*buffer = SC7660_XOUT_H;
	ret = sensor_rx_data(sc7660_client, buffer,1);
	acc_buf[1] = buffer[0];

	*buffer = SC7660_YOUT_L;
	ret = sensor_rx_data(sc7660_client, buffer,1);
	acc_buf[2] = buffer[0];
	*buffer = SC7660_YOUT_H;
	ret = sensor_rx_data(sc7660_client, buffer,1);
	acc_buf[3] = buffer[0];

	*buffer = SC7660_ZOUT_L;
	ret = sensor_rx_data(sc7660_client, buffer,1);
	acc_buf[4] = buffer[0];
	*buffer = SC7660_ZOUT_H;
	ret = sensor_rx_data(sc7660_client, buffer,1);
	acc_buf[5] = buffer[0];
}

static void Write_Input(char addr, char thedata)
{
	int result;
	result = sensor_write_reg(sc7660_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);
	//calculate the tilt with 12 ADC data
	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;
	//with relative value
	xoutp = xoutpt-x*16;
	youtp = youtpt-y*16;
	zoutp = zoutpt-z*16;


	//read out the tilt value in mtp to calculate the new
	*buffer = 0x10;
	sensor_rx_data(sc7660_client, buffer,1);
	mtpread[0]=(signed char)buffer[0];

	*buffer = 0x11;
	sensor_rx_data(sc7660_client, buffer,1);
	mtpread[1]=(signed char)buffer[0];

	*buffer = 0x12;
	sensor_rx_data(sc7660_client, buffer,1);
	mtpread[2]=(signed char)buffer[0];


//	mtpread[0]= (signed char)Read_One_Byte(0x3a, 0x10);
//	mtpread[1]= (signed char)Read_One_Byte(0x3a, 0x11);
//	mtpread[2]= (signed char)Read_One_Byte(0x3a, 0x12);

	//calculate the new tilt mtp value
	xtilt=(signed char)(xoutp/8)+ mtpread[0];
	ytilt=(signed char)(youtp/8)+ mtpread[1];
	ztilt=(signed char)(zoutp/8)+ mtpread[2];

	//write the new into mtp
	Write_Input(0x10,xtilt);
	Write_Input(0x11,ytilt);
	Write_Input(0x12,ztilt);

}

//正向
//255-0 map to 7f-0-80-ff
//
//255 map to 127(0x7f)
//254 map to 126(0x7e)
//.   map to .
//129 map to 001(0x01)
//128 map to 000(0x00)
//127 map to 128(0x80)
//126 map to 129(0x81)
//.   map to .
//001 map to 254(0xfe)
//000 map to 255(0xff)
static unsigned char forword_MisDataSpaceConvert(unsigned char continuous)
{
	if(continuous >= 128)
		return continuous - 128;
	else
		return 255 - continuous;
}

//反向
//255-0 map to ff-80-00-7f
//
//255 map to 255(0xff)
//254 map to 254(0xfe)
//.   map to .
//129 map to 129(0x81)
//128 map to 128(0x80)

//127 map to 0(0x00)
//126 map to 1(0x01)
//.   map to .
//001 map to 126(0x7e)
//000 map to 127(0x7f)
static unsigned char reverse_MisDataSpaceConvert(unsigned char continuous)
{
	if(continuous >= 128)
		return continuous;
	else
		return 127 - continuous;
}

//reverse
//7f-0 map to 0-7f
//

static unsigned char reverse_OffDataSpaceConvert(unsigned char continuous)
{
		return 127 - continuous;
}

//forword
//7f-0 map to 0-7f
//

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;
	}

}

//set the tempflag xtempf-ytempf-ztempf upto the finalflag
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;}
}

//return ornot,upto xfinalf-yfinalf-zfinalf
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;
}

//updata middle mismatch register with the new mismatch
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));
	}
}

//updata middle offset register with the new offset
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){
	//output 2 struct data
	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){
	//output 2 struct data
	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};

//===========================================================================
//===========================================================================
//step0=initialization
	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

//===========================================================================
//===========================================================================
//step1=if output is ok?
	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
	



	
//===========================================================================
//===========================================================================
//step2=can cali?
//max output reasonable?
//	calidata.zfinalf=1;
	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(sc7660_client,0x13,0x01);//allen
                Write_Input(0x1e, 0x15);  //保存校准寄存器的修改
                mdelay(300);
                Write_Input(0x1e, 0);
		return 0;
	}//if the max output is smaller than -25,then errs

	//min output reasonable?
	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(sc7660_client,0x13,0x01);//allen
                Write_Input(0x1e, 0x15);  //保存校准寄存器的修改
                mdelay(300);
                Write_Input(0x1e, 0);

		return 0;
	}

	//get the the smaller output,maybe the calibration finished
	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;
	}
	//write the mismatch of the smaller output into register
	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 the smaller output <25,the step3 mis is finished
	if(abs(calidata.xfoutput)<25) calidata.xtempf=1;
	if(abs(calidata.yfoutput)<25) calidata.ytempf=1;
	if(abs(calidata.zfoutput)<25) calidata.ztempf=1;
//can cali?
//===========================================================================
//===========================================================================
//===========================================================================
//step3=cali mis for zero in 25 LSB
	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 some errs happened,the cyclecount exceeded

		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
//cali mis for zero in 25 LSB
//===========================================================================


//===========================================================================
//===========================================================================
//step4=cali mis for rel and the most fit
	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.xpmis<calidata.xmmis)&&(calidata.xpmis==127))calidata.xpmis = calidata.xmmis + count-1 - 1;
			calidata.MisDataSpaceConvert = reverse_MisDataSpaceConvert;
			Write_Input(calidata.xaddmis, (*(calidata.MisDataSpaceConvert))(calidata.xpmis));
		}
		if(calidata.ytempf==0){
			calidata.ypmis = calidata.ymmis + count - 1;
			if((calidata.ypmis>calidata.ymmis)&&(calidata.ypmis==128))calidata.ypmis = calidata.ymmis + count-1 + 1;
			if((calidata.ypmis<calidata.ymmis)&&(calidata.ypmis==127))calidata.ypmis = calidata.ymmis + count-1 - 1;
			calidata.MisDataSpaceConvert = forword_MisDataSpaceConvert;
			Write_Input(calidata.yaddmis, (*(calidata.MisDataSpaceConvert))(calidata.ypmis));
		}
		if(calidata.ztempf==0){
			calidata.zpmis = calidata.zmmis + count - 1;
			if((calidata.zpmis>calidata.zmmis)&&(calidata.zpmis==128))calidata.zpmis = calidata.zmmis + count-1 + 1;
			if((calidata.zpmis<calidata.zmmis)&&(calidata.zpmis==127))calidata.zpmis = calidata.zmmis + count-1 - 1;
			calidata.MisDataSpaceConvert = reverse_MisDataSpaceConvert;
			Write_Input(calidata.zaddmis, (*(calidata.MisDataSpaceConvert))(calidata.zpmis));
		}
		Read_Output_3axis(acc_buf);
		if(abs((signed int)((signed char)acc_buf[1])-x)<abs(calidata.xfoutput)){
			calidata.xnmis=calidata.xpmis;
			calidata.xfoutput= (signed int)((signed char)acc_buf[1])-x;
		}
		if(abs((signed int)((signed char)acc_buf[3])-y)<abs(calidata.yfoutput)){
			calidata.ynmis=calidata.ypmis;
			calidata.yfoutput= (signed int)((signed char)acc_buf[3])-y;
		}
		if(abs((signed int)((signed char)acc_buf[5])-z)<abs(calidata.zfoutput)){
			calidata.znmis=calidata.zpmis;
			calidata.zfoutput= (signed int)((signed char)acc_buf[5])-z;
		}
		if(calidata.xtempf==0){
			calidata.MisDataSpaceConvert = reverse_MisDataSpaceConvert;
			Write_Input(calidata.xaddmis, (*(calidata.MisDataSpaceConvert))(calidata.xnmis));
		}
		if(calidata.ytempf==0){
			calidata.MisDataSpaceConvert = forword_MisDataSpaceConvert;
			Write_Input(calidata.yaddmis, (*(calidata.MisDataSpaceConvert))(calidata.ynmis));
		}
		if(calidata.ztempf==0){	
			calidata.MisDataSpaceConvert = reverse_MisDataSpaceConvert;
			Write_Input(calidata.zaddmis, (*(calidata.MisDataSpaceConvert))(calidata.znmis));
		}	
#ifdef PRINT
		printk("L%4d:xf=%4d,xmis=%4d,yf=%4d,ymis=%4d,zf=%4d,zmis=%4d\n\r",__LINE__,
					(signed int)((signed char)acc_buf[1])-x,(unsigned int)calidata.xpmis,
					(signed int)((signed char)acc_buf[3])-y,(unsigned int)calidata.ypmis,
					(signed int)((signed char)acc_buf[5])-z,(unsigned int)calidata.zpmis
					);
#endif

	}
	//Write_Input(AddMis, (*MisDataSpaceConvert)(FinaloutputMisConfiguration));
//===========================================================================
//===========================================================================
//step5=cali off for zero in 2 LSB
	calidata.xpoff=calidata.ypoff=calidata.zpoff=0x7f;
	calidata.xnoff=calidata.ynoff=calidata.znoff=0;
	calidata.xtempf=calidata.ytempf=calidata.ztempf=0;
#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
	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
	//offset max
	if(calidata.xtempf==0){
		calidata.OffDataSpaceConvert = reverse_OffDataSpaceConvert;
		Write_Input(calidata.xaddoff, (*(calidata.OffDataSpaceConvert))(calidata.xpoff)); // x off to max
	}
	if(calidata.ytempf==0){
		calidata.OffDataSpaceConvert = forword_OffDataSpaceConvert;
		Write_Input(calidata.yaddoff, (*(calidata.OffDataSpaceConvert))(calidata.xpoff)); // y off to max
	}
	if(calidata.ztempf==0){
		calidata.OffDataSpaceConvert = forword_OffDataSpaceConvert;
		Write_Input(calidata.zaddoff, (*(calidata.OffDataSpaceConvert))(calidata.xpoff)); // z off 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;
#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
	check_output_set_finalflag(&calidata,2);
#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
	//offset min
	if(calidata.xtempf==0){
		calidata.OffDataSpaceConvert = reverse_OffDataSpaceConvert;
		Write_Input(calidata.xaddoff, (*(calidata.OffDataSpaceConvert))(calidata.xnoff)); // x off to min
	}
	if(calidata.ytempf==0){
		calidata.OffDataSpaceConvert = forword_OffDataSpaceConvert;
		Write_Input(calidata.yaddoff, (*(calidata.OffDataSpaceConvert))(calidata.ynoff)); // y off to min
	}
	if(calidata.ztempf==0){
		calidata.OffDataSpaceConvert = forword_OffDataSpaceConvert;
		Write_Input(calidata.zaddoff, (*(calidata.OffDataSpaceConvert))(calidata.znoff)); // z off 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;
#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
	check_output_set_finalflag(&calidata,2);
#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
	if(abs(calidata.xpoutput)<=abs(calidata.xnoutput)){
		calidata.xfoutput=calidata.xpoutput;
		calidata.xmoff=calidata.xpoff;
	}
	else{
		calidata.xfoutput=calidata.xnoutput;
		calidata.xmoff=calidata.xnoff;
	}
	if(abs(calidata.ypoutput)<=abs(calidata.ynoutput)){
		calidata.yfoutput=calidata.ypoutput;
		calidata.ymoff=calidata.ypoff;
	}
	else{
		calidata.yfoutput=calidata.ynoutput;
		calidata.ymoff=calidata.ynoff;
	}
	if(abs(calidata.zpoutput)<=abs(calidata.znoutput)){
		calidata.zfoutput=calidata.zpoutput;
		calidata.zmoff=calidata.zpoff;
	}
	else{
		calidata.zfoutput=calidata.znoutput;
		calidata.zmoff=calidata.znoff;
	}
	if(calidata.xtempf==0){
		calidata.OffDataSpaceConvert = reverse_OffDataSpaceConvert;
		Write_Input(calidata.xaddoff, (*(calidata.OffDataSpaceConvert))(calidata.xmoff));
	}
	if(calidata.ytempf==0){
		calidata.OffDataSpaceConvert = forword_OffDataSpaceConvert;
		Write_Input(calidata.yaddoff, (*(calidata.OffDataSpaceConvert))(calidata.ymoff));
	}
	if(calidata.ztempf==0){
		calidata.OffDataSpaceConvert = forword_OffDataSpaceConvert;
		Write_Input(calidata.zaddoff, (*(calidata.OffDataSpaceConvert))(calidata.zmoff));
	}
	if((calidata.xpoutput>0 && 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
//cali mis for zero in 25 LSB
//===========================================================================

	return 1;
}

static int auto_calibration_instant_mtp(signed int x, signed int y, signed int z){
	unsigned char readbuf[3]={0};
	unsigned char buffer[6] = {0};
	//unsigned char tbuffer[6] = {0};
	signed int xoutp,youtp,zoutp;
	unsigned char xfinalf,yfinalf,zfinalf;
	char 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(sc7660_client, 0x1e,0x05);
           mdelay(100);
           sensor_write_reg(sc7660_client, 0x13,0x01);

           sensor_write_reg(sc7660_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(sc7660_client, tbuffer,1);
	readbuf[0]= Read_Reg(0x10);
	//*tbuffer = 0x40;
	//sensor_rx_data(sc7660_client, tbuffer,1);
	readbuf[1]= Read_Reg(0x40);
	//*tbuffer = 0x47;
	//sensor_rx_data(sc7660_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]
			);
	//*tbuffer = 0x11;
	//sensor_rx_data(sc7660_client, tbuffer,1);
	readbuf[0]= Read_Reg(0x11);
	//*tbuffer = 0x41;
	//sensor_rx_data(sc7660_client, tbuffer,1);
	readbuf[1]= Read_Reg(0x41);
	//*tbuffer = 0x48;
	//sensor_rx_data(sc7660_client, tbuffer,1);
	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]
			);

	//*tbuffer = 0x12;
	//sensor_rx_data(sc7660_client, tbuffer,1);
	readbuf[0]= Read_Reg(0x12);
	//*tbuffer = 0x42;
	//sensor_rx_data(sc7660_client, tbuffer,1);
	readbuf[1]= Read_Reg(0x42);
	//*tbuffer = 0x49;
	//sensor_rx_data(sc7660_client, tbuffer,1);
	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(sc7660_client,0x13,0x01);//allen MTP 
		reg_13 = sensor_read_reg(sc7660_client,0x13);
		printk("line %d  reg_13 = %x\n",__LINE__,reg_13);
		Write_Input(0x1e, 0x15);  //保存校准寄存器的修改
		mdelay(300);
		reg_13 = sensor_read_reg(sc7660_client,0x13);
		printk("line %d  reg_13 = %x\n",__LINE__,reg_13);
		Write_Input(0x1e, 0);

		printk(KERN_INFO "run calibration finished\n");

		return 1;//xyz cali ok
	}
	else
	{
		sensor_write_reg(sc7660_client,0x13,0x01);//allen MTP
                reg_13 = sensor_read_reg(sc7660_client,0x13);
                printk("line %d  reg_13 = %x\n",__LINE__,reg_13);
                Write_Input(0x1e, 0x15);  //保存校准寄存器的修改
                mdelay(300);
                reg_13 = sensor_read_reg(sc7660_client,0x13);
                printk("line %d  reg_13 = %x\n",__LINE__,reg_13);
                Write_Input(0x1e, 0);
		return 0;
       }
}





static ssize_t SC7660_3_axis_Calibration(struct device *dev,struct device_attribute *attr ,const char *buf, size_t count)
{
	//unsigned temp[3];
	//struct SC7660_acc	acc={0,0,-64};
	unsigned adj_ok = 0;

	Write_Input(0x1e, 0x05);   //为校准寄存器的修改开放权限
	Write_Input(0x20, 0x77);
    adj_ok = auto_calibration_instant_mtp(0,0,-64);
    if(adj_ok )
	{
		Write_Input(0x1e, 0x15);  //保存校准寄存器的修改
		mdelay(5);
		printk(KERN_INFO "run calibration finished\n");
	}
	else
		printk(KERN_INFO "run calibration not finished\n");
	mdelay(5);
	return 1;
}


static ssize_t SC7660_calibration_reset_store(struct device *dev,
        struct device_attribute *attr,
        const char *buf, size_t count)
{
	Read_Output(0x29);
        //printk(KERN_INFO "reset calibration finished\n");
	return count;
}

static ssize_t SC7660_calibration_value_show(struct device *dev,
        struct device_attribute *attr, char *buf)
{
    return sprintf(buf, "%d %d %d\n", offset.x,offset.y,offset.z);
}

static ssize_t SC7660_calibration_value_store(struct device *dev,
        struct device_attribute *attr,
        const char *buf, size_t count)
{
    int data[3];
    sscanf(buf, "%d %d %d", &data[0], &data[1], &data[2]);
    offset.x = data[0];
    offset.y = data[1];
    offset.z = data[2];
    printk(KERN_INFO "set calibration finished\n");
    return count;
}

static ssize_t SC7660_register_store(struct device *dev,
        struct device_attribute *attr,
        const char *buf, size_t count)
{
    int address, value;
    int result = 0;
    sscanf(buf, "0x%x=0x%x", &address, &value);

    result = sensor_write_reg(sc7660_client, address,value);

    if(result)
		printk("%s:fail to write sensor_register\n",__func__);

    return count;
}

static ssize_t SC7660_register_show(struct device *dev,
        struct device_attribute *attr, char *buf)
{
    size_t count = 0;
	char i;
	char buffer[3] = {0};
	i = 0x0f;
    *buffer = i;
    count = sensor_rx_data(sc7660_client, &buffer[0], 1);
    count += sprintf(buf, "0x%x: 0x%x\n", i, buffer[0]);
    for(i=0x10;i<0x5a;i++)
    {
		*buffer = i;

		sensor_rx_data(sc7660_client, buffer, 1);
		//sensor_rx_data(sc7660_client, &buffer[0], 1);
		count += sprintf(&buf[count],"0x%x: 0x%x\n", i, buffer[0]);
    }
    return count;
}

static ssize_t SC7660_value_show(struct device *dev,
        struct device_attribute *attr, char *buf)
{
    s16 x,y,z;
    int ret;
	char buffer1[3],buffer2[3] = {0};

	memset(buffer1, 0, 3);
	memset(buffer2, 0, 3);

	*buffer1 = SC7660_STATUS;
	ret = sensor_rx_data(sc7660_client, buffer1,1);
	buffer1[0] &= 0x08;
	if(!buffer1[0])
		return sprintf(buf, "SC7660 data is not ready!\n");

	*buffer1 = SC7660_XOUT_L;
	ret = sensor_rx_data(sc7660_client, buffer1,1);
    *buffer2 = SC7660_XOUT_H;
	ret = sensor_rx_data(sc7660_client, buffer2,1);
	x = (((s16)((buffer2[0] << 8) + buffer1[0])) >>4);

	*buffer1 = SC7660_YOUT_L;
	ret = sensor_rx_data(sc7660_client, buffer1,1);
	*buffer2 = SC7660_YOUT_H;
	ret = sensor_rx_data(sc7660_client, buffer2,1);
    y = (((s16)((buffer2[0] << 8) + buffer1[0])) >>4);

	*buffer1 = SC7660_ZOUT_L;
	ret = sensor_rx_data(sc7660_client, buffer1,1);
	*buffer2 = SC7660_ZOUT_H;
	ret = sensor_rx_data(sc7660_client, buffer2,1);
	z = (((s16)((buffer2[0] << 8) + buffer1[0])) >>4);

	if (ret < 0)
		return sprintf(buf, "SC7660_read_data failed!\n");
	else
		return sprintf(buf, "x=%4d(0x%4x),y=%4d(0x%4x),z=%4d(0x%4x)\n",x,x,y,y,z,z);

}

static DEVICE_ATTR(reg, 0664,
        SC7660_register_show, SC7660_register_store);

static DEVICE_ATTR(calibration_run, 0664, //calibration_run
        NULL, SC7660_3_axis_Calibration);
static DEVICE_ATTR(calibration_reset, 0664,
        NULL, SC7660_calibration_reset_store);
static DEVICE_ATTR(calibration_value,0664,
        SC7660_calibration_value_show,
        SC7660_calibration_value_store);
static DEVICE_ATTR(value, 0664,
        SC7660_value_show, NULL);
 
static struct attribute *SC7660_attributes[] = {
	&dev_attr_value.attr,
    &dev_attr_reg.attr,
    &dev_attr_calibration_run.attr,
    &dev_attr_calibration_reset.attr,
    &dev_attr_calibration_value.attr,
	NULL
};

static struct attribute_group SC7660_attribute_group = {
    .attrs = SC7660_attributes
};

/****************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;

	//register setting according to chip datasheet		
	if(enable)
	{
		status = SC7660_ENABLE;	//sc7660
		sensor->ops->ctrl_data |= SC7660_400HZ;
	}
	else
		status = ~SC7660_ENABLE;	//sc7660

	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);
	//sensor_write_reg(client, SC7660_BOOT, 0x80);
	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;
	int ret;
	unsigned char chip_id[3] = {0,0,0};
	//char reg_cali;

	//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;
	}
	sc7660_client = client;
	sensor->status_cur = SENSOR_OFF;
	//sensor->time_of_cali =0;//allen
	offset.x=offset.y=offset.z=0;

	*chip_id = 0x0f;
	ret = sensor_rx_data(client, chip_id,1);
	printk("sc7660_chip_id is %d",chip_id[0]);
	sensor_write_reg(client, SC7660_BOOT, 0x80);
	mdelay(20);
	sensor_write_reg(client, SC7660_MODE3, 0x88); 

	result = sensor_write_reg(client, SC7660_MODE, 0x07);

            //HR mode //sc7660

        //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, SC7660_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));

    if(noCreateAttr)
    {
        struct input_dev* pInputDev;
        pInputDev = input_allocate_device();
		if (!pInputDev) {
			dev_err(&client->dev,
				"Failed to allocate input device %s\n", sensor->input_dev->name);
			return -ENOMEM;
		}

		pInputDev->name = "sc7660";
		set_bit(EV_ABS, pInputDev->evbit);

		/* x-axis acceleration */
		input_set_abs_params(pInputDev, ABS_X, sensor->ops->range[0], sensor->ops->range[1], 0, 0);
		/* y-axis acceleration */
		input_set_abs_params(pInputDev, ABS_Y, sensor->ops->range[0], sensor->ops->range[1], 0, 0);
		/* z-axis acceleration */
		input_set_abs_params(pInputDev, ABS_Z, sensor->ops->range[0], sensor->ops->range[1], 0, 0);

		ret = input_register_device(pInputDev);
		if (ret) {
			dev_err(&client->dev,
				"Unable to register input device %s\n", pInputDev->name);
			return -ENOMEM;
		}

		DBG("Sys Attribute Register here %s is called for DA311.\n", __func__);
		ret = sysfs_create_group(&pInputDev->dev.kobj, &SC7660_attribute_group);
		if (ret) {
			DBG("sc7660 sysfs_create_group Error err=%d..", ret);
			ret = -EINVAL;
		}

		noCreateAttr = 0;
    }
	
	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;
	if (result < SC7660_BOUNDARY)
		result = result* SC7660_GRAVITY_STEP;
	else
		result = ~( ((~result & (0x7ffff>>(20-SC7660_PRECISION)) ) + 1)
				* SC7660_GRAVITY_STEP) + 1;

	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);

	/* Report acceleration sensor information */

	//8 in  -y -x -z    10 in x -y -z

	/* RK3326 platform board */
#if defined (CONFIG_BOARD_RK3326_AK47)
	input_report_abs(sensor->input_dev, ABS_X,axis->y);
	input_report_abs(sensor->input_dev, ABS_Y,axis->x);
	input_report_abs(sensor->input_dev, ABS_Z,-axis->z);
#elif defined (CONFIG_BOARD_RK3326_TH700)
	input_report_abs(sensor->input_dev, ABS_X,axis->y);
	input_report_abs(sensor->input_dev, ABS_Y,axis->x);
	input_report_abs(sensor->input_dev, ABS_Z,-axis->z);
#elif defined(CONFIG_BOARD_RK3326_TH863B_10)
	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);
#elif defined(CONFIG_BOARD_RK3326_TH863B_8)
	input_report_abs(sensor->input_dev, ABS_X,axis->y);
	input_report_abs(sensor->input_dev, ABS_Y,axis->x);
	input_report_abs(sensor->input_dev, ABS_Z,-axis->z);
#elif defined(CONFIG_BOARD_RK3326_TH863B_7)
	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);
#elif defined(CONFIG_BOARD_RK3326_TH863B_V31_7)
	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);
#elif defined(CONFIG_BOARD_RK3326_TH1021DN)
	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);
#elif defined(CONFIG_BOARD_RK3326_TH1021DN_V20)
	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);
#elif defined(CONFIG_BOARD_RK3326_TH7926_7)
	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);
#elif defined(CONFIG_BOARD_RK3326_TH7926_9)
	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);
#elif defined(CONFIG_BOARD_RK3326_MT1011)
	input_report_abs(sensor->input_dev, ABS_X,-axis->y);
	input_report_abs(sensor->input_dev, ABS_Y,-axis->x);
	input_report_abs(sensor->input_dev, ABS_Z,-axis->z);
#elif defined(CONFIG_BOARD_RK3326_M1011QR)
	input_report_abs(sensor->input_dev, ABS_X,-axis->y);
	input_report_abs(sensor->input_dev, ABS_Y,-axis->x);
	input_report_abs(sensor->input_dev, ABS_Z,-axis->z);

	/* RK3126C platform board */
#elif defined(CONFIG_BOARD_RK3126C_AK47)
	input_report_abs(sensor->input_dev, ABS_X,axis->y);
	input_report_abs(sensor->input_dev, ABS_Y,axis->x);
	input_report_abs(sensor->input_dev, ABS_Z,-axis->z);
#elif defined(CONFIG_BOARD_RK3126C_TH1021DN)
	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);
#elif defined(CONFIG_BOARD_RK3126C_TH863_7)
	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);
#elif defined(CONFIG_BOARD_RK3126C_TH863_8)
	input_report_abs(sensor->input_dev, ABS_X,axis->y);
	input_report_abs(sensor->input_dev, ABS_Y,axis->x);
	input_report_abs(sensor->input_dev, ABS_Z,-axis->z);
#elif defined(CONFIG_BOARD_RK3126C_TH98V)
	input_report_abs(sensor->input_dev, ABS_X,axis->y);
	input_report_abs(sensor->input_dev, ABS_Y,axis->x);
	input_report_abs(sensor->input_dev, ABS_Z,-axis->z);
#else
	input_report_abs(sensor->input_dev, ABS_X,-axis->y);
	input_report_abs(sensor->input_dev, ABS_Y,-axis->x);
	input_report_abs(sensor->input_dev, ABS_Z,-axis->z);
#endif

	input_sync(sensor->input_dev);
	DBG("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 buffer1[3],buffer2[3] = {0};
	char value = 0;
	//SC7660_load_user_calibration(client);
	memset(buffer1, 0, 3);
	memset(buffer2, 0, 3);

	*buffer1 = SC7660_STATUS;
	ret = sensor_rx_data(sc7660_client, buffer1,1);
	buffer1[0] &= 0x08;
	if(!buffer1[0])
		return ret;

	*buffer1 = SC7660_XOUT_L;
	ret = sensor_rx_data(sc7660_client, buffer1,1);  
        *buffer2 = SC7660_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 = SC7660_YOUT_L;
	ret = sensor_rx_data(sc7660_client, buffer1,1);
	*buffer2 = SC7660_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 = SC7660_ZOUT_L;
	ret = sensor_rx_data(sc7660_client, buffer1,1);
	*buffer2 = SC7660_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);

	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;

	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 >= SC7660_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;

		DBG( "%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) );
		}
	}

	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);
		DBG("%s:sensor int status :0x%x\n",__func__,value);
	}

	return ret;
}


static struct sensor_operate gsensor_sc7660_ops = {
	.name				= "gs_sc7660",
	.type				= SENSOR_TYPE_ACCEL,			//sensor type and it should be correct
	.id_i2c				= ACCEL_ID_SC7660,			//i2c id number
	.read_reg			= SC7660_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			= SC7660_PRECISION,			//12 bit
	.ctrl_reg 			= SC7660_MODE,			        //enable or disable SC7660_MODE
	.int_status_reg 		= SENSOR_UNKNOW_DATA,			//intterupt status register
	.range				= {-SC7660_RANGE,SC7660_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_sc7660_probe(struct i2c_client *client,
				const struct i2c_device_id *devid)
{
	return sensor_register_device(client, NULL, devid, &gsensor_sc7660_ops);
}

static int gsensor_sc7660_remove(struct i2c_client *client)
{
	return sensor_unregister_device(client, NULL, &gsensor_sc7660_ops);
}

static const struct i2c_device_id gsensor_sc7660_id[] = {
	{"gs_sc7660", ACCEL_ID_SC7660},
	{}
};

static struct i2c_driver gsensor_sc7660_driver = {
	.probe = gsensor_sc7660_probe,
	.remove = gsensor_sc7660_remove,
	.shutdown = sensor_shutdown,
	.id_table = gsensor_sc7660_id,
	.driver = {
		.name = "gsensor_sc7660",
	#ifdef CONFIG_PM
		.pm = &sensor_pm_ops,
	#endif
	},
};

module_i2c_driver(gsensor_sc7660_driver);

MODULE_AUTHOR("luowei <lw@rock-chips.com>");
MODULE_DESCRIPTION("sc7660 3-Axis accelerometer driver");
MODULE_LICENSE("GPL");