diff --git a/drivers/input/sensors/accel/Kconfig b/drivers/input/sensors/accel/Kconfig index fe3d25e6ee71..7b0d026f7f2f 100644 --- a/drivers/input/sensors/accel/Kconfig +++ b/drivers/input/sensors/accel/Kconfig @@ -12,83 +12,89 @@ menuconfig GSENSOR_DEVICE if GSENSOR_DEVICE config GS_MMA8452 - bool "gsensor mma8451/mma8452/mma8453/mma8653" - default y - help + bool "gsensor mma8451/mma8452/mma8453/mma8653" + default y + help To have support for your specific gsesnor you will have to select the proper drivers which depend on this option. - + +config STK8BAXX_ACC + bool "gsensor STK8BAXX" + default n + help + To have support for your specific gsesnor you will have to + select the proper drivers which depend on this option. + config MPU6880_ACC - bool "Sensor mpu6880_acc" - default y - help + bool "Sensor mpu6880_acc" + default y + help To have support for your specific gsesnor you will have to select the proper drivers which depend on this option. config MPU6500_ACC - bool "Sensor mpu6500_acc" - default y + bool "Sensor mpu6500_acc" + default y help To have support for your specific gsesnor you will have to select the proper drivers which depend on this option. config GS_KXTIK - bool "gsensor kxtik" + bool "gsensor kxtik" help To have support for your specific gsesnor you will have to select the proper drivers which depend on this option. - config GS_KXTJ9 - bool "gsensor kxtj9" - help - To have support for your specific gsesnor you will have to - select the proper drivers which depend on this option. + bool "gsensor kxtj9" + help + To have support for your specific gsesnor you will have to + select the proper drivers which depend on this option. config GS_LIS3DH - bool "gsensor lis3dh" - default y - help + bool "gsensor lis3dh" + default y + help To have support for your specific gsesnor you will have to select the proper drivers which depend on this option. config GS_MMA7660 - bool "gsensor mma7660" - default y - help + bool "gsensor mma7660" + default y + help To have support for your specific gsesnor you will have to select the proper drivers which depend on this option. - + config GS_MC3230 - bool "gsensor mc3230" - help + bool "gsensor mc3230" + help To have support for your specific gsesnor you will have to select the proper drivers which depend on this option. config GS_MXC6225 bool "gsensor mxc6225" help - To have support for your sepcific gsensor you will have to - select het proper drivers which depend on this option. + To have support for your sepcific gsensor you will have to + select het proper drivers which depend on this option. config GS_DMT10 bool "gsensor dmard10" help - To have support for your sepcific gsensor you will have to - select het proper drivers which depend on this option. + To have support for your sepcific gsensor you will have to + select het proper drivers which depend on this option. config GS_LSM303D bool "gsensor lsm303d" default y help - To have support for your sepcific gsensor you will have to - select het proper drivers which depend on this option. + To have support for your sepcific gsensor you will have to + select het proper drivers which depend on this option. config GS_BMA023 - bool "gsensor bma023" - help - To have support for your specific gsesnor you will have to - select the proper drivers which depend on this option. + bool "gsensor bma023" + help + To have support for your specific gsesnor you will have to + select the proper drivers which depend on this option. config LSM330_ACC bool "gsensor lsm330" @@ -105,4 +111,3 @@ config BMA2XX_ACC 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 d42d4d5ad597..deed0a8057dc 100644 --- a/drivers/input/sensors/accel/Makefile +++ b/drivers/input/sensors/accel/Makefile @@ -1,14 +1,15 @@ # SPDX-License-Identifier: GPL-2.0 -obj-$(CONFIG_GS_KXTIK) += kxtik.o -obj-$(CONFIG_GS_KXTJ9) += kxtj9.o -obj-$(CONFIG_GS_MMA8452) += mma8452.o -obj-$(CONFIG_GS_LIS3DH) += lis3dh.o -obj-$(CONFIG_GS_MMA7660) += mma7660.o -obj-$(CONFIG_GS_MXC6225) += mxc622x.o -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_MPU6500_ACC) += mpu6500_acc.o -obj-$(CONFIG_LSM330_ACC) += lsm330_acc.o +obj-$(CONFIG_GS_KXTIK) += kxtik.o +obj-$(CONFIG_GS_KXTJ9) += kxtj9.o +obj-$(CONFIG_GS_MMA8452) += mma8452.o +obj-$(CONFIG_GS_LIS3DH) += lis3dh.o +obj-$(CONFIG_GS_MMA7660) += mma7660.o +obj-$(CONFIG_GS_MXC6225) += mxc622x.o +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_MPU6500_ACC) += mpu6500_acc.o +obj-$(CONFIG_LSM330_ACC) += lsm330_acc.o obj-$(CONFIG_BMA2XX_ACC) += bma2xx.o +obj-$(CONFIG_STK8BAXX_ACC) += stk8baxx.o diff --git a/drivers/input/sensors/accel/stk8baxx.c b/drivers/input/sensors/accel/stk8baxx.c new file mode 100644 index 000000000000..c25573427fb0 --- /dev/null +++ b/drivers/input/sensors/accel/stk8baxx.c @@ -0,0 +1,950 @@ +/* + * 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; +} + +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 struct sensor_operate *stk8baxx_get_ops(void) +{ + return &gsensor_stk8baxx_ops; +} + +static int __init stk8baxx_init(void) +{ + struct sensor_operate *ops = stk8baxx_get_ops(); + int type = ops->type; + + return sensor_register_slave(type, NULL, NULL, stk8baxx_get_ops); +} + +static void __exit stk8baxx_exit(void) +{ + struct sensor_operate *ops = stk8baxx_get_ops(); + int type = ops->type; + + sensor_unregister_slave(type, NULL, NULL, stk8baxx_get_ops); +} + +module_init(stk8baxx_init); +module_exit(stk8baxx_exit); + +MODULE_AUTHOR("Lex Hsieh, Sensortek"); +MODULE_DESCRIPTION("stk8baxx 3-Axis accelerometer driver"); +MODULE_LICENSE("GPL"); +MODULE_VERSION(STK_ACC_DRIVER_VERSION); diff --git a/drivers/input/sensors/sensor-dev.c b/drivers/input/sensors/sensor-dev.c index f880460620ff..816a56a92a04 100644 --- a/drivers/input/sensors/sensor-dev.c +++ b/drivers/input/sensors/sensor-dev.c @@ -2012,6 +2012,7 @@ static const struct i2c_device_id sensor_id[] = { {"mpu6500_acc", ACCEL_ID_MPU6500}, {"lsm330_acc", ACCEL_ID_LSM330}, {"bma2xx_acc", ACCEL_ID_BMA2XX}, + {"gs_stk8baxx", ACCEL_ID_STK8BAXX}, /*compass*/ {"compass", COMPASS_ID_ALL}, {"ak8975", COMPASS_ID_AK8975}, @@ -2066,6 +2067,7 @@ static struct of_device_id sensor_dt_ids[] = { { .compatible = "gs_mc3230" }, { .compatible = "lsm330_acc" }, { .compatible = "bma2xx_acc" }, + { .compatible = "gs_stk8baxx" }, /*compass*/ { .compatible = "ak8975" }, { .compatible = "ak8963" }, diff --git a/include/linux/sensor-dev.h b/include/linux/sensor-dev.h index 8909c4faaad5..19a8f03f3e0c 100644 --- a/include/linux/sensor-dev.h +++ b/include/linux/sensor-dev.h @@ -59,6 +59,7 @@ enum sensor_id { ACCEL_ID_MPU6500, ACCEL_ID_LSM330, ACCEL_ID_BMA2XX, + ACCEL_ID_STK8BAXX, COMPASS_ID_ALL, COMPASS_ID_AK8975, COMPASS_ID_AK8963,