From e634183e788eed3a33b2ce359847faaa30b82c27 Mon Sep 17 00:00:00 2001 From: Wu Liangqing Date: Wed, 17 Jun 2020 17:39:49 +0800 Subject: [PATCH] driver: input: sensor: add sc7660 sc7a20 da223 Change-Id: I4206f328ed2245fdfe1f7d2955603b0bb5a5e0e3 Signed-off-by: Wu Liangqing --- drivers/input/sensors/accel/Kconfig | 18 + drivers/input/sensors/accel/Makefile | 4 + drivers/input/sensors/accel/da223_core.c | 1907 ++++++++++++++++++++++ drivers/input/sensors/accel/da223_core.h | 303 ++++ drivers/input/sensors/accel/da223_cust.c | 890 ++++++++++ drivers/input/sensors/accel/da223_cust.h | 44 + drivers/input/sensors/accel/sc7660.c | 1651 +++++++++++++++++++ drivers/input/sensors/accel/sc7a20.c | 1764 ++++++++++++++++++++ drivers/input/sensors/sensor-dev.c | 3 + include/linux/sensor-dev.h | 3 + 10 files changed, 6587 insertions(+) create mode 100644 drivers/input/sensors/accel/da223_core.c create mode 100644 drivers/input/sensors/accel/da223_core.h create mode 100644 drivers/input/sensors/accel/da223_cust.c create mode 100644 drivers/input/sensors/accel/da223_cust.h create mode 100644 drivers/input/sensors/accel/sc7660.c create mode 100644 drivers/input/sensors/accel/sc7a20.c diff --git a/drivers/input/sensors/accel/Kconfig b/drivers/input/sensors/accel/Kconfig index e328a2a11cec..9005db6bc996 100644 --- a/drivers/input/sensors/accel/Kconfig +++ b/drivers/input/sensors/accel/Kconfig @@ -71,6 +71,18 @@ 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_SC7660 + bool "gsensor sc7660" + help + To have support for your specific gsesnor you will have to + select the proper drivers which depend on this option. + +config GS_SC7A20 + bool "gsensor sc7a20" + help + 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 @@ -122,4 +134,10 @@ config BMA2XX_ACC To have support for your specific gsesnor you will have to select the proper drivers which depend on this option. +config GS_DA223 + bool "gsensor da223" + help + To have support for your specific gsesnor you will have to + select the proper drivers which depend on this option. + endif diff --git a/drivers/input/sensors/accel/Makefile b/drivers/input/sensors/accel/Makefile index b4fe3fb624c6..873a8a23ea74 100644 --- a/drivers/input/sensors/accel/Makefile +++ b/drivers/input/sensors/accel/Makefile @@ -10,8 +10,12 @@ 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_SC7660) += sc7660.o +obj-$(CONFIG_GS_SC7A20) += sc7a20.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 obj-$(CONFIG_STK8BAXX_ACC) += stk8baxx.o +obj-$(CONFIG_GS_DA223) += da223.o +da223-objs := da223_cust.o da223_core.o diff --git a/drivers/input/sensors/accel/da223_core.c b/drivers/input/sensors/accel/da223_core.c new file mode 100644 index 000000000000..b0e25eac9b5f --- /dev/null +++ b/drivers/input/sensors/accel/da223_core.c @@ -0,0 +1,1907 @@ +/* Core file for MiraMEMS 3-Axis Accelerometer's driver. + * + * mir3da_core.c - Linux kernel modules for 3-Axis Accelerometer + * + * Copyright (C) 2011-2013 MiraMEMS Sensing Technology Co., Ltd. + * + * 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 "da223_core.h" +#include "da223_cust.h" + +#define MIR3DA_REG_ADDR(REG) ((REG)&0xFF) + +#define MIR3DA_OFFSET_THRESHOLD 20 +#define PEAK_LVL 800 +#define STICK_LSB 2000 +#define AIX_HISTORY_SIZE 20 + +typedef struct reg_obj_s { + + short addr; + unsigned char mask; + unsigned char value; + +} reg_obj_t; + +struct gsensor_data_fmt_s { + + unsigned char msbw; + unsigned char lsbw; + unsigned char endian; /* 0: little endian; 1: big endian */ +}; + +struct gsensor_data_obj_s { + +#define MIR3DA_DATA_LEN 6 + reg_obj_t data_sect[MIR3DA_DATA_LEN]; + struct gsensor_data_fmt_s data_fmt; +}; + +struct gsensor_obj_s { + + char asic[10]; + + reg_obj_t chip_id; + reg_obj_t mod_id; + reg_obj_t soft_reset; + reg_obj_t power; + +#define MIR3DA_INIT_SECT_LEN 11 +#define MIR3DA_OFF_SECT_LEN MIR3DA_OFFSET_LEN +#define MIR3DA_ODR_SECT_LEN 3 + + reg_obj_t init_sect[MIR3DA_INIT_SECT_LEN]; + reg_obj_t offset_sect[MIR3DA_OFF_SECT_LEN]; + reg_obj_t odr_sect[MIR3DA_ODR_SECT_LEN]; + + struct gsensor_data_obj_s data; + + int (*calibrate)(MIR_HANDLE handle, int z_dir); + int (*auto_calibrate)(MIR_HANDLE handle, int xyz[3]); + int (*int_ops)(MIR_HANDLE handle, mir_int_ops_t *ops); + int (*get_reg_data)(MIR_HANDLE handle, char *buf); +}; + +struct gsensor_drv_s { + + struct general_op_s *method; + + struct gsensor_obj_s *obj; +}; + +typedef enum _asic_type{ + ASIC_NONE, + ASIC_2511, + ASIC_2512B, + ASIC_2513A, + ASIC_2516, +} asic_type; + +typedef enum _mems_type{ + MEMS_NONE, + MEMS_T4, + MEMS_T9, + MEMS_TV03, + MEMS_RTO3, + MEMS_GT2, + MEMS_GT3, +} mems_type; + +typedef enum _package_type{ + PACKAGE_NONE, + PACKAGE_2X2_12PIN, + PACKAGE_3X3_10PIN, + PACKAGE_3X3_16PIN, +} package_type; + +struct chip_info_s{ + unsigned char reg_value; + package_type package; + asic_type asic; + mems_type mems; +}; + +static struct chip_info_s gsensor_chip_info; + +static struct chip_info_s mir3da_chip_info_list[]= +{ + {0x00,PACKAGE_2X2_12PIN,ASIC_2512B,MEMS_TV03}, + {0x01,PACKAGE_2X2_12PIN,ASIC_2511,MEMS_T4}, + {0x02,PACKAGE_2X2_12PIN,ASIC_2511,MEMS_T9}, + {0x03,PACKAGE_3X3_10PIN,ASIC_2511,MEMS_T4}, + {0x04,PACKAGE_3X3_10PIN,ASIC_2511,MEMS_T9}, + {0x05,PACKAGE_3X3_10PIN,ASIC_2511,MEMS_T4}, + {0x06,PACKAGE_3X3_10PIN,ASIC_2511,MEMS_T9}, + {0x07,PACKAGE_3X3_16PIN,ASIC_2511,MEMS_T4}, + {0x08,PACKAGE_3X3_16PIN,ASIC_2511,MEMS_T9}, + {0x09,PACKAGE_2X2_12PIN,ASIC_2511,MEMS_T4}, + {0x0c,PACKAGE_2X2_12PIN,ASIC_2512B,MEMS_T9}, + {0x33,PACKAGE_2X2_12PIN,ASIC_2511,MEMS_T9}, + {0x34,PACKAGE_2X2_12PIN,ASIC_2511,MEMS_T9}, + {0x35,PACKAGE_2X2_12PIN,ASIC_2511,MEMS_T9}, +}; + +#define MIR3DA_NSA_INIT_SECTION { NSA_REG_G_RANGE, 0x03, 0x00 }, \ + { NSA_REG_POWERMODE_BW, 0xFF, 0x3e }, \ + { NSA_REG_ODR_AXIS_DISABLE, 0xFF, 0x09 }, \ + { NSA_REG_INTERRUPT_SETTINGS2, 0xFF, 0x00 }, \ + { NSA_REG_INTERRUPT_MAPPING2, 0xFF, 0x00 }, \ + { NSA_REG_ENGINEERING_MODE, 0xFF, 0x83 }, \ + { NSA_REG_ENGINEERING_MODE, 0xFF, 0x69 }, \ + { NSA_REG_ENGINEERING_MODE, 0xFF, 0xBD }, \ + { NSA_REG_INT_PIN_CONFIG, 0x0F, 0x05 }, \ + { -1, 0x00, 0x00 }, \ + { -1, 0x00, 0x00 }, \ + +#define MIR3DA_NSA_OFFSET_SECTION { NSA_REG_COARSE_OFFSET_TRIM_X, 0xFF, 0x00 }, \ + { NSA_REG_COARSE_OFFSET_TRIM_Y, 0xFF, 0x00 }, \ + { NSA_REG_COARSE_OFFSET_TRIM_Z, 0xFF, 0x00 }, \ + { NSA_REG_FINE_OFFSET_TRIM_X, 0xFF, 0x00 }, \ + { NSA_REG_FINE_OFFSET_TRIM_Y, 0xFF, 0x00 }, \ + { NSA_REG_FINE_OFFSET_TRIM_Z, 0xFF, 0x00 }, \ + { NSA_REG_CUSTOM_OFFSET_X, 0xFF, 0x00 }, \ + { NSA_REG_CUSTOM_OFFSET_Y, 0xFF, 0x00 }, \ + { NSA_REG_CUSTOM_OFFSET_Z, 0xFF, 0x00 }, \ + +#define MIR3DA_NSA_ODR_SECTION { NSA_REG_ODR_AXIS_DISABLE, 0x0F, 0x06 }, \ + { NSA_REG_ODR_AXIS_DISABLE, 0x0F, 0x07 }, \ + { NSA_REG_ODR_AXIS_DISABLE, 0x0F, 0x08 }, \ + + +#define MIR3DA_NSA_DATA_SECTION { { NSA_REG_ACC_X_LSB, 0xFF, 0x00 }, \ + { NSA_REG_ACC_X_MSB, 0xFF, 0x00 }, \ + { NSA_REG_ACC_Y_LSB, 0xFF, 0x00 }, \ + { NSA_REG_ACC_Y_MSB, 0xFF, 0x00 }, \ + { NSA_REG_ACC_Z_LSB, 0xFF, 0x00 }, \ + { NSA_REG_ACC_Z_MSB, 0xFF, 0x00 } }, \ + { 8, 4, 0 } + +static int NSA_NTO_calibrate(MIR_HANDLE handle, int z_dir); +static int NSA_NTO_auto_calibrate(MIR_HANDLE handle, int xyz[3]); +#if MIR3DA_AUTO_CALIBRATE +static int mir3da_auto_calibrate(MIR_HANDLE handle, int x, int y, int z); +#endif /* !MIR3DA_AUTO_CALIBRATE */ +static int NSA_interrupt_ops(MIR_HANDLE handle, mir_int_ops_t *ops); +static int NSA_get_reg_data(MIR_HANDLE handle, char *buf); + +#define MIR_NSA_NTO { "NSA_NTO", { NSA_REG_WHO_AM_I, 0xFF, 0x13 }, \ + { NSA_REG_FIFO_CTRL, 0xFF, 0x00 }, \ + { NSA_REG_SPI_I2C, 0x24, 0x24 }, \ + { NSA_REG_POWERMODE_BW, 0x80, 0x80 }, \ + { MIR3DA_NSA_INIT_SECTION }, \ + { MIR3DA_NSA_OFFSET_SECTION }, \ + { MIR3DA_NSA_ODR_SECTION }, \ + { MIR3DA_NSA_DATA_SECTION }, \ + NSA_NTO_calibrate , \ + NSA_NTO_auto_calibrate , \ + NSA_interrupt_ops , \ + NSA_get_reg_data , \ + } +/**************************************************************** COMMON ***************************************************************************/ +#define MIR3DA_GSENSOR_SCHEME MIR3DA_SUPPORT_CHIP_LIST + +#if YZ_CROSS_TALK_ENABLE +static short yzcross; +#endif + +/* this level can be modified while runtime through system attribute */ +int mir3da_Log_level = 0;//|DEBUG_ASSERT|DEBUG_MSG|DEBUG_FUNC|DEBUG_DATA; +static int gsensor_mod = -1; /* Initial value */ +static int gsensor_type = -1; /* Initial value */ +static struct gsensor_obj_s mir3da_gsensor[] = { MIR3DA_GSENSOR_SCHEME }; +struct gsensor_drv_s mir3da_gsensor_drv; +static int is_da217 = -1; + +#define MI_DATA(format, ...) if(DEBUG_DATA&mir3da_Log_level){mir3da_gsensor_drv.method->myprintf(MI_TAG format "\n", ## __VA_ARGS__);} +#define MI_MSG(format, ...) if(DEBUG_MSG&mir3da_Log_level){mir3da_gsensor_drv.method->myprintf(MI_TAG format "\n", ## __VA_ARGS__);} +#define MI_ERR(format, ...) if(DEBUG_ERR&mir3da_Log_level){mir3da_gsensor_drv.method->myprintf(MI_TAG format "\n", ## __VA_ARGS__);} +#define MI_FUN if(DEBUG_FUNC&mir3da_Log_level){mir3da_gsensor_drv.method->myprintf(MI_TAG "%s is called, line: %d\n", __FUNCTION__,__LINE__);} +#define MI_ASSERT(expr) \ + if (!(expr)) {\ + mir3da_gsensor_drv.method->myprintf("Assertion failed! %s,%d,%s,%s\n",\ + __FILE__, __LINE__, __func__, #expr);\ + } + +//#define abs(x) ({ long __x = (x); (__x < 0) ? -__x : __x; }) + +#if FILTER_AVERAGE_ENHANCE +typedef struct FilterAverageContextTag{ + int sample_l; + int sample_h; + int filter_param_l; + int filter_param_h; + int filter_threhold; + + int refN_l; + int refN_h; + +} FilterAverageContext; + +typedef struct mir3da_core_ctx_s{ + struct mir3da_filter_param_s filter_param; + FilterAverageContext tFac[3]; +} mir3da_core_ctx; + +static mir3da_core_ctx core_ctx; +#endif + +#if MIR3DA_SENS_TEMP_SOLUTION +static int bSensZoom = 0; +#endif + +#if MIR3DA_OFFSET_TEMP_SOLUTION +static int is_cali = 0; +static char bLoad = FILE_CHECKING; +static char readOffsetCnt=0; +static char readsubfileCnt=0; +static unsigned char original_offset[9]; +static int mir3da_write_offset_to_file(unsigned char* offset); +static int mir3da_read_offset_from_file(unsigned char* offset); +static void manual_load_cali_file(MIR_HANDLE handle); +#endif /* !MIR3DA_OFFSET_TEMP_SOLUTION */ + +#if MIR3DA_STK_TEMP_SOLUTION +static short aixHistort[AIX_HISTORY_SIZE*3] = {0}; +static short aixHistoryIndex = 0; +static char bxstk = 0; +static char bystk = 0; +static char bzstk = 0; + +static void addAixHistory(short x,short y,short z){ + aixHistort[aixHistoryIndex++] = x; + aixHistort[aixHistoryIndex++] = y; + aixHistort[aixHistoryIndex++] = z; + aixHistoryIndex = (aixHistoryIndex)%(AIX_HISTORY_SIZE*3); +} + +static char isXStick(void){ + int i=0,j=0,temp=0; + for (i = 0; i < AIX_HISTORY_SIZE; i++){ + if ((abs(aixHistort[i*3]) < STICK_LSB)&&(aixHistort[i*3] != 0)){ + break; + } + } + + for(j = 0; j< AIX_HISTORY_SIZE; j++){ + temp |= aixHistort[j*3]; + } + + if(0 == temp) + return 1; + + return i == AIX_HISTORY_SIZE; +} + +static char isYStick(void){ + int i=0,j=0,temp=0; + for (i = 0; i < AIX_HISTORY_SIZE; i++){ + if ((abs(aixHistort[i*3+1]) < STICK_LSB)&&(aixHistort[i*3+1] != 0)){ + break; + } + } + + for(j = 0; j < AIX_HISTORY_SIZE; j++){ + temp |= aixHistort[j*3+1]; + } + + if(0 == temp) + return 1; + + return i == AIX_HISTORY_SIZE; +} + +static char isZStick(void){ + int i=0,j=0,temp=0; + for (i = 0; i < AIX_HISTORY_SIZE; i++){ + if ((abs(aixHistort[i*3+2]) < STICK_LSB)&&(aixHistort[i*3+2] != 0)){ + break; + } + } + + for(j = 0; j < AIX_HISTORY_SIZE; j++){ + temp |= aixHistort[j*3+2]; + } + + if(0 == temp) + return 1; + + return i == AIX_HISTORY_SIZE; +} + +static int squareRoot(int val){ + int r = 0; + int shift; + + if (val < 0){ + return 0; + } + + for(shift=0;shift<32;shift+=2) + { + int x=0x40000000l >> shift; + if(x + r <= val) + { + val -= x + r; + r = (r >> 1) | x; + } else{ + r = r >> 1; + } + } + + return r; +} +#endif /* ! MIR3DA_STK_TEMP_SOLUTION */ + +#if FILTER_AVERAGE_ENHANCE +static short filter_average(short preAve, short sample, int paramN, int* refNum) +{ + #if FILTER_AVERAGE_EX + if( abs(sample-preAve) > PEAK_LVL && *refNum < 3 ){ + MI_DATA("Hit, sample = %d, preAve = %d, refN =%d\n", sample, preAve, *refNum); + sample = preAve; + (*refNum) ++; + }else{ + if (*refNum == 3){ + preAve = sample; + } + *refNum = 0; + } +#endif + + return preAve + (sample - preAve)/paramN; +} + +static int filter_average_enhance(FilterAverageContext* fac, short sample) +{ + if (fac == 0){ + MI_ERR("0 parameter fac"); + return 0; + } + + if (fac->filter_param_l == fac->filter_param_h){ + fac->sample_l = fac->sample_h = filter_average(fac->sample_l, sample, fac->filter_param_l, &fac->refN_l); + }else{ + fac->sample_l = filter_average(fac->sample_l, sample, fac->filter_param_l, &fac->refN_l); + fac->sample_h= filter_average(fac->sample_h, sample, fac->filter_param_h, &fac->refN_h); + if (abs(fac->sample_l- fac->sample_h) > fac->filter_threhold){ + MI_DATA("adjust, fac->sample_l = %d, fac->sample_h = %d\n", fac->sample_l, fac->sample_h); + fac->sample_h = fac->sample_l; + } + } + + return fac->sample_h; +} +#endif /* ! FILTER_AVERAGE_ENHANCE */ + +int mir3da_register_read(MIR_HANDLE handle, short addr, unsigned char *data) +{ + int res = 0; + + res = mir3da_gsensor_drv.method->smi.read(handle, MIR3DA_REG_ADDR(addr), data); + + return res; +} + +int mir3da_register_read_continuously(MIR_HANDLE handle, short addr, unsigned char count, unsigned char *data) +{ + int res = 0; + + res = (count==mir3da_gsensor_drv.method->smi.read_block(handle, MIR3DA_REG_ADDR(addr), count, data)) ? 0 : 1; + + return res; +} + +int mir3da_register_write(MIR_HANDLE handle, short addr, unsigned char data) +{ + int res = 0; + + res = mir3da_gsensor_drv.method->smi.write(handle, MIR3DA_REG_ADDR(addr), data); + + return res; +} + +int mir3da_register_mask_write(MIR_HANDLE handle, short addr, unsigned char mask, unsigned char data) +{ + int res = 0; + unsigned char tmp_data; + + res = mir3da_register_read(handle, addr, &tmp_data); + if(res) { + return res; + } + + tmp_data &= ~mask; + tmp_data |= data & mask; + res = mir3da_register_write(handle, addr, tmp_data); + + return res; +} + +static int mir3da_read_raw_data(MIR_HANDLE handle, short *x, short *y, short *z) +{ + unsigned char tmp_data[6] = {0}; + + if (mir3da_register_read_continuously(handle, mir3da_gsensor_drv.obj[gsensor_mod].data.data_sect[0].addr, 6, tmp_data) != 0) { + MI_ERR("i2c block read failed\n"); + return -1; + } + + *x = ((short)(tmp_data[1] << mir3da_gsensor_drv.obj[gsensor_mod].data.data_fmt.msbw | tmp_data[0]))>> (8-mir3da_gsensor_drv.obj[gsensor_mod].data.data_fmt.lsbw); + *y = ((short)(tmp_data[3] << mir3da_gsensor_drv.obj[gsensor_mod].data.data_fmt.msbw | tmp_data[2]))>> (8-mir3da_gsensor_drv.obj[gsensor_mod].data.data_fmt.lsbw); + *z = ((short)(tmp_data[5] << mir3da_gsensor_drv.obj[gsensor_mod].data.data_fmt.msbw | tmp_data[4]))>> (8-mir3da_gsensor_drv.obj[gsensor_mod].data.data_fmt.lsbw); + + MI_DATA("mir3da_raw: x=%d, y=%d, z=%d", *x, *y, *z); + +#if MIR3DA_SENS_TEMP_SOLUTION + if (bSensZoom == 1){ + *z = (*z )*5/4; + MI_DATA("SensZoom take effect, Zoomed Z = %d", *z); + } +#endif + +#if YZ_CROSS_TALK_ENABLE + if(yzcross) + *y=*y-(*z)*yzcross/100; +#endif + return 0; +} + +static int remap[8][4] = {{0,0,0,0}, + {0,1,0,1}, + {1,1,0,0}, + {1,0,0,1}, + {1,0,1,0}, + {0,0,1,1}, + {0,1,1,0}, + {1,1,1,1}}; + +int mir3da_direction_remap(short *x,short *y, short *z, int direction) +{ + short temp = 0; + + *x = *x - ((*x) * remap[direction][0]*2); + *y = *y - ((*y) * remap[direction][1]*2); + *z = *z - ((*z) * remap[direction][2]*2); + + if(remap[direction][3]) + { + temp = *x; + *x = *y; + *y = temp; + } + + if(remap[direction][2]) { + return -1; + } + + return 1; +} + +int mir3da_read_step(MIR_HANDLE handle, unsigned short *count){ + unsigned char step_temp[2]; + + mir3da_register_read_continuously(handle, NSA_REG_STEPS_MSB, 2, step_temp); + + *count = ((step_temp[0]<<8) + step_temp[1])/2; + return 0; +} + +int mir3da_read_data(MIR_HANDLE handle, short *x, short *y, short *z) +{ + int rst = 0; + +#if MIR3DA_SUPPORT_MULTI_LAYOUT + short temp =0; +#endif + +#if MIR3DA_OFFSET_TEMP_SOLUTION + if(is_cali){ + *x = *y = *z = 0; + return 0; + } + + manual_load_cali_file(handle); +#endif + + rst = mir3da_read_raw_data(handle, x, y, z); + if (rst != 0){ + MI_ERR("mir3da_read_raw_data failed, rst = %d", rst); + return rst; + } + +#if MIR3DA_AUTO_CALIBRATE +#if MIR3DA_SUPPORT_FAST_AUTO_CALI + if((mir3da_gsensor_drv.method->support_fast_auto_cali() &&(bLoad !=FILE_EXIST))||(bLoad ==FILE_NO_EXIST)) +#else + if(bLoad ==FILE_NO_EXIST) +#endif + { + mir3da_auto_calibrate(handle, *x, *y, *z); + } +#endif + +#if MIR3DA_STK_TEMP_SOLUTION + addAixHistory(*x,*y,*z); + + bxstk = isXStick(); + bystk = isYStick(); + bzstk = isZStick(); + + if((gsensor_chip_info.mems==MEMS_TV03 ||gsensor_chip_info.mems==MEMS_RTO3) + &&(gsensor_chip_info.reg_value != 0x4B) + &&(gsensor_chip_info.reg_value != 0x8C) + &&(gsensor_chip_info.reg_value != 0xCA)) + { + if ((bxstk + bystk+ bzstk) >0){ + if(resume_times<20){ + resume_times++; + MI_DATA("IN USE STK & resume!!\n"); + mir3da_chip_resume(handle); + } + }else + resume_times = 0; + } + else + { + if ((bxstk + bystk+ bzstk) < 2){ + if(bxstk) + *x = squareRoot(1024*1024 - (*y)*(*y) - (*z)*(*z)); + if(bystk) + *y = squareRoot(1024*1024 - (*x)*(*x) - (*z)*(*z)); + if(bzstk) + *z = squareRoot(1024*1024 - (*x)*(*x) - (*y)*(*y)); + }else{ + // MI_ERR( "CHIP ERR !MORE STK!\n"); + return 0; + } + } +#endif + + +#if FILTER_AVERAGE_ENHANCE + *x = filter_average_enhance(&core_ctx.tFac[0], *x); + *y = filter_average_enhance(&core_ctx.tFac[1], *y); + *z = filter_average_enhance(&core_ctx.tFac[2], *z); + MI_DATA("mir3da_filt: x=%d, y=%d, z=%d", *x, *y, *z); +#endif + + +#if MIR3DA_SUPPORT_MULTI_LAYOUT + if(gsensor_chip_info.package ==PACKAGE_2X2_12PIN ){ + *x =*x; + *y =*z; + *z =*z; + }else if(gsensor_chip_info.package ==PACKAGE_3X3_10PIN){ + temp = *x; + *x = *y; + *y = temp; + *z =*z; + }else if(gsensor_chip_info.package ==PACKAGE_3X3_16PIN){ + temp = -1*(*x); + *x = -1*(*y); + *y = temp; + *z =*z; + } +#endif + + if((gsensor_chip_info.reg_value == 0x4B) + ||(gsensor_chip_info.reg_value == 0x8C) + ||(gsensor_chip_info.reg_value == 0xCA) + ||(gsensor_chip_info.mems == MEMS_GT2)) + { + *z = 0; +#if MIR3DA_STK_TEMP_SOLUTION + bzstk = 1; +#endif + + } + + return 0; +} + +static int cycle_read_xyz(MIR_HANDLE handle, int* x, int* y, int* z, int ncycle) +{ + unsigned int j = 0; + short raw_x,raw_y,raw_z; + + *x = *y = *z = 0; + + for (j = 0; j < ncycle; j++) + { + raw_x = raw_y = raw_z = 0; + mir3da_read_raw_data (handle, &raw_x, &raw_y, &raw_z); + + (*x) += raw_x; + (*y) += raw_y; + (*z) += raw_z; + + mir3da_gsensor_drv.method->msdelay(5); + } + + (*x) /= ncycle; + (*y) /= ncycle; + (*z) /= ncycle; + + return 0; +} + +int mir3da_read_offset(MIR_HANDLE handle, unsigned char* offset) +{ + int i, res = 0; + + for(i=0;idata_save) + return 0; + + ret = mir3da_gsensor_drv.method->data_save(offset); + + MI_MSG("====sensor_sync_write, offset = 0x%x,0x%x,0x%x,0x%x,0x%x,0x%x,0x%x,0x%x,0x%x", offset[0],offset[1],offset[2],offset[3],offset[4],offset[5],offset[6],offset[7],offset[8]); + + return ret; +} + +static int mir3da_read_offset_from_file(unsigned char* offset) +{ + int ret = 0; + int i=0,sum=0; + + if(0 == mir3da_gsensor_drv.method->data_get) + return -1; + + ret = mir3da_gsensor_drv.method->data_get(offset); + + for(i=0;idata_check()){ + + readsubfileCnt++; + + if(!mir3da_read_offset_from_file(offset)) { + MI_ERR("========= FILE EXIST & WRITE OFFSET!"); + mir3da_write_offset(handle, offset); + bLoad = FILE_EXIST; + }else if(5 == readsubfileCnt){ + MI_ERR("========= NO FILE EXIST!"); + bLoad = FILE_NO_EXIST; + } + }else{ + MI_ERR("========= FILE CHECKING...."); + bLoad = FILE_CHECKING; + readsubfileCnt =0; + } + } + } +} + +static void mir3da_cali_off_to_lsb(int off, int *coarse, int coarse_step, int *fine, int fine_step) +{ + *coarse = off/coarse_step; + *fine = 100*(off-(*coarse)*coarse_step)/fine_step; + + MI_MSG("off = %d; delta_coarse = %d; delta_fine = %d", off, *coarse, *fine); +} + +#if MIR3DA_AUTO_CALIBRATE +static int NSA_once_calibrate(MIR_HANDLE handle, int coarse_step[3], int fine_step[3], int xyz[3]) +{ + int coarse[3] = {0}; + int coarse_delta[3] = {0}; + int fine[3] = {0}; + int fine_delta[3] = {0}; + int target[3] = {0}; + int i; + unsigned char offset_data[9] = {0}; + + if(mir3da_read_offset(handle, offset_data)){ + MI_ERR("Get old offset failed !"); + return -1; + } + coarse[0] = offset_data[0] & 0x3f; + coarse[1] = offset_data[1] & 0x3f; + coarse[2] = offset_data[2] & 0x3f; + fine[0] = (((int)offset_data[0] << 2) & 0x300)|offset_data[3]; + fine[1] = (((int)offset_data[1] << 2) & 0x300)|offset_data[4]; + fine[2] = (((int)offset_data[2] << 2) & 0x300)|offset_data[5]; + + MI_MSG("Old coarse_x = %d; coarse_y = %d; coarse_z = %d; fine_x = %d; fine_y = %d; fine_z = %d;", coarse[0], coarse[1], coarse[2], fine[0], fine[1], fine[2]); + + /* 0 means auto detect z direction assume z axis is verticle */ + if ((abs(target[0]) + abs(target[1]) + abs(target[2])) == 0){ + target[2] = (xyz[2] > 0) ? 1024 : (-1024); + } + + for(i = 0;i < 3; i++){ + coarse_step[i] *= coarse[i] >= 32 ? (-1) : 1; + mir3da_cali_off_to_lsb((xyz[i]-target[i]), &coarse_delta[i], coarse_step[i], &fine_delta[i], fine_step[i]); + + coarse[i] += coarse_delta[i]; + fine[i] += fine_delta[i]; + offset_data[i] = coarse[i]|((fine[i]>>2)&0xc0); + offset_data[i+3] = fine[i]&0xFF; + } + + if(mir3da_write_offset(handle, offset_data)){ + MI_ERR("Update offset failed !"); + return -1; + } + /* Discard unstable data after offset register changed */ + cycle_read_xyz(handle, &xyz[0], &xyz[1], &xyz[2], 5); + if(cycle_read_xyz(handle, &xyz[0], &xyz[1], &xyz[2], 10)){ + return -1; + } + MI_MSG("---calibrate_Done, x = %d, y = %d, z = %d, coarse_x = %d, coarse_y = %d, coarse_z = %d, fine_x = %d, fine_y = %d, fine_z = %d", xyz[0], xyz[1], xyz[2], coarse[0], coarse[1], coarse[2], fine[0], fine[1], fine[2]); + + return mir3da_write_offset_to_file(offset_data); +} +#endif /* !MIR3DA_AUTO_CALIBRATE */ + +static int NSA_calibrate(MIR_HANDLE handle, int coarse_step[3], int fine_step[3], int fine_max, int target[3]) +{ + int i = 0, j = 0; + unsigned char ncycle = 20; + unsigned char nLoop = 20; + unsigned char offset_data[9] = {0}; + unsigned char fine_ok_map = 0; + + int xyz[3] = {0}; + int coarse[3] = {0}; + int coarse_delta[3] = {0}; + int fine[3] = {0}; + int fine_delta[3] = {0}; + + if( (abs(target[0]) + abs(target[1]) + abs(target[2])) != 0 && (abs(target[0]) + abs(target[1]) + abs(target[2])) != 1024 ) { + MI_ERR("Invalid argument !"); + return -1; + } + + /* 0 means auto detect z direction assume z axis is verticle */ + if ((abs(target[0]) + abs(target[1]) + abs(target[2])) == 0){ + if(cycle_read_xyz(handle, &xyz[0], &xyz[1], &xyz[2], 5)){ + MI_ERR("check z direction failed\n"); + return -1; + } + target[2] = (xyz[2] > 0) ? 1024 : (-1024); + } + + MI_MSG("---Start Calibrate, trim target %d, %d, %d---\n", target[0], target[1], target[2]); + + // Stage1: Coarse tune once + MI_MSG("---Stage1, coarse tune---"); + // change to 16G mode + if(mir3da_register_mask_write(handle, NSA_REG_G_RANGE, 0x03, 3)){ + MI_ERR("i2c mask write failed !\n"); + return -1; + } + + /* reset coarse offset register */ + mir3da_write_offset(handle, offset_data); + /* Discard unstable data after offset register changed */ + cycle_read_xyz(handle, &xyz[0], &xyz[1], &xyz[2], 5); + + if( cycle_read_xyz(handle, &xyz[0], &xyz[1], &xyz[2], ncycle) ){ + goto EXIT_16G_MOD; + } + + for(i = 0; i < 3; i++){ + /* check rule */ + xyz[i] *= 8; + + coarse[i] = ((xyz[i]-target[i]) > 0) ? 0 : 32; + + MI_MSG("xyz[%d] = %d, coarse[%d] = 0x%x", i, xyz[i], i, coarse[i]); + + coarse_step[i] *= coarse[i] >= 32 ? (-1) : 1; + mir3da_cali_off_to_lsb((xyz[i]-target[i]), &coarse_delta[i], coarse_step[i], &fine_delta[i], fine_step[i]); + + coarse[i] += coarse_delta[i]; + fine[i] += fine_delta[i]; + mir3da_register_mask_write(handle, NSA_REG_COARSE_OFFSET_TRIM_X+i, 0x3f, (unsigned char)coarse[i]); + } + + /* Discard unstable data after offset register changed */ + cycle_read_xyz(handle, &xyz[0], &xyz[1], &xyz[2], 5); + if(cycle_read_xyz(handle, &xyz[0], &xyz[1], &xyz[2], 5)){ + return -1; + } + for(i = 0; i < 3; i++){ + fine[i] += (xyz[i] > 0) ? 0 : fine_max; + mir3da_register_write(handle, NSA_REG_FINE_OFFSET_TRIM_X+i, (unsigned char)(fine[i]&0xff)); + mir3da_register_mask_write(handle, NSA_REG_COARSE_OFFSET_TRIM_X+i, 0xc0, (unsigned char)(0xc0&(fine[i]>>2))); + } + +EXIT_16G_MOD: + // change back to 2G mode + if(mir3da_register_mask_write(handle, NSA_REG_G_RANGE, 0x03, 0)){ + MI_ERR("i2c mask write failed !\n"); + return -1; + } + /* Discard unstable data after offset register changed */ + cycle_read_xyz(handle, &xyz[0], &xyz[1], &xyz[2], 5); + if(cycle_read_xyz(handle, &xyz[0], &xyz[1], &xyz[2], ncycle)){ + return -1; + } + MI_MSG("---Stage1, coarse tune done: x = %d, y = %d, z = %d, coarse_x = %d, coarse_y = %d, coarse_z = %d, fine_x = %d, fine_y = %d, fine_z = %d", xyz[0], xyz[1], xyz[2], coarse[0], coarse[1], coarse[2], fine[0], fine[1], fine[2]); + + // Stage2: Fine tune + MI_MSG("---Stage2, Fine tune---"); + for (i = 0; i < nLoop; i++){ + + if( 0x07==(fine_ok_map & 0x07) ){ + break; + } + /* Discard unstable data after offset register changed */ + cycle_read_xyz(handle, &xyz[0], &xyz[1], &xyz[2], 5); + MI_MSG("---Stage2, Fine loop %d", i); + if(cycle_read_xyz(handle, &xyz[0], &xyz[1], &xyz[2], ncycle)){ + return -1; + } + + for(j = 0; j < 3; j++){ + MI_MSG("xyz[%d] = %d, caorse[%d] = 0x%x, fine[%d] = 0x%x", j, xyz[j], j, coarse[j], j, fine[j]); + if( abs(xyz[j]-target[j]) < MIR3DA_OFFSET_THRESHOLD ){ + fine_ok_map |= (1<>2)&0xc0); + offset_data[j+3] = fine[j]; + continue; + } + mir3da_cali_off_to_lsb((xyz[j]-target[j]), &coarse_delta[j], coarse_step[j], &fine_delta[j], fine_step[j]); + + coarse[j] += coarse_delta[j]; + fine[j] += fine_delta[j]; + mir3da_register_write(handle, NSA_REG_FINE_OFFSET_TRIM_X+j, (unsigned char)(fine[j]&0xff)); + mir3da_register_mask_write(handle, NSA_REG_COARSE_OFFSET_TRIM_X+j, 0xFF, (unsigned char)(0xc0&(fine[j]>>2))|coarse[j]); + } + } + MI_MSG("---Stage2, Fine tune done: x = %d, y = %d, z = %d, coarse_x = %d, coarse_y = %d, coarse_z = %d, fine_x = %d, fine_y = %d, fine_z = %d", xyz[0], xyz[1], xyz[2], coarse[0], coarse[1], coarse[2], fine[0], fine[1], fine[2]); + + if( 0x07==(fine_ok_map & 0x07) ){ + goto SUCCESS_EXIT; + } +#if MIR3DA_STK_TEMP_SOLUTION + if( 0x03==(fine_ok_map & 0x07) ){ + goto SUCCESS_EXIT; + } +#endif + + MI_MSG("---calibrate Failed !---"); + return -1; + +SUCCESS_EXIT: + MI_MSG("---calibrate OK !---"); + return mir3da_write_offset_to_file(offset_data); +} + +static int NSA_NTO_cali_step_calc(MIR_HANDLE handle, int coarse[3], int x100_fine[3], int x100_cust[3]) +{ + int i; + unsigned int total_gain[3] = {0}; + unsigned char coarse_gain = 0; + unsigned char fine_gain[3] = {0}; + unsigned int const coarse_gain_map[] = {1000, 1125, 1250, 1375, 500, 625, 750, 875}; /* *1000 */ + unsigned char const fine_dig_gain_map[] = {1, 2, 4, 8}; + + if(mir3da_register_read_continuously(handle, NSA_REG_SENSITIVITY_TRIM_X, 3, fine_gain) != 0){ + MI_ERR("i2c block read failed\n"); + return -1; + } + + if(mir3da_register_read(handle, NSA_REG_SENS_COARSE_TRIM, &coarse_gain) != 0){ + MI_ERR("i2c block read failed\n"); + return -1; + } + + for(i = 0;i < 3;i++) { + // *100*1000 + total_gain[i] = ((1000 + (fine_gain[i]&0x1F)*1000/32)/15) * fine_dig_gain_map[((fine_gain[i]>>5)&0x03)] * coarse_gain_map[coarse_gain&0x07]; + coarse[i] = (int)(total_gain[i] * 500 / 100000); + x100_fine[i] = (int)(total_gain[i] * 293 / 100000); + x100_cust[i] = (int)(total_gain[i] * 390 / 100000); + } + MI_MSG("coarse_step_x = %d, coarse_step_y = %d, coarse_step_z = %d\n", coarse[0], coarse[1], coarse[2]); + MI_MSG("fine_step_x = %d, fine_step_y = %d, fine_step_z = %d\n", x100_fine[0], x100_fine[1], x100_fine[2]); + MI_MSG("custom_step_x = %d, custom_step_y = %d, custom_step_z = %d\n", x100_cust[0], x100_cust[1], x100_cust[2]); + + return 0; +} +#endif /* !MIR3DA_OFFSET_TEMP_SOLUTION */ + +static int NSA_NTO_calibrate(MIR_HANDLE handle, int z_dir) +{ + int result = 0; + +#if MIR3DA_OFFSET_TEMP_SOLUTION + int coarse_step[3] = {0}; + int fine_step[3] = {0}; + int custom_step[3] = {0}; + int target[3] = {0}; + + unsigned char swap_plarity_old = 0; + + /* compute step */ + if( NSA_NTO_cali_step_calc(handle, coarse_step, fine_step, custom_step) ) { + MI_ERR("Compute step failed !"); + return -1; + } + target[2] = z_dir*1024; + + // save swap/plarity old setting + if(mir3da_register_read(handle, NSA_REG_SWAP_POLARITY, &swap_plarity_old)){ + MI_ERR("Get SWAP/PLARITY setting failed !"); + return -1; + } + + if((gsensor_chip_info.asic == ASIC_2512B)||(gsensor_chip_info.asic == ASIC_2513A)||(gsensor_chip_info.asic == ASIC_2516)){ + coarse_step[2] = 2 *coarse_step[2]; + target[2] = ((swap_plarity_old & (1<<1)) == 0) ? (-target[2]) :target[2]; + if(mir3da_register_mask_write(handle, NSA_REG_SWAP_POLARITY, 0x0F, 0x0E)){ + MI_ERR("Set Plarity failed !"); + return -1; + } + }else if(gsensor_chip_info.asic == ASIC_2511){ + target[2] = ((swap_plarity_old & (1<<1)) != 0) ? (-target[2]) :target[2]; + if(mir3da_register_mask_write(handle, NSA_REG_SWAP_POLARITY, 0x0F, 0x00)){ + MI_ERR("Set Plarity failed !"); + return -1; + } + } + + result=NSA_calibrate(handle, coarse_step, fine_step, 0x3ff, target); + + // Restore swap/plarity setting + if(mir3da_register_mask_write(handle, NSA_REG_SWAP_POLARITY, 0x0F, swap_plarity_old&0x0F)){ + MI_ERR("Restore SWAP/PLARITY setting failed !"); + return -1; + } +#endif /* !MIR3DA_OFFSET_TEMP_SOLUTION */ + return result; +} + +static int NSA_NTO_auto_calibrate(MIR_HANDLE handle, int xyz[3]) +{ + int result = 0; + +#if MIR3DA_AUTO_CALIBRATE + int coarse_step[3]; + int fine_step[3]; + int custom_step[3] = {0}; + unsigned char swap_plarity_old = 0; + int temp=0; + + /* compute step */ + if( NSA_NTO_cali_step_calc(handle, coarse_step, fine_step, custom_step) ) { + MI_ERR("Compute step failed !"); + return -1; + } + + // save swap/plarity old setting + if(mir3da_register_read(handle, NSA_REG_SWAP_POLARITY, &swap_plarity_old)){ + MI_ERR("Get SWAP/PLARITY setting failed !"); + return -1; + } + + if(gsensor_chip_info.asic == ASIC_2512B){ + coarse_step[2] = 2 *coarse_step[2]; + + if((swap_plarity_old & (1<<0))){ + temp = xyz[0]; + xyz[0] = ((swap_plarity_old & (1<<2)) == 0) ? (-xyz[1]) :xyz[1]; + xyz[1] = ((swap_plarity_old & (1<<3)) == 0) ? (-temp) :temp; + }else{ + xyz[0] = ((swap_plarity_old & (1<<3)) == 0) ? (-xyz[0]) :xyz[0]; + xyz[1] = ((swap_plarity_old & (1<<2)) == 0) ? (-xyz[1]) :xyz[1]; + } + xyz[2] = ((swap_plarity_old & (1<<1)) == 0) ? (-xyz[2]) :xyz[2]; + }else if(gsensor_chip_info.asic == ASIC_2511){ + if((swap_plarity_old & (1<<0))){ + temp = xyz[0]; + xyz[0] = ((swap_plarity_old & (1<<2)) != 0) ? (-xyz[1]) :xyz[1]; + xyz[1] = ((swap_plarity_old & (1<<3)) != 0) ? (-temp) :temp; + }else{ + xyz[0] = ((swap_plarity_old & (1<<3)) != 0) ? (-xyz[0]) :xyz[0]; + xyz[1] = ((swap_plarity_old & (1<<2)) != 0) ? (-xyz[1]) :xyz[1]; + } + + xyz[2] = ((swap_plarity_old & (1<<1)) != 0) ? (-xyz[2]) :xyz[2]; + } + + result = NSA_once_calibrate(handle, coarse_step, fine_step, xyz); +#endif /* !MIR3DA_AUTO_CALIBRATE */ + return result; +} + +int mir3da_calibrate(MIR_HANDLE handle, int z_dir) +{ + int res = 0; + +#if MIR3DA_OFFSET_TEMP_SOLUTION + + int xyz[3]={0}; + + if( is_cali ) + return -1; + is_cali = 1; + + /* restore original direction if last calibration was done in a wrong direction */ + mir3da_write_offset(handle, original_offset); + + cycle_read_xyz(handle, &xyz[0], &xyz[1], &xyz[2], 20); + + res = mir3da_gsensor_drv.obj[gsensor_mod].calibrate(handle, z_dir); + if (res != 0){ + MI_ERR("Calibrate failed !"); + mir3da_write_offset(handle, original_offset); + }else + bLoad = FILE_EXIST; + + is_cali = 0; +#endif /* !MIR3DA_OFFSET_TEMP_SOLUTION */ + return res; +} + +#if MIR3DA_AUTO_CALIBRATE +#define STABLE_CHECK_SAMPLE_NUM 10 +#define STABLE_CHECK_THRESHOLD 50000 +#define AUTO_CALI_THRESHOLD_XY 200 +#define AUTO_CALI_THRESHOLD_Z 200 + +static unsigned char stable_sample_cnt = 0; +static int stable_sample_pow_sum[STABLE_CHECK_SAMPLE_NUM] = {0}; +static int stable_sample_sum[3] = {0}; + +static int mir3da_auto_cali_condition_confirm(int x, int y, int z, int ave_xyz[3]) +{ + int max = 0, min = 0; + int i; + int x_ok=0,y_ok=0,z_ok=0; + + stable_sample_pow_sum[stable_sample_cnt] = x*x + y*y + z*z; + stable_sample_sum[0] += x; + stable_sample_sum[1] += y; + stable_sample_sum[2] += z; + stable_sample_cnt++; + + MI_MSG("---stable_sample_cnt = %d", stable_sample_cnt); + + if( stable_sample_cnt < STABLE_CHECK_SAMPLE_NUM ) + return -1; + stable_sample_cnt = 0; + + max = stable_sample_pow_sum[0]; + min = stable_sample_pow_sum[0]; + stable_sample_pow_sum[0] = 0; + for(i = 1; i < STABLE_CHECK_SAMPLE_NUM; i++){ + if( stable_sample_pow_sum[i] > max ) + max = stable_sample_pow_sum[i]; + if( stable_sample_pow_sum[i] < min ) + min = stable_sample_pow_sum[i]; + stable_sample_pow_sum[i] = 0; + } + MI_MSG("---max = %d; min = %d", max, min); + + ave_xyz[0] = stable_sample_sum[0]/STABLE_CHECK_SAMPLE_NUM; + stable_sample_sum[0] = 0; + ave_xyz[1] = stable_sample_sum[1]/STABLE_CHECK_SAMPLE_NUM; + stable_sample_sum[1] = 0; + ave_xyz[2] = stable_sample_sum[2]/STABLE_CHECK_SAMPLE_NUM; + stable_sample_sum[2] = 0; + + MI_MSG("ave_x = %d, ave_y = %d, ave_z = %d", ave_xyz[0], ave_xyz[1], ave_xyz[2]); + x_ok = (abs(ave_xyz[0]) < AUTO_CALI_THRESHOLD_XY) ? 1:0; + y_ok = (abs(ave_xyz[1]) < AUTO_CALI_THRESHOLD_XY) ? 1:0; + z_ok = (abs(abs(ave_xyz[2])-1024) < AUTO_CALI_THRESHOLD_Z) ? 1:0; + + if( (abs(max-min) > STABLE_CHECK_THRESHOLD) ||((x_ok + y_ok + z_ok) < 2) ) { + return -1; + } + + return 0; +} + +static int mir3da_auto_calibrate(MIR_HANDLE handle, int x, int y, int z) +{ + int res = 0; + int xyz[3] = {0}; + + if((gsensor_chip_info.mems== MEMS_RTO3) + ||(gsensor_chip_info.reg_value == 0x4B) + ||(gsensor_chip_info.reg_value == 0x8C) + ||(gsensor_chip_info.reg_value == 0xCA) + ||(gsensor_chip_info.mems == MEMS_GT2)) + return -1; + + if( is_cali ) + return -1; + is_cali = 1; + +#if MIR3DA_SUPPORT_FAST_AUTO_CALI + if(mir3da_gsensor_drv.method->support_fast_auto_cali()){ + cycle_read_xyz(handle,&xyz[0],&xyz[1],&xyz[2],5); + } + else{ + if( mir3da_auto_cali_condition_confirm(x, y, z, xyz) ){ + res = -1; + goto EXIT; + } + } +#else + if( mir3da_auto_cali_condition_confirm(x, y, z, xyz) ){ + res = -1; + goto EXIT; + } +#endif + + mir3da_write_offset(handle, original_offset); + + res = mir3da_gsensor_drv.obj[gsensor_mod].auto_calibrate(handle, xyz); + if (res != 0){ + MI_ERR("Calibrate failed !"); + mir3da_write_offset(handle, original_offset); + }else + bLoad = FILE_EXIST; + +EXIT: + is_cali = 0; + + return res; +} +#endif /* !MIR3DA_AUTO_CALIBRATE */ + +static int NSA_interrupt_ops(MIR_HANDLE handle, mir_int_ops_t *ops) +{ + switch(ops->type) + { + case INTERRUPT_OP_INIT: + + /* latch */ + mir3da_register_mask_write(handle, NSA_REG_INT_LATCH, 0x0f, ops->data.init.latch); + /* active level & output mode */ + mir3da_register_mask_write(handle, NSA_REG_INT_PIN_CONFIG, 0x0f, ops->data.init.level|(ops->data.init.pin_mod<<1)|(ops->data.init.level<<2)|(ops->data.init.pin_mod<<3)); + + break; + + case INTERRUPT_OP_ENABLE: + switch( ops->data.int_src ) + { + case INTERRUPT_ACTIVITY: + /* Enable active interrupt */ + mir3da_register_mask_write(handle, NSA_REG_INTERRUPT_SETTINGS1, 0x07, 0x07); + break; + case INTERRUPT_CLICK: + /* Enable single and double tap detect */ + mir3da_register_mask_write(handle, NSA_REG_INTERRUPT_SETTINGS1, 0x30, 0x30); + break; + } + break; + + case INTERRUPT_OP_CONFIG: + + switch( ops->data.cfg.int_src ) + { + case INTERRUPT_ACTIVITY: + + mir3da_register_write(handle, NSA_REG_ACTIVE_THRESHOLD, ops->data.cfg.int_cfg.act.threshold); + mir3da_register_mask_write(handle, NSA_REG_ACTIVE_DURATION, 0x03, ops->data.cfg.int_cfg.act.duration); + + /* Int mapping */ + if(ops->data.cfg.pin == INTERRUPT_PIN1) { + mir3da_register_mask_write(handle, NSA_REG_INTERRUPT_MAPPING1, (1<<2), (1<<2)); + } + else if(ops->data.cfg.pin == INTERRUPT_PIN2) { + mir3da_register_mask_write(handle, NSA_REG_INTERRUPT_MAPPING3, (1<<2), (1<<2)); + } + break; + + case INTERRUPT_CLICK: + + mir3da_register_mask_write(handle, NSA_REG_TAP_THRESHOLD, 0x1f, ops->data.cfg.int_cfg.clk.threshold); + mir3da_register_mask_write(handle, NSA_REG_TAP_DURATION, (0x03<<5)|(0x07), (ops->data.cfg.int_cfg.clk.quiet_time<<7)|(ops->data.cfg.int_cfg.clk.click_time<<6)|(ops->data.cfg.int_cfg.clk.window)); + + if(ops->data.cfg.pin == INTERRUPT_PIN1) { + mir3da_register_mask_write(handle, NSA_REG_INTERRUPT_MAPPING1, 0x30, 0x30); + } + else if(ops->data.cfg.pin == INTERRUPT_PIN2) { + mir3da_register_mask_write(handle, NSA_REG_INTERRUPT_MAPPING3, 0x30, 0x30); + } + break; + } + break; + + case INTERRUPT_OP_DISABLE: + switch( ops->data.int_src ) + { + case INTERRUPT_ACTIVITY: + /* Enable active interrupt */ + mir3da_register_mask_write(handle, NSA_REG_INTERRUPT_SETTINGS1, 0x07, 0x00); + break; + + case INTERRUPT_CLICK: + /* Enable single and double tap detect */ + mir3da_register_mask_write(handle, NSA_REG_INTERRUPT_SETTINGS1, 0x30, 0x00); + break; + } + break; + + default: + MI_ERR("Unsupport operation !"); + } + return 0; +} + +int mir3da_interrupt_ops(MIR_HANDLE handle, mir_int_ops_t *ops) +{ + int res = 0; + + res = mir3da_gsensor_drv.obj[gsensor_mod].int_ops(handle, ops); + return res; +} + +#if FILTER_AVERAGE_ENHANCE +int mir3da_get_filter_param(struct mir3da_filter_param_s* param){ + if (param == 0){ + MI_ERR("Invalid param!"); + return -1; + } + + param->filter_param_h = core_ctx.tFac[0].filter_param_h; + param->filter_param_l = core_ctx.tFac[0].filter_param_l; + param->filter_threhold = core_ctx.tFac[0].filter_threhold; + + MI_MSG("FILTER param is get: filter_param_h = %d, filter_param_l = %d, filter_threhold = %d", param->filter_param_h, param->filter_param_l, param->filter_threhold); + + return 0; +} + +int mir3da_set_filter_param(struct mir3da_filter_param_s* param){ + + if (param == 0){ + MI_ERR("Invalid param!"); + return -1; + } + + MI_MSG("FILTER param is set: filter_param_h = %d, filter_param_l = %d, filter_threhold = %d", param->filter_param_h, param->filter_param_l, param->filter_threhold); + + core_ctx.tFac[1].filter_param_l = core_ctx.tFac[2].filter_param_l = core_ctx.tFac[0].filter_param_l = param->filter_param_l; + core_ctx.tFac[1].filter_param_h =core_ctx.tFac[2].filter_param_h = core_ctx.tFac[0].filter_param_h = param->filter_param_h; + core_ctx.tFac[1].filter_threhold = core_ctx.tFac[2].filter_threhold =core_ctx.tFac[0].filter_threhold = param->filter_threhold; + + return 0; +} +#endif //#if FILTER_AVERAGE_ENHANCE + +int mir3da_get_enable(MIR_HANDLE handle, char *enable) +{ + int res = 0; + unsigned char reg_data=0; + + res = mir3da_register_read(handle, mir3da_gsensor_drv.obj[gsensor_mod].power.addr, ®_data); + if(res != 0) { + return res; + } + + *enable = ( reg_data & mir3da_gsensor_drv.obj[gsensor_mod].power.mask ) ? 0 : 1; + + return res; +} + +int mir3da_set_enable(MIR_HANDLE handle, char enable) +{ + int res = 0; + unsigned char reg_data = 0; + + if(!enable) { + reg_data = mir3da_gsensor_drv.obj[gsensor_mod].power.value; + } + + res = mir3da_register_mask_write(handle, mir3da_gsensor_drv.obj[gsensor_mod].power.addr, mir3da_gsensor_drv.obj[gsensor_mod].power.mask, reg_data); + + return res; +} + +static int NSA_get_reg_data(MIR_HANDLE handle, char *buf) +{ + int count = 0; + int i; + unsigned char val; + + count += mir3da_gsensor_drv.method->mysprintf(buf+count, "---------start---------"); + for (i = 0; i <= 0xd2; i++){ + if(i%16 == 0) + count += mir3da_gsensor_drv.method->mysprintf(buf+count, "\n%02x\t", i); + mir3da_register_read(handle, i, &val); + count += mir3da_gsensor_drv.method->mysprintf(buf+count, "%02X ", val); + } + + count += mir3da_gsensor_drv.method->mysprintf(buf+count, "\n--------end---------\n"); + return count; +} + +int mir3da_get_reg_data(MIR_HANDLE handle, char *buf) +{ + return mir3da_gsensor_drv.obj[gsensor_mod].get_reg_data(handle, buf); +} + +int mir3da_set_odr(MIR_HANDLE handle, int delay) +{ + int res = 0; + int odr = 0; + + if(delay <= 5) + { + odr = MIR3DA_ODR_200HZ; + } + else if(delay <= 10) + { + odr = MIR3DA_ODR_100HZ; + } + else + { + odr = MIR3DA_ODR_50HZ; + } + + res = mir3da_register_mask_write(handle, mir3da_gsensor_drv.obj[gsensor_mod].odr_sect[odr].addr, + mir3da_gsensor_drv.obj[gsensor_mod].odr_sect[odr].mask,mir3da_gsensor_drv.obj[gsensor_mod].odr_sect[odr].value); + if(res != 0) { + return res; + } + + return res; +} + +static int mir3da_soft_reset(MIR_HANDLE handle) +{ + int res = 0; + unsigned char reg_data; + + reg_data = mir3da_gsensor_drv.obj[gsensor_mod].soft_reset.value; + res = mir3da_register_mask_write(handle, mir3da_gsensor_drv.obj[gsensor_mod].soft_reset.addr, mir3da_gsensor_drv.obj[gsensor_mod].soft_reset.mask, reg_data); + mir3da_gsensor_drv.method->msdelay(5); + + return res; +} + +static int mir3da_module_detect(PLAT_HANDLE handle) +{ + int i, res = 0; + unsigned char cid, mid; + int is_find = -1; + + /* Probe gsensor module */ + for(i=0;i>6)){ + return -1; + } + + if(!(reg_value&0xc0)){ + gsensor_chip_info.asic = ASIC_2511; + gsensor_chip_info.mems= MEMS_T9; + gsensor_chip_info.package= PACKAGE_NONE; + + for(i=0;i>6); + + if((reg_value&0x38)>>3 == 0x01) + gsensor_chip_info.asic =ASIC_2512B; + else if((reg_value&0x38)>>3 == 0x02) + gsensor_chip_info.asic =ASIC_2513A; + else if((reg_value&0x38)>>3 == 0x03) + gsensor_chip_info.asic =ASIC_2516; + + res = mir3da_register_read(handle, NSA_REG_CHIP_INFO_SECOND, ®_value1); + if(res != 0) { + return res; + } + + if(gsensor_chip_info.asic == ASIC_2512B){ + res = mir3da_register_read(handle, NSA_REG_MEMS_OPTION, ®_value); + if(res != 0) { + return res; + } + tmp= ((reg_value&0x01)<<2) |((reg_value1&0xc0)>>6); + } + else + { + tmp= (reg_value1&0xe0)>>5; + } + + res = mir3da_register_read(handle, NSA_REG_MEMS_OPTION, ®_value2); + if(res != 0) { + return res; + } + + if(tmp == 0x00){ + if(reg_value2&0x80) + gsensor_chip_info.mems =MEMS_TV03; + else + gsensor_chip_info.mems =MEMS_T9; + }else if(tmp == 0x01){ + gsensor_chip_info.mems =MEMS_RTO3; + } + else if(tmp == 0x03){ + gsensor_chip_info.mems =MEMS_GT2; + if((gsensor_chip_info.reg_value!=0x5A)&&(gsensor_chip_info.asic==ASIC_2516)) + gsensor_chip_info.mems =MEMS_GT3; + } + else if(tmp == 0x04){ + gsensor_chip_info.mems =MEMS_GT3; + } + +#if YZ_CROSS_TALK_ENABLE + if(reg_value1&0x10) + yzcross = -(reg_value1&0x0f); + else + yzcross = (reg_value1&0x0f); +#endif + } + + return 0; +} + + +int mir3da_install_general_ops(struct general_op_s *ops) +{ + if(0 == ops){ + return -1; + } + + mir3da_gsensor_drv.method = ops; + return 0; +} + +MIR_HANDLE mir3da_core_init(PLAT_HANDLE handle) +{ + int res = 0; + +#if FILTER_AVERAGE_ENHANCE +int i =0; +#endif + + mir3da_gsensor_drv.obj = mir3da_gsensor; + + if(gsensor_mod < 0){ + res = mir3da_module_detect(handle); + if(res) { + MI_ERR("Can't find Mir3da gsensor!!"); + return 0; + } + + /* No miramems gsensor instance found */ + if(gsensor_mod < 0) { + return 0; + } + } + + MI_MSG("Probe gsensor module: %s", mir3da_gsensor[gsensor_mod].asic); + +#if FILTER_AVERAGE_ENHANCE + /* configure default filter param */ + for (i = 0; i < 3;i++){ + core_ctx.tFac[i].filter_param_l = 2; + core_ctx.tFac[i].filter_param_h = 8; + core_ctx.tFac[i].filter_threhold = 60; + + core_ctx.tFac[i].refN_l = 0; + core_ctx.tFac[i].refN_h = 0; + } +#endif + + res = mir3da_chip_resume(handle); + if(res) { + MI_ERR("chip resume fail!!\n"); + return 0; + } + + return handle; +} + +int mir3da_chip_resume(MIR_HANDLE handle) +{ + int res = 0; + unsigned char reg_data; + unsigned char i = 0; + + res = mir3da_soft_reset(handle); + if(res) { + MI_ERR("Do softreset failed !"); + return res; + } + + for(i=0;imsdelay(10); + if(gsensor_type<0){ + gsensor_type=mir3da_parse_chip_info(handle); + + if(gsensor_type<0){ + MI_ERR("Can't parse Mir3da gsensor chipinfo!!"); + return -1; + } + } + + if(gsensor_chip_info.asic==ASIC_2513A){ + + res = mir3da_register_read(handle, NSA_REG_CHIP_INFO, ®_data); + if((reg_data == 0x55)||(reg_data == 0x50)){ + + mir3da_register_mask_write(handle, 0x40, 0xff, 0x96); + mir3da_register_read(handle, 0x41, ®_data); + if(reg_data != 0xBB){ + MI_ERR("error chip"); + return -1; + } + + mir3da_register_mask_write(handle, NSA_REG_POWERMODE_BW, 0x36, 0x30); + mir3da_register_mask_write(handle, NSA_REG_INT_PIN_CONFIG, 0xff, 0x00); + + mir3da_register_read(handle, NAS_REG_OSC_TRIM, ®_data); + if(reg_data == 0x00) + mir3da_register_mask_write(handle, NAS_REG_OSC_TRIM, 0xff, 0x50); + + is_da217 = 1; + }else{ + MI_ERR("parse asic error"); + return -1; + } + } + + if((gsensor_chip_info.asic==ASIC_2512B)||(gsensor_chip_info.asic == ASIC_2513A)){ + + reg_data = mir3da_gsensor_drv.method->get_address(handle); + + + if(reg_data ==0x26 ||reg_data ==0x4c){ + + mir3da_register_mask_write(handle,NSA_REG_SENS_COMP,0xc0,0x00); + } + } + +#if MIR3DA_OFFSET_TEMP_SOLUTION + res = mir3da_read_offset(handle, original_offset); + if (res != 0){ + MI_ERR("Read offset failed !"); + return res; + } + + bLoad = FILE_CHECKING; + readOffsetCnt = 0; + readsubfileCnt =0; + manual_load_cali_file(handle); +#endif + +#if 0 + if(is_da217 == 1){ + res = mir3da_irq_init(handle); + if(res){ + MI_ERR("step count init fail!!\n"); + return 0; + } + } +#endif + return res; +} + +int mir3da_get_primary_offset(MIR_HANDLE handle,int *x,int *y,int *z){ + int res = 0; + unsigned char reg_data; + unsigned char i = 0; + unsigned char offset[9]={0}; + + res = mir3da_read_offset(handle, offset); + if (res != 0){ + MI_ERR("Read offset failed !"); + return -1; + } + + res = mir3da_soft_reset(handle); + if(res) { + MI_ERR("Do softreset failed !"); + return -1; + } + + for(i=0;imsdelay(100); + + res = cycle_read_xyz(handle, x, y, z, 20); + if (res){ + MI_ERR("i2c block read failed\n"); + goto EXIT; + } + + mir3da_write_offset(handle, offset); + + if((gsensor_chip_info.reg_value == 0x4B) + ||(gsensor_chip_info.reg_value == 0x8C) + ||(gsensor_chip_info.reg_value == 0xCA) + ||(gsensor_chip_info.mems == MEMS_GT2)) + { + *z = 0; + } + + return 0; + +EXIT: + mir3da_write_offset(handle, offset); + return -1; +} + +int mir3da_irq_init(MIR_HANDLE handle){ + int res = 0; + // irq config + res |= mir3da_register_mask_write(handle, NSA_REG_INT_LATCH, 0x0F, 0x00); //latch 0s + + // step config + res |= mir3da_register_mask_write(handle, NSA_REG_STEP_CONFIG1, 0xff, 0x01); + res |= mir3da_register_mask_write(handle, NSA_REG_STEP_CONFIG2, 0xff, 0x62); + res |= mir3da_register_mask_write(handle, NSA_REG_STEP_CONFIG3, 0xff, 0x46); + res |= mir3da_register_mask_write(handle, NSA_REG_STEP_CONFIG4, 0xff, 0x32); + res |= mir3da_register_mask_write(handle, NSA_REG_STEP_FILTER, 0xff, 0x22); //enable bit + + //step count + res |= mir3da_register_mask_write(handle, NSA_REG_INTERRUPT_MAPPING1, 0x02, 0x02); + res |= mir3da_register_mask_write(handle, NAS_REG_INT_SET0, 0x01, 0x00); //irq bit + + //significont motion + res |= mir3da_register_mask_write(handle, NSA_REG_INTERRUPT_MAPPING1, 0x80, 0x80); + res |= mir3da_register_mask_write(handle, NAS_REG_INT_SET0, 0x02, 0x00); //irq bit + res |= mir3da_register_mask_write(handle, NSA_REG_SM_THRESHOLD, 0x0A, 0x0A); //step number + + //tilt + res |= mir3da_register_mask_write(handle, NSA_REG_INTERRUPT_MAPPING1, 0x08, 0x08); + res |= mir3da_register_mask_write(handle, NAS_REG_INT_SET0, 0x10, 0x00); //irq bit + + //active + res |= mir3da_register_mask_write(handle, NSA_REG_INTERRUPT_MAPPING1, 0x04, 0x04); + res |= mir3da_register_mask_write(handle, NSA_REG_INTERRUPT_SETTINGS1, 0xC7, 0x80); + res |= mir3da_register_mask_write(handle, NSA_REG_ACTIVE_DURATION, 0xff, 0x01); + res |= mir3da_register_mask_write(handle, NSA_REG_ACTIVE_THRESHOLD, 0xff, 0x14); + + if(res) + MI_ERR("irq init error"); + + MI_MSG("irq init ok") + return res; +} + +int mir3da_step_count_init(MIR_HANDLE handle){ + int res = 0; + + // step config + res |= mir3da_register_mask_write(handle, NSA_REG_STEP_CONFIG1, 0xff, 0x01); + res |= mir3da_register_mask_write(handle, NSA_REG_STEP_CONFIG2, 0xff, 0x62); + res |= mir3da_register_mask_write(handle, NSA_REG_STEP_CONFIG3, 0xff, 0x46); + res |= mir3da_register_mask_write(handle, NSA_REG_STEP_CONFIG4, 0xff, 0x32); + res |= mir3da_register_mask_write(handle, NSA_REG_STEP_FILTER, 0xff, 0x22); + + return res; +} + +int mir3da_get_step_enable(MIR_HANDLE handle, char *enable) +{ + int res = 0; + unsigned char reg_data = 0; + + res = mir3da_register_read(handle, NSA_REG_STEP_FILTER, ®_data); //check irq + if(res != 0) { + return res; + } + + *enable = ( reg_data & 0x80 ) ? 1 : 0; + + return res; +} + +int mir3da_set_step_enable(MIR_HANDLE handle, char enable) +{ + int res = 0; + + if(enable){ + res |= mir3da_register_mask_write(handle, NSA_REG_STEP_FILTER, 0x80, 0x80); //step count enable + //res |= mir3da_register_mask_write(handle, NAS_REG_INT_SET0, 0x01, 0x01); //step irq bit + }else{ + res |= mir3da_register_mask_write(handle, NSA_REG_STEP_FILTER, 0x80, 0x00); + //res |= mir3da_register_mask_write(handle, NAS_REG_INT_SET0, 0x01, 0x00); + } + + return res; +} + +int mir3da_get_sm_enable(MIR_HANDLE handle, char *enable) +{ + int res = 0; + unsigned char reg_data = 0; + + res = mir3da_register_read(handle, NSA_REG_STEP_FILTER, ®_data); + if(res != 0) { + return res; + } + + *enable = ( reg_data & 0x80 ) ? 1 : 0; + + return res; +} + +int mir3da_set_sm_enable(MIR_HANDLE handle, char enable) +{ + int res = 0; + + if(enable){ + res |= mir3da_register_mask_write(handle, NSA_REG_STEP_FILTER, 0x80, 0x80); + res |= mir3da_register_mask_write(handle, NAS_REG_INT_SET0, 0x02, 0x02); + }else{ + res |= mir3da_register_mask_write(handle, NSA_REG_STEP_FILTER, 0x80, 0x00); + res |= mir3da_register_mask_write(handle, NAS_REG_INT_SET0, 0x02, 0x00); + } + + return res; +} + +int mir3da_get_tilt_enable(MIR_HANDLE handle, char *enable) +{ + int res = 0; + unsigned char reg_data = 0; + + res = mir3da_register_read(handle, NAS_REG_INT_SET0, ®_data); + if(res != 0) { + return res; + } + + *enable = ( reg_data & 0x10 ) ? 1 : 0; + + return res; +} + +int mir3da_set_tilt_enable(MIR_HANDLE handle, char enable) +{ + int res = 0; + + if(enable){ + res |= mir3da_register_mask_write(handle, NAS_REG_INT_SET0, 0x10, 0x10); + }else{ + res |= mir3da_register_mask_write(handle, NAS_REG_INT_SET0, 0x10, 0x00); + } + + return res; +} diff --git a/drivers/input/sensors/accel/da223_core.h b/drivers/input/sensors/accel/da223_core.h new file mode 100644 index 000000000000..de67d711b486 --- /dev/null +++ b/drivers/input/sensors/accel/da223_core.h @@ -0,0 +1,303 @@ +/* Core header for MiraMEMS 3-Axis Accelerometer's driver. + * + * mir3da_core.h - Linux kernel modules for MiraMEMS 3-Axis Accelerometer + * + * Copyright (C) 2011-2013 MiraMEMS Sensing Technology Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef __MIR3DA_CORE_H__ +#define __MIR3DA_CORE_H__ + +#define CUST_VER "" /* for Custom debug version */ +#define CORE_VER "4.2.0_2018-08-10-14:56:30_"CUST_VER + +#define MIR3DA_SUPPORT_CHIP_LIST MIR_NSA_NTO + +#define MIR3DA_BUFSIZE 256 + +#define MIR3DA_STK_TEMP_SOLUTION 0 +#define MIR3DA_OFFSET_TEMP_SOLUTION 0 +#if MIR3DA_OFFSET_TEMP_SOLUTION +#define MIR3DA_AUTO_CALIBRATE 0 +#else +#define MIR3DA_AUTO_CALIBRATE 0 +#endif /* !MIR3DA_OFFSET_TEMP_SOLUTION */ +#if MIR3DA_AUTO_CALIBRATE +#define MIR3DA_SUPPORT_FAST_AUTO_CALI 0 +#else +#define MIR3DA_SUPPORT_FAST_AUTO_CALI 0 +#endif +#define MIR3DA_SENS_TEMP_SOLUTION 1 +#define FILTER_AVERAGE_ENHANCE 0 +#define FILTER_AVERAGE_EX 0 +#define MIR3DA_SUPPORT_MULTI_LAYOUT 0 +#define YZ_CROSS_TALK_ENABLE 1 + +#define MIR3DA_OFFSET_LEN 9 + +typedef void* MIR_HANDLE; +typedef void* PLAT_HANDLE; + + +struct serial_manage_if_s { + + int (*read)(PLAT_HANDLE handle, unsigned char addr, unsigned char *data); + int (*write)(PLAT_HANDLE handle, unsigned char addr, unsigned char data); + int (*read_block)(PLAT_HANDLE handle, unsigned char base_addr, unsigned char count, unsigned char *data); +}; + +struct general_op_s { + + struct serial_manage_if_s smi; + + int (*data_save)(unsigned char *data); + int (*data_get)(unsigned char *data); + int (*data_check)(void); + int (*get_address)(PLAT_HANDLE handle); + int (*support_fast_auto_cali)(void); + + int (*myprintf)(const char *fmt, ...); + int (*mysprintf)(char *buf, const char *fmt, ...); + void (*msdelay)(int ms); +}; + +#define MIR_GENERAL_OPS_DECLARE(OPS_HDL, SMI_RD, SMI_RDBL, SMI_WR, DAT_SAVE, DAT_GET,DAT_CHECK, GET_ADDRESS,SUPPORT_FAST_AUTO_CALI,MDELAY, MYPRINTF, MYSPRINTF) \ + \ + struct general_op_s OPS_HDL = { { SMI_RD, SMI_WR, SMI_RDBL }, DAT_SAVE, DAT_GET,DAT_CHECK,GET_ADDRESS, SUPPORT_FAST_AUTO_CALI,MYPRINTF, MYSPRINTF, MDELAY } +enum interrupt_src { + + INTERRUPT_ACTIVITY = 1, + INTERRUPT_CLICK, + +}; + +typedef enum _int_op_type { + + INTERRUPT_OP_INIT, + INTERRUPT_OP_ENABLE, + INTERRUPT_OP_CONFIG, + INTERRUPT_OP_DISABLE, + +} mir_int_op_type; + +enum interrupt_pin { + + INTERRUPT_PIN1, + INTERRUPT_PIN2, +}; + +enum pin_output_mode { + + OUTPUT_MOD_PULL_PUSH, + OUTPUT_MOD_OD, +}; + +struct int_act_cfg_s { + + unsigned char threshold; + unsigned char duration; +}; + +struct int_clk_cfg_s { + + unsigned char threshold; + unsigned char click_time; /* click time */ + unsigned char quiet_time; /* quiet time after click */ + unsigned char window; /* for second click time window */ +}; + +typedef union _int_src_configuration { + + struct int_act_cfg_s act; + struct int_clk_cfg_s clk; + +} mir_int_src_cfg_t; + +typedef struct _int_configuration { + + enum interrupt_pin pin; + enum interrupt_src int_src; + + mir_int_src_cfg_t int_cfg; + +} mir_int_cfg_t; + +typedef struct _int_init_data { + + enum pin_output_mode pin_mod; + + unsigned char level; /* 1: high active, 0: low active */ + unsigned char latch; /* >0: latch time, 0: no latch */ + +} mir_int_init_t ; + +typedef union _int_op_data { + + enum interrupt_src int_src; + mir_int_init_t init; + mir_int_cfg_t cfg; + +} mir_int_op_data; + +typedef struct _int_operations { + + mir_int_op_type type; + mir_int_op_data data; + +} mir_int_ops_t; + +/* Register define for NSA asic */ +#define NSA_REG_SPI_I2C 0x00 +#define NSA_REG_WHO_AM_I 0x01 +#define NSA_REG_ACC_X_LSB 0x02 +#define NSA_REG_ACC_X_MSB 0x03 +#define NSA_REG_ACC_Y_LSB 0x04 +#define NSA_REG_ACC_Y_MSB 0x05 +#define NSA_REG_ACC_Z_LSB 0x06 +#define NSA_REG_ACC_Z_MSB 0x07 +#define NSA_REG_MOTION_FLAG 0x09 +#define NSA_REG_STEPS_MSB 0x0D +#define NSA_REG_STEPS_LSB 0x0E +#define NSA_REG_G_RANGE 0x0F +#define NSA_REG_ODR_AXIS_DISABLE 0x10 +#define NSA_REG_POWERMODE_BW 0x11 +#define NSA_REG_SWAP_POLARITY 0x12 +#define NSA_REG_FIFO_CTRL 0x14 +#define NAS_REG_INT_SET0 0x15 +#define NSA_REG_INTERRUPT_SETTINGS1 0x16 +#define NSA_REG_INTERRUPT_SETTINGS2 0x17 +#define NSA_REG_INTERRUPT_MAPPING1 0x19 +#define NSA_REG_INTERRUPT_MAPPING2 0x1a +#define NSA_REG_INTERRUPT_MAPPING3 0x1b +#define NSA_REG_INT_PIN_CONFIG 0x20 +#define NSA_REG_INT_LATCH 0x21 +#define NSA_REG_ACTIVE_DURATION 0x27 +#define NSA_REG_ACTIVE_THRESHOLD 0x28 +#define NSA_REG_TAP_DURATION 0x2A +#define NSA_REG_TAP_THRESHOLD 0x2B +#define NSA_REG_STEP_CONFIG1 0x2F +#define NSA_REG_STEP_CONFIG2 0x30 +#define NSA_REG_STEP_CONFIG3 0x31 +#define NSA_REG_STEP_CONFIG4 0x32 +#define NSA_REG_STEP_FILTER 0x33 +#define NSA_REG_SM_THRESHOLD 0x34 +#define NSA_REG_CUSTOM_OFFSET_X 0x38 +#define NSA_REG_CUSTOM_OFFSET_Y 0x39 +#define NSA_REG_CUSTOM_OFFSET_Z 0x3a +#define NSA_REG_ENGINEERING_MODE 0x7f +#define NSA_REG_SENSITIVITY_TRIM_X 0x80 +#define NSA_REG_SENSITIVITY_TRIM_Y 0x81 +#define NSA_REG_SENSITIVITY_TRIM_Z 0x82 +#define NSA_REG_COARSE_OFFSET_TRIM_X 0x83 +#define NSA_REG_COARSE_OFFSET_TRIM_Y 0x84 +#define NSA_REG_COARSE_OFFSET_TRIM_Z 0x85 +#define NSA_REG_FINE_OFFSET_TRIM_X 0x86 +#define NSA_REG_FINE_OFFSET_TRIM_Y 0x87 +#define NSA_REG_FINE_OFFSET_TRIM_Z 0x88 +#define NSA_REG_SENS_COMP 0x8c +#define NSA_REG_MEMS_OPTION 0x8f +#define NSA_REG_CHIP_INFO 0xc0 +#define NSA_REG_CHIP_INFO_SECOND 0xc1 +#define NSA_REG_MEMS_OPTION_SECOND 0xc7 +#define NSA_REG_SENS_COARSE_TRIM 0xd1 +#define NAS_REG_OSC_TRIM 0x8e + +#define MIR3DA_ODR_50HZ 0 +#define MIR3DA_ODR_100HZ 1 +#define MIR3DA_ODR_200HZ 2 + +#define MI_TAG "[MIR3DA] " +enum{ + DEBUG_ERR=1, + DEBUG_ASSERT=1<<1, + DEBUG_MSG=1<<2, + DEBUG_FUNC=1<<3, + DEBUG_DATA=1<<4, +}; + +extern int mir3da_Log_level; + +/* register operation */ +int mir3da_register_read(MIR_HANDLE handle, short reg, unsigned char *data); +int mir3da_register_write(MIR_HANDLE handle, short reg, unsigned char data); +int mir3da_register_read_continuously(MIR_HANDLE handle, short base_reg, unsigned char count, unsigned char *data); +int mir3da_register_mask_write(MIR_HANDLE handle, short addr, unsigned char mask, unsigned char data); + +int mir3da_install_general_ops(struct general_op_s *ops); +/* chip init */ +MIR_HANDLE mir3da_core_init(PLAT_HANDLE handle); + +/* data polling */ +int mir3da_read_data(MIR_HANDLE handle, short *x, short *y, short *z); + +/* filter configure */ +#if FILTER_AVERAGE_ENHANCE +struct mir3da_filter_param_s{ + int filter_param_l; + int filter_param_h; + int filter_threhold; +}; + +int mir3da_get_filter_param(struct mir3da_filter_param_s* param); +int mir3da_set_filter_param(struct mir3da_filter_param_s* param); +#endif + +#if MIR3DA_STK_TEMP_SOLUTION +#endif + +enum { + GSENSOR_MOD_NSA_NTO=0, +}; + +/* CALI */ +int mir3da_calibrate(MIR_HANDLE handle, int z_dir); + +/* calibration */ +#if MIR3DA_OFFSET_TEMP_SOLUTION +enum file_check_statu { + FILE_NO_EXIST , + FILE_CHECKING , + FILE_EXIST, +}; +#endif + +/* Interrupt operations */ +int mir3da_interrupt_ops(MIR_HANDLE handle, mir_int_ops_t *ops); + +int mir3da_read_offset(MIR_HANDLE handle, unsigned char* offst); +int mir3da_write_offset(MIR_HANDLE handle, unsigned char* offset); + +int mir3da_set_enable(MIR_HANDLE handle, char bEnable); +int mir3da_get_enable(MIR_HANDLE handle, char *bEnable); +int mir3da_get_reg_data(MIR_HANDLE handle, char *buf); +int mir3da_set_odr(MIR_HANDLE handle, int delay); +int mir3da_direction_remap(short *x,short *y, short *z, int direction); + +int mir3da_chip_resume(MIR_HANDLE handle); +int mir3da_get_primary_offset(MIR_HANDLE handle,int *x,int *y,int *z); + +int mir3da_read_step(MIR_HANDLE handle, unsigned short *count); +int mir3da_step_count_init(MIR_HANDLE handle); +int mir3da_irq_init(MIR_HANDLE handle); +int mir3da_step_count_init(MIR_HANDLE handle); +int mir3da_get_step_enable(MIR_HANDLE handle, char *enable); +int mir3da_set_step_enable(MIR_HANDLE handle, char enable); +int mir3da_get_sm_enable(MIR_HANDLE handle, char *enable); +int mir3da_set_sm_enable(MIR_HANDLE handle, char enable); +int mir3da_get_tilt_enable(MIR_HANDLE handle, char *enable); +int mir3da_set_tilt_enable(MIR_HANDLE handle, char enable); + + +#endif /* __MIR3DA_CORE_H__ */ + + diff --git a/drivers/input/sensors/accel/da223_cust.c b/drivers/input/sensors/accel/da223_cust.c new file mode 100644 index 000000000000..c2833ab97f59 --- /dev/null +++ b/drivers/input/sensors/accel/da223_cust.c @@ -0,0 +1,890 @@ +/* For RockChip android platform. + * + * mir3da.c - Linux kernel modules for 3-Axis Accelerometer + * + * Copyright (C) 2011-2013 MiraMEMS Sensing Technology Co., Ltd. + * + * 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 +#ifdef CONFIG_HAS_EARLYSUSPEND +#include +#endif +#include +#include +#include + +#include "da223_core.h" +#include "da223_cust.h" +/******************************************************************************/ +#define GSENSOR_MIN 2 +#define MIR3DA_PRECISION 11 +#define MIR3DA_RANGE 1000000 +#define DA311_BOUNDARY (0x1 << (MIR3DA_PRECISION - 1)) +#define DA311_GRAVITY_STEP (MIR3DA_RANGE/DA311_BOUNDARY) +/******************************************************************************/ +#define MIR3DA_DRV_NAME "mir3da" +#define MIR3DA_INPUT_DEV_NAME MIR3DA_DRV_NAME +/******************************************************************************/ +static MIR_HANDLE mir_handle; +static int is_init =0; +/******************************************************************************/ +#define MI_DATA(format, ...) if(DEBUG_DATA&mir3da_Log_level){printk(KERN_ERR MI_TAG format "\n", ## __VA_ARGS__);} +#define MI_MSG(format, ...) if(DEBUG_MSG&mir3da_Log_level){printk(KERN_ERR MI_TAG format "\n", ## __VA_ARGS__);} +#define MI_ERR(format, ...) if(DEBUG_ERR&mir3da_Log_level){printk(KERN_ERR MI_TAG format "\n", ## __VA_ARGS__);} +#define MI_FUN if(DEBUG_FUNC&mir3da_Log_level){printk(KERN_ERR MI_TAG "%s is called, line: %d\n", __FUNCTION__,__LINE__);} +#define MI_ASSERT(expr) \ + if (!(expr)) {\ + printk(KERN_ERR "Assertion failed! %s,%d,%s,%s\n",\ + __FILE__, __LINE__, __func__, #expr);\ + } +/******************************************************************************/ +#if MIR3DA_OFFSET_TEMP_SOLUTION +static char OffsetFileName[] = "/data/misc/miraGSensorOffset.txt"; +static char OffsetFolerName[] = "/data/misc/"; +#define OFFSET_STRING_LEN 26 +struct work_info +{ + char tst1[20]; + char tst2[20]; + char buffer[OFFSET_STRING_LEN]; + struct workqueue_struct *wq; + struct delayed_work read_work; + struct delayed_work write_work; + struct completion completion; + int len; + int rst; +}; + +static struct work_info m_work_info = {{0}}; +/******************************************************************************/ +static void sensor_write_work( struct work_struct *work ) +{ + struct work_info* pWorkInfo; + struct file *filep; + mm_segment_t orgfs; + int ret; + + orgfs = get_fs(); + set_fs(KERNEL_DS); + + pWorkInfo = container_of((struct delayed_work*)work, struct work_info, write_work); + if (pWorkInfo == NULL){ + MI_ERR("get pWorkInfo failed!"); + return; + } + + filep = filp_open(OffsetFileName, O_RDWR|O_CREAT, 0600); + if (IS_ERR(filep)){ + MI_ERR("write, sys_open %s error!!.\n", OffsetFileName); + ret = -1; + } + else + { + filep->f_op->write(filep, pWorkInfo->buffer, pWorkInfo->len, &filep->f_pos); + filp_close(filep, NULL); + ret = 0; + + set_fs(orgfs); + pWorkInfo->rst = ret; + complete( &pWorkInfo->completion ); +} +/******************************************************************************/ +static void sensor_read_work( struct work_struct *work ) +{ + mm_segment_t orgfs; + struct file *filep; + int ret; + struct work_info* pWorkInfo; + + orgfs = get_fs(); + set_fs(KERNEL_DS); + + pWorkInfo = container_of((struct delayed_work*)work, struct work_info, read_work); + if (pWorkInfo == NULL){ + MI_ERR("get pWorkInfo failed!"); + return; + } + + filep = filp_open(OffsetFileName, O_RDONLY, 0600); + if (IS_ERR(filep)){ + MI_ERR("read, sys_open %s error!!.\n",OffsetFileName); + set_fs(orgfs); + ret = -1; + } + else{ + filep->f_op->read(filep, pWorkInfo->buffer, sizeof(pWorkInfo->buffer), &filep->f_pos); + filp_close(filep, NULL); + set_fs(orgfs); + ret = 0; + } + + pWorkInfo->rst = ret; + complete( &(pWorkInfo->completion) ); +} +/******************************************************************************/ +static int sensor_sync_read(u8* offset) +{ + int err; + int off[MIR3DA_OFFSET_LEN] = {0}; + struct work_info* pWorkInfo = &m_work_info; + + init_completion( &pWorkInfo->completion ); + queue_delayed_work( pWorkInfo->wq, &pWorkInfo->read_work, msecs_to_jiffies(0) ); + err = wait_for_completion_timeout( &pWorkInfo->completion, msecs_to_jiffies( 2000 ) ); + if ( err == 0 ){ + MI_ERR("wait_for_completion_timeout TIMEOUT"); + return -1; + } + + if (pWorkInfo->rst != 0){ + MI_ERR("work_info.rst not equal 0"); + return pWorkInfo->rst; + } + + sscanf(m_work_info.buffer, "%x,%x,%x,%x,%x,%x,%x,%x,%x", &off[0], &off[1], &off[2], &off[3], &off[4], &off[5],&off[6], &off[7], &off[8]); + + offset[0] = (u8)off[0]; + offset[1] = (u8)off[1]; + offset[2] = (u8)off[2]; + offset[3] = (u8)off[3]; + offset[4] = (u8)off[4]; + offset[5] = (u8)off[5]; + offset[6] = (u8)off[6]; + offset[7] = (u8)off[7]; + offset[8] = (u8)off[8]; + + return 0; +} +/******************************************************************************/ +static int sensor_sync_write(u8* off) +{ + int err = 0; + struct work_info* pWorkInfo = &m_work_info; + + init_completion( &pWorkInfo->completion ); + + sprintf(m_work_info.buffer, "%x,%x,%x,%x,%x,%x,%x,%x,%x\n", off[0],off[1],off[2],off[3],off[4],off[5],off[6],off[7],off[8]); + + pWorkInfo->len = sizeof(m_work_info.buffer); + + queue_delayed_work( pWorkInfo->wq, &pWorkInfo->write_work, msecs_to_jiffies(0) ); + err = wait_for_completion_timeout( &pWorkInfo->completion, msecs_to_jiffies( 2000 ) ); + if ( err == 0 ){ + MI_ERR("wait_for_completion_timeout TIMEOUT"); + return -1; + } + + if (pWorkInfo->rst != 0){ + MI_ERR("work_info.rst not equal 0"); + return pWorkInfo->rst; + } + + return 0; +} +/******************************************************************************/ +static int check_califolder_exist(void) +{ + mm_segment_t orgfs; + struct file *filep; + + orgfs = get_fs(); + set_fs(KERNEL_DS); + + filep = filp_open(OffsetFolerName, O_RDONLY, 0600); + if (IS_ERR(filep)) { + MI_ERR("%s read, sys_open %s error!!.\n",__func__,OffsetFolerName); + set_fs(orgfs); + return 0; + } + + filp_close(filep, NULL); + set_fs(orgfs); + + return 1; +} +/******************************************************************************/ +static int support_fast_auto_cali(void) +{ +#if MIR3DA_SUPPORT_FAST_AUTO_CALI + return 1; +#else + return 0; +#endif +} +#endif +/******************************************************************************/ +static int get_address(PLAT_HANDLE handle) +{ + if(NULL == handle){ + MI_ERR("chip init failed !\n"); + return -1; + } + + return ((struct i2c_client *)handle)->addr; +} +/******************************************************************************/ +static int i2c_smbus_read(PLAT_HANDLE handle, u8 addr, u8 *data) +{ + int res = 0; + struct i2c_client *client = (struct i2c_client*)handle; + + *data = i2c_smbus_read_byte_data(client, addr); + + return res; +} +/******************************************************************************/ +static int i2c_smbus_read_block(PLAT_HANDLE handle, u8 addr, u8 count, u8 *data) +{ + int res = 0; + struct i2c_client *client = (struct i2c_client*)handle; + + res = i2c_smbus_read_i2c_block_data(client, addr, count, data); + + return res; +} +/******************************************************************************/ +static int i2c_smbus_write(PLAT_HANDLE handle, u8 addr, u8 data) +{ + int res = 0; + struct i2c_client *client = (struct i2c_client*)handle; + + res = i2c_smbus_write_byte_data(client, addr, data); + + return res; +} +/******************************************************************************/ +static void msdelay(int ms) +{ + mdelay(ms); +} +/******************************************************************************/ + +#if MIR3DA_OFFSET_TEMP_SOLUTION +static MIR_GENERAL_OPS_DECLARE(ops_handle, i2c_smbus_read, i2c_smbus_read_block, i2c_smbus_write, sensor_sync_write, sensor_sync_read, check_califolder_exist,get_address,support_fast_auto_cali,msdelay, printk, sprintf); +#else +static MIR_GENERAL_OPS_DECLARE(ops_handle, i2c_smbus_read, i2c_smbus_read_block, i2c_smbus_write, NULL, NULL, NULL,get_address,NULL,msdelay, printk, sprintf); +#endif + +/******************************************************************************/ +static ssize_t enable_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int ret; + char bEnable; + + MI_FUN; + + ret = mir3da_get_enable(mir_handle, &bEnable); + if (ret < 0){ + ret = -EINVAL; + } + else{ + ret = sprintf(buf, "%d\n", bEnable); + } + + return ret; +} +/******************************************************************************/ +static ssize_t enable_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + int ret; + bool bEnable; + unsigned long enable; + + if (buf == NULL){ + return -1; + } + + enable = simple_strtoul(buf, NULL, 10); + bEnable = (enable > 0) ? true : false; + + MI_MSG("%s:enable=%d\n",__func__,bEnable); + + ret = mir3da_set_enable (mir_handle, bEnable); + if (ret < 0){ + ret = -EINVAL; + } + else{ + ret = count; + } + + return ret; +} +/******************************************************************************/ +static ssize_t axis_data_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int result; + short x,y,z; + int count = 0; + + result = mir3da_read_data(mir_handle, &x, &y, &z); + if (result == 0) + count += sprintf(buf+count, "x= %d;y=%d;z=%d\n", x,y,z); + else + count += sprintf(buf+count, "reading failed!"); + + return count; +} +/******************************************************************************/ +static ssize_t reg_data_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + int addr, data; + int result; + + sscanf(buf, "0x%x, 0x%x\n", &addr, &data); + + result = mir3da_register_write(mir_handle, addr, data); + + MI_ASSERT(result==0); + + return count; +} +/******************************************************************************/ +static ssize_t reg_data_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + MIR_HANDLE handle = mir_handle; + + return mir3da_get_reg_data(handle, buf); +} +/******************************************************************************/ + +#if MIR3DA_OFFSET_TEMP_SOLUTION +static ssize_t offset_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + ssize_t count = 0; + + if(bLoad==FILE_EXIST) + count += sprintf(buf,"%s",m_work_info.buffer); + else + count += sprintf(buf,"%s","Calibration file not exist!\n"); + + return count; +} +#endif +/******************************************************************************/ +#if FILTER_AVERAGE_ENHANCE +static ssize_t average_enhance_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int ret = 0; + struct mir3da_filter_param_s param = {0}; + + ret = mir3da_get_filter_param(¶m); + ret |= sprintf(buf, "%d %d %d\n", param.filter_param_l, param.filter_param_h, param.filter_threhold); + + return ret; +} +/******************************************************************************/ +static ssize_t average_enhance_store(struct device *dev,struct device_attribute *attr,const char *buf, size_t count) +{ + int ret = 0; + struct mir3da_filter_param_s param = {0}; + + sscanf(buf, "%d %d %d\n", ¶m.filter_param_l, ¶m.filter_param_h, ¶m.filter_threhold); + + ret = mir3da_set_filter_param(¶m); + + return count; +} +#endif +/******************************************************************************/ +#if MIR3DA_OFFSET_TEMP_SOLUTION +static int bCaliResult = -1; +static ssize_t calibrate_miraGSensor_show(struct device *dev,struct device_attribute *attr,char *buf) +{ + int ret; + + ret = sprintf(buf, "%d\n", bCaliResult); + return ret; +} +/******************************************************************************/ +static ssize_t calibrate_miraGSensor_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + s8 z_dir = 0; + MIR_HANDLE handle = mir_handle; + + z_dir = simple_strtol(buf, NULL, 10); + bCaliResult = mir3da_calibrate(handle,z_dir); + + return count; +} +#endif +/******************************************************************************/ +static ssize_t log_level_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int ret; + + ret = sprintf(buf, "%d\n", mir3da_Log_level); + + return ret; +} +/******************************************************************************/ +static ssize_t log_level_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + mir3da_Log_level = simple_strtoul(buf, NULL, 10); + + return count; +} +/******************************************************************************/ +static ssize_t primary_offset_show(struct device *dev, + struct device_attribute *attr, char *buf){ + MIR_HANDLE handle = mir_handle; + int x=0,y=0,z=0; + + mir3da_get_primary_offset(handle,&x,&y,&z); + + return sprintf(buf, "x=%d ,y=%d ,z=%d\n",x,y,z); +} +/******************************************************************************/ +static ssize_t version_show(struct device *dev, + struct device_attribute *attr, char *buf){ + + return sprintf(buf, "%s_%s\n", DRI_VER, CORE_VER); +} +/******************************************************************************/ +static ssize_t vendor_show(struct device *dev, + struct device_attribute *attr, char *buf){ + return sprintf(buf, "%s\n", "MiraMEMS"); +} +/******************************************************************************/ +static DEVICE_ATTR_RW(enable); +static DEVICE_ATTR_RO(axis_data); +static DEVICE_ATTR_RW(reg_data); +static DEVICE_ATTR_RW(log_level); +#if MIR3DA_OFFSET_TEMP_SOLUTION +static DEVICE_ATTR_RO(offset); +static DEVICE_ATTR_RW(calibrate_miraGSensor); +#endif +#if FILTER_AVERAGE_ENHANCE +static DEVICE_ATTR_RW(average_enhance); +#endif +static DEVICE_ATTR_RO(primary_offset); +static DEVICE_ATTR_RO(version); +static DEVICE_ATTR_RO(vendor); + +/******************************************************************************/ +static struct attribute *mir3da_attributes[] = { + &dev_attr_enable.attr, + &dev_attr_axis_data.attr, + &dev_attr_reg_data.attr, + &dev_attr_log_level.attr, +#if MIR3DA_OFFSET_TEMP_SOLUTION + &dev_attr_offset.attr, + &dev_attr_calibrate_miraGSensor.attr, +#endif +#if FILTER_AVERAGE_ENHANCE + &dev_attr_average_enhance.attr, +#endif + &dev_attr_primary_offset.attr, + &dev_attr_version.attr, + &dev_attr_vendor.attr, + NULL +}; + +static const struct attribute_group mir3da_attr_group = { + .attrs = mir3da_attributes, +}; +/******************************************************************************/ +static int sensor_init(struct i2c_client *client) +{ + int ret = 0; + static int withSysAttr = 1; + unsigned char chip_id=0; + unsigned char i=0; + + struct sensor_private_data *sensor =(struct sensor_private_data *) i2c_get_clientdata(client); + + MI_FUN; + + if(is_init) + return 0; + + sensor->status_cur = SENSOR_OFF; + + if(mir3da_install_general_ops(&ops_handle)){ + MI_ERR("Install ops failed !\n"); + return -1; + } + +#if MIR3DA_OFFSET_TEMP_SOLUTION + m_work_info.wq = create_singlethread_workqueue( "oo" ); + if(NULL==m_work_info.wq) { + MI_ERR("Failed to create workqueue !"); + return -1; + } + + INIT_DELAYED_WORK( &m_work_info.read_work, sensor_read_work ); + INIT_DELAYED_WORK( &m_work_info.write_work, sensor_write_work ); +#endif + i2c_smbus_read((PLAT_HANDLE) client, NSA_REG_WHO_AM_I, &chip_id); + if(chip_id != 0x13){ + for(i=0;i<5;i++){ + mdelay(5); + i2c_smbus_read((PLAT_HANDLE) client, NSA_REG_WHO_AM_I, &chip_id); + if(chip_id == 0x13) + break; + } + if(i == 5) + client->addr = 0x27; + } + + mir_handle = mir3da_core_init(client); + if(NULL == mir_handle){ + MI_ERR("chip init failed !\n"); + return -1; + } + + if(withSysAttr) + { + struct input_dev* pInputDev; + pInputDev = input_allocate_device(); + if (!pInputDev) { + MI_ERR("Failed to allocate input device %s\n", sensor->input_dev->name); + return -ENOMEM; + } + + pInputDev->name = MIR3DA_INPUT_DEV_NAME; + 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) { + MI_ERR("Unable to register input device %s\n", pInputDev->name); + return -ENOMEM; + } + MI_MSG("Sys Attribute Register here %s is called for MIR3DA.\n", __func__); + + ret = sysfs_create_group(&pInputDev->dev.kobj, &mir3da_attr_group); + if (ret) { + MI_ERR("mir3da_attr_group create Error err=%d..", ret); + ret = -EINVAL; + } + + withSysAttr = 0; + } + + is_init =1; + + return ret; +} +/******************************************************************************/ +static int sensor_active(struct i2c_client *client, int enable, int rate) +{ + int result = 0; + + MI_MSG("%s. enable=%d.\n", __func__,enable); + + if(!is_init) + return -1; + + mdelay(10); + if(enable){ + /* result = mir3da_chip_resume(client); + if(result) { + MI_ERR("sensor_active chip resume fail!!\n"); + return result; + } +*/ + result = mir3da_set_enable(client, true); + if(result){ + MI_ERR("sensor_active enable fail!!\n"); + return result; + } + } + else{ + result = mir3da_set_enable(client, false); + if(result){ + MI_ERR("sensor_active disable fail!!\n"); + return result; + } + } + mdelay(10); + + return result; +} +/******************************************************************************/ +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; + struct sensor_axis axis; + int ret = 0; + short x=0,y=0,z=0; + int tmp_x=0,tmp_y=0,tmp_z=0; + static struct sensor_axis last_axis; + static int flag; + + if(!is_init) + return -1; + + ret = mir3da_read_data (client,&x, &y, &z); + if (ret){ + MI_ERR("read data failed!"); + return ret; + } + + //MI_DATA(" x = %d, y = %d, z = %d\n", x, y, z); + + tmp_x = x*DA311_GRAVITY_STEP; + tmp_y = y*DA311_GRAVITY_STEP; + tmp_z = z*DA311_GRAVITY_STEP; + + //MI_DATA(" tmp_x = %d, tmp_y = %d, tmp_z = %d\n", tmp_x, tmp_y, tmp_z); + + axis.x = (pdata->orientation[0])*tmp_x + (pdata->orientation[1])*tmp_y + (pdata->orientation[2])*tmp_z; + axis.y = (pdata->orientation[3])*tmp_x + (pdata->orientation[4])*tmp_y + (pdata->orientation[5])*tmp_z; +#if MIR3DA_STK_TEMP_SOLUTION + axis.z = (pdata->orientation[6])*tmp_x + (pdata->orientation[7])*tmp_y + (bzstk?1:(pdata->orientation[8]))*tmp_z; +#else + axis.z = (pdata->orientation[6])*tmp_x + (pdata->orientation[7])*tmp_y + (pdata->orientation[8])*tmp_z; +#endif + //MI_DATA( "map: axis = %d %d %d \n", axis.x, axis.y, axis.z); +#if 0 + if (axis.x == last_axis.x && axis.y == last_axis.y && axis.z == last_axis.z) + axis.x += 1; +#else + if ((sensor->axis.x == axis.x) && (sensor->axis.y == axis.y) && (sensor->axis.z == axis.z)) { + if (flag) { + flag = 0; + axis.x += 1; + axis.y += 1; + axis.z += 1; + } else { + flag = 1; + axis.x -= 1; + axis.y -= 1; + axis.z -= 1; + } + } +#endif + // 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)) + { + + /* RK3326 platform board */ +#if defined (CONFIG_BOARD_RK3326_AK47) + input_report_abs(sensor->input_dev, ABS_X, -(axis.y/64)); + input_report_abs(sensor->input_dev, ABS_Y, -(axis.x/64)); + input_report_abs(sensor->input_dev, ABS_Z, -(axis.z/64)); +#elif defined (CONFIG_BOARD_RK3326_TH700) + input_report_abs(sensor->input_dev, ABS_X, -(axis.y/64)); + input_report_abs(sensor->input_dev, ABS_Y, -(axis.x/64)); + input_report_abs(sensor->input_dev, ABS_Z, -(axis.z/64)); +#elif defined(CONFIG_BOARD_RK3326_TH863B_10) + input_report_abs(sensor->input_dev, ABS_X, -(axis.x/64)); + input_report_abs(sensor->input_dev, ABS_Y, (axis.y/64)); + input_report_abs(sensor->input_dev, ABS_Z, -(axis.z/64)); +#elif defined(CONFIG_BOARD_RK3326_TH863B_7) + input_report_abs(sensor->input_dev, ABS_X, -(axis.x/64)); + input_report_abs(sensor->input_dev, ABS_Y, (axis.y/64)); + input_report_abs(sensor->input_dev, ABS_Z, -(axis.z/64)); +#elif defined(CONFIG_BOARD_RK3326_TH863B_V31_7) + input_report_abs(sensor->input_dev, ABS_X, -(axis.x/64)); + input_report_abs(sensor->input_dev, ABS_Y, (axis.y/64)); + input_report_abs(sensor->input_dev, ABS_Z, -(axis.z/64)); +#elif defined(CONFIG_BOARD_RK3326_TH863B_8) + input_report_abs(sensor->input_dev, ABS_X, (axis.y/64)); + input_report_abs(sensor->input_dev, ABS_Y, (axis.x/64)); + input_report_abs(sensor->input_dev, ABS_Z, -(axis.z/64)); +#elif defined(CONFIG_BOARD_RK3326_TH7926_7) + input_report_abs(sensor->input_dev, ABS_X, -(axis.y/64)); + input_report_abs(sensor->input_dev, ABS_Y, -(axis.x/64)); + input_report_abs(sensor->input_dev, ABS_Z, -(axis.z/64)); +#elif defined(CONFIG_BOARD_RK3326_TH7926_9) + input_report_abs(sensor->input_dev, ABS_X, -(axis.y/64)); + input_report_abs(sensor->input_dev, ABS_Y, -(axis.x/64)); + input_report_abs(sensor->input_dev, ABS_Z, -(axis.z/64)); +#elif defined(CONFIG_BOARD_RK3326_MT1011) + input_report_abs(sensor->input_dev, ABS_X, (axis.y/64)); + input_report_abs(sensor->input_dev, ABS_Y, (axis.x/64)); + input_report_abs(sensor->input_dev, ABS_Z, -(axis.z/64)); +#elif defined(CONFIG_BOARD_RK3326_M1011QR) + input_report_abs(sensor->input_dev, ABS_X, (axis.y/64)); + input_report_abs(sensor->input_dev, ABS_Y, (axis.x/64)); + input_report_abs(sensor->input_dev, ABS_Z, -(axis.z/64)); +#elif defined(CONFIG_BOARD_RK3326_TH1021DN) + input_report_abs(sensor->input_dev, ABS_X, -(axis.x/64)); + input_report_abs(sensor->input_dev, ABS_Y, (axis.y/64)); + input_report_abs(sensor->input_dev, ABS_Z, -(axis.z/64)); +#elif defined(CONFIG_BOARD_RK3326_TH1021DN_V20) + input_report_abs(sensor->input_dev, ABS_X, -(axis.x/64)); + input_report_abs(sensor->input_dev, ABS_Y, (axis.y/64)); + input_report_abs(sensor->input_dev, ABS_Z, -(axis.z/64)); + + /* RK3126C platform board */ +#elif defined(CONFIG_BOARD_RK3126C_AK47) + input_report_abs(sensor->input_dev, ABS_X, (axis.y/64)); + input_report_abs(sensor->input_dev, ABS_Y, (axis.x/64)); + input_report_abs(sensor->input_dev, ABS_Z, -(axis.z/64)); +#elif defined(CONFIG_BOARD_RK3126C_TH1021DN) + input_report_abs(sensor->input_dev, ABS_X, (axis.x/64)); + input_report_abs(sensor->input_dev, ABS_Y, -(axis.y/64)); + input_report_abs(sensor->input_dev, ABS_Z, -(axis.z/64)); +#elif defined(CONFIG_BOARD_RK3126C_TH863_7) + input_report_abs(sensor->input_dev, ABS_X, -(axis.x/64)); + input_report_abs(sensor->input_dev, ABS_Y, (axis.y/64)); + input_report_abs(sensor->input_dev, ABS_Z, -(axis.z/64)); +#elif defined(CONFIG_BOARD_RK3126C_TH863_8) + input_report_abs(sensor->input_dev, ABS_X, (axis.y/64)); + input_report_abs(sensor->input_dev, ABS_Y, (axis.x/64)); + input_report_abs(sensor->input_dev, ABS_Z, -(axis.z/64)); +#elif defined(CONFIG_BOARD_RK3126C_TH98V) + input_report_abs(sensor->input_dev, ABS_X, (axis.y/64)); + input_report_abs(sensor->input_dev, ABS_Y, (axis.x/64)); + input_report_abs(sensor->input_dev, ABS_Z, -(axis.z/64)); + + /* RK3368 platform board */ +#elif defined(CONFIG_BOARD_RK3368_TH863C_10) + input_report_abs(sensor->input_dev, ABS_X, -(axis.x/64)); + input_report_abs(sensor->input_dev, ABS_Y, (axis.y/64)); + input_report_abs(sensor->input_dev, ABS_Z, -(axis.z/64)); +#else + input_report_abs(sensor->input_dev, ABS_X, -(axis.x/64)); + input_report_abs(sensor->input_dev, ABS_Y, (axis.y/64)); + input_report_abs(sensor->input_dev, ABS_Z, -(axis.z/64)); +#endif + + input_sync(sensor->input_dev); + last_axis = axis; + + mutex_lock(&(sensor->data_mutex) ); + sensor->axis = axis; + mutex_unlock(&(sensor->data_mutex) ); + } + + return ret; +} +/******************************************************************************/ +static int sensor_suspend(struct i2c_client *client) +{ + int result = 0; + + MI_FUN; + + mdelay(10); + + result = mir3da_set_enable(client, false); + if(result){ + MI_ERR("sensor_suspend disable fail!!\n"); + return result; + } + + mdelay(10); + + return result; +} + +/******************************************************************************/ +static int sensor_resume(struct i2c_client *client) +{ + int result = 0; + + MI_FUN; + + mdelay(10); + + /* + result = mir3da_chip_resume(client); + if(result) { + MI_ERR("sensor_resume chip resume fail!!\n"); + return result; + } + */ + result = mir3da_set_enable(client, true); + if(result){ + MI_ERR("sensor_resume enable fail!!\n"); + return result; + } + + mdelay(10); + + return result; +} + +/******************************************************************************/ +struct sensor_operate gsensor_ops = { + .name = MIR3DA_DRV_NAME, + .type = SENSOR_TYPE_ACCEL, + .id_i2c = ACCEL_ID_MIR3DA, + .read_reg =-1, + .read_len = 0, + .id_reg = -1, + .id_data = 0, + .precision = MIR3DA_PRECISION, + .ctrl_reg = -1, + .int_status_reg = 0x00, + .range = {-MIR3DA_RANGE,MIR3DA_RANGE}, + .trig = IRQF_TRIGGER_LOW|IRQF_ONESHOT, + .active = sensor_active, + .init = sensor_init, + .report = sensor_report_value, + .suspend =sensor_suspend, + .resume =sensor_resume, +}; +/******************************************************************************/ +static struct sensor_operate *gsensor_get_ops(void) +{ + return &gsensor_ops; +} +/******************************************************************************/ +static int __init mir3da_init(void) +{ + struct sensor_operate *ops = gsensor_get_ops(); + int result = 0; + int type = ops->type; + + MI_FUN; + + result = sensor_register_slave(type, NULL, NULL, gsensor_get_ops); + return result; +} +/******************************************************************************/ +static void __exit mir3da_exit(void) +{ + struct sensor_operate *ops = gsensor_get_ops(); + int type = ops->type; + + MI_FUN; + + sensor_unregister_slave(type, NULL, NULL, gsensor_get_ops); +} +/******************************************************************************/ + +module_init(mir3da_init); +module_exit(mir3da_exit); diff --git a/drivers/input/sensors/accel/da223_cust.h b/drivers/input/sensors/accel/da223_cust.h new file mode 100644 index 000000000000..e6bf15a02da8 --- /dev/null +++ b/drivers/input/sensors/accel/da223_cust.h @@ -0,0 +1,44 @@ +/* For RockChip android platform. + * + * mir3da.h - Linux kernel modules for 3-Axis Accelerometer + * + * Copyright (C) 2011-2013 MiraMEMS Sensing Technology Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef __MIR3DA_STANDARD_H__ +#define __MIR3DA_STANDARD_H__ + +#include +#include +#include "da223_core.h" + +#define DRI_VER "1.0" +#define MIR3DA_I2C_ADDR 0x26//0x26<-> SD0=GND;0x27<-> SD0=High + +#define MIR3DA_ACC_IOCTL_BASE 88 +#define IOCTL_INDEX_BASE 0x00 + +#define MIR3DA_ACC_IOCTL_SET_DELAY _IOW(MIR3DA_ACC_IOCTL_BASE, IOCTL_INDEX_BASE, int) +#define MIR3DA_ACC_IOCTL_GET_DELAY _IOR(MIR3DA_ACC_IOCTL_BASE, IOCTL_INDEX_BASE+1, int) +#define MIR3DA_ACC_IOCTL_SET_ENABLE _IOW(MIR3DA_ACC_IOCTL_BASE, IOCTL_INDEX_BASE+2, int) +#define MIR3DA_ACC_IOCTL_GET_ENABLE _IOR(MIR3DA_ACC_IOCTL_BASE, IOCTL_INDEX_BASE+3, int) +#define MIR3DA_ACC_IOCTL_SET_G_RANGE _IOW(MIR3DA_ACC_IOCTL_BASE, IOCTL_INDEX_BASE+4, int) +#define MIR3DA_ACC_IOCTL_GET_G_RANGE _IOR(MIR3DA_ACC_IOCTL_BASE, IOCTL_INDEX_BASE+5, int) + +#define MIR3DA_ACC_IOCTL_GET_COOR_XYZ _IOW(MIR3DA_ACC_IOCTL_BASE, IOCTL_INDEX_BASE+22, int) +#define MIR3DA_ACC_IOCTL_CALIBRATION _IOW(MIR3DA_ACC_IOCTL_BASE, IOCTL_INDEX_BASE+23, int) +#define MIR3DA_ACC_IOCTL_UPDATE_OFFSET _IOW(MIR3DA_ACC_IOCTL_BASE, IOCTL_INDEX_BASE+24, int) + +#endif /* !__MIR3DA_STANDARD_H__ */ + + diff --git a/drivers/input/sensors/accel/sc7660.c b/drivers/input/sensors/accel/sc7660.c new file mode 100644 index 000000000000..0a0b0b0a9dbe --- /dev/null +++ b/drivers/input/sensors/accel/sc7660.c @@ -0,0 +1,1651 @@ +/* drivers/input/sensors/access/sc7660.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 +#ifdef CONFIG_HAS_EARLYSUSPEND +#include +#endif +#include + +#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.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 +//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************/ + +//function name should not be changed +static struct sensor_operate *gsensor_get_ops(void) +{ + return &gsensor_sc7660_ops; +} + + +static int __init gsensor_sc7660_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_sc7660_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_sc7660_init); +module_exit(gsensor_sc7660_exit); + + + diff --git a/drivers/input/sensors/accel/sc7a20.c b/drivers/input/sensors/accel/sc7a20.c new file mode 100644 index 000000000000..ffafc9a887c6 --- /dev/null +++ b/drivers/input/sensors/accel/sc7a20.c @@ -0,0 +1,1764 @@ +/* drivers/input/sensors/access/sc7a20.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 +#ifdef CONFIG_HAS_EARLYSUSPEND +#include +#endif +#include + +#define SC7A20_ENABLE 1 +#define SC7A20_XOUT_L 0x28 +#define SC7A20_XOUT_H 0x29 +#define SC7A20_YOUT_L 0x2A +#define SC7A20_YOUT_H 0x2B +#define SC7A20_ZOUT_L 0x2C +#define SC7A20_ZOUT_H 0x2D +#define SC7A20_MODE 0x20 +#define SC7A20_MODE1 0x21 +#define SC7A20_MODE2 0x22 +#define SC7A20_MODE3 0x23 +#define SC7A20_BOOT 0x24 +#define SC7A20_STATUS 0x27 +#define SC7A20_50HZ 0x40 +#define SC7A20_100HZ 0x50 +#define SC7A20_200HZ 0x60 +#define SC7A20_400HZ 0x70 +#define SC7A20_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 SC7A20_PRECISION 12 +#define SC7A20_BOUNDARY (0x1 << (SC7A20_PRECISION - 1)) +#define SC7A20_GRAVITY_STEP (SC7A20_RANGE / SC7A20_BOUNDARY) + +#define SC7A20_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 sc7a20_acc_get_data( int *xyz); + +struct SC7A20_acc{ + int x; + int y; + int z; +} ; + +static struct SC7A20_acc offset1; +//static int calibrated; +static struct i2c_client *sc7a20_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_sc7a20(unsigned char reg) +{ + char buffer[3]={0}; + *buffer = reg; + sensor_rx_data(sc7a20_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 = SC7A20_STATUS; + ret = sensor_rx_data(sc7a20_client, buffer,1); + + if( (buffer[0] & 0x08) != 0 ) + { + break; + } + //msleep(1); + + index++; + + if(index > 40) + break; + + } + + + *buffer = SC7A20_XOUT_L; + ret = sensor_rx_data(sc7a20_client, buffer,1); + *buffer = SC7A20_XOUT_H; + ret = sensor_rx_data(sc7a20_client, buffer,1); + acc_buf[1] = buffer[0]; + + + *buffer = SC7A20_YOUT_L; + ret = sensor_rx_data(sc7a20_client, buffer,1); + *buffer = SC7A20_YOUT_H; + ret = sensor_rx_data(sc7a20_client, buffer,1); + acc_buf[3] = buffer[0]; + + *buffer = SC7A20_ZOUT_L; + ret = sensor_rx_data(sc7a20_client, buffer,1); + *buffer = SC7A20_ZOUT_H; + ret = sensor_rx_data(sc7a20_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 = SC7A20_STATUS; + //ret = sensor_rx_data(sc7a20_client, buffer,1); + buffer[0] = Read_Reg_sc7a20(0x27); + if( (buffer[0] & 0x08) != 0 ){break;} + index++; + if(index > 40)break; + } + //6 register data be read out + *buffer = SC7A20_XOUT_L; + ret = sensor_rx_data(sc7a20_client, buffer,1); + acc_buf[0] = buffer[0]; + *buffer = SC7A20_XOUT_H; + ret = sensor_rx_data(sc7a20_client, buffer,1); + acc_buf[1] = buffer[0]; + + *buffer = SC7A20_YOUT_L; + ret = sensor_rx_data(sc7a20_client, buffer,1); + acc_buf[2] = buffer[0]; + *buffer = SC7A20_YOUT_H; + ret = sensor_rx_data(sc7a20_client, buffer,1); + acc_buf[3] = buffer[0]; + + *buffer = SC7A20_ZOUT_L; + ret = sensor_rx_data(sc7a20_client, buffer,1); + acc_buf[4] = buffer[0]; + *buffer = SC7A20_ZOUT_H; + ret = sensor_rx_data(sc7a20_client, buffer,1); + acc_buf[5] = buffer[0]; +} + +static void Write_Input(char addr, char thedata) +{ + int result; + result = sensor_write_reg(sc7a20_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(sc7a20_client, buffer,1); + mtpread[0]=(signed char)buffer[0]; + + *buffer = 0x11; + sensor_rx_data(sc7a20_client, buffer,1); + mtpread[1]=(signed char)buffer[0]; + + *buffer = 0x12; + sensor_rx_data(sc7a20_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_sc7a20(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(sc7a20_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(sc7a20_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.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 +//cali mis for zero in 25 LSB +//=========================================================================== + + + + return 1; +} + +static int auto_calibration_instant_mtp_sc7a20(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_sc7a20(x,y,z)==0) + { + printk("auto_calibration_instant ==0 \n"); + sensor_write_reg(sc7a20_client, 0x1e,0x05); + mdelay(100); + sensor_write_reg(sc7a20_client, 0x13,0x01); + + sensor_write_reg(sc7a20_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(sc7a20_client, tbuffer,1); + readbuf[0]= Read_Reg_sc7a20(0x10); + //*tbuffer = 0x40; + //sensor_rx_data(sc7a20_client, tbuffer,1); + readbuf[1]= Read_Reg_sc7a20(0x40); + //*tbuffer = 0x47; + //sensor_rx_data(sc7a20_client, tbuffer,1); + readbuf[2]= Read_Reg_sc7a20(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(sc7a20_client, tbuffer,1); + readbuf[0]= Read_Reg_sc7a20(0x11); + //*tbuffer = 0x41; + //sensor_rx_data(sc7a20_client, tbuffer,1); + readbuf[1]= Read_Reg_sc7a20(0x41); + //*tbuffer = 0x48; + //sensor_rx_data(sc7a20_client, tbuffer,1); + readbuf[2]= Read_Reg_sc7a20(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(sc7a20_client, tbuffer,1); + readbuf[0]= Read_Reg_sc7a20(0x12); + //*tbuffer = 0x42; + //sensor_rx_data(sc7a20_client, tbuffer,1); + readbuf[1]= Read_Reg_sc7a20(0x42); + //*tbuffer = 0x49; + //sensor_rx_data(sc7a20_client, tbuffer,1); + readbuf[2]= Read_Reg_sc7a20(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(sc7a20_client,0x13,0x01);//allen MTP + reg_13 = sensor_read_reg(sc7a20_client,0x13); + printk("line %d reg_13 = %x\n",__LINE__,reg_13); + Write_Input(0x1e, 0x15); //保存校准寄存器的修改 + mdelay(300); + reg_13 = sensor_read_reg(sc7a20_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(sc7a20_client,0x13,0x01);//allen MTP + reg_13 = sensor_read_reg(sc7a20_client,0x13); + printk("line %d reg_13 = %x\n",__LINE__,reg_13); + Write_Input(0x1e, 0x15); //保存校准寄存器的修改 + mdelay(300); + reg_13 = sensor_read_reg(sc7a20_client,0x13); + printk("line %d reg_13 = %x\n",__LINE__,reg_13); + Write_Input(0x1e, 0); + return 0; + } +} + + + + + +static ssize_t SC7A20_3_axis_Calibration(struct device *dev,struct device_attribute *attr ,const char *buf, size_t count) +{ + //unsigned temp[3]; + //struct SC7A20_acc acc={0,0,-64}; + unsigned adj_ok = 0; + + Write_Input(0x1e, 0x05); //为校准寄存器的修改开放权限 + Write_Input(0x20, 0x77); + adj_ok = auto_calibration_instant_mtp_sc7a20(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 SC7A20_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 SC7A20_calibration_value_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "%d %d %d\n", offset1.x,offset1.y,offset1.z); +} + +static ssize_t SC7A20_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]); + offset1.x = data[0]; + offset1.y = data[1]; + offset1.z = data[2]; + printk(KERN_INFO "set calibration finished\n"); + return count; +} + +static ssize_t SC7A20_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(sc7a20_client, address,value); + + if(result) + printk("%s:fail to write sensor_register\n",__func__); + + return count; +} + +static ssize_t SC7A20_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(sc7a20_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(sc7a20_client, &buffer[0], 1); + count += sprintf(&buf[count],"0x%x: 0x%x\n", i, buffer[0]); + } + return count; +} + +static ssize_t SC7A20_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 = SC7A20_STATUS; + ret = sensor_rx_data(sc7a20_client, buffer1,1); + buffer1[0] &= 0x08; + if(!buffer1[0]) + return sprintf(buf, "SC7A20 data is not ready!\n"); + + *buffer1 = SC7A20_XOUT_L; + ret = sensor_rx_data(sc7a20_client, buffer1,1); + *buffer2 = SC7A20_XOUT_H; + ret = sensor_rx_data(sc7a20_client, buffer2,1); + x = (((s16)((buffer2[0] << 8) + buffer1[0])) >>4); + + *buffer1 = SC7A20_YOUT_L; + ret = sensor_rx_data(sc7a20_client, buffer1,1); + *buffer2 = SC7A20_YOUT_H; + ret = sensor_rx_data(sc7a20_client, buffer2,1); + y = (((s16)((buffer2[0] << 8) + buffer1[0])) >>4); + + *buffer1 = SC7A20_ZOUT_L; + ret = sensor_rx_data(sc7a20_client, buffer1,1); + *buffer2 = SC7A20_ZOUT_H; + ret = sensor_rx_data(sc7a20_client, buffer2,1); + z = (((s16)((buffer2[0] << 8) + buffer1[0])) >>4); + + if (ret < 0) + return sprintf(buf, "SC7A20_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, + SC7A20_register_show, SC7A20_register_store); + +static DEVICE_ATTR(calibration_run, 0664, //calibration_run + NULL, SC7A20_3_axis_Calibration); +static DEVICE_ATTR(calibration_reset, 0664, + NULL, SC7A20_calibration_reset_store); +static DEVICE_ATTR(calibration_value,0664, + SC7A20_calibration_value_show, + SC7A20_calibration_value_store); +static DEVICE_ATTR(value, 0664, + SC7A20_value_show, NULL); + +static struct attribute *SC7A20_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 SC7A20_attribute_group = { + .attrs = SC7A20_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 = SC7A20_ENABLE; //sc7a20 + sensor->ops->ctrl_data |= SC7A20_400HZ; + } + else + status = ~SC7A20_ENABLE; //sc7a20 + + + 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, SC7A20_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; + } + sc7a20_client = client; + sensor->status_cur = SENSOR_OFF; + //sensor->time_of_cali =0;//allen + offset1.x=offset1.y=offset1.z=0; + + + *chip_id = 0x0f; + ret = sensor_rx_data(client, chip_id,1); + printk("sc7a20_chip_id is %d",chip_id[0]); + + sensor_write_reg(client, SC7A20_BOOT, 0x80); + mdelay(20); + sensor_write_reg(client, SC7A20_MODE3, 0x88); + + result = sensor_write_reg(client, SC7A20_MODE, 0x07); + + + //HR mode //sc7a20 + + + //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, SC7A20_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 = "sc7a20"; + 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, &SC7A20_attribute_group); + if (ret) { + DBG("sc7a20 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 < SC7A20_BOUNDARY) + result = result* SC7A20_GRAVITY_STEP; + else + result = ~( ((~result & (0x7ffff>>(20-SC7A20_PRECISION)) ) + 1) + * SC7A20_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 */ + + /* 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->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_TH7926_9) + 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_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->x); + input_report_abs(sensor->input_dev, ABS_Y,-axis->y); + 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; + static int flag; + + //SC7A20_load_user_calibration(client); + memset(buffer1, 0, 3); + memset(buffer2, 0, 3); + + *buffer1 = SC7A20_STATUS; + ret = sensor_rx_data(sc7a20_client, buffer1,1); + buffer1[0] &= 0x08; + if(!buffer1[0]) + return ret; + + *buffer1 = SC7A20_XOUT_L; + ret = sensor_rx_data(sc7a20_client, buffer1,1); + *buffer2 = SC7A20_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 = SC7A20_YOUT_L; + ret = sensor_rx_data(sc7a20_client, buffer1,1); + *buffer2 = SC7A20_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 = SC7A20_ZOUT_L; + ret = sensor_rx_data(sc7a20_client, buffer1,1); + *buffer2 = SC7A20_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; + +#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 >= SC7A20_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) ); + } + } +#else + /* + *input dev will ignore report data if data value is the same with last_value, + *sample rate will not enough by this way, so just avoid this case + */ + if ((sensor->axis.x == axis.x) && (sensor->axis.y == axis.y) && (sensor->axis.z == axis.z)) { + if (flag) { + flag = 0; + axis.x += 1; + axis.y += 1; + axis.z += 1; + } else { + flag = 1; + axis.x -= 1; + axis.y -= 1; + axis.z -= 1; + } + } + + 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); + DBG("%s:sensor int status :0x%x\n",__func__,value); + } + + return ret; +} + + +static struct sensor_operate gsensor_sc7a20_ops = { + .name = "gs_sc7a20", + .type = SENSOR_TYPE_ACCEL, //sensor type and it should be correct + .id_i2c = ACCEL_ID_SC7A20, //i2c id number + .read_reg = SC7A20_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 = SC7A20_PRECISION, //12 bit + .ctrl_reg = SC7A20_MODE, //enable or disable SC7A20_MODE + .int_status_reg = SENSOR_UNKNOW_DATA, //intterupt status register + .range = {-SC7A20_RANGE,SC7A20_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_sc7a20_ops; +} + + +static int __init gsensor_sc7a20_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_sc7a20_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_sc7a20_init); +module_exit(gsensor_sc7a20_exit); + + + diff --git a/drivers/input/sensors/sensor-dev.c b/drivers/input/sensors/sensor-dev.c index 22411ae98509..1ea9d153cbfb 100644 --- a/drivers/input/sensors/sensor-dev.c +++ b/drivers/input/sensors/sensor-dev.c @@ -2016,6 +2016,8 @@ static const struct i2c_device_id sensor_id[] = { {"gs_mxc6655xa", ACCEL_ID_MXC6655XA}, {"gs_dmard10", ACCEL_ID_DMARD10}, {"gs_lsm303d", ACCEL_ID_LSM303D}, + {"gs_sc7660", ACCEL_ID_SC7660}, + {"gs_sc7a20", ACCEL_ID_SC7A20}, {"gs_sc7a30",ACCEL_ID_SC7A30}, {"gs_mc3230", ACCEL_ID_MC3230}, {"mpu6880_acc", ACCEL_ID_MPU6880}, @@ -2023,6 +2025,7 @@ static const struct i2c_device_id sensor_id[] = { {"lsm330_acc", ACCEL_ID_LSM330}, {"bma2xx_acc", ACCEL_ID_BMA2XX}, {"gs_stk8baxx", ACCEL_ID_STK8BAXX}, + {"gs_da223", ACCEL_ID_MIR3DA}, /*compass*/ {"compass", COMPASS_ID_ALL}, {"ak8975", COMPASS_ID_AK8975}, diff --git a/include/linux/sensor-dev.h b/include/linux/sensor-dev.h index 81074d69b61e..9aaab331fdaa 100644 --- a/include/linux/sensor-dev.h +++ b/include/linux/sensor-dev.h @@ -51,6 +51,8 @@ enum sensor_id { ACCEL_ID_MMA8450, ACCEL_ID_MMA845X, ACCEL_ID_MMA7660, + ACCEL_ID_SC7660, + ACCEL_ID_SC7A20, ACCEL_ID_SC7A30, ACCEL_ID_MPU6050, ACCEL_ID_MXC6225, @@ -63,6 +65,7 @@ enum sensor_id { ACCEL_ID_LSM330, ACCEL_ID_BMA2XX, ACCEL_ID_STK8BAXX, + ACCEL_ID_MIR3DA, COMPASS_ID_ALL, COMPASS_ID_AK8975, COMPASS_ID_AK8963,