/* * stk8baxx.c - Linux kernel modules for sensortek stk8ba50 / stk8ba50-R / * stk8ba53 accelerometer * * Copyright (C) 2012~2016 Lex Hsieh / Sensortek * * 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. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define STK_ACC_DRIVER_VERSION "3.7.1_rk_0425_0428" /*------------------User-defined settings-------------------------*/ /* #define CONFIG_SENSORS_STK8BA53 */ #define CONFIG_SENSORS_STK8BA50 /* #define STK_DEBUG_PRINT */ /* #define STK_LOWPASS */ #define STK_FIR_LEN 4 /* 1~32 */ /* #define STK_TUNE */ /* #define STK_ZG_FILTER */ #define STK_HOLD_ODR #define STK_DEBUG_CALI #define STK8BAXX_DEF_PLACEMENT 7 /*------------------Miscellaneous settings-------------------------*/ #define STK8BAXX_I2C_NAME "stk8baxx" #define ACC_IDEVICE_NAME "accelerometer" #define STK8BAXX_INIT_ODR 0xD /* 0xB:125Hz, 0xA:62Hz */ #define STK8BAXX_RNG_2G 0x3 #define STK8BAXX_RNG_4G 0x5 #define STK8BAXX_RNG_8G 0x8 #define STK8BAXX_RNG_16G 0xC #ifdef CONFIG_SENSORS_STK8BA53 /* Parameters under +-4g dynamic range */ #define STK_DEF_DYNAMIC_RANGE STK8BAXX_RNG_4G #if (STK_DEF_DYNAMIC_RANGE == STK8BAXX_RNG_4G) #define STK_LSB_1G 512 #define STK_DEF_RANGE 4 #elif (STK_DEF_DYNAMIC_RANGE == STK8BAXX_RNG_2G) #define STK_LSB_1G 1024 #define STK_DEF_RANGE 2 #elif (STK_DEF_DYNAMIC_RANGE == STK8BAXX_RNG_8G) #define STK_LSB_1G 256 #define STK_DEF_RANGE 8 #elif (STK_DEF_DYNAMIC_RANGE == STK8BAXX_RNG_16G) #define STK_LSB_1G 128 #define STK_DEF_RANGE 16 #endif #define STK_ZG_COUNT (STK_LSB_1G / 128) #define STK_TUNE_XYOFFSET (STK_LSB_1G * 3 / 10) #define STK_TUNE_ZOFFSET (STK_LSB_1G * 3 / 10) /* (STK_LSB_1G * 3 / 20) */ #define STK_TUNE_NOISE (STK_LSB_1G / 10) #else /* Parameters under +-2g dynamic range */ #define STK_DEF_DYNAMIC_RANGE STK8BAXX_RNG_2G #if (STK_DEF_DYNAMIC_RANGE == STK8BAXX_RNG_2G) #define STK_LSB_1G 256 #define STK_DEF_RANGE 2 #elif (STK_DEF_DYNAMIC_RANGE == STK8BAXX_RNG_4G) #define STK_LSB_1G 128 #define STK_DEF_RANGE 4 #elif (STK_DEF_DYNAMIC_RANGE == STK8BAXX_RNG_8G) #define STK_LSB_1G 64 #define STK_DEF_RANGE 8 #elif (STK_DEF_DYNAMIC_RANGE == STK8BAXX_RNG_16G) #define STK_LSB_1G 32 #define STK_DEF_RANGE 16 #endif #define STK_ZG_COUNT (STK_LSB_1G / 128 + 1) #define STK_TUNE_XYOFFSET (STK_LSB_1G * 4 / 10) #define STK_TUNE_ZOFFSET (STK_LSB_1G * 4 / 10) /* (STK_LSB_1G * 3 / 20) */ #define STK_TUNE_NOISE (STK_LSB_1G / 10) #endif #define STK8BAXX_RANGE_UG (STK_DEF_RANGE * 16384) /* STK_OFFSET_REG_LSB_1G is fixed for all dynamic range */ #define STK_OFFSET_REG_LSB_1G 128 #define STK_TUNE_NUM 60 #define STK_TUNE_DELAY 30 #define STK_EVENT_SINCE_EN_LIMIT_DEF (1) #define STK8BA50_ID 0x09 #define STK8BA50R_ID 0x86 #define STK8BA53_ID 0x87 /*------------------Calibration prameters-------------------------*/ #define STK_SAMPLE_NO 10 #define STK_ACC_CALI_VER0 0x18 #define STK_ACC_CALI_VER1 0x03 #define STK_ACC_CALI_END '\0' #define STK_ACC_CALI_FILE "/data/misc/stkacccali.conf" #define STK_ACC_CALI_FILE_SDCARD "/sdcard/.stkacccali.conf" #define STK_ACC_CALI_FILE_SIZE 25 #define STK_K_SUCCESS_TUNE 0x04 #define STK_K_SUCCESS_FT2 0x03 #define STK_K_SUCCESS_FT1 0x02 #define STK_K_SUCCESS_FILE 0x01 #define STK_K_NO_CALI 0xFF #define STK_K_RUNNING 0xFE #define STK_K_FAIL_LRG_DIFF 0xFD #define STK_K_FAIL_OPEN_FILE 0xFC #define STK_K_FAIL_W_FILE 0xFB #define STK_K_FAIL_R_BACK 0xFA #define STK_K_FAIL_R_BACK_COMP 0xF9 #define STK_K_FAIL_I2C 0xF8 #define STK_K_FAIL_K_PARA 0xF7 #define STK_K_FAIL_OUT_RG 0xF6 #define STK_K_FAIL_ENG_I2C 0xF5 #define STK_K_FAIL_FT1_USD 0xF4 #define STK_K_FAIL_FT2_USD 0xF3 #define STK_K_FAIL_WRITE_NOFST 0xF2 #define STK_K_FAIL_OTP_5T 0xF1 #define STK_K_FAIL_PLACEMENT 0xF0 /*------------------stk8baxx registers-------------------------*/ #define STK8BAXX_XOUT1 0x02 #define STK8BAXX_XOUT2 0x03 #define STK8BAXX_YOUT1 0x04 #define STK8BAXX_YOUT2 0x05 #define STK8BAXX_ZOUT1 0x06 #define STK8BAXX_ZOUT2 0x07 #define STK8BAXX_INTSTS1 0x09 #define STK8BAXX_INTSTS2 0x0A #define STK8BAXX_EVENTINFO1 0x0B #define STK8BAXX_EVENTINFO2 0x0C #define STK8BAXX_RANGESEL 0x0F #define STK8BAXX_BWSEL 0x10 #define STK8BAXX_POWMODE 0x11 #define STK8BAXX_DATASETUP 0x13 #define STK8BAXX_SWRST 0x14 #define STK8BAXX_INTEN1 0x16 #define STK8BAXX_INTEN2 0x17 #define STK8BAXX_INTMAP1 0x19 #define STK8BAXX_INTMAP2 0x1A #define STK8BAXX_INTMAP3 0x1B #define STK8BAXX_DATASRC 0x1E #define STK8BAXX_INTCFG1 0x20 #define STK8BAXX_INTCFG2 0x21 #define STK8BAXX_LGDLY 0x22 #define STK8BAXX_LGTHD 0x23 #define STK8BAXX_HLGCFG 0x24 #define STK8BAXX_HGDLY 0x25 #define STK8BAXX_HGTHD 0x26 #define STK8BAXX_SLOPEDLY 0x27 #define STK8BAXX_SLOPETHD 0x28 #define STK8BAXX_TAPTIME 0x2A #define STK8BAXX_TAPCFG 0x2B #define STK8BAXX_ORIENTCFG 0x2C #define STK8BAXX_ORIENTTHETA 0x2D #define STK8BAXX_FLATTHETA 0x2E #define STK8BAXX_FLATHOLD 0x2F #define STK8BAXX_SLFTST 0x32 #define STK8BAXX_INTFCFG 0x34 #define STK8BAXX_OFSTCOMP1 0x36 #define STK8BAXX_OFSTCOMP2 0x37 #define STK8BAXX_OFSTFILTX 0x38 #define STK8BAXX_OFSTFILTY 0x39 #define STK8BAXX_OFSTFILTZ 0x3A #define STK8BAXX_OFSTUNFILTX 0x3B #define STK8BAXX_OFSTUNFILTY 0x3C #define STK8BAXX_OFSTUNFILTZ 0x3D /* ZOUT1 register */ #define STK8BAXX_O_NEW 0x01 /* SWRST register */ #define STK8BAXX_SWRST_VAL 0xB6 /* STK8BAXX_POWMODE register */ #define STK8BAXX_MD_SUSPEND 0x80 #define STK8BAXX_MD_NORMAL 0x00 #define STK8BAXX_MD_SLP_MASK 0x1E /* RANGESEL register */ #define STK8BAXX_RANGE_MASK 0x0F /* OFSTCOMP1 register */ #define STK8BAXX_OF_CAL_DRY_MASK 0x10 #define CAL_AXIS_X_EN 0x20 #define CAL_AXIS_Y_EN 0x40 #define CAL_AXIS_Z_EN 0x60 #define CAL_OFST_RST 0x80 /* OFSTCOMP2 register */ #define CAL_TG_X0_Y0_ZPOS1 0x20 #define CAL_TG_X0_Y0_ZNEG1 0x40 /*no_create_attr:the initial is 1-->no create attr. if created, change no_create_att to 0.*/ static int no_create_att = 1; static int enable_status = -1; /*------------------Data structure-------------------------*/ struct stk8baxx_acc { union { struct { s16 x; s16 y; s16 z; }; s16 acc[3]; }; }; #if defined(STK_LOWPASS) #define MAX_FIR_LEN 32 struct data_filter { s16 raw[MAX_FIR_LEN][3]; int sum[3]; int num; int idx; }; #endif struct stk8baxx_data { struct i2c_client *client; struct input_dev *input_dev; int irq; struct stk8baxx_acc acc_xyz; atomic_t enabled; bool first_enable; struct work_struct stk_work; struct hrtimer acc_timer; struct workqueue_struct *stk_mems_work_queue; unsigned char stk8baxx_placement; atomic_t cali_status; atomic_t recv_reg; bool re_enable; #if defined(STK_LOWPASS) atomic_t firlength; atomic_t fir_en; struct data_filter fir; #endif int event_since_en; int event_since_en_limit; u8 stk_tune_offset_record[3]; #ifdef STK_TUNE int stk_tune_offset[3]; int stk_tune_sum[3]; int stk_tune_max[3]; int stk_tune_min[3]; int stk_tune_index; int stk_tune_done; s64 stk_tune_square_sum[3]; u32 variance[3]; #endif }; /*------------------Function prototype-------------------------*/ static int stk8baxx_set_enable(struct stk8baxx_data *stk, char en); static int stk8baxx_read_sensor_data(struct stk8baxx_data *stk); /*------------------Global variables-------------------------*/ static struct stk8baxx_data *stk8baxx_data_ptr; static struct sensor_private_data *sensor_ptr; /*------------------Main functions-------------------------*/ static s32 stk8baxx_smbus_write_byte_data(u8 command, u8 value) { return sensor_write_reg(stk8baxx_data_ptr->client, command, value); } static int stk8baxx_smbus_read_byte_data(u8 command) { return sensor_read_reg(stk8baxx_data_ptr->client, command); } static int stk8baxx_chk_for_addr(struct stk8baxx_data *stk, s32 org_address, unsigned short reset_address) { int result; s32 expected_reg0 = 0x86; if ((org_address & 0xFE) == 0x18) expected_reg0 = 0x86; else expected_reg0 = 0x87; stk->client->addr = reset_address; result = stk8baxx_smbus_write_byte_data(STK8BAXX_SWRST, STK8BAXX_SWRST_VAL); printk(KERN_INFO "%s:issue sw reset to 0x%x, result=%d\n", __func__, reset_address, result); usleep_range(2000, 3000); stk->client->addr = org_address; printk(KERN_INFO "%s Revise I2C Address = 0x%x\n", __func__, org_address); result = stk8baxx_smbus_write_byte_data(STK8BAXX_POWMODE, STK8BAXX_MD_NORMAL); result = stk8baxx_smbus_read_byte_data(0x0); if (result < 0) { printk(KERN_INFO "%s: read 0x0, result=%d\n", __func__, result); return result; } if (result == expected_reg0) { printk(KERN_INFO "%s:passed, expected_reg0=0x%x\n", __func__, expected_reg0); result = stk8baxx_smbus_write_byte_data(STK8BAXX_SWRST, STK8BAXX_SWRST_VAL); if (result < 0) { printk(KERN_ERR "%s:failed to issue software reset, error=%d\n", __func__, result); return result; } usleep_range(2000, 3000); return 1; } return 0; } static int stk8baxx_sw_reset(struct stk8baxx_data *stk) { unsigned short org_addr = 0; int result; org_addr = stk->client->addr; printk(KERN_INFO "%s:org_addr=0x%x\n", __func__, org_addr); if ((org_addr & 0xFE) == 0x18) { result = stk8baxx_chk_for_addr(stk, org_addr, 0x18); if (result == 1) return 0; result = stk8baxx_chk_for_addr(stk, org_addr, 0x19); if (result == 1) return 0; result = stk8baxx_chk_for_addr(stk, org_addr, 0x08); if (result == 1) return 0; result = stk8baxx_chk_for_addr(stk, org_addr, 0x28); if (result == 1) return 0; } else if (org_addr == 0x28) { result = stk8baxx_chk_for_addr(stk, org_addr, 0x28); if (result == 1) return 0; result = stk8baxx_chk_for_addr(stk, org_addr, 0x18); if (result == 1) return 0; result = stk8baxx_chk_for_addr(stk, org_addr, 0x08); if (result == 1) return 0; } result = stk8baxx_chk_for_addr(stk, org_addr, 0x0B); return 0; } static int stk8baxx_reg_init(struct stk8baxx_data *stk, struct i2c_client *client, struct sensor_private_data *sensor) { int result; int aa; #ifdef CONFIG_SENSORS_STK8BA53 printk(KERN_INFO "%s: Initialize stk8ba53\n", __func__); #else printk(KERN_INFO "%s: Initialize stk8ba50/stk8ba50-r\n", __func__); #endif /* sw reset */ result = stk8baxx_sw_reset(stk); if (result < 0) { printk(KERN_ERR "%s:failed to stk8baxx_sw_reset, error=%d\n", __func__, result); return result; } result = stk8baxx_smbus_write_byte_data(STK8BAXX_POWMODE, STK8BAXX_MD_NORMAL); if (result < 0) { printk(KERN_ERR "%s:failed to write reg 0x%x, error=%d\n", __func__, STK8BAXX_POWMODE, result); return result; } result = stk8baxx_smbus_read_byte_data(STK8BAXX_LGDLY); if (result < 0) { printk(KERN_ERR "%s: failed to read acc data, error=%d\n", __func__, result); return result; } if (result == STK8BA50_ID) { printk(KERN_INFO "%s: chip is stk8ba50\n", __func__); sensor->devid = STK8BA50_ID; } else { result = stk8baxx_smbus_read_byte_data(0x0); if (result < 0) { printk(KERN_ERR "%s: failed to read acc data, error=%d\n", __func__, result); return result; } printk(KERN_INFO "%s: 0x0=0x%x\n", __func__, result); if (result == STK8BA50R_ID) { printk(KERN_INFO "%s: chip is stk8ba50-R\n", __func__); sensor->devid = STK8BA50R_ID; } else { printk(KERN_INFO "%s: chip is stk8ba53\n", __func__); sensor->devid = STK8BA53_ID; } } #ifdef CONFIG_SENSORS_STK8BA53 if (sensor->devid != STK8BA53_ID) { printk(KERN_ERR "%s: stk8ba53 is not attached, devid=0x%x\n", __func__, sensor->devid); return -ENODEV; } #else if (sensor->devid == STK8BA53_ID) { printk(KERN_ERR "%s: stk8ba50/stk8ba50-R is not attached, devid=0x%x\n", __func__, sensor->devid); return -ENODEV; } #endif if (sensor->pdata->irq_enable) { /* map new data int to int1 */ result = stk8baxx_smbus_write_byte_data(STK8BAXX_INTMAP2, 0x01); if (result < 0) { printk(KERN_ERR "%s:failed to write reg 0x%x, error=%d\n", __func__, STK8BAXX_INTMAP2, result); return result; } /* enable new data in */ result = stk8baxx_smbus_write_byte_data(STK8BAXX_INTEN2, 0x10); if (result < 0) { printk(KERN_ERR "%s:failed to write reg 0x%x, error=%d\n", __func__, STK8BAXX_INTEN2, result); return result; } /* non-latch int */ result = stk8baxx_smbus_write_byte_data(STK8BAXX_INTCFG2, 0x00); if (result < 0) { printk(KERN_ERR "%s:failed to write reg 0x%x, error=%d\n", __func__, STK8BAXX_INTCFG2, result); return result; } /* filtered data source for new data int */ result = stk8baxx_smbus_write_byte_data(STK8BAXX_DATASRC, 0x00); if (result < 0) { printk(KERN_ERR "%s:failed to write reg 0x%x, error=%d\n", __func__, STK8BAXX_DATASRC, result); return result; } /* int1, push-pull, active high */ result = stk8baxx_smbus_write_byte_data(STK8BAXX_INTCFG1, 0x01); if (result < 0) { printk(KERN_ERR "%s:failed to write reg 0x%x, error=%d\n", __func__, STK8BAXX_INTCFG1, result); return result; } } #ifdef CONFIG_SENSORS_STK8BA53 /* +- 4g */ result = stk8baxx_smbus_write_byte_data(STK8BAXX_RANGESEL, STK_DEF_DYNAMIC_RANGE); if (result < 0) { printk(KERN_ERR "%s:failed to write reg 0x%x, error=%d\n", __func__, STK8BAXX_RANGESEL, result); return result; } #else /* +- 2g */ result = stk8baxx_smbus_write_byte_data(STK8BAXX_RANGESEL, STK_DEF_DYNAMIC_RANGE); if (result < 0) { printk(KERN_ERR "%s:failed to write reg 0x%x, error=%d\n", __func__, STK8BAXX_RANGESEL, result); return result; } #endif /* ODR = 62 Hz */ result = stk8baxx_smbus_write_byte_data(STK8BAXX_BWSEL, STK8BAXX_INIT_ODR); if (result < 0) { printk(KERN_ERR "%s:failed to write reg 0x%x, error=%d\n", __func__, STK8BAXX_BWSEL, result); return result; } /* i2c watchdog enable, 1 ms timer perios */ result = stk8baxx_smbus_write_byte_data(STK8BAXX_INTFCFG, 0x04); if (result < 0) { printk(KERN_ERR "%s:failed to write reg 0x%x, error=%d\n", __func__, STK8BAXX_INTFCFG, result); return result; } result = stk8baxx_smbus_write_byte_data(STK8BAXX_POWMODE, STK8BAXX_MD_SUSPEND); if (result < 0) { printk(KERN_ERR "%s:failed to write reg 0x%x, error=%d\n", __func__, STK8BAXX_POWMODE, result); return result; } atomic_set(&stk->enabled, 0); stk->first_enable = true; atomic_set(&stk->cali_status, STK_K_NO_CALI); atomic_set(&stk->recv_reg, 0); #ifdef STK_LOWPASS memset(&stk->fir, 0x00, sizeof(stk->fir)); atomic_set(&stk->firlength, STK_FIR_LEN); atomic_set(&stk->fir_en, 1); #endif for (aa = 0; aa < 3; aa++) stk->stk_tune_offset_record[aa] = 0; #ifdef STK_TUNE for (aa = 0; aa < 3; aa++) { stk->stk_tune_offset[aa] = 0; stk->stk_tune_sum[aa] = 0; stk->stk_tune_max[aa] = 0; stk->stk_tune_min[aa] = 0; stk->stk_tune_square_sum[aa] = 0LL; stk->variance[aa] = 0; } stk->stk_tune_done = 0; stk->stk_tune_index = 0; #endif stk->event_since_en_limit = STK_EVENT_SINCE_EN_LIMIT_DEF; return 0; } #ifdef STK_LOWPASS static void stk8baxx_low_pass(struct stk8baxx_data *stk, struct stk8baxx_acc *acc_lp) { int idx, firlength = atomic_read(&stk->firlength); #ifdef STK_ZG_FILTER s16 zero_fir = 0; #endif if (atomic_read(&stk->fir_en)) { if (stk->fir.num < firlength) { stk->fir.raw[stk->fir.num][0] = acc_lp->x; stk->fir.raw[stk->fir.num][1] = acc_lp->y; stk->fir.raw[stk->fir.num][2] = acc_lp->z; stk->fir.sum[0] += acc_lp->x; stk->fir.sum[1] += acc_lp->y; stk->fir.sum[2] += acc_lp->z; stk->fir.num++; stk->fir.idx++; } else { idx = stk->fir.idx % firlength; stk->fir.sum[0] -= stk->fir.raw[idx][0]; stk->fir.sum[1] -= stk->fir.raw[idx][1]; stk->fir.sum[2] -= stk->fir.raw[idx][2]; stk->fir.raw[idx][0] = acc_lp->x; stk->fir.raw[idx][1] = acc_lp->y; stk->fir.raw[idx][2] = acc_lp->z; stk->fir.sum[0] += acc_lp->x; stk->fir.sum[1] += acc_lp->y; stk->fir.sum[2] += acc_lp->z; stk->fir.idx++; #ifdef STK_ZG_FILTER if (abs(stk->fir.sum[0] / firlength) <= STK_ZG_COUNT) acc_lp->x = (stk->fir.sum[0] * zero_fir) / firlength; else acc_lp->x = stk->fir.sum[0] / firlength; if (abs(stk->fir.sum[1] / firlength) <= STK_ZG_COUNT) acc_lp->y = (stk->fir.sum[1] * zero_fir) / firlength; else acc_lp->y = stk->fir.sum[1] / firlength; if (abs(stk->fir.sum[2] / firlength) <= STK_ZG_COUNT) acc_lp->z = (stk->fir.sum[2] * zero_fir) / firlength; else acc_lp->z = stk->fir.sum[2] / firlength; #else acc_lp->x = stk->fir.sum[0] / firlength; acc_lp->y = stk->fir.sum[1] / firlength; acc_lp->z = stk->fir.sum[2] / firlength; #endif } } } #endif #ifdef STK_TUNE static void stk8baxx_reset_para(struct stk8baxx_data *stk) { int ii; for (ii = 0; ii < 3; ii++) { stk->stk_tune_sum[ii] = 0; stk->stk_tune_square_sum[ii] = 0LL; stk->stk_tune_min[ii] = 4096; stk->stk_tune_max[ii] = -4096; stk->variance[ii] = 0; } } static void stk8baxx_tune(struct stk8baxx_data *stk, struct stk8baxx_acc *acc_xyz) { int ii; u8 offset[3]; s16 acc[3]; s64 s64_temp; const s64 var_enlarge_scale = 64; if (stk->stk_tune_done != 0) return; acc[0] = acc_xyz->x; acc[1] = acc_xyz->y; acc[2] = acc_xyz->z; if (stk->event_since_en >= STK_TUNE_DELAY) { if ((abs(acc[0]) <= STK_TUNE_XYOFFSET) && (abs(acc[1]) <= STK_TUNE_XYOFFSET) && (abs(abs(acc[2]) - STK_LSB_1G) <= STK_TUNE_ZOFFSET)) { stk->stk_tune_index++; /* printk("\n-qhy20161108--%s----acc[0]=0x%x,,acc[1]=0x%x,,acc[2]=0x%x\n",__func__,acc[0],acc[1],acc[2]); */ } else { stk->stk_tune_index = 0; } if (stk->stk_tune_index == 0) { stk8baxx_reset_para(stk); /* printk("\n--qhy20161108--%s-- %d--\n",__func__,__LINE__); */ } else { for (ii = 0; ii < 3; ii++) { stk->stk_tune_sum[ii] += acc[ii]; stk->stk_tune_square_sum[ii] += acc[ii] * acc[ii]; if (acc[ii] > stk->stk_tune_max[ii]) stk->stk_tune_max[ii] = acc[ii]; if (acc[ii] < stk->stk_tune_min[ii]) stk->stk_tune_min[ii] = acc[ii]; } } if (stk->stk_tune_index == STK_TUNE_NUM) { for (ii = 0; ii < 3; ii++) { if ((stk->stk_tune_max[ii] - stk->stk_tune_min[ii]) > STK_TUNE_NOISE) { stk->stk_tune_index = 0; stk8baxx_reset_para(stk); return; } } stk->stk_tune_offset[0] = stk->stk_tune_sum[0] / STK_TUNE_NUM; stk->stk_tune_offset[1] = stk->stk_tune_sum[1] / STK_TUNE_NUM; if (acc[2] > 0) stk->stk_tune_offset[2] = stk->stk_tune_sum[2] / STK_TUNE_NUM - STK_LSB_1G; else stk->stk_tune_offset[2] = stk->stk_tune_sum[2] / STK_TUNE_NUM - (-STK_LSB_1G); offset[0] = (u8)(-stk->stk_tune_offset[0]); offset[1] = (u8)(-stk->stk_tune_offset[1]); offset[2] = (u8)(-stk->stk_tune_offset[2]); stk->stk_tune_offset_record[0] = offset[0]; stk->stk_tune_offset_record[1] = offset[1]; stk->stk_tune_offset_record[2] = offset[2]; stk->stk_tune_done = 1; atomic_set(&stk->cali_status, STK_K_SUCCESS_TUNE); stk->event_since_en = 0; printk(KERN_INFO "%s:TUNE done, %d,%d,%d\n", __func__, offset[0], offset[1], offset[2]); printk(KERN_INFO "%s:TUNE done, var=%u,%u,%u\n", __func__, stk->variance[0], stk->variance[1], stk->variance[2]); } } } #endif static void stk8baxx_sign_conv(struct stk8baxx_data *stk, s16 raw_acc_data[], u8 acc_reg_data[]) { #ifdef CONFIG_SENSORS_STK8BA53 raw_acc_data[0] = acc_reg_data[1] << 8 | acc_reg_data[0]; raw_acc_data[0] >>= 4; raw_acc_data[1] = acc_reg_data[3] << 8 | acc_reg_data[2]; raw_acc_data[1] >>= 4; raw_acc_data[2] = acc_reg_data[5] << 8 | acc_reg_data[4]; raw_acc_data[2] >>= 4; #else raw_acc_data[0] = acc_reg_data[1] << 8 | acc_reg_data[0]; raw_acc_data[0] >>= 6; raw_acc_data[1] = acc_reg_data[3] << 8 | acc_reg_data[2]; raw_acc_data[1] >>= 6; raw_acc_data[2] = acc_reg_data[5] << 8 | acc_reg_data[4]; raw_acc_data[2] >>= 6; #endif } static int stk8baxx_set_enable(struct stk8baxx_data *stk, char en) { s8 result; s8 write_buffer = 0; int new_enabled = (en) ? 1 : 0; /*int k_status = atomic_read(&stk->cali_status);*/ #ifdef STK_DEBUG_PRINT printk("%s:+++1+++--k_status=%d,first_enable=%d\n", __func__, k_status, stk->first_enable); if (stk->first_enable && k_status != STK_K_RUNNING) { stk->first_enable = false; printk("%s:+++2+++first_enable=%d\n", __func__, stk->first_enable); stk8baxx_load_cali(stk); } #endif enable_status = new_enabled; if (new_enabled == atomic_read(&stk->enabled)) return 0; /* printk(KERN_INFO "%s:%x\n", __func__, en); */ if (en) write_buffer = STK8BAXX_MD_NORMAL; else write_buffer = STK8BAXX_MD_SUSPEND; result = stk8baxx_smbus_write_byte_data(STK8BAXX_POWMODE, write_buffer); if (result < 0) { printk(KERN_ERR "%s:failed to write reg 0x%x, error=%d\n", __func__, STK8BAXX_POWMODE, result); goto error_enable; } if (en) { stk->event_since_en = 0; #ifdef STK_TUNE if ((k_status & 0xF0) != 0 && stk->stk_tune_done == 0) { stk->stk_tune_index = 0; stk8baxx_reset_para(stk); } #endif } atomic_set(&stk->enabled, new_enabled); return 0; error_enable: return 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 */ input_report_abs(sensor->input_dev, ABS_X, axis->x); input_report_abs(sensor->input_dev, ABS_Y, axis->y); input_report_abs(sensor->input_dev, ABS_Z, axis->z); input_sync(sensor->input_dev); #ifdef STK_DEBUG_PRINT printk(KERN_INFO "Gsensor x==%d y==%d z==%d\n", axis->x, axis->y, axis->z); #endif return 0; } static int stk8baxx_read_sensor_data(struct stk8baxx_data *stk) { int result; u8 acc_reg[6]; int x, y, z; struct stk8baxx_acc acc; struct sensor_private_data *sensor = (struct sensor_private_data *)i2c_get_clientdata(stk->client); struct sensor_platform_data *pdata = sensor->pdata; s16 raw_acc[3]; acc.x = 0; acc.y = 0; acc.z = 0; *acc_reg = sensor->ops->read_reg; result = sensor_rx_data(stk->client, (char *)acc_reg, sensor->ops->read_len); if (result < 0) { printk(KERN_ERR "%s: failed to read acc data, error=%d\n", __func__, result); return result; } stk8baxx_sign_conv(stk, raw_acc, acc_reg); #ifdef STK_DEBUG_PRINT printk(KERN_INFO "%s: raw_acc=%4d,%4d,%4d\n", __func__, (int)raw_acc[0], (int)raw_acc[1], (int)raw_acc[2]); #endif acc.x = raw_acc[0]; acc.y = raw_acc[1]; acc.z = raw_acc[2]; #ifdef STK_TUNE if ((k_status & 0xF0) != 0) stk8baxx_tune(stk, &acc); #endif x = acc.x; y = acc.y; z = acc.z; acc.x = (pdata->orientation[0]) * x + (pdata->orientation[1]) * y + (pdata->orientation[2]) * z; acc.y = (pdata->orientation[3]) * x + (pdata->orientation[4]) * y + (pdata->orientation[5]) * z; acc.z = (pdata->orientation[6]) * x + (pdata->orientation[7]) * y + (pdata->orientation[8]) * z; #ifdef STK_LOWPASS stk8baxx_low_pass(stk, &acc); #endif stk->acc_xyz.x = acc.x; stk->acc_xyz.y = acc.y; stk->acc_xyz.z = acc.z; #ifdef STK_DEBUG_PRINT printk(KERN_INFO "stk8baxx acc= %4d, %4d, %4d\n", (int)stk->acc_xyz.x, (int)stk->acc_xyz.y, (int)stk->acc_xyz.z); #endif return 0; } static int sensor_report_value(struct i2c_client *client) { unsigned int xyz_adc_rang = 0; struct sensor_axis axis; struct sensor_private_data *sensor = (struct sensor_private_data *)i2c_get_clientdata(client); static int flag; stk8baxx_read_sensor_data(stk8baxx_data_ptr); xyz_adc_rang = STK_LSB_1G * STK_DEF_RANGE; axis.x = stk8baxx_data_ptr->acc_xyz.x * (STK8BAXX_RANGE_UG / xyz_adc_rang); axis.y = stk8baxx_data_ptr->acc_xyz.y * (STK8BAXX_RANGE_UG / xyz_adc_rang); axis.z = stk8baxx_data_ptr->acc_xyz.z * (STK8BAXX_RANGE_UG / xyz_adc_rang); /* *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); mutex_lock(&sensor->data_mutex); sensor->axis = axis; mutex_unlock(&sensor->data_mutex); return 0; } static int sensor_active(struct i2c_client *client, int enable, int rate) { if (enable) stk8baxx_set_enable(stk8baxx_data_ptr, 1); else stk8baxx_set_enable(stk8baxx_data_ptr, 0); return 0; } static int sensor_init(struct i2c_client *client) { int ret = 0; struct stk8baxx_data *stk; struct sensor_private_data *sensor = (struct sensor_private_data *)i2c_get_clientdata(client); printk(KERN_INFO "driver version:%s\n", STK_ACC_DRIVER_VERSION); if (!enable_status) return 0; stk = kzalloc(sizeof(*stk), GFP_KERNEL); if (!stk) { printk(KERN_ERR "%s:memory allocation error\n", __func__); return -ENOMEM; } stk8baxx_data_ptr = stk; sensor_ptr = sensor; stk->stk8baxx_placement = STK8BAXX_DEF_PLACEMENT; stk->client = client; ret = stk8baxx_reg_init(stk, client, sensor); if (ret) { printk(KERN_ERR "%s:stk8baxx initialization failed\n", __func__); return ret; } stk->re_enable = false; sensor->status_cur = SENSOR_OFF; /* Sys Attribute Register */ if (no_create_att) { struct input_dev *p_input_dev = NULL; p_input_dev = input_allocate_device(); if (!p_input_dev) { dev_err(&client->dev, "Failed to allocate input device\n"); return -ENOMEM; } p_input_dev->name = "stk8baxx_attr"; set_bit(EV_ABS, p_input_dev->evbit); dev_set_drvdata(&p_input_dev->dev, stk); ret = input_register_device(p_input_dev); if (ret) { dev_err(&client->dev, "Unable to register input device %s\n", p_input_dev->name); return ret; } DBG("Sys Attribute Register here %s is called for stk8baxx.\n", __func__); no_create_att = 0; } return 0; } static struct sensor_operate gsensor_stk8baxx_ops = { .name = "gs_stk8baxx", .type = SENSOR_TYPE_ACCEL, /*sensor type and it should be correct*/ .id_i2c = ACCEL_ID_STK8BAXX, /*i2c id number*/ .read_reg = STK8BAXX_XOUT1, /*read data*/ .read_len = 6, /*data length*/ .id_reg = SENSOR_UNKNOW_DATA, /*read device id from this register*/ .id_data = SENSOR_UNKNOW_DATA, /*device id*/ .precision = SENSOR_UNKNOW_DATA, /*12 bit*/ .ctrl_reg = STK8BAXX_POWMODE, /*enable or disable*/ /*intterupt status register*/ .int_status_reg = STK8BAXX_INTSTS2, .range = {-STK8BAXX_RANGE_UG, STK8BAXX_RANGE_UG}, /*range*/ .trig = IRQF_TRIGGER_FALLING | IRQF_ONESHOT, .active = sensor_active, .init = sensor_init, .report = sensor_report_value, }; static int gsensor_stk8baxx_probe(struct i2c_client *client, const struct i2c_device_id *devid) { return sensor_register_device(client, NULL, devid, &gsensor_stk8baxx_ops); } static void gsensor_stk8baxx_remove(struct i2c_client *client) { sensor_unregister_device(client, NULL, &gsensor_stk8baxx_ops); } static const struct i2c_device_id gsensor_stk8baxx_id[] = { {"gs_stk8baxx", ACCEL_ID_STK8BAXX}, {} }; static struct i2c_driver gsensor_stk8baxx_driver = { .probe = gsensor_stk8baxx_probe, .remove = (void *)gsensor_stk8baxx_remove, .shutdown = sensor_shutdown, .id_table = gsensor_stk8baxx_id, .driver = { .name = "gsensor_stk8baxx", #ifdef CONFIG_PM .pm = &sensor_pm_ops, #endif }, }; module_i2c_driver(gsensor_stk8baxx_driver); MODULE_AUTHOR("Lex Hsieh, Sensortek"); MODULE_DESCRIPTION("stk8baxx 3-Axis accelerometer driver"); MODULE_LICENSE("GPL"); MODULE_VERSION(STK_ACC_DRIVER_VERSION);