Files
threeeye bc1d038eac REVVL 6 Pro kernel bring-up: full working tree snapshot (2026-09-12)
Squashed backup commit (no shallow-clone history issues) of
xiaomi-mt6833-dev/kernel_xiaomi_mt6833 (lineage-23.2 branch, upstream
commit 9eece662e) plus all fixes applied to get everpal_defconfig building
clean against a modern (GCC 15.2.0) toolchain -- see the previous commit
message on the lineage-23.2 branch (also in this repo history is not
available here since this is a squashed snapshot; full incremental history
lives in the local DL380 checkout and the upstream GitHub remote).

Upstream: https://github.com/xiaomi-mt6833-dev/kernel_xiaomi_mt6833 (lineage-23.2)
2026-09-12 13:36:46 +00:00

4872 lines
131 KiB
C

/*
* Copyright (C) 2017 MediaTek Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* 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 http://www.gnu.org/licenses/gpl-2.0.html for more details.
*/
#define pr_fmt(fmt) "<BMI160_ACCELGYRO> " fmt
#include <linux/atomic.h>
#include <linux/delay.h>
#include <linux/gpio.h>
#include <linux/input.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/kobject.h>
#include <linux/miscdevice.h>
#include <linux/module.h>
#include <linux/of_gpio.h>
#include <linux/of_irq.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/spi/spi.h>
#include <linux/spi/spidev.h>
#include <linux/suspend.h>
#include <linux/uaccess.h>
#include <linux/workqueue.h>
#include "accelgyro.h"
#include "bmi160_accgyro.h"
#include "cust_accelgyro.h"
#include "linux/platform_data/spi-mt65xx.h"
#define SW_CALIBRATION
#define BYTES_PER_LINE (16)
static int bmi160_accelgyro_spi_probe(struct spi_device *spi);
static int bmi160_accelgyro_spi_remove(struct spi_device *spi);
static int bmi160_accelgyro_local_init(void);
static int bmi160_accelgyro_remove(void);
struct scale_factor {
u8 whole;
u8 fraction;
};
struct data_resolution {
struct scale_factor scalefactor;
int sensitivity;
};
/* gyro sensor type */
enum SENSOR_TYPE_ENUM { BMI160_GYRO_TYPE = 0x0, INVALID_TYPE = 0xff };
/* range */
enum BMG_RANGE_ENUM {
BMG_RANGE_2000 = 0x0, /* +/- 2000 degree/s */
BMG_RANGE_1000, /* +/- 1000 degree/s */
BMG_RANGE_500, /* +/- 500 degree/s */
BMG_RANGE_250, /* +/- 250 degree/s */
BMG_RANGE_125, /* +/- 125 degree/s */
BMG_UNDEFINED_RANGE = 0xff
};
/* power mode */
enum BMG_POWERMODE_ENUM {
BMG_SUSPEND_MODE = 0x0,
BMG_NORMAL_MODE,
BMG_UNDEFINED_POWERMODE = 0xff
};
/* debug information flags */
enum GYRO_TRC {
GYRO_TRC_FILTER = 0x01,
GYRO_TRC_RAWDATA = 0x02,
GYRO_TRC_IOCTL = 0x04,
GYRO_TRC_CALI = 0x08,
GYRO_TRC_INFO = 0x10,
};
/* s/w data filter */
struct gyro_data_filter {
s16 raw[C_MAX_FIR_LENGTH][BMG_AXES_NUM];
int sum[BMG_AXES_NUM];
int num;
int idx;
};
struct bmi160_accelgyro_data {
struct accelgyro_hw hw;
struct hwmsen_convert cvt;
struct bmi160_t device;
/*misc */
struct data_resolution *accel_reso;
atomic_t accel_trace;
atomic_t accel_suspend;
atomic_t accel_selftest;
atomic_t accel_filter;
s16 accel_cali_sw[BMI160_ACC_AXES_NUM + 1];
struct mutex accel_lock;
struct mutex spi_lock;
/* +1: for 4-byte alignment */
s8 accel_offset[BMI160_ACC_AXES_NUM + 1];
s16 accel_data[BMI160_ACC_AXES_NUM + 1];
u8 fifo_count;
u8 fifo_head_en;
u8 fifo_data_sel;
u16 fifo_bytecount;
struct odr_t accel_odr;
u64 fifo_time;
atomic_t layout;
bool is_input_enable;
struct delayed_work work;
struct input_dev *input;
struct hrtimer timer;
int is_timer_running;
struct work_struct report_data_work;
ktime_t work_delay_kt;
uint64_t time_odr;
struct mutex mutex_ring_buf;
atomic_t wkqueue_en;
atomic_t accel_delay;
int accel_IRQ;
uint16_t accel_gpio_pin;
struct work_struct accel_irq_work;
/* step detector */
u8 std;
/* spi */
struct spi_device *spi;
u8 *spi_buffer; /* only used for SPI transfer internal */
/* gyro sensor info */
u8 gyro_sensor_name[MAX_SENSOR_NAME];
enum SENSOR_TYPE_ENUM gyro_sensor_type;
enum BMG_POWERMODE_ENUM gyro_power_mode;
enum BMG_RANGE_ENUM gyro_range;
int gyro_datarate;
/* sensitivity = 2^bitnum/range
* [+/-2000 = 4000; +/-1000 = 2000;
* +/-500 = 1000; +/-250 = 500;
* +/-125 = 250 ]
*/
u16 gyro_sensitivity;
/*misc */
struct mutex gyro_lock;
atomic_t gyro_trace;
atomic_t gyro_suspend;
atomic_t gyro_filter;
/* unmapped axis value */
s16 gyro_cali_sw[BMG_AXES_NUM + 1];
/* hw offset */
s8 gyro_offset[BMG_AXES_NUM + 1]; /* +1:for 4-byte alignment */
#if defined(CONFIG_BMG_LOWPASS)
atomic_t gyro_firlen;
atomic_t gyro_fir_en;
struct gyro_data_filter gyro_fir;
#endif
};
struct bmi160_axis_data_t {
s16 x;
s16 y;
s16 z;
};
static struct accelgyro_init_info bmi160_accelgyro_init_info;
static struct bmi160_accelgyro_data *accelgyro_obj_data;
static bool sensor_power = true;
static struct GSENSOR_VECTOR3D gsensor_gain;
/* signification motion flag*/
int sig_flag;
static int bmi160_acc_init_flag = -1;
struct bmi160_t *p_bmi160;
#ifdef MTK_NEW_ARCH_ACCEL
struct platform_device *accelPltFmDev;
#endif
/* 0=OK, -1=fail */
static int bmi160_gyro_init_flag = -1;
static struct bmi160_accelgyro_data *gyro_obj_data;
static int bmg_set_powermode(struct bmi160_accelgyro_data *obj,
enum BMG_POWERMODE_ENUM power_mode);
static struct data_resolution bmi160_acc_data_resolution[1] = {
{{0, 12}, 8192} /* +/-4G range */
};
static struct data_resolution bmi160_acc_offset_resolution = {{0, 12}, 8192};
static unsigned int bufsiz = (15 * 1024);
int BMP160_spi_read_bytes(struct spi_device *spi, u16 addr, u8 *rx_buf,
u32 data_len)
{
struct spi_message msg;
struct spi_transfer *xfer = NULL;
u8 *tmp_buf = NULL;
u32 package, reminder, retry;
package = (data_len + 2) / 1024;
reminder = (data_len + 2) % 1024;
if ((package > 0) && (reminder != 0)) {
xfer = kzalloc(sizeof(*xfer) * 4, GFP_KERNEL);
retry = 1;
} else {
xfer = kzalloc(sizeof(*xfer) * 2, GFP_KERNEL);
retry = 0;
}
if (xfer == NULL) {
pr_err("%s, no memory for SPI transfer\n", __func__);
return -ENOMEM;
}
mutex_lock(&accelgyro_obj_data->spi_lock);
tmp_buf = accelgyro_obj_data->spi_buffer;
spi_message_init(&msg);
memset(tmp_buf, 0, 1 + data_len);
*tmp_buf = (u8)(addr & 0xFF) | 0x80;
xfer[0].tx_buf = tmp_buf;
xfer[0].rx_buf = tmp_buf;
xfer[0].len = 1 + data_len;
xfer[0].delay_usecs = 5;
xfer[0].speed_hz = 4 * 1000 * 1000; /*4M*/
spi_message_add_tail(&xfer[0], &msg);
spi_sync(accelgyro_obj_data->spi, &msg);
memcpy(rx_buf, tmp_buf + 1, data_len);
kfree(xfer);
if (xfer != NULL)
xfer = NULL;
mutex_unlock(&accelgyro_obj_data->spi_lock);
return 0;
}
int BMP160_spi_write_bytes(struct spi_device *spi, u16 addr, u8 *tx_buf,
u32 data_len)
{
struct spi_message msg;
struct spi_transfer *xfer = NULL;
u8 *tmp_buf = NULL;
u32 package, reminder, retry;
package = (data_len + 1) / 1024;
reminder = (data_len + 1) % 1024;
if ((package > 0) && (reminder != 0)) {
xfer = kzalloc(sizeof(*xfer) * 2, GFP_KERNEL);
retry = 1;
} else {
xfer = kzalloc(sizeof(*xfer), GFP_KERNEL);
retry = 0;
}
if (xfer == NULL) {
pr_err("%s, no memory for SPI transfer\n", __func__);
return -ENOMEM;
}
tmp_buf = accelgyro_obj_data->spi_buffer;
mutex_lock(&accelgyro_obj_data->spi_lock);
spi_message_init(&msg);
*tmp_buf = (u8)(addr & 0xFF);
if (retry) {
memcpy(tmp_buf + 1, tx_buf, (package * 1024 - 1));
xfer[0].len = package * 1024;
} else {
memcpy(tmp_buf + 1, tx_buf, data_len);
xfer[0].len = data_len + 1;
}
xfer[0].tx_buf = tmp_buf;
xfer[0].delay_usecs = 5;
xfer[0].speed_hz = 4 * 1000 * 1000;
spi_message_add_tail(&xfer[0], &msg);
spi_sync(accelgyro_obj_data->spi, &msg);
if (retry) {
addr = addr + package * 1024 - 1;
spi_message_init(&msg);
*tmp_buf = (u8)(addr & 0xFF);
memcpy(tmp_buf + 1, (tx_buf + package * 1024 - 1), reminder);
xfer[1].tx_buf = tmp_buf;
xfer[1].len = reminder + 1;
xfer[1].delay_usecs = 5;
xfer[0].speed_hz = 4 * 1000 * 1000;
spi_message_add_tail(&xfer[1], &msg);
spi_sync(accelgyro_obj_data->spi, &msg);
}
kfree(xfer);
if (xfer != NULL)
xfer = NULL;
mutex_unlock(&accelgyro_obj_data->spi_lock);
return 0;
}
s8 bmi_read_wrapper(u8 dev_addr, u8 reg_addr, u8 *data, u8 len)
{
int err = 0;
err = BMP160_spi_read_bytes(accelgyro_obj_data->spi, reg_addr, data,
len);
if (err < 0)
pr_err("read bmi160 i2c failed.\n");
return err;
}
s8 bmi_write_wrapper(u8 dev_addr, u8 reg_addr, u8 *data, u8 len)
{
int err = 0;
err = BMP160_spi_write_bytes(accelgyro_obj_data->spi, reg_addr, data,
len);
if (err < 0)
pr_err("read bmi160 i2c failed.\n");
return err;
}
static void bmi_delay(u32 msec)
{
mdelay(msec);
}
/*!
* @brief Set data resolution
*
* @param[in] client the pointer of bmi160_accelgyro_data
*
* @return zero success, non-zero failed
*/
static int BMI160_ACC_SetDataResolution(struct bmi160_accelgyro_data *obj)
{
obj->accel_reso = &bmi160_acc_data_resolution[0];
return 0;
}
static int BMI160_ACC_ReadData(struct bmi160_accelgyro_data *obj,
s16 data[BMI160_ACC_AXES_NUM])
{
int err = 0;
u8 addr = BMI160_USER_DATA_14_ACC_X_LSB__REG;
u8 buf[BMI160_ACC_DATA_LEN] = {0};
err = BMP160_spi_read_bytes(obj->spi, addr, buf, BMI160_ACC_DATA_LEN);
if (err) {
pr_err("read data failed.\n");
} else {
/* Convert sensor raw data to 16-bit integer */
/*Data X */
data[BMI160_ACC_AXIS_X] =
(s16)((((s32)((s8)buf[1])) << BMI160_SHIFT_8_POSITION) |
(buf[0]));
/*Data Y */
data[BMI160_ACC_AXIS_Y] =
(s16)((((s32)((s8)buf[3])) << BMI160_SHIFT_8_POSITION) |
(buf[2]));
/* Data Z */
data[BMI160_ACC_AXIS_Z] =
(s16)((((s32)((s8)buf[5])) << BMI160_SHIFT_8_POSITION) |
(buf[4]));
}
return err;
}
static int BMI160_ACC_ReadOffset(struct bmi160_accelgyro_data *obj,
s8 ofs[BMI160_ACC_AXES_NUM])
{
int err = 0;
#ifdef SW_CALIBRATION
ofs[0] = ofs[1] = ofs[2] = 0x0;
#else
err = BMP160_spi_read_bytes(obj->spi, BMI160_ACC_REG_OFSX, ofs,
BMI160_ACC_AXES_NUM);
if (err)
pr_err("error: %d\n", err);
#endif
return err;
}
/*!
* @brief Reset calibration for acc
*
* @param[in] obj the pointer of struct bmi160_accelgyro_data
*
* @return zero success, non-zero failed
*/
static int BMI160_ACC_ResetCalibration(struct bmi160_accelgyro_data *obj)
{
int err = 0;
#ifdef SW_CALIBRATION
#else
u8 ofs[4] = {0, 0, 0, 0};
err = BMP160_spi_write_bytes(obj->spi, BMI160_ACC_REG_OFSX, ofs, 4);
if (err)
pr_err("write accel_offset failed.\n");
#endif
memset(obj->accel_cali_sw, 0x00, sizeof(obj->accel_cali_sw));
memset(obj->accel_offset, 0x00, sizeof(obj->accel_offset));
return err;
}
static int BMI160_ACC_ReadCalibration(struct bmi160_accelgyro_data *obj,
int dat[BMI160_ACC_AXES_NUM])
{
int err = 0;
int mul;
#ifdef SW_CALIBRATION
mul = 0; /* only SW Calibration, disable HW Calibration */
#else
err = BMI160_ACC_ReadOffset(obj, obj->accel_offset);
if (err) {
pr_err("read accel_offset fail, %d\n", err);
return err;
}
mul = obj->accel_reso->sensitivity /
bmi160_acc_offset_resolution.sensitivity;
#endif
dat[obj->cvt.map[BMI160_ACC_AXIS_X]] =
obj->cvt.sign[BMI160_ACC_AXIS_X] *
(obj->accel_offset[BMI160_ACC_AXIS_X] * mul +
obj->accel_cali_sw[BMI160_ACC_AXIS_X]);
dat[obj->cvt.map[BMI160_ACC_AXIS_Y]] =
obj->cvt.sign[BMI160_ACC_AXIS_Y] *
(obj->accel_offset[BMI160_ACC_AXIS_Y] * mul +
obj->accel_cali_sw[BMI160_ACC_AXIS_Y]);
dat[obj->cvt.map[BMI160_ACC_AXIS_Z]] =
obj->cvt.sign[BMI160_ACC_AXIS_Z] *
(obj->accel_offset[BMI160_ACC_AXIS_Z] * mul +
obj->accel_cali_sw[BMI160_ACC_AXIS_Z]);
return err;
}
static int BMI160_ACC_ReadCalibrationEx(struct bmi160_accelgyro_data *obj,
int act[BMI160_ACC_AXES_NUM],
int raw[BMI160_ACC_AXES_NUM])
{
/* raw: the raw calibration data; act: the actual calibration data */
int mul;
#ifdef SW_CALIBRATION
/* only SW Calibration, disable Calibration */
mul = 0;
#else
int err;
err = BMI160_ACC_ReadOffset(obj, obj->accel_offset);
if (err) {
pr_err("read accel_offset fail, %d\n", err);
return err;
}
mul = obj->accel_reso->sensitivity /
bmi160_acc_offset_resolution.sensitivity;
#endif
raw[BMI160_ACC_AXIS_X] = obj->accel_offset[BMI160_ACC_AXIS_X] * mul +
obj->accel_cali_sw[BMI160_ACC_AXIS_X];
raw[BMI160_ACC_AXIS_Y] = obj->accel_offset[BMI160_ACC_AXIS_Y] * mul +
obj->accel_cali_sw[BMI160_ACC_AXIS_Y];
raw[BMI160_ACC_AXIS_Z] = obj->accel_offset[BMI160_ACC_AXIS_Z] * mul +
obj->accel_cali_sw[BMI160_ACC_AXIS_Z];
act[obj->cvt.map[BMI160_ACC_AXIS_X]] =
obj->cvt.sign[BMI160_ACC_AXIS_X] * raw[BMI160_ACC_AXIS_X];
act[obj->cvt.map[BMI160_ACC_AXIS_Y]] =
obj->cvt.sign[BMI160_ACC_AXIS_Y] * raw[BMI160_ACC_AXIS_Y];
act[obj->cvt.map[BMI160_ACC_AXIS_Z]] =
obj->cvt.sign[BMI160_ACC_AXIS_Z] * raw[BMI160_ACC_AXIS_Z];
return 0;
}
static int BMI160_ACC_WriteCalibration(struct bmi160_accelgyro_data *obj,
int dat[BMI160_ACC_AXES_NUM])
{
int err = 0;
int cali[BMI160_ACC_AXES_NUM] = {0};
int raw[BMI160_ACC_AXES_NUM] = {0};
#ifndef SW_CALIBRATION
int lsb = bmi160_acc_offset_resolution.sensitivity;
int divisor = obj->accel_reso->sensitivity / lsb;
#endif
err = BMI160_ACC_ReadCalibrationEx(obj, cali, raw);
/* accel_offset will be updated in obj->accel_offset */
if (err) {
pr_err("read accel_offset fail, %d\n", err);
return err;
}
pr_debug("OLDOFF:(%+3d %+3d %+3d): (%+3d %+3d %+3d)/(%+3d %+3d %+3d)\n",
raw[BMI160_ACC_AXIS_X], raw[BMI160_ACC_AXIS_Y],
raw[BMI160_ACC_AXIS_Z], obj->accel_offset[BMI160_ACC_AXIS_X],
obj->accel_offset[BMI160_ACC_AXIS_Y],
obj->accel_offset[BMI160_ACC_AXIS_Z],
obj->accel_cali_sw[BMI160_ACC_AXIS_X],
obj->accel_cali_sw[BMI160_ACC_AXIS_Y],
obj->accel_cali_sw[BMI160_ACC_AXIS_Z]);
/* calculate the real accel_offset expected by caller */
cali[BMI160_ACC_AXIS_X] += dat[BMI160_ACC_AXIS_X];
cali[BMI160_ACC_AXIS_Y] += dat[BMI160_ACC_AXIS_Y];
cali[BMI160_ACC_AXIS_Z] += dat[BMI160_ACC_AXIS_Z];
pr_debug("UPDATE: (%+3d %+3d %+3d)\n", dat[BMI160_ACC_AXIS_X],
dat[BMI160_ACC_AXIS_Y], dat[BMI160_ACC_AXIS_Z]);
#ifdef SW_CALIBRATION
obj->accel_cali_sw[BMI160_ACC_AXIS_X] =
obj->cvt.sign[BMI160_ACC_AXIS_X] *
(cali[obj->cvt.map[BMI160_ACC_AXIS_X]]);
obj->accel_cali_sw[BMI160_ACC_AXIS_Y] =
obj->cvt.sign[BMI160_ACC_AXIS_Y] *
(cali[obj->cvt.map[BMI160_ACC_AXIS_Y]]);
obj->accel_cali_sw[BMI160_ACC_AXIS_Z] =
obj->cvt.sign[BMI160_ACC_AXIS_Z] *
(cali[obj->cvt.map[BMI160_ACC_AXIS_Z]]);
#else
obj->accel_offset[BMI160_ACC_AXIS_X] =
(s8)(obj->cvt.sign[BMI160_ACC_AXIS_X] *
(cali[obj->cvt.map[BMI160_ACC_AXIS_X]]) / (divisor));
obj->accel_offset[BMI160_ACC_AXIS_Y] =
(s8)(obj->cvt.sign[BMI160_ACC_AXIS_Y] *
(cali[obj->cvt.map[BMI160_ACC_AXIS_Y]]) / (divisor));
obj->accel_offset[BMI160_ACC_AXIS_Z] =
(s8)(obj->cvt.sign[BMI160_ACC_AXIS_Z] *
(cali[obj->cvt.map[BMI160_ACC_AXIS_Z]]) / (divisor));
/*convert software calibration using standard calibration */
obj->accel_cali_sw[BMI160_ACC_AXIS_X] =
obj->cvt.sign[BMI160_ACC_AXIS_X] *
(cali[obj->cvt.map[BMI160_ACC_AXIS_X]]) % (divisor);
obj->accel_cali_sw[BMI160_ACC_AXIS_Y] =
obj->cvt.sign[BMI160_ACC_AXIS_Y] *
(cali[obj->cvt.map[BMI160_ACC_AXIS_Y]]) % (divisor);
obj->accel_cali_sw[BMI160_ACC_AXIS_Z] =
obj->cvt.sign[BMI160_ACC_AXIS_Z] *
(cali[obj->cvt.map[BMI160_ACC_AXIS_Z]]) % (divisor);
pr_debug("NEWOFF:(%+3d %+3d %+3d): (%+3d %+3d %+3d)/(%+3d %+3d %+3d)\n",
obj->accel_offset[BMI160_ACC_AXIS_X] * divisor +
obj->accel_cali_sw[BMI160_ACC_AXIS_X],
obj->accel_offset[BMI160_ACC_AXIS_Y] * divisor +
obj->accel_cali_sw[BMI160_ACC_AXIS_Y],
obj->accel_offset[BMI160_ACC_AXIS_Z] * divisor +
obj->accel_cali_sw[BMI160_ACC_AXIS_Z],
obj->accel_offset[BMI160_ACC_AXIS_X],
obj->accel_offset[BMI160_ACC_AXIS_Y],
obj->accel_offset[BMI160_ACC_AXIS_Z],
obj->accel_cali_sw[BMI160_ACC_AXIS_X],
obj->accel_cali_sw[BMI160_ACC_AXIS_Y],
obj->accel_cali_sw[BMI160_ACC_AXIS_Z]);
err = BMP160_spi_write_bytes(obj->spi, BMI160_ACC_REG_OFSX,
obj->accel_offset, BMI160_ACC_AXES_NUM);
if (err) {
pr_err("write accel_offset fail: %d\n", err);
return err;
}
#endif
return err;
}
/*!
* @brief Input event initialization for device
*
* @param[in] obj the pointer of struct bmi160_accelgyro_data
*
* @return zero success, non-zero failed
*/
static int BMI160_ACC_CheckDeviceID(struct bmi160_accelgyro_data *obj)
{
int err = 0;
u8 databuf[2] = {0};
err = BMP160_spi_read_bytes(obj->spi, 0x7F, databuf, 1);
err = BMP160_spi_read_bytes(obj->spi, BMI160_USER_CHIP_ID__REG, databuf,
1);
if (err < 0) {
pr_err("read chip id failed.\n");
return BMI160_ACC_ERR_SPI;
}
switch (databuf[0]) {
case SENSOR_CHIP_ID_BMI:
case SENSOR_CHIP_ID_BMI_C2:
case SENSOR_CHIP_ID_BMI_C3:
pr_debug("check chip id %d successfully.\n", databuf[0]);
break;
default:
pr_debug("check chip id %d %d failed.\n", databuf[0],
databuf[1]);
err = -1;
break;
}
return err;
}
/*!
* @brief Set power mode for acc
*
* @param[in] obj the pointer of struct bmi160_accelgyro_data
* @param[in] enable
*
* @return zero success, non-zero failed
*/
static int BMI160_ACC_SetPowerMode(struct bmi160_accelgyro_data *obj,
bool enable)
{
int err = 0;
u8 databuf[2] = {0};
if (enable == sensor_power) {
pr_debug("power status is newest!\n");
return 0;
}
mutex_lock(&obj->accel_lock);
if (enable == true)
databuf[0] = CMD_PMU_ACC_NORMAL;
else
databuf[0] = CMD_PMU_ACC_SUSPEND;
err = BMP160_spi_write_bytes(obj->spi, BMI160_CMD_COMMANDS__REG,
&databuf[0], 1);
if (err < 0) {
pr_err("write power mode value to register failed.\n");
mutex_unlock(&obj->accel_lock);
return BMI160_ACC_ERR_SPI;
}
sensor_power = enable;
mdelay(1);
mutex_unlock(&obj->accel_lock);
pr_debug("set power mode enable = %d ok!\n", enable);
return 0;
}
/*!
* @brief Set range value for acc
*
* @param[in] obj the pointer of struct bmi160_accelgyro_data
* @param[in] range value
*
* @return zero success, non-zero failed
*/
static int BMI160_ACC_SetDataFormat(struct bmi160_accelgyro_data *obj,
u8 dataformat)
{
int res = 0;
u8 databuf[2] = {0};
mutex_lock(&obj->accel_lock);
res = BMP160_spi_read_bytes(obj->spi, BMI160_USER_ACC_RANGE__REG,
&databuf[0], 1);
databuf[0] = BMI160_SET_BITSLICE(databuf[0], BMI160_USER_ACC_RANGE,
dataformat);
res += BMP160_spi_write_bytes(obj->spi, BMI160_USER_ACC_RANGE__REG,
&databuf[0], 1);
mdelay(1);
if (res < 0) {
pr_err("set range failed.\n");
mutex_unlock(&obj->accel_lock);
return BMI160_ACC_ERR_SPI;
}
mutex_unlock(&obj->accel_lock);
return BMI160_ACC_SetDataResolution(obj);
}
/*!
* @brief Set bandwidth for acc
*
* @param[in] obj the pointer of struct bmi160_accelgyro_data
* @param[in] bandwidth value
*
* @return zero success, non-zero failed
*/
static int BMI160_ACC_SetBWRate(struct bmi160_accelgyro_data *obj, u8 bwrate)
{
int err = 0;
u8 databuf[2] = {0};
if (bwrate == 0)
return 0;
mutex_lock(&obj->accel_lock);
err = BMP160_spi_read_bytes(obj->spi, BMI160_USER_ACC_CONF_ODR__REG,
&databuf[0], 1);
databuf[0] = BMI160_SET_BITSLICE(databuf[0], BMI160_USER_ACC_CONF_ODR,
bwrate);
err += BMP160_spi_write_bytes(obj->spi, BMI160_USER_ACC_CONF_ODR__REG,
&databuf[0], 1);
mdelay(20);
if (err < 0) {
pr_err("set bandwidth failed, res = %d\n", err);
mutex_unlock(&obj->accel_lock);
return BMI160_ACC_ERR_SPI;
}
pr_debug("set bandwidth = %d ok.\n", bwrate);
mutex_unlock(&obj->accel_lock);
return err;
}
/*!
* @brief Set OSR for acc
*
* @param[in] obj the pointer of struct bmi160_accelgyro_data
*
* @return zero success, non-zero failed
*/
static int BMI160_ACC_SetOSR4(struct bmi160_accelgyro_data *obj)
{
int err = 0;
uint8_t databuf[2] = {0};
uint8_t bandwidth = BMI160_ACCEL_OSR4_AVG1;
uint8_t accel_undersampling_parameter = 0;
mutex_lock(&obj->accel_lock);
err = BMP160_spi_read_bytes(obj->spi, BMI160_USER_ACC_CONF_ODR__REG,
&databuf[0], 1);
databuf[0] = BMI160_SET_BITSLICE(
databuf[0], BMI160_USER_ACC_CONF_ACC_BWP, bandwidth);
databuf[0] = BMI160_SET_BITSLICE(
databuf[0], BMI160_USER_ACC_CONF_ACC_UNDER_SAMPLING,
accel_undersampling_parameter);
err += BMP160_spi_write_bytes(obj->spi, BMI160_USER_ACC_CONF_ODR__REG,
&databuf[0], 1);
mdelay(10);
if (err < 0) {
pr_err("set OSR failed.\n");
mutex_unlock(&obj->accel_lock);
return BMI160_ACC_ERR_SPI;
}
pr_debug("[%s] acc_bmp = %d, acc_us = %d ok.\n", __func__, bandwidth,
accel_undersampling_parameter);
mutex_unlock(&obj->accel_lock);
return err;
}
/*!
* @brief Set interrupt enable
*
* @param[in] obj the pointer of struct bmi160_accelgyro_data
* @param[in] enable for interrupt
*
* @return zero success, non-zero failed
*/
static int BMI160_ACC_SetIntEnable(struct bmi160_accelgyro_data *obj, u8 enable)
{
int err = 0;
mutex_lock(&obj->accel_lock);
err = BMP160_spi_write_bytes(obj->spi, BMI160_USER_INT_EN_0_ADDR,
&enable, 0x01);
mdelay(1);
if (err < 0) {
mutex_unlock(&obj->accel_lock);
return err;
}
err = BMP160_spi_write_bytes(obj->spi, BMI160_USER_INT_EN_1_ADDR,
&enable, 0x01);
mdelay(1);
if (err < 0) {
mutex_unlock(&obj->accel_lock);
return err;
}
err = BMP160_spi_write_bytes(obj->spi, BMI160_USER_INT_EN_2_ADDR,
&enable, 0x01);
mdelay(1);
if (err < 0) {
mutex_unlock(&obj->accel_lock);
return err;
}
mutex_unlock(&obj->accel_lock);
pr_debug("bmi160 set interrupt enable = %d ok.\n", enable);
return 0;
}
/*!
* @brief bmi160 initialization
*
* @param[in] obj the pointer of struct bmi160_accelgyro_data
* @param[in] int reset calibration value
*
* @return zero success, non-zero failed
*/
static int bmi160_acc_init_client(struct bmi160_accelgyro_data *obj,
int reset_cali)
{
int err = 0;
err = BMI160_ACC_CheckDeviceID(obj);
if (err < 0)
return err;
err = BMI160_ACC_SetBWRate(obj, BMI160_ACCEL_ODR_200HZ);
if (err < 0)
return err;
err = BMI160_ACC_SetOSR4(obj);
if (err < 0)
return err;
err = BMI160_ACC_SetDataFormat(obj, BMI160_ACCEL_RANGE_4G);
if (err < 0)
return err;
gsensor_gain.x = gsensor_gain.y = gsensor_gain.z =
obj->accel_reso->sensitivity;
err = BMI160_ACC_SetIntEnable(obj, 0);
if (err < 0)
return err;
err = BMI160_ACC_SetPowerMode(obj, false);
if (err < 0)
return err;
if (reset_cali != 0) {
/* reset calibration only in power on */
err = BMI160_ACC_ResetCalibration(obj);
if (err < 0)
return err;
}
pr_debug("bmi160 acc init OK.\n");
return 0;
}
static int BMI160_ACC_ReadChipInfo(struct bmi160_accelgyro_data *obj, char *buf,
int bufsize)
{
sprintf(buf, "bmi160_acc");
return 0;
}
static int BMI160_ACC_CompassReadData(struct bmi160_accelgyro_data *obj,
char *buf, int bufsize)
{
int res = 0;
int acc[BMI160_ACC_AXES_NUM] = {0};
s16 databuf[BMI160_ACC_AXES_NUM] = {0};
if (sensor_power == false) {
res = BMI160_ACC_SetPowerMode(obj, true);
if (res)
pr_err("Power on bmi160_acc error %d!\n", res);
}
res = BMI160_ACC_ReadData(obj, databuf);
if (res) {
pr_err("read acc data failed.\n");
return -3;
}
/* Add compensated value performed by MTK calibration process */
databuf[BMI160_ACC_AXIS_X] += obj->accel_cali_sw[BMI160_ACC_AXIS_X];
databuf[BMI160_ACC_AXIS_Y] += obj->accel_cali_sw[BMI160_ACC_AXIS_Y];
databuf[BMI160_ACC_AXIS_Z] += obj->accel_cali_sw[BMI160_ACC_AXIS_Z];
/*remap coordinate */
acc[obj->cvt.map[BMI160_ACC_AXIS_X]] =
obj->cvt.sign[BMI160_ACC_AXIS_X] * databuf[BMI160_ACC_AXIS_X];
acc[obj->cvt.map[BMI160_ACC_AXIS_Y]] =
obj->cvt.sign[BMI160_ACC_AXIS_Y] * databuf[BMI160_ACC_AXIS_Y];
acc[obj->cvt.map[BMI160_ACC_AXIS_Z]] =
obj->cvt.sign[BMI160_ACC_AXIS_Z] * databuf[BMI160_ACC_AXIS_Z];
sprintf(buf, "%d %d %d", (s16)acc[BMI160_ACC_AXIS_X],
(s16)acc[BMI160_ACC_AXIS_Y], (s16)acc[BMI160_ACC_AXIS_Z]);
return 0;
}
static int BMI160_ACC_ReadSensorData(struct bmi160_accelgyro_data *obj,
char *buf, int bufsize)
{
int err = 0;
int acc[BMI160_ACC_AXES_NUM] = {0};
s16 databuf[BMI160_ACC_AXES_NUM] = {0};
if (sensor_power == false) {
err = BMI160_ACC_SetPowerMode(obj, true);
if (err) {
pr_err("set power on acc failed.\n");
return err;
}
}
err = BMI160_ACC_ReadData(obj, databuf);
if (err) {
pr_err("read acc data failed.\n");
return err;
}
databuf[BMI160_ACC_AXIS_X] += obj->accel_cali_sw[BMI160_ACC_AXIS_X];
databuf[BMI160_ACC_AXIS_Y] += obj->accel_cali_sw[BMI160_ACC_AXIS_Y];
databuf[BMI160_ACC_AXIS_Z] += obj->accel_cali_sw[BMI160_ACC_AXIS_Z];
/* remap coordinate */
acc[obj->cvt.map[BMI160_ACC_AXIS_X]] =
obj->cvt.sign[BMI160_ACC_AXIS_X] * databuf[BMI160_ACC_AXIS_X];
acc[obj->cvt.map[BMI160_ACC_AXIS_Y]] =
obj->cvt.sign[BMI160_ACC_AXIS_Y] * databuf[BMI160_ACC_AXIS_Y];
acc[obj->cvt.map[BMI160_ACC_AXIS_Z]] =
obj->cvt.sign[BMI160_ACC_AXIS_Z] * databuf[BMI160_ACC_AXIS_Z];
/* Output the mg */
acc[BMI160_ACC_AXIS_X] = acc[BMI160_ACC_AXIS_X] * GRAVITY_EARTH_1000 /
obj->accel_reso->sensitivity;
acc[BMI160_ACC_AXIS_Y] = acc[BMI160_ACC_AXIS_Y] * GRAVITY_EARTH_1000 /
obj->accel_reso->sensitivity;
acc[BMI160_ACC_AXIS_Z] = acc[BMI160_ACC_AXIS_Z] * GRAVITY_EARTH_1000 /
obj->accel_reso->sensitivity;
sprintf(buf, "%04x %04x %04x", acc[BMI160_ACC_AXIS_X],
acc[BMI160_ACC_AXIS_Y], acc[BMI160_ACC_AXIS_Z]);
return 0;
}
static int BMI160_ACC_ReadRawData(struct bmi160_accelgyro_data *obj, char *buf)
{
int err = 0;
s16 databuf[BMI160_ACC_AXES_NUM] = {0};
err = BMI160_ACC_ReadData(obj, databuf);
if (err) {
pr_err("read acc raw data failed.\n");
return -EIO;
}
sprintf(buf, "%s %04x %04x %04x", __func__,
databuf[BMI160_ACC_AXIS_X], databuf[BMI160_ACC_AXIS_Y],
databuf[BMI160_ACC_AXIS_Z]);
return 0;
}
int bmi160_acc_get_mode(struct bmi160_accelgyro_data *obj, unsigned char *mode)
{
int comres = 0;
u8 v_data_u8r = C_BMI160_ZERO_U8X;
comres = BMP160_spi_read_bytes(
obj->spi, BMI160_USER_ACC_PMU_STATUS__REG, &v_data_u8r, 1);
*mode = BMI160_GET_BITSLICE(v_data_u8r, BMI160_USER_ACC_PMU_STATUS);
return comres;
}
static int bmi160_acc_set_range(struct bmi160_accelgyro_data *obj,
unsigned char range)
{
int comres = 0;
unsigned char data[2] = {BMI160_USER_ACC_RANGE__REG};
if (obj == NULL)
return -1;
mutex_lock(&obj->accel_lock);
comres = BMP160_spi_read_bytes(obj->spi, BMI160_USER_ACC_RANGE__REG,
data + 1, 1);
data[1] = BMI160_SET_BITSLICE(data[1], BMI160_USER_ACC_RANGE, range);
/* comres = i2c_master_send(client, data, 2); */
comres = BMP160_spi_write_bytes(obj->spi, data[0], &data[1], 1);
mutex_unlock(&obj->accel_lock);
if (comres <= 0)
return BMI160_ACC_ERR_SPI;
else
return comres;
}
static int bmi160_acc_get_range(struct bmi160_accelgyro_data *obj, u8 *range)
{
int comres = 0;
u8 data;
comres = BMP160_spi_read_bytes(obj->spi, BMI160_USER_ACC_RANGE__REG,
&data, 1);
*range = BMI160_GET_BITSLICE(data, BMI160_USER_ACC_RANGE);
return comres;
}
static int bmi160_acc_set_bandwidth(struct bmi160_accelgyro_data *obj,
unsigned char bandwidth)
{
int comres = 0;
unsigned char data[2] = {BMI160_USER_ACC_CONF_ODR__REG};
pr_debug("[%s] bandwidth = %d\n", __func__, bandwidth);
mutex_lock(&obj->accel_lock);
comres = BMP160_spi_read_bytes(obj->spi, BMI160_USER_ACC_CONF_ODR__REG,
data + 1, 1);
data[1] = BMI160_SET_BITSLICE(data[1], BMI160_USER_ACC_CONF_ODR,
bandwidth);
/* comres = i2c_master_send(client, data, 2); */
comres = BMP160_spi_write_bytes(obj->spi, data[0], &data[1], 1);
mdelay(1);
mutex_unlock(&obj->accel_lock);
if (comres <= 0)
return BMI160_ACC_ERR_SPI;
else
return comres;
}
static int bmi160_acc_get_bandwidth(struct bmi160_accelgyro_data *obj,
unsigned char *bandwidth)
{
int comres = 0;
comres = BMP160_spi_read_bytes(obj->spi, BMI160_USER_ACC_CONF_ODR__REG,
bandwidth, 1);
*bandwidth = BMI160_GET_BITSLICE(*bandwidth, BMI160_USER_ACC_CONF_ODR);
return comres;
}
static ssize_t accel_show_chipinfo_value(struct device_driver *ddri, char *buf)
{
char strbuf[BMI160_BUFSIZE];
struct bmi160_accelgyro_data *obj = accelgyro_obj_data;
BMI160_ACC_ReadChipInfo(obj, strbuf, BMI160_BUFSIZE);
return snprintf(buf, PAGE_SIZE, "%s\n", strbuf);
}
static ssize_t accel_show_acc_op_mode_value(struct device_driver *ddri,
char *buf)
{
int err = 0;
u8 data = 0;
err = bmi160_acc_get_mode(accelgyro_obj_data, &data);
if (err < 0) {
pr_err("get acc op mode failed.\n");
return err;
}
return sprintf(buf, "%d\n", data);
}
static ssize_t accel_store_acc_op_mode_value(struct device_driver *ddri,
const char *buf, size_t count)
{
int err;
unsigned long data;
err = kstrtoul(buf, 10, &data);
if (err)
return err;
pr_debug("store_acc_op_mode_value = %d .\n", (int)data);
if (data == BMI160_ACC_MODE_NORMAL)
err = BMI160_ACC_SetPowerMode(accelgyro_obj_data, true);
else
err = BMI160_ACC_SetPowerMode(accelgyro_obj_data, false);
if (err < 0) {
pr_err("set acc op mode = %d failed.\n", (int)data);
return err;
}
return count;
}
static ssize_t accel_show_acc_range_value(struct device_driver *ddri, char *buf)
{
int err = 0;
u8 data;
err = bmi160_acc_get_range(accelgyro_obj_data, &data);
if (err < 0) {
pr_debug("get acc range failed.\n");
return err;
}
return sprintf(buf, "%d\n", data);
}
static ssize_t accel_store_acc_range_value(struct device_driver *ddri,
const char *buf, size_t count)
{
unsigned long data;
int err;
err = kstrtoul(buf, 10, &data);
if (err)
return err;
err = bmi160_acc_set_range(accelgyro_obj_data, (u8)data);
if (err < 0) {
pr_err("set acc range = %d failed.\n", (int)data);
return err;
}
return count;
}
static ssize_t accel_show_acc_odr_value(struct device_driver *ddri, char *buf)
{
int err;
u8 data;
err = bmi160_acc_get_bandwidth(accelgyro_obj_data, &data);
if (err < 0) {
pr_debug("get acc odr failed.\n");
return err;
}
return sprintf(buf, "%d\n", data);
}
static ssize_t accel_store_acc_odr_value(struct device_driver *ddri,
const char *buf, size_t count)
{
unsigned long data;
int err;
struct bmi160_accelgyro_data *obj = accelgyro_obj_data;
err = kstrtoul(buf, 10, &data);
if (err)
return err;
err = bmi160_acc_set_bandwidth(obj, (u8)data);
if (err < 0) {
pr_err("set acc bandwidth failed.\n");
return err;
}
obj->accel_odr.acc_odr = data;
return count;
}
static ssize_t accel_show_cpsdata_value(struct device_driver *ddri, char *buf)
{
char strbuf[BMI160_BUFSIZE] = {0};
struct bmi160_accelgyro_data *obj = accelgyro_obj_data;
BMI160_ACC_CompassReadData(obj, strbuf, BMI160_BUFSIZE);
return snprintf(buf, PAGE_SIZE, "%s\n", strbuf);
}
static ssize_t accel_show_sensordata_value(struct device_driver *ddri,
char *buf)
{
char strbuf[BMI160_BUFSIZE] = {0};
struct bmi160_accelgyro_data *obj = accelgyro_obj_data;
BMI160_ACC_ReadSensorData(obj, strbuf, BMI160_BUFSIZE);
return snprintf(buf, PAGE_SIZE, "%s\n", strbuf);
}
static ssize_t accel_show_cali_value(struct device_driver *ddri, char *buf)
{
int err = 0;
int len = 0;
int mul;
int tmp[BMI160_ACC_AXES_NUM] = {0};
struct bmi160_accelgyro_data *obj = accelgyro_obj_data;
obj = accelgyro_obj_data;
err = BMI160_ACC_ReadOffset(obj, obj->accel_offset);
if (err)
return -EINVAL;
err = BMI160_ACC_ReadCalibration(obj, tmp);
if (err)
return -EINVAL;
mul = obj->accel_reso->sensitivity /
bmi160_acc_offset_resolution.sensitivity;
len += snprintf(
buf + len, PAGE_SIZE - len,
"[HW ][%d] (%+3d, %+3d, %+3d) : (0x%02X, 0x%02X, 0x%02X)\n",
mul, obj->accel_offset[BMI160_ACC_AXIS_X],
obj->accel_offset[BMI160_ACC_AXIS_Y],
obj->accel_offset[BMI160_ACC_AXIS_Z],
obj->accel_offset[BMI160_ACC_AXIS_X],
obj->accel_offset[BMI160_ACC_AXIS_Y],
obj->accel_offset[BMI160_ACC_AXIS_Z]);
len += snprintf(buf + len, PAGE_SIZE - len,
"[SW ][%d] (%+3d, %+3d, %+3d)\n", 1,
obj->accel_cali_sw[BMI160_ACC_AXIS_X],
obj->accel_cali_sw[BMI160_ACC_AXIS_Y],
obj->accel_cali_sw[BMI160_ACC_AXIS_Z]);
len += snprintf(buf + len, PAGE_SIZE - len,
"[ALL] (%+3d, %+3d, %+3d) : (%+3d, %+3d, %+3d)\n",
obj->accel_offset[BMI160_ACC_AXIS_X] * mul +
obj->accel_cali_sw[BMI160_ACC_AXIS_X],
obj->accel_offset[BMI160_ACC_AXIS_Y] * mul +
obj->accel_cali_sw[BMI160_ACC_AXIS_Y],
obj->accel_offset[BMI160_ACC_AXIS_Z] * mul +
obj->accel_cali_sw[BMI160_ACC_AXIS_Z],
tmp[BMI160_ACC_AXIS_X], tmp[BMI160_ACC_AXIS_Y],
tmp[BMI160_ACC_AXIS_Z]);
return len;
}
static ssize_t accel_store_cali_value(struct device_driver *ddri,
const char *buf, size_t count)
{
int err, x, y, z;
int dat[BMI160_ACC_AXES_NUM] = {0};
struct bmi160_accelgyro_data *obj = accelgyro_obj_data;
if (!strncmp(buf, "rst", 3)) {
err = BMI160_ACC_ResetCalibration(obj);
if (err)
pr_err("reset accel_offset err = %d\n", err);
} else if (sscanf(buf, "0x%02X 0x%02X 0x%02X", &x, &y, &z) == 3) {
dat[BMI160_ACC_AXIS_X] = x;
dat[BMI160_ACC_AXIS_Y] = y;
dat[BMI160_ACC_AXIS_Z] = z;
err = BMI160_ACC_WriteCalibration(obj, dat);
if (err)
pr_err("write calibration err = %d\n", err);
} else {
pr_err("set calibration value by invalid format.\n");
}
return count;
}
static ssize_t accel_show_firlen_value(struct device_driver *ddri, char *buf)
{
return snprintf(buf, PAGE_SIZE, "not support\n");
}
static ssize_t accel_store_firlen_value(struct device_driver *ddri,
const char *buf, size_t count)
{
return count;
}
static ssize_t accel_show_trace_value(struct device_driver *ddri, char *buf)
{
int err;
struct bmi160_accelgyro_data *obj = accelgyro_obj_data;
err = snprintf(buf, PAGE_SIZE, "0x%04X\n",
atomic_read(&obj->accel_trace));
return err;
}
static ssize_t accel_store_trace_value(struct device_driver *ddri,
const char *buf, size_t count)
{
int trace;
struct bmi160_accelgyro_data *obj = accelgyro_obj_data;
if (sscanf(buf, "0x%x", &trace) == 1)
atomic_set(&obj->accel_trace, trace);
else
pr_err("invalid content: '%s'\n", buf);
return count;
}
static ssize_t accel_show_status_value(struct device_driver *ddri, char *buf)
{
ssize_t len = 0;
struct bmi160_accelgyro_data *obj = accelgyro_obj_data;
len += snprintf(buf + len, PAGE_SIZE - len, "CUST: %d\n",
obj->hw.direction);
return len;
}
static ssize_t accel_show_power_status_value(struct device_driver *ddri,
char *buf)
{
if (sensor_power)
pr_debug("G sensor is in work mode, sensor_power = %d\n",
sensor_power);
else
pr_debug("G sensor is in standby mode, sensor_power = %d\n",
sensor_power);
return 0;
}
static int bmi160_fifo_length(uint32_t *fifo_length)
{
int comres = 0;
struct bmi160_accelgyro_data *obj = accelgyro_obj_data;
uint8_t a_data_u8r[2] = {0, 0};
comres += BMP160_spi_read_bytes(obj->spi,
BMI160_USER_FIFO_BYTE_COUNTER_LSB__REG,
a_data_u8r, 2);
a_data_u8r[1] = BMI160_GET_BITSLICE(a_data_u8r[1],
BMI160_USER_FIFO_BYTE_COUNTER_MSB);
*fifo_length = (uint32_t)(((uint32_t)((uint8_t)(a_data_u8r[1])
<< BMI160_SHIFT_8_POSITION)) |
a_data_u8r[0]);
return comres;
}
int bmi160_set_fifo_time_enable(u8 v_fifo_time_enable_u8)
{
/* variable used for return the status of communication result */
int com_rslt = -1;
u8 v_data_u8 = 0;
struct bmi160_accelgyro_data *obj = accelgyro_obj_data;
if (v_fifo_time_enable_u8 <= 1) {
/* write the fifo sensor time */
com_rslt = BMP160_spi_read_bytes(
obj->spi, BMI160_USER_FIFO_TIME_ENABLE__REG, &v_data_u8,
1);
if (com_rslt == 0) {
v_data_u8 = BMI160_SET_BITSLICE(
v_data_u8, BMI160_USER_FIFO_TIME_ENABLE,
v_fifo_time_enable_u8);
com_rslt += BMP160_spi_write_bytes(
obj->spi, BMI160_USER_FIFO_TIME_ENABLE__REG,
&v_data_u8, 1);
}
} else {
com_rslt = -2;
}
return com_rslt;
}
int bmi160_set_fifo_header_enable(u8 v_fifo_header_enable_u8)
{
/* variable used for return the status of communication result */
int com_rslt = -1;
u8 v_data_u8 = 0;
struct bmi160_accelgyro_data *obj = accelgyro_obj_data;
if (v_fifo_header_enable_u8 <= 1) {
/* read the fifo sensor header enable */
com_rslt = BMP160_spi_read_bytes(
obj->spi, BMI160_USER_FIFO_HEADER_EN__REG, &v_data_u8,
1);
if (com_rslt == 0) {
v_data_u8 = BMI160_SET_BITSLICE(
v_data_u8, BMI160_USER_FIFO_HEADER_EN,
v_fifo_header_enable_u8);
com_rslt += BMP160_spi_write_bytes(
obj->spi, BMI160_USER_FIFO_HEADER_EN__REG,
&v_data_u8, 1);
}
} else {
com_rslt = -2;
}
return com_rslt;
}
int bmi160_get_fifo_time_enable(u8 *v_fifo_time_enable_u8)
{
/* variable used for return the status of communication result */
int com_rslt = -1;
u8 v_data_u8 = 0;
struct bmi160_accelgyro_data *obj = accelgyro_obj_data;
com_rslt = BMP160_spi_read_bytes(
obj->spi, BMI160_USER_FIFO_TIME_ENABLE__REG, &v_data_u8, 1);
*v_fifo_time_enable_u8 =
BMI160_GET_BITSLICE(v_data_u8, BMI160_USER_FIFO_TIME_ENABLE);
return com_rslt;
}
static int bmi160_get_fifo_header_enable(u8 *v_fifo_header_u8)
{
/* variable used for return the status of communication result */
int com_rslt = -1;
u8 v_data_u8 = 0;
struct bmi160_accelgyro_data *obj = accelgyro_obj_data;
com_rslt = BMP160_spi_read_bytes(
obj->spi, BMI160_USER_FIFO_HEADER_EN__REG, &v_data_u8, 1);
*v_fifo_header_u8 =
BMI160_GET_BITSLICE(v_data_u8, BMI160_USER_FIFO_HEADER_EN);
return com_rslt;
}
/*!
* @brief This API is used to read
* interrupt enable step detector interrupt from
* the register bit 0x52 bit 3
*
* @param v_step_intr_u8 : The value of step detector interrupt enable
*
* @return results of bus communication function
* @retval 0 -> Success
* @retval -1 -> Error
*/
static BMI160_RETURN_FUNCTION_TYPE bmi160_get_std_enable(u8 *v_step_intr_u8)
{
/* variable used for return the status of communication result */
BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES;
u8 v_data_u8 = BMI160_INIT_VALUE;
/* check the p_bmi160 structure as NULL */
if (p_bmi160 == BMI160_NULL)
return E_BMI160_NULL_PTR;
/* read the step detector interrupt */
com_rslt = p_bmi160->BMI160_BUS_READ_FUNC(
p_bmi160->dev_addr,
BMI160_USER_INTR_ENABLE_2_STEP_DETECTOR_ENABLE__REG, &v_data_u8,
BMI160_GEN_READ_WRITE_DATA_LENGTH);
*v_step_intr_u8 = BMI160_GET_BITSLICE(
v_data_u8, BMI160_USER_INTR_ENABLE_2_STEP_DETECTOR_ENABLE);
return com_rslt;
}
BMI160_RETURN_FUNCTION_TYPE bmi160_write_reg(u8 v_addr_u8, u8 *v_data_u8,
u8 v_len_u8)
{
/* variable used for return the status of communication result */
BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES;
/* check the p_bmi160 structure as NULL */
if (p_bmi160 == BMI160_NULL)
return E_BMI160_NULL_PTR;
/* write data from register */
com_rslt = p_bmi160->BMI160_BUS_WRITE_FUNC(
p_bmi160->dev_addr, v_addr_u8, v_data_u8, v_len_u8);
return com_rslt;
}
BMI160_RETURN_FUNCTION_TYPE bmi160_init(struct bmi160_t *bmi160)
{
/* variable used for return the status of communication result */
BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES;
u8 v_data_u8 = BMI160_INIT_VALUE;
u8 v_pmu_data_u8 = BMI160_INIT_VALUE;
/* assign bmi160 ptr */
p_bmi160 = bmi160;
com_rslt = p_bmi160->BMI160_BUS_READ_FUNC(
p_bmi160->dev_addr, BMI160_USER_CHIP_ID__REG, &v_data_u8,
BMI160_GEN_READ_WRITE_DATA_LENGTH);
/* read Chip Id */
p_bmi160->chip_id = v_data_u8;
/* To avoid gyro wakeup it is required to write 0x00 to 0x6C */
com_rslt +=
bmi160_write_reg(BMI160_USER_PMU_TRIGGER_ADDR, &v_pmu_data_u8,
BMI160_GEN_READ_WRITE_DATA_LENGTH);
return com_rslt;
}
/*!
* @brief Configure trigger condition of interrupt1
* and interrupt2 pin from the register 0x53
* @brief interrupt1 - bit 0
* @brief interrupt2 - bit 4
*
* @param v_channel_u8: The value of edge trigger selection
* v_channel_u8 | Edge trigger
* ---------------|---------------
* 0 | BMI160_INTR1_EDGE_CTRL
* 1 | BMI160_INTR2_EDGE_CTRL
*
* @param v_intr_edge_ctrl_u8 : The value of edge trigger enable
* value | interrupt enable
* ----------|-------------------
* 0x01 | BMI160_EDGE
* 0x00 | BMI160_LEVEL
*
* @return results of bus communication function
* @retval 0 -> Success
* @retval -1 -> Error
*
*/
BMI160_RETURN_FUNCTION_TYPE bmi160_set_intr_edge_ctrl(u8 v_channel_u8,
u8 v_intr_edge_ctrl_u8)
{
/* variable used for return the status of communication result */
BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES;
u8 v_data_u8 = BMI160_INIT_VALUE;
/* check the p_bmi160 structure as NULL */
if (p_bmi160 == BMI160_NULL)
return E_BMI160_NULL_PTR;
switch (v_channel_u8) {
case BMI160_INTR1_EDGE_CTRL:
/* write the edge trigger interrupt1 */
com_rslt = p_bmi160->BMI160_BUS_READ_FUNC(
p_bmi160->dev_addr, BMI160_USER_INTR1_EDGE_CTRL__REG,
&v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH);
if (com_rslt == SUCCESS) {
v_data_u8 = BMI160_SET_BITSLICE(
v_data_u8, BMI160_USER_INTR1_EDGE_CTRL,
v_intr_edge_ctrl_u8);
com_rslt += p_bmi160->BMI160_BUS_WRITE_FUNC(
p_bmi160->dev_addr,
BMI160_USER_INTR1_EDGE_CTRL__REG, &v_data_u8,
BMI160_GEN_READ_WRITE_DATA_LENGTH);
}
break;
case BMI160_INTR2_EDGE_CTRL:
/* write the edge trigger interrupt2 */
com_rslt = p_bmi160->BMI160_BUS_READ_FUNC(
p_bmi160->dev_addr, BMI160_USER_INTR2_EDGE_CTRL__REG,
&v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH);
if (com_rslt == SUCCESS) {
v_data_u8 = BMI160_SET_BITSLICE(
v_data_u8, BMI160_USER_INTR2_EDGE_CTRL,
v_intr_edge_ctrl_u8);
com_rslt += p_bmi160->BMI160_BUS_WRITE_FUNC(
p_bmi160->dev_addr,
BMI160_USER_INTR2_EDGE_CTRL__REG, &v_data_u8,
BMI160_GEN_READ_WRITE_DATA_LENGTH);
}
break;
default:
com_rslt = E_BMI160_OUT_OF_RANGE;
break;
}
return com_rslt;
}
static int bmi160_set_command_register(u8 cmd_reg)
{
int comres = 0;
struct bmi160_accelgyro_data *obj = accelgyro_obj_data;
comres += BMP160_spi_write_bytes(obj->spi, BMI160_CMD_COMMANDS__REG,
&cmd_reg, 1);
return comres;
}
static ssize_t accel_bmi160_fifo_bytecount_show(struct device_driver *ddri,
char *buf)
{
int comres = 0;
uint32_t fifo_bytecount = 0;
uint8_t a_data_u8r[2] = {0, 0};
struct bmi160_accelgyro_data *obj = accelgyro_obj_data;
comres += BMP160_spi_read_bytes(obj->spi,
BMI160_USER_FIFO_BYTE_COUNTER_LSB__REG,
a_data_u8r, 2);
a_data_u8r[1] = BMI160_GET_BITSLICE(a_data_u8r[1],
BMI160_USER_FIFO_BYTE_COUNTER_MSB);
fifo_bytecount = (uint32_t)(((uint32_t)((uint8_t)(a_data_u8r[1])
<< BMI160_SHIFT_8_POSITION)) |
a_data_u8r[0]);
comres = sprintf(buf, "%u\n", fifo_bytecount);
return comres;
}
static ssize_t accel_bmi160_fifo_bytecount_store(struct device_driver *ddri,
const char *buf, size_t count)
{
int err;
unsigned long data;
struct bmi160_accelgyro_data *client_data = accelgyro_obj_data;
err = kstrtoul(buf, 10, &data);
if (err)
return err;
client_data->fifo_bytecount = (u16)data;
return count;
}
static int bmi160_fifo_data_sel_get(struct bmi160_accelgyro_data *client_data)
{
int err = 0;
struct bmi160_accelgyro_data *obj = accelgyro_obj_data;
unsigned char data;
unsigned char fifo_acc_en, fifo_gyro_en, fifo_mag_en;
unsigned char fifo_datasel;
err = BMP160_spi_read_bytes(obj->spi, BMI160_USER_FIFO_ACC_EN__REG,
&data, 1);
fifo_acc_en = BMI160_GET_BITSLICE(data, BMI160_USER_FIFO_ACC_EN);
err += BMP160_spi_read_bytes(obj->spi, BMI160_USER_FIFO_GYRO_EN__REG,
&data, 1);
fifo_gyro_en = BMI160_GET_BITSLICE(data, BMI160_USER_FIFO_GYRO_EN);
err += BMP160_spi_read_bytes(obj->spi, BMI160_USER_FIFO_MAG_EN__REG,
&data, 1);
fifo_mag_en = BMI160_GET_BITSLICE(data, BMI160_USER_FIFO_MAG_EN);
if (err)
return err;
fifo_datasel = (fifo_acc_en << BMI_ACC_SENSOR) |
(fifo_gyro_en << BMI_GYRO_SENSOR) |
(fifo_mag_en << BMI_MAG_SENSOR);
client_data->fifo_data_sel = fifo_datasel;
return err;
}
static ssize_t accel_bmi160_fifo_data_sel_show(struct device_driver *ddri,
char *buf)
{
int err = 0;
struct bmi160_accelgyro_data *client_data = accelgyro_obj_data;
err = bmi160_fifo_data_sel_get(client_data);
if (err)
return -EINVAL;
return sprintf(buf, "%d\n", client_data->fifo_data_sel);
}
static ssize_t accel_bmi160_fifo_data_sel_store(struct device_driver *ddri,
const char *buf, size_t count)
{
struct bmi160_accelgyro_data *client_data = accelgyro_obj_data;
struct bmi160_accelgyro_data *obj = accelgyro_obj_data;
int err;
unsigned long data;
unsigned char fifo_datasel;
unsigned char fifo_acc_en, fifo_gyro_en, fifo_mag_en;
err = kstrtoul(buf, 10, &data);
if (err)
return err;
/* data format: aimed 0b0000 0x(m)x(g)x(a), x:1 enable, 0:disable */
if (data > 7)
return -EINVAL;
fifo_datasel = (unsigned char)data;
fifo_acc_en = fifo_datasel & (1 << BMI_ACC_SENSOR) ? 1 : 0;
fifo_gyro_en = fifo_datasel & (1 << BMI_GYRO_SENSOR) ? 1 : 0;
fifo_mag_en = fifo_datasel & (1 << BMI_MAG_SENSOR) ? 1 : 0;
err += BMP160_spi_read_bytes(obj->spi, BMI160_USER_FIFO_ACC_EN__REG,
&fifo_datasel, 1);
fifo_datasel = BMI160_SET_BITSLICE(
fifo_datasel, BMI160_USER_FIFO_ACC_EN, fifo_acc_en);
err += BMP160_spi_write_bytes(obj->spi, BMI160_USER_FIFO_ACC_EN__REG,
&fifo_datasel, 1);
udelay(500);
err += BMP160_spi_read_bytes(obj->spi, BMI160_USER_FIFO_GYRO_EN__REG,
&fifo_datasel, 1);
fifo_datasel = BMI160_SET_BITSLICE(
fifo_datasel, BMI160_USER_FIFO_GYRO_EN, fifo_gyro_en);
err += BMP160_spi_write_bytes(obj->spi, BMI160_USER_FIFO_GYRO_EN__REG,
&fifo_datasel, 1);
udelay(500);
err += BMP160_spi_read_bytes(obj->spi, BMI160_USER_FIFO_MAG_EN__REG,
&fifo_datasel, 1);
fifo_datasel = BMI160_SET_BITSLICE(
fifo_datasel, BMI160_USER_FIFO_MAG_EN, fifo_mag_en);
err += BMP160_spi_write_bytes(obj->spi, BMI160_USER_FIFO_MAG_EN__REG,
&fifo_datasel, 1);
udelay(500);
if (err)
return -EIO;
client_data->fifo_data_sel = (u8)data;
pr_debug("FIFO fifo_data_sel %d, A_en:%d, G_en:%d, M_en:%d\n",
client_data->fifo_data_sel, fifo_acc_en, fifo_gyro_en,
fifo_mag_en);
return count;
}
static ssize_t accel_bmi160_fifo_data_out_frame_show(struct device_driver *ddri,
char *buf)
{
int err = 0;
struct bmi160_accelgyro_data *obj = accelgyro_obj_data;
struct bmi160_accelgyro_data *client_data = accelgyro_obj_data;
uint32_t fifo_bytecount = 0;
static char tmp_buf[1003] = {0};
char *pBuf = NULL;
pBuf = &tmp_buf[0];
err = bmi160_fifo_length(&fifo_bytecount);
if (err < 0) {
pr_err("read fifo length error.\n");
return -EINVAL;
}
if (fifo_bytecount == 0)
return 0;
client_data->fifo_bytecount = fifo_bytecount;
#ifdef FIFO_READ_USE_DMA_MODE_I2C
err = i2c_dma_read(client, BMI160_USER_FIFO_DATA__REG, buf,
client_data->fifo_bytecount);
#else
err = BMP160_spi_read_bytes(obj->spi, BMI160_USER_FIFO_DATA__REG, buf,
fifo_bytecount);
#endif
if (err < 0) {
pr_err("read fifo data error.\n");
return sprintf(buf, "Read byte block error.");
}
return client_data->fifo_bytecount;
}
static ssize_t accel_show_layout_value(struct device_driver *ddri, char *buf)
{
struct bmi160_accelgyro_data *data = accelgyro_obj_data;
return sprintf(buf, "(%d, %d)\n[%+2d %+2d %+2d]\n[%+2d %+2d %+2d]\n",
data->hw.direction, atomic_read(&data->layout),
data->cvt.sign[0], data->cvt.sign[1], data->cvt.sign[2],
data->cvt.map[0], data->cvt.map[1], data->cvt.map[2]);
}
static ssize_t accel_store_layout_value(struct device_driver *ddri,
const char *buf, size_t count)
{
struct bmi160_accelgyro_data *data = accelgyro_obj_data;
int layout = 0;
if (kstrtos32(buf, 10, &layout) == 0) {
atomic_set(&data->layout, layout);
if (!hwmsen_get_convert(layout, &data->cvt)) {
pr_err("HWMSEN_GET_CONVERT function error!\r\n");
} else if (!hwmsen_get_convert(data->hw.direction,
&data->cvt)) {
pr_err("invalid layout: %d, restore to %d\n",
layout, data->hw.direction);
} else {
pr_err("invalid layout: (%d, %d)\n", layout,
data->hw.direction);
hwmsen_get_convert(0, &data->cvt);
}
} else {
pr_err("invalid format = '%s'\n", buf);
}
return count;
}
static void bmi_dump_reg(struct bmi160_accelgyro_data *client_data)
{
int i;
u8 dbg_buf0[REG_MAX0];
u8 dbg_buf1[REG_MAX1];
u8 dbg_buf_str0[REG_MAX0 * 3 + 1] = "";
u8 dbg_buf_str1[REG_MAX1 * 3 + 1] = "";
struct bmi160_accelgyro_data *obj = accelgyro_obj_data;
pr_debug("\nFrom 0x00:\n");
BMP160_spi_read_bytes(obj->spi, BMI160_USER_CHIP_ID__REG, dbg_buf0,
REG_MAX0);
for (i = 0; i < REG_MAX0; i++) {
sprintf(dbg_buf_str0 + i * 3, "%02x%c", dbg_buf0[i],
(((i + 1) % BYTES_PER_LINE == 0) ? '\n' : ' '));
}
pr_debug("%s\n", dbg_buf_str0);
BMP160_spi_read_bytes(obj->spi, BMI160_USER_ACCEL_CONFIG_ADDR, dbg_buf1,
REG_MAX1);
pr_debug("\nFrom 0x40:\n");
for (i = 0; i < REG_MAX1; i++) {
sprintf(dbg_buf_str1 + i * 3, "%02x%c", dbg_buf1[i],
(((i + 1) % BYTES_PER_LINE == 0) ? '\n' : ' '));
}
pr_debug("\n%s\n", dbg_buf_str1);
}
static ssize_t accel_bmi_register_show(struct device_driver *ddri, char *buf)
{
struct bmi160_accelgyro_data *client_data = accelgyro_obj_data;
bmi_dump_reg(client_data);
return sprintf(buf, "Dump OK\n");
}
static ssize_t accel_bmi_register_store(struct device_driver *ddri,
const char *buf, size_t count)
{
int err;
int reg_addr = 0;
int data;
u8 write_reg_add = 0;
u8 write_data = 0;
struct bmi160_accelgyro_data *obj = accelgyro_obj_data;
err = sscanf(buf, "%3d %3d", &reg_addr, &data);
if (err < 2)
return err;
if (data > 0xff)
return -EINVAL;
write_reg_add = (u8)reg_addr;
write_data = (u8)data;
err += BMP160_spi_write_bytes(obj->spi, write_reg_add, &write_data, 1);
if (!err) {
pr_err("write reg 0x%2x, value= 0x%2x\n", reg_addr, data);
} else {
pr_err("write reg fail\n");
return err;
}
return count;
}
static ssize_t accel_bmi160_bmi_value_show(struct device_driver *ddri,
char *buf)
{
int err;
u8 raw_data[12] = {0};
struct bmi160_accelgyro_data *obj = accelgyro_obj_data;
memset(raw_data, 0, sizeof(raw_data));
err = BMP160_spi_read_bytes(
obj->spi, BMI160_USER_DATA_8_GYRO_X_LSB__REG, raw_data, 12);
if (err)
return err;
/* output:gyro x y z acc x y z */
return sprintf(buf, "%hd %d %hd %hd %hd %hd\n",
(s16)(raw_data[1] << 8 | raw_data[0]),
(s16)(raw_data[3] << 8 | raw_data[2]),
(s16)(raw_data[5] << 8 | raw_data[4]),
(s16)(raw_data[7] << 8 | raw_data[6]),
(s16)(raw_data[9] << 8 | raw_data[8]),
(s16)(raw_data[11] << 8 | raw_data[10]));
}
static int bmi160_get_fifo_wm(u8 *v_fifo_wm_u8)
{
/* variable used for return the status of communication result */
int com_rslt = -1;
u8 v_data_u8 = 0;
struct bmi160_accelgyro_data *obj = accelgyro_obj_data;
/* check the p_bmi160 structure as NULL */
/* read the fifo water mark level */
com_rslt = BMP160_spi_read_bytes(obj->spi, BMI160_USER_FIFO_WM__REG,
&v_data_u8, 1);
*v_fifo_wm_u8 = BMI160_GET_BITSLICE(v_data_u8, BMI160_USER_FIFO_WM);
return com_rslt;
}
static int bmi160_set_fifo_wm(u8 v_fifo_wm_u8)
{
/* variable used for return the status of communication result */
int com_rslt = -1;
struct bmi160_accelgyro_data *obj = accelgyro_obj_data;
/* write the fifo water mark level */
com_rslt = BMP160_spi_write_bytes(obj->spi, BMI160_USER_FIFO_WM__REG,
&v_fifo_wm_u8, 1);
return com_rslt;
}
static ssize_t accel_bmi160_fifo_watermark_show(struct device_driver *ddri,
char *buf)
{
int err;
u8 data = 0xff;
err = bmi160_get_fifo_wm(&data);
if (err)
return err;
return sprintf(buf, "%d\n", data);
}
static ssize_t accel_bmi160_fifo_watermark_store(struct device_driver *ddri,
const char *buf, size_t count)
{
int err;
unsigned long data;
u8 fifo_watermark;
err = kstrtoul(buf, 10, &data);
if (err)
return err;
fifo_watermark = (u8)data;
err = bmi160_set_fifo_wm(fifo_watermark);
if (err)
return -EIO;
pr_debug("set fifo watermark = %d ok.", (int)fifo_watermark);
return count;
}
static ssize_t accel_bmi160_delay_show(struct device_driver *ddri, char *buf)
{
struct bmi160_accelgyro_data *client_data = accelgyro_obj_data;
return sprintf(buf, "%d\n", atomic_read(&client_data->accel_delay));
}
static ssize_t accel_bmi160_delay_store(struct device_driver *ddri,
const char *buf, size_t count)
{
int err;
unsigned long data;
struct bmi160_accelgyro_data *client_data = accelgyro_obj_data;
err = kstrtoul(buf, 10, &data);
if (err)
return err;
if (data < BMI_DELAY_MIN)
data = BMI_DELAY_MIN;
atomic_set(&client_data->accel_delay, (unsigned int)data);
return count;
}
static ssize_t accel_bmi160_fifo_flush_store(struct device_driver *ddri,
const char *buf, size_t count)
{
int err;
unsigned long enable;
err = kstrtoul(buf, 10, &enable);
if (err)
return err;
if (enable)
err = bmi160_set_command_register(CMD_CLR_FIFO_DATA);
if (err)
pr_err("fifo flush failed!\n");
return count;
}
static ssize_t accel_bmi160_fifo_header_en_show(struct device_driver *ddri,
char *buf)
{
int err;
u8 data = 0xff;
err = bmi160_get_fifo_header_enable(&data);
if (err)
return err;
return sprintf(buf, "%d\n", data);
}
static ssize_t accel_bmi160_fifo_header_en_store(struct device_driver *ddri,
const char *buf, size_t count)
{
int err;
unsigned long data;
u8 fifo_header_en;
struct bmi160_accelgyro_data *client_data = accelgyro_obj_data;
err = kstrtoul(buf, 10, &data);
if (err)
return err;
if (data > 1)
return -ENOENT;
fifo_header_en = (u8)data;
err = bmi160_set_fifo_header_enable(fifo_header_en);
if (err)
return -EIO;
client_data->fifo_head_en = fifo_header_en;
return count;
}
static int bmg_read_raw_data(struct bmi160_accelgyro_data *obj,
s16 data[BMG_AXES_NUM])
{
int err = 0;
struct bmi160_accelgyro_data *priv = gyro_obj_data;
if (priv->gyro_power_mode == BMG_SUSPEND_MODE) {
err = bmg_set_powermode(
NULL, (enum BMG_POWERMODE_ENUM)BMG_NORMAL_MODE);
if (err < 0) {
pr_err("set power mode failed, err = %d\n", err);
return err;
}
}
if (priv->gyro_sensor_type == BMI160_GYRO_TYPE) {
u8 buf_tmp[BMG_DATA_LEN] = {0};
err = BMP160_spi_read_bytes(
NULL, BMI160_USER_DATA_8_GYR_X_LSB__REG, buf_tmp, 6);
if (err) {
pr_err("read gyro raw data failed.\n");
return err;
}
/* Data X */
data[BMG_AXIS_X] = (s16)(
(((s32)((s8)buf_tmp[1])) << BMI160_SHIFT_8_POSITION) |
(buf_tmp[0]));
/* Data Y */
data[BMG_AXIS_Y] = (s16)(
(((s32)((s8)buf_tmp[3])) << BMI160_SHIFT_8_POSITION) |
(buf_tmp[2]));
/* Data Z */
data[BMG_AXIS_Z] = (s16)(
(((s32)((s8)buf_tmp[5])) << BMI160_SHIFT_8_POSITION) |
(buf_tmp[4]));
if (atomic_read(&priv->gyro_trace) & GYRO_TRC_RAWDATA) {
pr_debug(
"[%s][16bit raw][%08X %08X %08X] => [%5d %5d %5d]\n",
priv->gyro_sensor_name, data[BMG_AXIS_X],
data[BMG_AXIS_Y], data[BMG_AXIS_Z],
data[BMG_AXIS_X], data[BMG_AXIS_Y],
data[BMG_AXIS_Z]);
}
}
#ifdef CONFIG_BMG_LOWPASS
/*
*Example: firlen = 16, filter buffer = [0] ... [15],
*when 17th data come, replace [0] with this new data.
*Then, average this filter buffer and report average value to upper
*layer.
*/
if (atomic_read(&priv->gyro_filter)) {
if (atomic_read(&priv->gyro_fir_en) &&
!atomic_read(&priv->gyro_suspend)) {
int idx, firlen = atomic_read(&priv->gyro_firlen);
if (priv->gyro_fir.num < firlen) {
priv->gyro_fir
.raw[priv->gyro_fir.num][BMG_AXIS_X] =
data[BMG_AXIS_X];
priv->gyro_fir
.raw[priv->gyro_fir.num][BMG_AXIS_Y] =
data[BMG_AXIS_Y];
priv->gyro_fir
.raw[priv->gyro_fir.num][BMG_AXIS_Z] =
data[BMG_AXIS_Z];
priv->gyro_fir.sum[BMG_AXIS_X] +=
data[BMG_AXIS_X];
priv->gyro_fir.sum[BMG_AXIS_Y] +=
data[BMG_AXIS_Y];
priv->gyro_fir.sum[BMG_AXIS_Z] +=
data[BMG_AXIS_Z];
if (atomic_read(&priv->gyro_trace) &
GYRO_TRC_FILTER) {
pr_debug(
"add [%2d][%5d %5d %5d] => [%5d %5d %5d]\n",
priv->gyro_fir.num,
priv->gyro_fir
.raw[priv->gyro_fir.num]
[BMG_AXIS_X],
priv->gyro_fir
.raw[priv->gyro_fir.num]
[BMG_AXIS_Y],
priv->gyro_fir
.raw[priv->gyro_fir.num]
[BMG_AXIS_Z],
priv->gyro_fir.sum[BMG_AXIS_X],
priv->gyro_fir.sum[BMG_AXIS_Y],
priv->gyro_fir.sum[BMG_AXIS_Z]);
}
priv->gyro_fir.num++;
priv->gyro_fir.idx++;
} else {
idx = priv->gyro_fir.idx % firlen;
priv->gyro_fir.sum[BMG_AXIS_X] -=
priv->gyro_fir.raw[idx][BMG_AXIS_X];
priv->gyro_fir.sum[BMG_AXIS_Y] -=
priv->gyro_fir.raw[idx][BMG_AXIS_Y];
priv->gyro_fir.sum[BMG_AXIS_Z] -=
priv->gyro_fir.raw[idx][BMG_AXIS_Z];
priv->gyro_fir.raw[idx][BMG_AXIS_X] =
data[BMG_AXIS_X];
priv->gyro_fir.raw[idx][BMG_AXIS_Y] =
data[BMG_AXIS_Y];
priv->gyro_fir.raw[idx][BMG_AXIS_Z] =
data[BMG_AXIS_Z];
priv->gyro_fir.sum[BMG_AXIS_X] +=
data[BMG_AXIS_X];
priv->gyro_fir.sum[BMG_AXIS_Y] +=
data[BMG_AXIS_Y];
priv->gyro_fir.sum[BMG_AXIS_Z] +=
data[BMG_AXIS_Z];
priv->gyro_fir.idx++;
data[BMG_AXIS_X] =
priv->gyro_fir.sum[BMG_AXIS_X] / firlen;
data[BMG_AXIS_Y] =
priv->gyro_fir.sum[BMG_AXIS_Y] / firlen;
data[BMG_AXIS_Z] =
priv->gyro_fir.sum[BMG_AXIS_Z] / firlen;
if (atomic_read(&priv->gyro_trace) &
GYRO_TRC_FILTER) {
pr_debug(
"add [%2d][%5d %5d %5d] =>[%5d %5d %5d] : [%5d %5d %5d]\n",
idx,
priv->gyro_fir
.raw[idx][BMG_AXIS_X],
priv->gyro_fir
.raw[idx][BMG_AXIS_Y],
priv->gyro_fir
.raw[idx][BMG_AXIS_Z],
priv->gyro_fir.sum[BMG_AXIS_X],
priv->gyro_fir.sum[BMG_AXIS_Y],
priv->gyro_fir.sum[BMG_AXIS_Z],
data[BMG_AXIS_X],
data[BMG_AXIS_Y],
data[BMG_AXIS_Z]);
}
}
}
}
#endif
return err;
}
#ifndef SW_CALIBRATION
/* get hardware offset value from chip register */
static int bmg_get_hw_offset(struct bmi160_accelgyro_data *obj,
s8 offset[BMG_AXES_NUM + 1])
{
int err = 0;
/* HW calibration is under construction */
pr_debug("hw offset x=%x, y=%x, z=%x\n", offset[BMG_AXIS_X],
offset[BMG_AXIS_Y], offset[BMG_AXIS_Z]);
return err;
}
#endif
#ifndef SW_CALIBRATION
/* set hardware offset value to chip register*/
static int bmg_set_hw_offset(struct bmi160_accelgyro_data *obj,
s8 offset[BMG_AXES_NUM + 1])
{
int err = 0;
/* HW calibration is under construction */
pr_debug("hw offset x=%x, y=%x, z=%x\n", offset[BMG_AXIS_X],
offset[BMG_AXIS_Y], offset[BMG_AXIS_Z]);
return err;
}
#endif
static int bmg_reset_calibration(struct bmi160_accelgyro_data *obj)
{
int err = 0;
#ifdef SW_CALIBRATION
#else
err = bmg_set_hw_offset(NULL, obj->gyro_offset);
if (err) {
pr_err("read hw offset failed, %d\n", err);
return err;
}
#endif
memset(obj->gyro_cali_sw, 0x00, sizeof(obj->gyro_cali_sw));
memset(obj->gyro_offset, 0x00, sizeof(obj->gyro_offset));
return err;
}
static int bmg_read_calibration(struct bmi160_accelgyro_data *obj,
int act[BMG_AXES_NUM], int raw[BMG_AXES_NUM])
{
/*
*raw: the raw calibration data, unmapped;
*act: the actual calibration data, mapped
*/
int err = 0;
int mul;
obj = gyro_obj_data;
#ifdef SW_CALIBRATION
/* only sw calibration, disable hw calibration */
mul = 0;
#else
err = bmg_get_hw_offset(NULL, obj->gyro_offset);
if (err) {
pr_err("read hw offset failed, %d\n", err);
return err;
}
mul = 1; /* mul = sensor sensitivity / offset sensitivity */
#endif
raw[BMG_AXIS_X] = obj->gyro_offset[BMG_AXIS_X] * mul +
obj->gyro_cali_sw[BMG_AXIS_X];
raw[BMG_AXIS_Y] = obj->gyro_offset[BMG_AXIS_Y] * mul +
obj->gyro_cali_sw[BMG_AXIS_Y];
raw[BMG_AXIS_Z] = obj->gyro_offset[BMG_AXIS_Z] * mul +
obj->gyro_cali_sw[BMG_AXIS_Z];
act[obj->cvt.map[BMG_AXIS_X]] =
obj->cvt.sign[BMG_AXIS_X] * raw[BMG_AXIS_X];
act[obj->cvt.map[BMG_AXIS_Y]] =
obj->cvt.sign[BMG_AXIS_Y] * raw[BMG_AXIS_Y];
act[obj->cvt.map[BMG_AXIS_Z]] =
obj->cvt.sign[BMG_AXIS_Z] * raw[BMG_AXIS_Z];
return err;
}
static int bmg_write_calibration(struct bmi160_accelgyro_data *obj,
int dat[BMG_AXES_NUM])
{
/* dat array : Android coordinate system, mapped, unit:LSB */
int err = 0;
int cali[BMG_AXES_NUM] = {0};
int raw[BMG_AXES_NUM] = {0};
obj = gyro_obj_data;
/*offset will be updated in obj->offset */
err = bmg_read_calibration(NULL, cali, raw);
if (err) {
pr_err("read offset fail, %d\n", err);
return err;
}
/* calculate the real offset expected by caller */
cali[BMG_AXIS_X] += dat[BMG_AXIS_X];
cali[BMG_AXIS_Y] += dat[BMG_AXIS_Y];
cali[BMG_AXIS_Z] += dat[BMG_AXIS_Z];
pr_debug("UPDATE: add mapped data(%+3d %+3d %+3d)\n", dat[BMG_AXIS_X],
dat[BMG_AXIS_Y], dat[BMG_AXIS_Z]);
#ifdef SW_CALIBRATION
/* obj->cali_sw array : chip coordinate system, unmapped,unit:LSB */
obj->gyro_cali_sw[BMG_AXIS_X] =
obj->cvt.sign[BMG_AXIS_X] * (cali[obj->cvt.map[BMG_AXIS_X]]);
obj->gyro_cali_sw[BMG_AXIS_Y] =
obj->cvt.sign[BMG_AXIS_Y] * (cali[obj->cvt.map[BMG_AXIS_Y]]);
obj->gyro_cali_sw[BMG_AXIS_Z] =
obj->cvt.sign[BMG_AXIS_Z] * (cali[obj->cvt.map[BMG_AXIS_Z]]);
#else
/* divisor = sensor sensitivity / offset sensitivity */
int divisor = 1;
obj->gyro_offset[BMG_AXIS_X] =
(s8)(obj->cvt.sign[BMG_AXIS_X] *
(cali[obj->cvt.map[BMG_AXIS_X]]) / (divisor));
obj->gyro_offset[BMG_AXIS_Y] =
(s8)(obj->cvt.sign[BMG_AXIS_Y] *
(cali[obj->cvt.map[BMG_AXIS_Y]]) / (divisor));
obj->gyro_offset[BMG_AXIS_Z] =
(s8)(obj->cvt.sign[BMG_AXIS_Z] *
(cali[obj->cvt.map[BMG_AXIS_Z]]) / (divisor));
/*convert software calibration using standard calibration */
obj->gyro_cali_sw[BMG_AXIS_X] = obj->cvt.sign[BMG_AXIS_X] *
(cali[obj->cvt.map[BMG_AXIS_X]]) %
(divisor);
obj->gyro_cali_sw[BMG_AXIS_Y] = obj->cvt.sign[BMG_AXIS_Y] *
(cali[obj->cvt.map[BMG_AXIS_Y]]) %
(divisor);
obj->gyro_cali_sw[BMG_AXIS_Z] = obj->cvt.sign[BMG_AXIS_Z] *
(cali[obj->cvt.map[BMG_AXIS_Z]]) %
(divisor);
/* HW calibration is under construction */
err = bmg_set_hw_offset(NULL, obj->gyro_offset);
if (err) {
pr_err("read hw offset failed.\n");
return err;
}
#endif
return err;
}
/* get chip type */
static int bmg_get_chip_type(struct bmi160_accelgyro_data *obj)
{
int err = 0;
u8 chip_id = 0;
obj = gyro_obj_data;
/* twice */
err = BMP160_spi_read_bytes(NULL, BMI160_USER_CHIP_ID__REG, &chip_id,
1);
err = BMP160_spi_read_bytes(NULL, BMI160_USER_CHIP_ID__REG, &chip_id,
1);
if (err != 0) {
pr_err("read chip id failed.\n");
return err;
}
switch (chip_id) {
case SENSOR_CHIP_ID_BMI:
case SENSOR_CHIP_ID_BMI_C2:
case SENSOR_CHIP_ID_BMI_C3:
obj->gyro_sensor_type = BMI160_GYRO_TYPE;
strcpy(obj->gyro_sensor_name, BMG_DEV_NAME);
break;
default:
obj->gyro_sensor_type = INVALID_TYPE;
strcpy(obj->gyro_sensor_name, UNKNOWN_DEV);
break;
}
if (obj->gyro_sensor_type == INVALID_TYPE) {
pr_err("unknown gyroscope.\n");
return -1;
}
return err;
}
static int bmg_set_powermode(struct bmi160_accelgyro_data *obj,
enum BMG_POWERMODE_ENUM power_mode)
{
int err = 0;
u8 data = 0;
u8 actual_power_mode = 0;
obj = gyro_obj_data;
if (power_mode == obj->gyro_power_mode)
return 0;
mutex_lock(&obj->gyro_lock);
if (obj->gyro_sensor_type == BMI160_GYRO_TYPE) {
if (power_mode == BMG_SUSPEND_MODE) {
actual_power_mode = CMD_PMU_GYRO_SUSPEND;
} else if (power_mode == BMG_NORMAL_MODE) {
actual_power_mode = CMD_PMU_GYRO_NORMAL;
} else {
err = -EINVAL;
pr_err("invalid power mode = %d\n", power_mode);
mutex_unlock(&obj->gyro_lock);
return err;
}
data = actual_power_mode;
err += BMP160_spi_write_bytes(NULL, BMI160_CMD_COMMANDS__REG,
&data, 1);
mdelay(55);
}
if (err < 0) {
pr_err(
"set power mode failed, err = %d, sensor name = %s\n",
err, obj->gyro_sensor_name);
} else {
obj->gyro_power_mode = power_mode;
}
mutex_unlock(&obj->gyro_lock);
pr_debug("set power mode = %d ok.\n", (int)data);
return err;
}
static int bmg_set_range(struct bmi160_accelgyro_data *obj,
enum BMG_RANGE_ENUM range)
{
u8 err = 0;
u8 data = 0;
u8 actual_range = 0;
obj = gyro_obj_data;
if (range == obj->gyro_range)
return 0;
mutex_lock(&obj->gyro_lock);
if (obj->gyro_sensor_type == BMI160_GYRO_TYPE) {
if (range == BMG_RANGE_2000)
actual_range = BMI160_RANGE_2000;
else if (range == BMG_RANGE_1000)
actual_range = BMI160_RANGE_1000;
else if (range == BMG_RANGE_500)
actual_range = BMI160_RANGE_500;
else if (range == BMG_RANGE_250)
actual_range = BMI160_RANGE_250;
else if (range == BMG_RANGE_125)
actual_range = BMI160_RANGE_125;
else {
err = -EINVAL;
pr_err("invalid range = %d\n", range);
mutex_unlock(&obj->gyro_lock);
return err;
}
err = BMP160_spi_read_bytes(NULL, BMI160_USER_GYR_RANGE__REG,
&data, 1);
data = BMG_SET_BITSLICE(data, BMI160_USER_GYR_RANGE,
actual_range);
err += BMP160_spi_write_bytes(NULL, BMI160_USER_GYR_RANGE__REG,
&data, 1);
mdelay(1);
if (err < 0) {
pr_err("set range failed.\n");
} else {
obj->gyro_range = range;
/* bitnum: 16bit */
switch (range) {
case BMG_RANGE_2000:
obj->gyro_sensitivity =
BMI160_FS_2000_LSB; /* 16; */
break;
case BMG_RANGE_1000:
obj->gyro_sensitivity =
BMI160_FS_1000_LSB; /* 33; */
break;
case BMG_RANGE_500:
obj->gyro_sensitivity =
BMI160_FS_500_LSB; /* 66; */
break;
case BMG_RANGE_250:
obj->gyro_sensitivity =
BMI160_FS_250_LSB; /* 131; */
break;
case BMG_RANGE_125:
obj->gyro_sensitivity =
BMI160_FS_125_LSB; /* 262; */
break;
default:
obj->gyro_sensitivity =
BMI160_FS_2000_LSB; /* 16; */
break;
}
}
}
mutex_unlock(&obj->gyro_lock);
pr_debug("set range ok.\n");
return err;
}
static int bmg_set_datarate(struct bmi160_accelgyro_data *obj, int datarate)
{
int err = 0;
u8 data = 0;
obj = gyro_obj_data;
if (datarate == obj->gyro_datarate) {
pr_debug("set new data rate = %d, old data rate = %d\n",
datarate, obj->gyro_datarate);
return 0;
}
mutex_lock(&obj->gyro_lock);
if (obj->gyro_sensor_type == BMI160_GYRO_TYPE) {
err = BMP160_spi_read_bytes(NULL, BMI160_USER_GYR_CONF_ODR__REG,
&data, 1);
data = BMG_SET_BITSLICE(data, BMI160_USER_GYR_CONF_ODR,
datarate);
err += BMP160_spi_write_bytes(
NULL, BMI160_USER_GYR_CONF_ODR__REG, &data, 1);
}
if (err < 0)
pr_err("set data rate failed.\n");
else
obj->gyro_datarate = datarate;
mutex_unlock(&obj->gyro_lock);
pr_debug("set data rate = %d ok.\n", datarate);
return err;
}
static int bmg_init_client(struct bmi160_accelgyro_data *obj, int reset_cali)
{
#ifdef CONFIG_BMG_LOWPASS
struct bmi160_accelgyro_data *obj =
(struct bmi160_accelgyro_data *)gyro_obj_data;
#endif
int err = 0;
err = bmg_get_chip_type(NULL);
if (err < 0)
return err;
err = bmg_set_datarate(NULL, BMI160_GYRO_ODR_100HZ);
if (err < 0)
return err;
err = bmg_set_range(NULL, (enum BMG_RANGE_ENUM)BMG_RANGE_2000);
if (err < 0)
return err;
err = bmg_set_powermode(NULL,
(enum BMG_POWERMODE_ENUM)BMG_SUSPEND_MODE);
if (err < 0)
return err;
if (reset_cali != 0) {
/*reset calibration only in power on */
err = bmg_reset_calibration(obj);
if (err < 0) {
pr_err("reset calibration failed.\n");
return err;
}
}
#ifdef CONFIG_BMG_LOWPASS
memset(&obj->gyro_fir, 0x00, sizeof(obj->gyro_fir));
#endif
return 0;
}
/*
*Returns compensated and mapped value. unit is :degree/second
*/
static int bmg_read_sensor_data(struct bmi160_accelgyro_data *obj, char *buf,
int bufsize)
{
s16 databuf[BMG_AXES_NUM] = {0};
int gyro[BMG_AXES_NUM] = {0};
int err = 0;
obj = gyro_obj_data;
err = bmg_read_raw_data(NULL, databuf);
if (err) {
pr_err("bmg read raw data failed.\n");
return err;
}
/* compensate data */
databuf[BMG_AXIS_X] += obj->gyro_cali_sw[BMG_AXIS_X];
databuf[BMG_AXIS_Y] += obj->gyro_cali_sw[BMG_AXIS_Y];
databuf[BMG_AXIS_Z] += obj->gyro_cali_sw[BMG_AXIS_Z];
/* remap coordinate */
gyro[obj->cvt.map[BMG_AXIS_X]] =
obj->cvt.sign[BMG_AXIS_X] * databuf[BMG_AXIS_X];
gyro[obj->cvt.map[BMG_AXIS_Y]] =
obj->cvt.sign[BMG_AXIS_Y] * databuf[BMG_AXIS_Y];
gyro[obj->cvt.map[BMG_AXIS_Z]] =
obj->cvt.sign[BMG_AXIS_Z] * databuf[BMG_AXIS_Z];
/* convert: LSB -> degree/second(o/s) */
gyro[BMG_AXIS_X] =
gyro[BMG_AXIS_X] * BMI160_FS_250_LSB / obj->gyro_sensitivity;
gyro[BMG_AXIS_Y] =
gyro[BMG_AXIS_Y] * BMI160_FS_250_LSB / obj->gyro_sensitivity;
gyro[BMG_AXIS_Z] =
gyro[BMG_AXIS_Z] * BMI160_FS_250_LSB / obj->gyro_sensitivity;
sprintf(buf, "%04x %04x %04x", gyro[BMG_AXIS_X], gyro[BMG_AXIS_Y],
gyro[BMG_AXIS_Z]);
if (atomic_read(&obj->gyro_trace) & GYRO_TRC_IOCTL)
pr_debug("gyroscope data: %s\n", buf);
return 0;
}
static ssize_t gyro_show_chipinfo_value(struct device_driver *ddri, char *buf)
{
struct bmi160_accelgyro_data *obj = gyro_obj_data;
return snprintf(buf, PAGE_SIZE, "%s\n", obj->gyro_sensor_name);
}
/*
* sensor data format is hex, unit:degree/second
*/
static ssize_t gyro_show_sensordata_value(struct device_driver *ddri, char *buf)
{
char strbuf[BMG_BUFSIZE] = {0};
bmg_read_sensor_data(NULL, strbuf, BMG_BUFSIZE);
return snprintf(buf, PAGE_SIZE, "%s\n", strbuf);
}
/*
* raw data format is s16, unit:LSB, axis mapped
*/
static ssize_t gyro_show_rawdata_value(struct device_driver *ddri, char *buf)
{
s16 databuf[BMG_AXES_NUM] = {0};
s16 dataraw[BMG_AXES_NUM] = {0};
struct bmi160_accelgyro_data *obj = gyro_obj_data;
bmg_read_raw_data(NULL, dataraw);
/*remap coordinate */
databuf[obj->cvt.map[BMG_AXIS_X]] =
obj->cvt.sign[BMG_AXIS_X] * dataraw[BMG_AXIS_X];
databuf[obj->cvt.map[BMG_AXIS_Y]] =
obj->cvt.sign[BMG_AXIS_Y] * dataraw[BMG_AXIS_Y];
databuf[obj->cvt.map[BMG_AXIS_Z]] =
obj->cvt.sign[BMG_AXIS_Z] * dataraw[BMG_AXIS_Z];
return snprintf(buf, PAGE_SIZE, "%hd %hd %hd\n", databuf[BMG_AXIS_X],
databuf[BMG_AXIS_Y], databuf[BMG_AXIS_Z]);
}
static ssize_t gyro_show_cali_value(struct device_driver *ddri, char *buf)
{
int err = 0;
int len = 0;
int mul;
int act[BMG_AXES_NUM] = {0};
int raw[BMG_AXES_NUM] = {0};
struct bmi160_accelgyro_data *obj = gyro_obj_data;
err = bmg_read_calibration(NULL, act, raw);
if (err)
return -EINVAL;
mul = 1; /* mul = sensor sensitivity / offset sensitivity */
len += snprintf(
buf + len, PAGE_SIZE - len,
"[HW ][%d] (%+3d, %+3d, %+3d) : (0x%02X, 0x%02X, 0x%02X)\n",
mul, obj->gyro_offset[BMG_AXIS_X], obj->gyro_offset[BMG_AXIS_Y],
obj->gyro_offset[BMG_AXIS_Z], obj->gyro_offset[BMG_AXIS_X],
obj->gyro_offset[BMG_AXIS_Y], obj->gyro_offset[BMG_AXIS_Z]);
len += snprintf(
buf + len, PAGE_SIZE - len, "[SW ][%d] (%+3d, %+3d, %+3d)\n", 1,
obj->gyro_cali_sw[BMG_AXIS_X], obj->gyro_cali_sw[BMG_AXIS_Y],
obj->gyro_cali_sw[BMG_AXIS_Z]);
len += snprintf(
buf + len, PAGE_SIZE - len,
"[ALL]unmapped(%+3d, %+3d, %+3d), mapped(%+3d, %+3d, %+3d)\n",
raw[BMG_AXIS_X], raw[BMG_AXIS_Y], raw[BMG_AXIS_Z],
act[BMG_AXIS_X], act[BMG_AXIS_Y], act[BMG_AXIS_Z]);
return len;
}
static ssize_t gyro_store_cali_value(struct device_driver *ddri,
const char *buf, size_t count)
{
int err = 0;
int dat[BMG_AXES_NUM] = {0};
struct bmi160_accelgyro_data *obj = gyro_obj_data;
if (!strncmp(buf, "rst", 3)) {
err = bmg_reset_calibration(obj);
if (err)
pr_err("reset offset err = %d\n", err);
} else if (sscanf(buf, "0x%02X 0x%02X 0x%02X", &dat[BMG_AXIS_X],
&dat[BMG_AXIS_Y], &dat[BMG_AXIS_Z]) == BMG_AXES_NUM) {
err = bmg_write_calibration(NULL, dat);
if (err)
pr_err("bmg write calibration failed, err = %d\n",
err);
} else {
pr_info("invalid format\n");
}
return count;
}
static ssize_t gyro_show_firlen_value(struct device_driver *ddri, char *buf)
{
#ifdef CONFIG_BMG_LOWPASS
struct bmi160_accelgyro_data *obj = gyro_obj_data;
if (atomic_read(&obj->gyro_firlen)) {
int idx, len = atomic_read(&obj->gyro_firlen);
pr_debug("len = %2d, idx = %2d\n", obj->gyro_fir.num,
obj->gyro_fir.idx);
for (idx = 0; idx < len; idx++) {
pr_debug("[%5d %5d %5d]\n",
obj->gyro_fir.raw[idx][BMG_AXIS_X],
obj->gyro_fir.raw[idx][BMG_AXIS_Y],
obj->gyro_fir.raw[idx][BMG_AXIS_Z]);
}
pr_debug("sum = [%5d %5d %5d]\n", obj->gyro_fir.sum[BMG_AXIS_X],
obj->gyro_fir.sum[BMG_AXIS_Y],
obj->gyro_fir.sum[BMG_AXIS_Z]);
pr_debug("avg = [%5d %5d %5d]\n",
obj->gyro_fir.sum[BMG_AXIS_X] / len,
obj->gyro_fir.sum[BMG_AXIS_Y] / len,
obj->gyro_fir.sum[BMG_AXIS_Z] / len);
}
return snprintf(buf, PAGE_SIZE, "%d\n", atomic_read(&obj->gyro_firlen));
#else
return snprintf(buf, PAGE_SIZE, "not support\n");
#endif
}
static ssize_t gyro_store_firlen_value(struct device_driver *ddri,
const char *buf, size_t count)
{
#ifdef CONFIG_BMG_LOWPASS
struct bmi160_accelgyro_data *obj = gyro_obj_data;
int firlen;
if (kstrtos32(buf, 10, &firlen) != 0) {
pr_info("invallid format\n");
} else if (firlen > C_MAX_FIR_LENGTH) {
pr_info("exceeds maximum filter length\n");
} else {
atomic_set(&obj->gyro_firlen, firlen);
if (firlen == NULL) {
atomic_set(&obj->gyro_fir_en, 0);
} else {
memset(&obj->gyro_fir, 0x00, sizeof(obj->gyro_fir));
atomic_set(&obj->gyro_fir_en, 1);
}
}
#endif
return count;
}
static ssize_t gyro_show_trace_value(struct device_driver *ddri, char *buf)
{
ssize_t res;
struct bmi160_accelgyro_data *obj = gyro_obj_data;
res = snprintf(buf, PAGE_SIZE, "0x%04X\n",
atomic_read(&obj->gyro_trace));
return res;
}
static ssize_t gyro_store_trace_value(struct device_driver *ddri,
const char *buf, size_t count)
{
int trace;
struct bmi160_accelgyro_data *obj = gyro_obj_data;
if (kstrtos32(buf, 10, &trace) == 0)
atomic_set(&obj->gyro_trace, trace);
else
pr_info("invalid content: '%s'\n", buf);
return count;
}
static ssize_t gyro_show_status_value(struct device_driver *ddri, char *buf)
{
ssize_t len = 0;
struct bmi160_accelgyro_data *obj = gyro_obj_data;
len += snprintf(buf + len, PAGE_SIZE - len, "CUST: %d\n",
obj->hw.direction);
len += snprintf(buf + len, PAGE_SIZE - len, "ver:%s\n",
BMG_DRIVER_VERSION);
return len;
}
static ssize_t gyro_show_power_mode_value(struct device_driver *ddri, char *buf)
{
ssize_t len = 0;
struct bmi160_accelgyro_data *obj = gyro_obj_data;
len += snprintf(buf + len, PAGE_SIZE - len, "%s mode\n",
obj->gyro_power_mode == BMG_NORMAL_MODE ? "normal"
: "suspend");
return len;
}
static ssize_t gyro_store_power_mode_value(struct device_driver *ddri,
const char *buf, size_t count)
{
int err;
unsigned long power_mode;
err = kstrtoul(buf, 10, &power_mode);
if (err < 0)
return err;
if (power_mode == BMI_GYRO_PM_NORMAL)
err = bmg_set_powermode(NULL, BMG_NORMAL_MODE);
else
err = bmg_set_powermode(NULL, BMG_SUSPEND_MODE);
if (err < 0)
pr_err("set power mode failed.\n");
return err;
}
static ssize_t gyro_show_range_value(struct device_driver *ddri, char *buf)
{
ssize_t len = 0;
struct bmi160_accelgyro_data *obj = gyro_obj_data;
len += snprintf(buf + len, PAGE_SIZE - len, "%d\n", obj->gyro_range);
return len;
}
static ssize_t gyro_store_range_value(struct device_driver *ddri,
const char *buf, size_t count)
{
unsigned long range;
int err;
err = kstrtoul(buf, 10, &range);
if (err == 0) {
if ((range == BMG_RANGE_2000) || (range == BMG_RANGE_1000) ||
(range == BMG_RANGE_500) || (range == BMG_RANGE_250) ||
(range == BMG_RANGE_125)) {
err = bmg_set_range(NULL, range);
if (err) {
pr_err("set range value failed.\n");
return err;
}
}
}
return count;
}
static ssize_t gyro_show_datarate_value(struct device_driver *ddri, char *buf)
{
ssize_t len = 0;
struct bmi160_accelgyro_data *obj = gyro_obj_data;
len += snprintf(buf + len, PAGE_SIZE - len, "%d\n", obj->gyro_datarate);
return len;
}
static ssize_t gyro_store_datarate_value(struct device_driver *ddri,
const char *buf, size_t count)
{
int err;
unsigned long datarate;
err = kstrtoul(buf, 10, &datarate);
if (err < 0)
return err;
err = bmg_set_datarate(NULL, datarate);
if (err < 0) {
pr_err("set data rate failed.\n");
return err;
}
return count;
}
static DRIVER_ATTR(acc_chipinfo, 0644, accel_show_chipinfo_value,
NULL);
static DRIVER_ATTR(acc_cpsdata, 0644, accel_show_cpsdata_value,
NULL);
static DRIVER_ATTR(acc_op_mode, 0644, accel_show_acc_op_mode_value,
accel_store_acc_op_mode_value);
static DRIVER_ATTR(acc_range, 0644, accel_show_acc_range_value,
accel_store_acc_range_value);
static DRIVER_ATTR(acc_odr, 0644, accel_show_acc_odr_value,
accel_store_acc_odr_value);
static DRIVER_ATTR(acc_sensordata, 0644,
accel_show_sensordata_value, NULL);
static DRIVER_ATTR(acc_cali, 0644, accel_show_cali_value,
accel_store_cali_value);
static DRIVER_ATTR(acc_firlen, 0644, accel_show_firlen_value,
accel_store_firlen_value);
static DRIVER_ATTR(acc_trace, 0644, accel_show_trace_value,
accel_store_trace_value);
static DRIVER_ATTR(acc_status, 0444, accel_show_status_value, NULL);
static DRIVER_ATTR(acc_powerstatus, 0444, accel_show_power_status_value,
NULL);
static DRIVER_ATTR(acc_fifo_bytecount, 0644,
accel_bmi160_fifo_bytecount_show,
accel_bmi160_fifo_bytecount_store);
static DRIVER_ATTR(acc_fifo_data_sel, 0644,
accel_bmi160_fifo_data_sel_show,
accel_bmi160_fifo_data_sel_store);
static DRIVER_ATTR(acc_fifo_data_frame, 0444,
accel_bmi160_fifo_data_out_frame_show, NULL);
static DRIVER_ATTR(acc_layout, 0644, accel_show_layout_value,
accel_store_layout_value);
static DRIVER_ATTR(acc_register, 0644, accel_bmi_register_show,
accel_bmi_register_store);
static DRIVER_ATTR(acc_bmi_value, 0444, accel_bmi160_bmi_value_show, NULL);
static DRIVER_ATTR(acc_fifo_watermark, 0644,
accel_bmi160_fifo_watermark_show,
accel_bmi160_fifo_watermark_store);
static DRIVER_ATTR(acc_delay, 0644, accel_bmi160_delay_show,
accel_bmi160_delay_store);
static DRIVER_ATTR(acc_fifo_flush, 0644, NULL,
accel_bmi160_fifo_flush_store);
static DRIVER_ATTR(acc_fifo_header_en, 0644,
accel_bmi160_fifo_header_en_show,
accel_bmi160_fifo_header_en_store);
static DRIVER_ATTR(gyro_chipinfo, 0644, gyro_show_chipinfo_value,
NULL);
static DRIVER_ATTR(gyro_sensordata, 0644,
gyro_show_sensordata_value, NULL);
static DRIVER_ATTR(gyro_rawdata, 0644, gyro_show_rawdata_value,
NULL);
static DRIVER_ATTR(gyro_cali, 0644, gyro_show_cali_value,
gyro_store_cali_value);
static DRIVER_ATTR(gyro_firlen, 0644, gyro_show_firlen_value,
gyro_store_firlen_value);
static DRIVER_ATTR(gyro_trace, 0644, gyro_show_trace_value,
gyro_store_trace_value);
static DRIVER_ATTR(gyro_status, 0444, gyro_show_status_value, NULL);
static DRIVER_ATTR(gyro_op_mode, 0644, gyro_show_power_mode_value,
gyro_store_power_mode_value);
static DRIVER_ATTR(gyro_range, 0644, gyro_show_range_value,
gyro_store_range_value);
static DRIVER_ATTR(gyro_odr, 0644, gyro_show_datarate_value,
gyro_store_datarate_value);
static struct driver_attribute *bmi160_accelgyro_attr_list[] = {
&driver_attr_acc_chipinfo, /*chip information */
&driver_attr_acc_sensordata, /*dump sensor data */
&driver_attr_acc_cali, /*show calibration data */
/*filter length: 0: disable, others: enable */
&driver_attr_acc_firlen,
&driver_attr_acc_trace, /*trace log */
&driver_attr_acc_status,
&driver_attr_acc_powerstatus,
/*g data for compass tilt compensation */
&driver_attr_acc_cpsdata,
/*g opmode compass tilt compensation */
&driver_attr_acc_op_mode,
/*g range compass tilt compensation */
&driver_attr_acc_range,
/*g bw compass tilt compensation */
&driver_attr_acc_odr,
&driver_attr_acc_fifo_bytecount,
&driver_attr_acc_fifo_data_sel,
&driver_attr_acc_fifo_data_frame, &driver_attr_acc_layout,
&driver_attr_acc_register, &driver_attr_acc_bmi_value,
&driver_attr_acc_fifo_watermark, &driver_attr_acc_delay,
&driver_attr_acc_fifo_flush, &driver_attr_acc_fifo_header_en,
/* chip information */
&driver_attr_gyro_chipinfo,
/* dump sensor data */
&driver_attr_gyro_sensordata,
/* dump raw data */
&driver_attr_gyro_rawdata,
/* show calibration data */
&driver_attr_gyro_cali,
/* filter length: 0: disable, others: enable */
&driver_attr_gyro_firlen,
/* trace flag */
&driver_attr_gyro_trace,
/* get hw configuration */
&driver_attr_gyro_status,
/* get power mode */
&driver_attr_gyro_op_mode,
/* get range */
&driver_attr_gyro_range,
/* get data rate */
&driver_attr_gyro_odr,
};
static int bmi160_accelgyro_create_attr(struct device_driver *driver)
{
int err = 0;
int idx = 0;
int num = ARRAY_SIZE(bmi160_accelgyro_attr_list);
if (driver == NULL)
return -EINVAL;
for (idx = 0; idx < num; idx++) {
err = driver_create_file(driver,
bmi160_accelgyro_attr_list[idx]);
if (err) {
pr_err("create driver file (%s) failed.\n",
bmi160_accelgyro_attr_list[idx]->attr.name);
break;
}
}
return err;
}
static int bmi160_accelgyro_delete_attr(struct device_driver *driver)
{
int idx = 0;
int err = 0;
int num = ARRAY_SIZE(bmi160_accelgyro_attr_list);
for (idx = 0; idx < num; idx++)
driver_remove_file(driver, bmi160_accelgyro_attr_list[idx]);
return err;
}
#ifdef CONFIG_PM
static int bmi160_acc_suspend(void)
{
#if 0
int err = 0;
u8 op_mode = 0;
struct bmi160_accelgyro_data *obj = accelgyro_obj_data;
if (atomic_read(&obj->wkqueue_en) == 1) {
BMI160_ACC_SetPowerMode(obj, false);
cancel_delayed_work_sync(&obj->work);
}
err = bmi160_acc_get_mode(obj, &op_mode);
atomic_set(&obj->accel_suspend, 1);
if (op_mode != BMI160_ACC_MODE_SUSPEND && sig_flag != 1)
err = BMI160_ACC_SetPowerMode(obj, false);
if (err) {
pr_err("write power control failed.\n");
return err;
}
BMI160_ACC_power(obj->hw, 0);
return err;
#else
pr_debug("%s\n", __func__);
return 0;
#endif
}
static int bmi160_acc_resume(void)
{
#if 0
int err;
struct bmi160_accelgyro_data *obj = accelgyro_obj_data;
BMI160_ACC_power(obj->hw, 1);
err = bmi160_acc_init_client(obj, 0);
if (err) {
pr_err("initialize client fail!!\n");
return err;
}
atomic_set(&obj->accel_suspend, 0);
return 0;
#else
pr_debug("%s\n", __func__);
return 0;
#endif
}
#ifdef CONFIG_PM
static int bmg_suspend(void)
{
#if 0
struct bmi160_accelgyro_data *obj = accelgyro_obj_data;
int err = 0;
if (obj == NULL) {
pr_info("null pointer\n");
return -EINVAL;
}
atomic_set(&obj->suspend, 1);
err = bmg_set_powermode(NULL, BMG_SUSPEND_MODE);
if (err)
pr_err("bmg set suspend mode failed.\n");
return err;
#else
return 0;
#endif
}
static int bmg_resume(void)
{
#if 0
int err;
struct bmi160_accelgyro_data *obj = accelgyro_obj_data;
err = bmg_init_client(obj, 0);
if (err) {
pr_err("initialize client failed, err = %d\n", err);
return err;
}
atomic_set(&obj->suspend, 0);
return 0;
#else
return 0;
#endif
}
static int pm_event_handler(struct notifier_block *notifier,
unsigned long pm_event, void *unused)
{
switch (pm_event) {
case PM_SUSPEND_PREPARE:
bmi160_acc_suspend();
bmg_suspend();
return NOTIFY_DONE;
case PM_POST_SUSPEND:
bmi160_acc_resume();
bmg_resume();
return NOTIFY_DONE;
}
return NOTIFY_DONE;
}
static struct notifier_block pm_notifier_func = {
.notifier_call = pm_event_handler, .priority = 0,
};
#endif /* CONFIG_PM */
#ifdef CONFIG_OF
static const struct of_device_id accelgyrosensor_of_match[] = {
{
.compatible = "mediatek,accelgyrosensor",
},
{},
};
#endif
static struct spi_driver bmi160_accelgyro_spi_driver = {
.driver = {
.name = BMI160_ACCELGYRO_DEV_NAME,
.bus = &spi_bus_type,
#ifdef CONFIG_OF
.of_match_table = accelgyrosensor_of_match,
#endif
},
.probe = bmi160_accelgyro_spi_probe,
.remove = bmi160_accelgyro_spi_remove,
};
/*!
* @brief If use this type of enable, Gsensor only enabled but not report
* inputEvent to HAL
*
* @param[in] int enable true or false
*
* @return zero success, non-zero failed
*/
static int bmi160_acc_enable_nodata(int en)
{
int err = 0;
bool power = false;
if (en == 1)
power = true;
else
power = false;
err = BMI160_ACC_SetPowerMode(accelgyro_obj_data, power);
if (err < 0) {
pr_err("BMI160_ACC_SetPowerMode failed.\n");
return -1;
}
pr_debug("%s ok!\n", __func__);
return err;
}
/*!
* @brief set ODR rate value for acc
*
* @param[in] u64 ns for sensor delay
*
* @return zero success, non-zero failed
*/
static int bmi160_acc_batch(int flag, int64_t samplingPeriodNs,
int64_t maxBatchReportLatencyNs)
{
int value = 0;
int sample_delay = 0;
int err = 0;
value = (int)samplingPeriodNs / 1000 / 1000;
if (value <= 5)
sample_delay = BMI160_ACCEL_ODR_400HZ;
else if (value <= 10)
sample_delay = BMI160_ACCEL_ODR_200HZ;
else
sample_delay = BMI160_ACCEL_ODR_100HZ;
err = BMI160_ACC_SetBWRate(accelgyro_obj_data, sample_delay);
if (err < 0) {
pr_err("set delay parameter error!\n");
return -1;
}
pr_debug("bmi160 acc set delay = (%d) ok.\n", value);
return 0;
}
static int bmi160_acc_flush(void)
{
return acc_flush_report();
}
/*!
* @brief get the raw data for gsensor
*
* @param[in] int x axis value
* @param[in] int y axis value
* @param[in] int z axis value
* @param[in] int status
*
* @return zero success, non-zero failed
*/
static int bmi160_acc_get_data(int *x, int *y, int *z, int *status)
{
int err = 0;
char buff[BMI160_BUFSIZE];
struct bmi160_accelgyro_data *obj = accelgyro_obj_data;
err = BMI160_ACC_ReadSensorData(obj, buff, BMI160_BUFSIZE);
if (err < 0) {
pr_err("%s failed.\n", __func__);
return err;
}
err = sscanf(buff, "%x %x %x", x, y, z);
if (err < 0) {
pr_err("%s failed.\n", __func__);
return err;
}
*status = SENSOR_STATUS_ACCURACY_MEDIUM;
return 0;
}
int gyroscope_operate(void *self, uint32_t command, void *buff_in, int size_in,
void *buff_out, int size_out, int *actualout)
{
int err = 0;
int value, sample_delay;
char buff[BMG_BUFSIZE] = {0};
struct bmi160_accelgyro_data *priv =
(struct bmi160_accelgyro_data *)self;
struct hwm_sensor_data *gyroscope_data;
switch (command) {
case SENSOR_DELAY:
if ((buff_in == NULL) || (size_in < sizeof(int))) {
pr_err("set delay parameter error\n");
err = -EINVAL;
} else {
value = *(int *)buff_in;
/*
*Currently, fix data rate to 100Hz.
*/
sample_delay = BMI160_GYRO_ODR_100HZ;
pr_debug(
"sensor delay command: %d, sample_delay = %d\n",
value, sample_delay);
err = bmg_set_datarate(NULL, sample_delay);
if (err < 0)
pr_info("set delay parameter error\n");
if (value >= 40)
atomic_set(&priv->gyro_filter, 0);
else {
#if defined(CONFIG_BMG_LOWPASS)
priv->gyro_fir.num = 0;
priv->gyro_fir.idx = 0;
priv->gyro_fir.sum[BMG_AXIS_X] = 0;
priv->gyro_fir.sum[BMG_AXIS_Y] = 0;
priv->gyro_fir.sum[BMG_AXIS_Z] = 0;
atomic_set(&priv->gyro_filter, 1);
#endif
}
}
break;
case SENSOR_ENABLE:
if ((buff_in == NULL) || (size_in < sizeof(int))) {
pr_err("enable sensor parameter error\n");
err = -EINVAL;
} else {
/* value:[0--->suspend, 1--->normal] */
value = *(int *)buff_in;
pr_debug("sensor enable/disable command: %s\n",
value ? "enable" : "disable");
err = bmg_set_powermode(
NULL, (enum BMG_POWERMODE_ENUM)(!!value));
if (err)
pr_err("set power mode failed, err = %d\n",
err);
}
break;
case SENSOR_GET_DATA:
if ((buff_out == NULL) ||
(size_out < sizeof(struct hwm_sensor_data))) {
pr_err("get sensor data parameter error\n");
err = -EINVAL;
} else {
gyroscope_data = (struct hwm_sensor_data *)buff_out;
bmg_read_sensor_data(NULL, buff, BMG_BUFSIZE);
err = sscanf(buff, "%x %x %x",
&gyroscope_data->values[0],
&gyroscope_data->values[1],
&gyroscope_data->values[2]);
if (err)
pr_info("get data failed, err = %d\n", err);
gyroscope_data->status = SENSOR_STATUS_ACCURACY_MEDIUM;
gyroscope_data->value_divide = DEGREE_TO_RAD;
}
break;
default:
pr_info("gyroscope operate function no this parameter %d\n",
command);
err = -1;
break;
}
return err;
}
#endif /* CONFIG_PM */
static int bmi160_gyro_open_report_data(int open)
{
/* should queuq work to report event if is_report_input_direct=true */
return 0;
}
static int bmi160_gyro_enable_nodata(int en)
{
int err = 0;
int retry = 0;
bool power = false;
if (en == 1)
power = true;
else
power = false;
for (retry = 0; retry < 3; retry++) {
err = bmg_set_powermode(NULL, power);
if (err == 0) {
pr_debug("bmi160_gyro_SetPowerMode ok.\n");
break;
}
}
if (err < 0)
pr_debug("bmi160_gyro_SetPowerMode fail!\n");
return err;
}
static int bmi160_gyro_batch(int flag, int64_t samplingPeriodNs,
int64_t maxBatchReportLatencyNs)
{
int err;
int value = (int)samplingPeriodNs / 1000 / 1000;
/* Currently, fix data rate to 100Hz. */
int sample_delay = BMI160_GYRO_ODR_100HZ;
struct bmi160_accelgyro_data *priv = gyro_obj_data;
err = bmg_set_datarate(NULL, sample_delay);
if (err < 0)
pr_err("set data rate failed.\n");
if (value >= 40)
atomic_set(&priv->gyro_filter, 0);
else {
#if defined(CONFIG_BMG_LOWPASS)
priv->gyro_fir.num = 0;
priv->gyro_fir.idx = 0;
priv->gyro_fir.sum[BMG_AXIS_X] = 0;
priv->gyro_fir.sum[BMG_AXIS_Y] = 0;
priv->gyro_fir.sum[BMG_AXIS_Z] = 0;
atomic_set(&priv->gyro_filter, 1);
#endif
}
pr_debug("set gyro delay = %d\n", sample_delay);
return 0;
}
static int bmi160_gyro_flush(void)
{
return gyro_flush_report();
}
#if 0
static int bmi160_gyro_enable_nodata(int en)
{
int err = 0;
int retry = 0;
bool power = false;
if (en == 1)
power = true;
else
power = false;
for (retry = 0; retry < 3; retry++) {
err = bmg_set_powermode(NULL, power);
if (err == 0) {
pr_debug("bmi160_gyro_SetPowerMode ok.\n");
break;
}
}
if (err < 0)
pr_debug("bmi160_gyro_SetPowerMode fail!\n");
return err;
}
static int bmi160_gyro_set_delay(u64 ns)
{
int err;
int value = (int)ns / 1000 / 1000;
/* Currently, fix data rate to 100Hz. */
int sample_delay = BMI160_GYRO_ODR_100HZ;
struct bmi160_accelgyro_data *priv = accelgyro_obj_data;
err = bmg_set_datarate(NULL, sample_delay);
if (err < 0)
pr_info("set data rate failed.\n");
if (value >= 40)
atomic_set(&priv->filter, 0);
else {
#if defined(CONFIG_BMG_LOWPASS)
priv->fir.num = 0;
priv->fir.idx = 0;
priv->fir.sum[BMG_AXIS_X] = 0;
priv->fir.sum[BMG_AXIS_Y] = 0;
priv->fir.sum[BMG_AXIS_Z] = 0;
atomic_set(&priv->filter, 1);
#endif
}
pr_debug("set gyro delay = %d\n", sample_delay);
return 0;
}
#endif
static int bmi160_gyro_get_data(int *x, int *y, int *z, int *status)
{
char buff[BMG_BUFSIZE] = {0};
bmg_read_sensor_data(NULL, buff, BMG_BUFSIZE);
if (sscanf(buff, "%x %x %x", x, y, z) != 3)
pr_err("%s failed\n", __func__);
*status = SENSOR_STATUS_ACCURACY_MEDIUM;
return 0;
}
static int bmi160_accel_factory_enable_sensor(bool enabledisable,
int64_t sample_periods_ms)
{
int err;
err = bmi160_acc_enable_nodata(enabledisable == true ? 1 : 0);
if (err) {
pr_err("%s enable sensor failed!\n", __func__);
return -1;
}
err = bmi160_acc_batch(0, sample_periods_ms * 1000000, 0);
if (err) {
pr_err("%s enable set batch failed!\n", __func__);
return -1;
}
return 0;
}
static int bmi160_accel_factory_get_data(int32_t data[3], int *status)
{
return bmi160_acc_get_data(&data[0], &data[1], &data[2], status);
}
static int bmi160_accel_factory_get_raw_data(int32_t data[3])
{
char strbuf[BMI160_BUFSIZE] = {0};
BMI160_ACC_ReadRawData(accelgyro_obj_data, strbuf);
pr_info("don't support bmi160_factory_get_raw_data!\n");
return 0;
}
static int bmi160_accel_factory_enable_calibration(void)
{
return 0;
}
static int bmi160_accel_factory_clear_cali(void)
{
int err = 0;
err = BMI160_ACC_ResetCalibration(accelgyro_obj_data);
if (err) {
pr_err("bmi160_ResetCalibration failed!\n");
return -1;
}
return 0;
}
static int bmi160_accel_factory_set_cali(int32_t data[3])
{
int err = 0;
int cali[3] = {0};
cali[BMI160_ACC_AXIS_X] = data[0] *
accelgyro_obj_data->accel_reso->sensitivity /
GRAVITY_EARTH_1000;
cali[BMI160_ACC_AXIS_Y] = data[1] *
accelgyro_obj_data->accel_reso->sensitivity /
GRAVITY_EARTH_1000;
cali[BMI160_ACC_AXIS_Z] = data[2] *
accelgyro_obj_data->accel_reso->sensitivity /
GRAVITY_EARTH_1000;
err = BMI160_ACC_WriteCalibration(accelgyro_obj_data, cali);
if (err) {
pr_err("bmi160_WriteCalibration failed!\n");
return -1;
}
return 0;
}
static int bmi160_accel_factory_get_cali(int32_t data[3])
{
int err = 0;
int cali[3] = {0};
err = BMI160_ACC_ReadCalibration(accelgyro_obj_data, cali);
if (err) {
pr_err("bmi160_ReadCalibration failed!\n");
return -1;
}
data[0] = cali[BMI160_ACC_AXIS_X] * GRAVITY_EARTH_1000 /
accelgyro_obj_data->accel_reso->sensitivity;
data[1] = cali[BMI160_ACC_AXIS_Y] * GRAVITY_EARTH_1000 /
accelgyro_obj_data->accel_reso->sensitivity;
data[2] = cali[BMI160_ACC_AXIS_Z] * GRAVITY_EARTH_1000 /
accelgyro_obj_data->accel_reso->sensitivity;
return 0;
}
static int bmi160_accel_factory_do_self_test(void)
{
return 0;
}
static struct accel_factory_fops bmi160_accel_factory_fops = {
.enable_sensor = bmi160_accel_factory_enable_sensor,
.get_data = bmi160_accel_factory_get_data,
.get_raw_data = bmi160_accel_factory_get_raw_data,
.enable_calibration = bmi160_accel_factory_enable_calibration,
.clear_cali = bmi160_accel_factory_clear_cali,
.set_cali = bmi160_accel_factory_set_cali,
.get_cali = bmi160_accel_factory_get_cali,
.do_self_test = bmi160_accel_factory_do_self_test,
};
static struct accel_factory_public bmi160_accel_factory_device = {
.gain = 1, .sensitivity = 1, .fops = &bmi160_accel_factory_fops,
};
int bmi160_set_intr_fifo_wm(u8 v_channel_u8, u8 v_intr_fifo_wm_u8)
{
/* variable used for return the status of communication result */
int com_rslt = -1;
u8 v_data_u8 = 0;
struct bmi160_accelgyro_data *obj = accelgyro_obj_data;
switch (v_channel_u8) {
/* write the fifo water mark interrupt */
case BMI160_INTR1_MAP_FIFO_WM:
com_rslt = BMP160_spi_read_bytes(
obj->spi, BMI160_USER_INTR_MAP_1_INTR1_FIFO_WM__REG,
&v_data_u8, 1);
if (com_rslt == 0) {
v_data_u8 = BMI160_SET_BITSLICE(
v_data_u8, BMI160_USER_INTR_MAP_1_INTR1_FIFO_WM,
v_intr_fifo_wm_u8);
com_rslt += BMP160_spi_write_bytes(
obj->spi,
BMI160_USER_INTR_MAP_1_INTR1_FIFO_WM__REG,
&v_data_u8, 1);
}
break;
case BMI160_INTR2_MAP_FIFO_WM:
com_rslt = BMP160_spi_read_bytes(
obj->spi, BMI160_USER_INTR_MAP_1_INTR2_FIFO_WM__REG,
&v_data_u8, 1);
if (com_rslt == 0) {
v_data_u8 = BMI160_SET_BITSLICE(
v_data_u8, BMI160_USER_INTR_MAP_1_INTR2_FIFO_WM,
v_intr_fifo_wm_u8);
com_rslt += BMP160_spi_write_bytes(
obj->spi,
BMI160_USER_INTR_MAP_1_INTR2_FIFO_WM__REG,
&v_data_u8, 1);
}
break;
default:
com_rslt = -2;
break;
}
return com_rslt;
}
/*!
* @brief API used for set the Configure level condition of interrupt1
* and interrupt2 pin form the register 0x53
* @brief interrupt1 - bit 1
* @brief interrupt2 - bit 5
*
* @param v_channel_u8: The value of level condition selection
* v_channel_u8 | level selection
* ---------------|---------------
* 0 | BMI160_INTR1_LEVEL
* 1 | BMI160_INTR2_LEVEL
*
* @param v_intr_level_u8 : The value of level of interrupt enable
* value | Behaviour
* ----------|-------------------
* 0x01 | BMI160_LEVEL_HIGH
* 0x00 | BMI160_LEVEL_LOW
*
* @return results of bus communication function
* @retval 0 -> Success
* @retval -1 -> Error
*
*
*/
BMI160_RETURN_FUNCTION_TYPE bmi160_set_intr_level(u8 v_channel_u8,
u8 v_intr_level_u8)
{
/* variable used for return the status of communication result */
BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES;
u8 v_data_u8 = BMI160_INIT_VALUE;
/* check the p_bmi160 structure as NULL */
if (p_bmi160 == BMI160_NULL)
return E_BMI160_NULL_PTR;
switch (v_channel_u8) {
case BMI160_INTR1_LEVEL:
/* write the interrupt1 level */
com_rslt = p_bmi160->BMI160_BUS_READ_FUNC(
p_bmi160->dev_addr, BMI160_USER_INTR1_LEVEL__REG,
&v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH);
if (com_rslt == SUCCESS) {
v_data_u8 = BMI160_SET_BITSLICE(v_data_u8,
BMI160_USER_INTR1_LEVEL,
v_intr_level_u8);
com_rslt += p_bmi160->BMI160_BUS_WRITE_FUNC(
p_bmi160->dev_addr,
BMI160_USER_INTR1_LEVEL__REG, &v_data_u8,
BMI160_GEN_READ_WRITE_DATA_LENGTH);
}
break;
case BMI160_INTR2_LEVEL:
/* write the interrupt2 level */
com_rslt = p_bmi160->BMI160_BUS_READ_FUNC(
p_bmi160->dev_addr, BMI160_USER_INTR2_LEVEL__REG,
&v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH);
if (com_rslt == SUCCESS) {
v_data_u8 = BMI160_SET_BITSLICE(v_data_u8,
BMI160_USER_INTR2_LEVEL,
v_intr_level_u8);
com_rslt += p_bmi160->BMI160_BUS_WRITE_FUNC(
p_bmi160->dev_addr,
BMI160_USER_INTR2_LEVEL__REG, &v_data_u8,
BMI160_GEN_READ_WRITE_DATA_LENGTH);
}
break;
default:
com_rslt = E_BMI160_OUT_OF_RANGE;
break;
}
return com_rslt;
}
/*!
* @brief API used to set the Output enable for interrupt1
* and interrupt1 pin from the register 0x53
* @brief interrupt1 - bit 3
* @brief interrupt2 - bit 7
*
* @param v_channel_u8: The value of output enable selection
* v_channel_u8 | level selection
* ---------------|---------------
* 0 | BMI160_INTR1_OUTPUT_TYPE
* 1 | BMI160_INTR2_OUTPUT_TYPE
*
* @param v_output_enable_u8 :
* The value of output enable of interrupt enable
* value | Behaviour
* ----------|-------------------
* 0x01 | BMI160_INPUT
* 0x00 | BMI160_OUTPUT
*
* @return results of bus communication function
* @retval 0 -> Success
* @retval -1 -> Error
*
*/
BMI160_RETURN_FUNCTION_TYPE bmi160_set_output_enable(u8 v_channel_u8,
u8 v_output_enable_u8)
{
/* variable used for return the status of communication result */
BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES;
u8 v_data_u8 = BMI160_INIT_VALUE;
/* check the p_bmi160 structure as NULL */
if (p_bmi160 == BMI160_NULL)
return E_BMI160_NULL_PTR;
switch (v_channel_u8) {
case BMI160_INTR1_OUTPUT_ENABLE:
/* write the output enable of interrupt1 */
com_rslt = p_bmi160->BMI160_BUS_READ_FUNC(
p_bmi160->dev_addr,
BMI160_USER_INTR1_OUTPUT_ENABLE__REG, &v_data_u8,
BMI160_GEN_READ_WRITE_DATA_LENGTH);
if (com_rslt == SUCCESS) {
v_data_u8 = BMI160_SET_BITSLICE(
v_data_u8, BMI160_USER_INTR1_OUTPUT_ENABLE,
v_output_enable_u8);
com_rslt += p_bmi160->BMI160_BUS_WRITE_FUNC(
p_bmi160->dev_addr,
BMI160_USER_INTR1_OUTPUT_ENABLE__REG,
&v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH);
}
break;
case BMI160_INTR2_OUTPUT_ENABLE:
/* write the output enable of interrupt2 */
com_rslt = p_bmi160->BMI160_BUS_READ_FUNC(
p_bmi160->dev_addr, BMI160_USER_INTR2_OUTPUT_EN__REG,
&v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH);
if (com_rslt == SUCCESS) {
v_data_u8 = BMI160_SET_BITSLICE(
v_data_u8, BMI160_USER_INTR2_OUTPUT_EN,
v_output_enable_u8);
com_rslt += p_bmi160->BMI160_BUS_WRITE_FUNC(
p_bmi160->dev_addr,
BMI160_USER_INTR2_OUTPUT_EN__REG, &v_data_u8,
BMI160_GEN_READ_WRITE_DATA_LENGTH);
}
break;
default:
com_rslt = E_BMI160_OUT_OF_RANGE;
break;
}
return com_rslt;
}
/*!
* @brief This API is used to set
* interrupt enable step detector interrupt from
* the register bit 0x52 bit 3
*
* @param v_step_intr_u8 : The value of step detector interrupt enable
*
* @return results of bus communication function
* @retval 0 -> Success
* @retval -1 -> Error
*
*/
static BMI160_RETURN_FUNCTION_TYPE bmi160_set_std_enable(u8 v_step_intr_u8)
{
/* variable used for return the status of communication result */
BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES;
u8 v_data_u8 = BMI160_INIT_VALUE;
/* check the p_bmi160 structure as NULL */
if (p_bmi160 == BMI160_NULL)
return E_BMI160_NULL_PTR;
com_rslt = p_bmi160->BMI160_BUS_READ_FUNC(
p_bmi160->dev_addr,
BMI160_USER_INTR_ENABLE_2_STEP_DETECTOR_ENABLE__REG, &v_data_u8,
BMI160_GEN_READ_WRITE_DATA_LENGTH);
if (com_rslt == SUCCESS) {
v_data_u8 = BMI160_SET_BITSLICE(
v_data_u8,
BMI160_USER_INTR_ENABLE_2_STEP_DETECTOR_ENABLE,
v_step_intr_u8);
com_rslt += p_bmi160->BMI160_BUS_WRITE_FUNC(
p_bmi160->dev_addr,
BMI160_USER_INTR_ENABLE_2_STEP_DETECTOR_ENABLE__REG,
&v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH);
}
return com_rslt;
}
/*!
* @brief
* This API reads the data from
* the given register
*
* @param v_addr_u8 -> Address of the register
* @param v_data_u8 -> The data from the register
* @param v_len_u8 -> no of bytes to read
*
* @return results of bus communication function
* @retval 0 -> Success
* @retval -1 -> Error
*
*/
BMI160_RETURN_FUNCTION_TYPE bmi160_read_reg(u8 v_addr_u8, u8 *v_data_u8,
u8 v_len_u8)
{
/* variable used for return the status of communication result */
BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES;
/* check the p_bmi160 structure as NULL */
if (p_bmi160 == BMI160_NULL)
return E_BMI160_NULL_PTR;
/* Read data from register */
com_rslt = p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160->dev_addr, v_addr_u8,
v_data_u8, v_len_u8);
return com_rslt;
}
/*!
* @brief This API used to trigger the step detector
* interrupt
*
* @param v_step_detector_u8 : The value of interrupt selection
* value | interrupt
* ----------|-----------
* 0 | BMI160_MAP_INTR1
* 1 | BMI160_MAP_INTR2
*
* @return results of bus communication function
* @retval 0 -> Success
* @retval -1 -> Error
*
*/
static BMI160_RETURN_FUNCTION_TYPE bmi160_map_std_intr(u8 v_step_detector_u8)
{
/* variable used for return the status of communication result */
BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES;
u8 v_step_det_u8 = BMI160_INIT_VALUE;
u8 v_data_u8 = BMI160_INIT_VALUE;
u8 v_low_g_intr_u81_stat_u8 = BMI160_LOW_G_INTR_STAT;
u8 v_low_g_intr_u82_stat_u8 = BMI160_LOW_G_INTR_STAT;
u8 v_low_g_enable_u8 = BMI160_ENABLE_LOW_G;
/* read the v_status_s8 of step detector interrupt */
com_rslt = bmi160_get_std_enable(&v_step_det_u8);
if (v_step_det_u8 != BMI160_STEP_DET_STAT_HIGH)
com_rslt +=
bmi160_set_std_enable(BMI160_STEP_DETECT_INTR_ENABLE);
switch (v_step_detector_u8) {
case BMI160_MAP_INTR1:
com_rslt += bmi160_read_reg(
BMI160_USER_INTR_MAP_0_INTR1_LOW_G__REG, &v_data_u8,
BMI160_GEN_READ_WRITE_DATA_LENGTH);
v_data_u8 |= v_low_g_intr_u81_stat_u8;
/* map the step detector interrupt to Low-g interrupt 1 */
com_rslt += bmi160_write_reg(
BMI160_USER_INTR_MAP_0_INTR1_LOW_G__REG, &v_data_u8,
BMI160_GEN_READ_WRITE_DATA_LENGTH);
p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY);
/* Enable the Low-g interrupt */
com_rslt = bmi160_read_reg(
BMI160_USER_INTR_ENABLE_1_LOW_G_ENABLE__REG, &v_data_u8,
BMI160_GEN_READ_WRITE_DATA_LENGTH);
v_data_u8 |= v_low_g_enable_u8;
com_rslt += bmi160_write_reg(
BMI160_USER_INTR_ENABLE_1_LOW_G_ENABLE__REG, &v_data_u8,
BMI160_GEN_READ_WRITE_DATA_LENGTH);
p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY);
break;
case BMI160_MAP_INTR2:
/* map the step detector interrupt to Low-g interrupt 1 */
com_rslt += bmi160_read_reg(
BMI160_USER_INTR_MAP_2_INTR2_LOW_G__REG, &v_data_u8,
BMI160_GEN_READ_WRITE_DATA_LENGTH);
v_data_u8 |= v_low_g_intr_u82_stat_u8;
com_rslt += bmi160_write_reg(
BMI160_USER_INTR_MAP_2_INTR2_LOW_G__REG, &v_data_u8,
BMI160_GEN_READ_WRITE_DATA_LENGTH);
p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY);
/* Enable the Low-g interrupt */
com_rslt = bmi160_read_reg(
BMI160_USER_INTR_ENABLE_1_LOW_G_ENABLE__REG, &v_data_u8,
BMI160_GEN_READ_WRITE_DATA_LENGTH);
v_data_u8 |= v_low_g_enable_u8;
com_rslt += bmi160_write_reg(
BMI160_USER_INTR_ENABLE_1_LOW_G_ENABLE__REG, &v_data_u8,
BMI160_GEN_READ_WRITE_DATA_LENGTH);
p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY);
break;
default:
com_rslt = E_BMI160_OUT_OF_RANGE;
break;
}
return com_rslt;
}
/*!
* @brief This API is used to select
* the significant or any motion interrupt from the register 0x62 bit 1
*
* @param v_intr_significant_motion_select_u8 :
* the value of significant or any motion interrupt selection
* value | Behaviour
* ----------|-------------------
* 0x00 | ANY_MOTION
* 0x01 | SIGNIFICANT_MOTION
*
* @return results of bus communication function
* @retval 0 -> Success
* @retval -1 -> Error
*
*/
BMI160_RETURN_FUNCTION_TYPE
bmi160_get_intr_sm_select(u8 *v_intr_significant_motion_select_u8)
{
/* variable used for return the status of communication result */
BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES;
u8 v_data_u8 = BMI160_INIT_VALUE;
/* check the p_bmi160 structure as NULL */
if (p_bmi160 == BMI160_NULL)
return E_BMI160_NULL_PTR;
/* read the significant or any motion interrupt */
com_rslt = p_bmi160->BMI160_BUS_READ_FUNC(
p_bmi160->dev_addr,
BMI160_USER_INTR_SIGNIFICATION_MOTION_SELECT__REG, &v_data_u8,
BMI160_GEN_READ_WRITE_DATA_LENGTH);
*v_intr_significant_motion_select_u8 = BMI160_GET_BITSLICE(
v_data_u8, BMI160_USER_INTR_SIGNIFICATION_MOTION_SELECT);
return com_rslt;
}
/*!
* @brief This API is used to write threshold
* definition for the any-motion interrupt
* from the register 0x60 bit 0 to 7
*
* @param v_any_motion_thres_u8 : The value of any motion threshold
*
* @note any motion threshold changes according to accel g range
* accel g range can be set by the function ""
* accel_range | any motion threshold
* ----------------|---------------------
* 2g | v_any_motion_thres_u8*3.91 mg
* 4g | v_any_motion_thres_u8*7.81 mg
* 8g | v_any_motion_thres_u8*15.63 mg
* 16g | v_any_motion_thres_u8*31.25 mg
* @note when v_any_motion_thres_u8 = 0
* accel_range | any motion threshold
* ----------------|---------------------
* 2g | 1.95 mg
* 4g | 3.91 mg
* 8g | 7.81 mg
* 16g | 15.63 mg
*
* @return results of bus communication function
* @retval 0 -> Success
* @retval -1 -> Error
*
*
*/
BMI160_RETURN_FUNCTION_TYPE
bmi160_set_intr_any_motion_thres(u8 v_any_motion_thres_u8)
{
/* variable used for return the status of communication result */
BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES;
/* check the p_bmi160 structure as NULL */
if (p_bmi160 == BMI160_NULL)
return E_BMI160_NULL_PTR;
/* write any motion threshold */
com_rslt = p_bmi160->BMI160_BUS_WRITE_FUNC(
p_bmi160->dev_addr,
BMI160_USER_INTR_MOTION_1_INTR_ANY_MOTION_THRES__REG,
&v_any_motion_thres_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH);
return com_rslt;
}
/*!
* @brief This API is used to write
* the significant skip time from the register 0x62 bit 2 and 3
*
* @param v_int_sig_mot_skip_u8 : the value of significant skip time
* value | Behaviour
* ----------|-------------------
* 0x00 | skip time 1.5 seconds
* 0x01 | skip time 3 seconds
* 0x02 | skip time 6 seconds
* 0x03 | skip time 12 seconds
*
* @return results of bus communication function
* @retval 0 -> Success
* @retval -1 -> Error
*
*/
static BMI160_RETURN_FUNCTION_TYPE
bmi160_set_intr_sm_skip(u8 v_int_sig_mot_skip_u8)
{
/* variable used for return the status of communication result */
BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES;
u8 v_data_u8 = BMI160_INIT_VALUE;
/* check the p_bmi160 structure as NULL */
if (p_bmi160 == BMI160_NULL)
return E_BMI160_NULL_PTR;
if (v_int_sig_mot_skip_u8 <= BMI160_MAX_UNDER_SIG_MOTION) {
/* write significant skip time */
com_rslt = p_bmi160->BMI160_BUS_READ_FUNC(
p_bmi160->dev_addr,
BMI160_USER_INTR_SIGNIFICANT_MOTION_SKIP__REG,
&v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH);
if (com_rslt == SUCCESS) {
v_data_u8 = BMI160_SET_BITSLICE(
v_data_u8,
BMI160_USER_INTR_SIGNIFICANT_MOTION_SKIP,
v_int_sig_mot_skip_u8);
com_rslt += p_bmi160->BMI160_BUS_WRITE_FUNC(
p_bmi160->dev_addr,
BMI160_USER_INTR_SIGNIFICANT_MOTION_SKIP__REG,
&v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH);
}
} else {
com_rslt = E_BMI160_OUT_OF_RANGE;
}
return com_rslt;
}
/*!
* @brief This API is used to write
* the significant proof time from the register 0x62 bit 4 and 5
*
* @param v_significant_motion_proof_u8 :
* the value of significant proof time
* value | Behaviour
* ----------|-------------------
* 0x00 | proof time 0.25 seconds
* 0x01 | proof time 0.5 seconds
* 0x02 | proof time 1 seconds
* 0x03 | proof time 2 seconds
*
* @return results of bus communication function
* @retval 0 -> Success
* @retval -1 -> Error
*
*/
static BMI160_RETURN_FUNCTION_TYPE
bmi160_set_intr_sm_proof(u8 v_significant_motion_proof_u8)
{
/* variable used for return the status of communication result */
BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES;
u8 v_data_u8 = BMI160_INIT_VALUE;
/* check the p_bmi160 structure as NULL */
if (p_bmi160 == BMI160_NULL)
return E_BMI160_NULL_PTR;
if (v_significant_motion_proof_u8 <= BMI160_MAX_UNDER_SIG_MOTION) {
/* write significant proof time */
com_rslt = p_bmi160->BMI160_BUS_READ_FUNC(
p_bmi160->dev_addr,
BMI160_USER_INTR_SIGNIFICANT_MOTION_PROOF__REG,
&v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH);
if (com_rslt == SUCCESS) {
v_data_u8 = BMI160_SET_BITSLICE(
v_data_u8,
BMI160_USER_INTR_SIGNIFICANT_MOTION_PROOF,
v_significant_motion_proof_u8);
com_rslt += p_bmi160->BMI160_BUS_WRITE_FUNC(
p_bmi160->dev_addr,
BMI160_USER_INTR_SIGNIFICANT_MOTION_PROOF__REG,
&v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH);
}
} else {
com_rslt = E_BMI160_OUT_OF_RANGE;
}
return com_rslt;
}
/*!
* @brief This API is used to write, select
* the significant or any motion interrupt from the register 0x62 bit 1
*
* @param v_intr_significant_motion_select_u8 :
* the value of significant or any motion interrupt selection
* value | Behaviour
* ----------|-------------------
* 0x00 | ANY_MOTION
* 0x01 | SIGNIFICANT_MOTION
*
* @return results of bus communication function
* @retval 0 -> Success
* @retval -1 -> Error
*
*/
static BMI160_RETURN_FUNCTION_TYPE
bmi160_set_intr_sm_select(u8 v_intr_significant_motion_select_u8)
{
/* variable used for return the status of communication result */
BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES;
u8 v_data_u8 = BMI160_INIT_VALUE;
/* check the p_bmi160 structure as NULL */
if (p_bmi160 == BMI160_NULL)
return E_BMI160_NULL_PTR;
if (v_intr_significant_motion_select_u8 <=
BMI160_MAX_VALUE_SIGNIFICANT_MOTION) {
/* write the significant or any motion interrupt */
com_rslt = p_bmi160->BMI160_BUS_READ_FUNC(
p_bmi160->dev_addr,
BMI160_USER_INTR_SIGNIFICATION_MOTION_SELECT__REG,
&v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH);
if (com_rslt == SUCCESS) {
v_data_u8 = BMI160_SET_BITSLICE(
v_data_u8,
BMI160_USER_INTR_SIGNIFICATION_MOTION_SELECT,
v_intr_significant_motion_select_u8);
com_rslt += p_bmi160->BMI160_BUS_WRITE_FUNC(
p_bmi160->dev_addr,
BMI160_USER_INTR_SIGNIFICATION_MOTION_SELECT__REG,
&v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH);
}
} else {
com_rslt = E_BMI160_OUT_OF_RANGE;
}
return com_rslt;
}
/*!
* @brief This API used to trigger the signification motion
* interrupt
*
* @param v_significant_u8 : The value of interrupt selection
* value | interrupt
* ----------|-----------
* 0 | BMI160_MAP_INTR1
* 1 | BMI160_MAP_INTR2
*
* @return results of bus communication function
* @retval 0 -> Success
* @retval -1 -> Error
*
*/
static BMI160_RETURN_FUNCTION_TYPE bmi160_map_sm_intr(u8 v_significant_u8)
{
/* variable used for return the status of communication result */
BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES;
u8 v_sig_motion_u8 = BMI160_INIT_VALUE;
u8 v_data_u8 = BMI160_INIT_VALUE;
u8 v_any_motion_intr1_stat_u8 = BMI160_ENABLE_ANY_MOTION_INTR1;
u8 v_any_motion_intr2_stat_u8 = BMI160_ENABLE_ANY_MOTION_INTR2;
u8 v_any_motion_axis_stat_u8 = BMI160_ENABLE_ANY_MOTION_AXIS;
/* enable the significant motion interrupt */
com_rslt = bmi160_get_intr_sm_select(&v_sig_motion_u8);
if (v_sig_motion_u8 != BMI160_SIG_MOTION_STAT_HIGH)
com_rslt += bmi160_set_intr_sm_select(
BMI160_SIG_MOTION_INTR_ENABLE);
switch (v_significant_u8) {
case BMI160_MAP_INTR1:
/* interrupt */
com_rslt += bmi160_read_reg(
BMI160_USER_INTR_MAP_0_INTR1_ANY_MOTION__REG,
&v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH);
v_data_u8 |= v_any_motion_intr1_stat_u8;
/* map the signification interrupt to any-motion interrupt1 */
com_rslt += bmi160_write_reg(
BMI160_USER_INTR_MAP_0_INTR1_ANY_MOTION__REG,
&v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH);
p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY);
/* axis */
com_rslt = bmi160_read_reg(BMI160_USER_INTR_ENABLE_0_ADDR,
&v_data_u8,
BMI160_GEN_READ_WRITE_DATA_LENGTH);
v_data_u8 |= v_any_motion_axis_stat_u8;
com_rslt += bmi160_write_reg(BMI160_USER_INTR_ENABLE_0_ADDR,
&v_data_u8,
BMI160_GEN_READ_WRITE_DATA_LENGTH);
p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY);
break;
case BMI160_MAP_INTR2:
/* map the signification interrupt to any-motion interrupt2 */
com_rslt += bmi160_read_reg(
BMI160_USER_INTR_MAP_2_INTR2_ANY_MOTION__REG,
&v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH);
v_data_u8 |= v_any_motion_intr2_stat_u8;
com_rslt += bmi160_write_reg(
BMI160_USER_INTR_MAP_2_INTR2_ANY_MOTION__REG,
&v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH);
p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY);
/* axis */
com_rslt = bmi160_read_reg(BMI160_USER_INTR_ENABLE_0_ADDR,
&v_data_u8,
BMI160_GEN_READ_WRITE_DATA_LENGTH);
v_data_u8 |= v_any_motion_axis_stat_u8;
com_rslt += bmi160_write_reg(BMI160_USER_INTR_ENABLE_0_ADDR,
&v_data_u8,
BMI160_GEN_READ_WRITE_DATA_LENGTH);
p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY);
break;
default:
com_rslt = E_BMI160_OUT_OF_RANGE;
break;
}
return com_rslt;
}
/*!
* @brief This API is used to set
* interrupt enable from the register 0x50 bit 0 to 7
*
* @param v_enable_u8 : Value to decided to select interrupt
* v_enable_u8 | interrupt
* ---------------|---------------
* 0 | BMI160_ANY_MOTION_X_ENABLE
* 1 | BMI160_ANY_MOTION_Y_ENABLE
* 2 | BMI160_ANY_MOTION_Z_ENABLE
* 3 | BMI160_DOUBLE_TAP_ENABLE
* 4 | BMI160_SINGLE_TAP_ENABLE
* 5 | BMI160_ORIENT_ENABLE
* 6 | BMI160_FLAT_ENABLE
*
* @param v_intr_enable_zero_u8 : The interrupt enable value
* value | interrupt enable
* ----------|-------------------
* 0x01 | BMI160_ENABLE
* 0x00 | BMI160_DISABLE
*
* @return results of bus communication function
* @retval 0 -> Success
* @retval -1 -> Error
*
*/
static BMI160_RETURN_FUNCTION_TYPE
bmi160_set_intr_enable_0(u8 v_enable_u8, u8 v_intr_enable_zero_u8)
{
/* variable used for return the status of communication result */
BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES;
u8 v_data_u8 = BMI160_INIT_VALUE;
/* check the p_bmi160 structure as NULL */
if (p_bmi160 == BMI160_NULL)
return E_BMI160_NULL_PTR;
switch (v_enable_u8) {
case BMI160_ANY_MOTION_X_ENABLE:
/* write any motion x */
com_rslt = p_bmi160->BMI160_BUS_READ_FUNC(
p_bmi160->dev_addr,
BMI160_USER_INTR_ENABLE_0_ANY_MOTION_X_ENABLE__REG,
&v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH);
if (com_rslt == SUCCESS) {
v_data_u8 = BMI160_SET_BITSLICE(
v_data_u8,
BMI160_USER_INTR_ENABLE_0_ANY_MOTION_X_ENABLE,
v_intr_enable_zero_u8);
com_rslt += p_bmi160->BMI160_BUS_WRITE_FUNC(
p_bmi160->dev_addr,
BMI160_USER_INTR_ENABLE_0_ANY_MOTION_X_ENABLE__REG,
&v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH);
}
break;
case BMI160_ANY_MOTION_Y_ENABLE:
/* write any motion y */
com_rslt = p_bmi160->BMI160_BUS_READ_FUNC(
p_bmi160->dev_addr,
BMI160_USER_INTR_ENABLE_0_ANY_MOTION_Y_ENABLE__REG,
&v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH);
if (com_rslt == SUCCESS) {
v_data_u8 = BMI160_SET_BITSLICE(
v_data_u8,
BMI160_USER_INTR_ENABLE_0_ANY_MOTION_Y_ENABLE,
v_intr_enable_zero_u8);
com_rslt += p_bmi160->BMI160_BUS_WRITE_FUNC(
p_bmi160->dev_addr,
BMI160_USER_INTR_ENABLE_0_ANY_MOTION_Y_ENABLE__REG,
&v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH);
}
break;
case BMI160_ANY_MOTION_Z_ENABLE:
/* write any motion z */
com_rslt = p_bmi160->BMI160_BUS_READ_FUNC(
p_bmi160->dev_addr,
BMI160_USER_INTR_ENABLE_0_ANY_MOTION_Z_ENABLE__REG,
&v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH);
if (com_rslt == SUCCESS) {
v_data_u8 = BMI160_SET_BITSLICE(
v_data_u8,
BMI160_USER_INTR_ENABLE_0_ANY_MOTION_Z_ENABLE,
v_intr_enable_zero_u8);
com_rslt += p_bmi160->BMI160_BUS_WRITE_FUNC(
p_bmi160->dev_addr,
BMI160_USER_INTR_ENABLE_0_ANY_MOTION_Z_ENABLE__REG,
&v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH);
}
break;
case BMI160_DOUBLE_TAP_ENABLE:
/* write double tap */
com_rslt = p_bmi160->BMI160_BUS_READ_FUNC(
p_bmi160->dev_addr,
BMI160_USER_INTR_ENABLE_0_DOUBLE_TAP_ENABLE__REG,
&v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH);
if (com_rslt == SUCCESS) {
v_data_u8 = BMI160_SET_BITSLICE(
v_data_u8,
BMI160_USER_INTR_ENABLE_0_DOUBLE_TAP_ENABLE,
v_intr_enable_zero_u8);
com_rslt += p_bmi160->BMI160_BUS_WRITE_FUNC(
p_bmi160->dev_addr,
BMI160_USER_INTR_ENABLE_0_DOUBLE_TAP_ENABLE__REG,
&v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH);
}
break;
case BMI160_SINGLE_TAP_ENABLE:
/* write single tap */
com_rslt = p_bmi160->BMI160_BUS_READ_FUNC(
p_bmi160->dev_addr,
BMI160_USER_INTR_ENABLE_0_SINGLE_TAP_ENABLE__REG,
&v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH);
if (com_rslt == SUCCESS) {
v_data_u8 = BMI160_SET_BITSLICE(
v_data_u8,
BMI160_USER_INTR_ENABLE_0_SINGLE_TAP_ENABLE,
v_intr_enable_zero_u8);
com_rslt += p_bmi160->BMI160_BUS_WRITE_FUNC(
p_bmi160->dev_addr,
BMI160_USER_INTR_ENABLE_0_SINGLE_TAP_ENABLE__REG,
&v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH);
}
break;
case BMI160_ORIENT_ENABLE:
/* write orient interrupt */
com_rslt = p_bmi160->BMI160_BUS_READ_FUNC(
p_bmi160->dev_addr,
BMI160_USER_INTR_ENABLE_0_ORIENT_ENABLE__REG,
&v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH);
if (com_rslt == SUCCESS) {
v_data_u8 = BMI160_SET_BITSLICE(
v_data_u8,
BMI160_USER_INTR_ENABLE_0_ORIENT_ENABLE,
v_intr_enable_zero_u8);
com_rslt += p_bmi160->BMI160_BUS_WRITE_FUNC(
p_bmi160->dev_addr,
BMI160_USER_INTR_ENABLE_0_ORIENT_ENABLE__REG,
&v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH);
}
break;
case BMI160_FLAT_ENABLE:
/* write flat interrupt */
com_rslt = p_bmi160->BMI160_BUS_READ_FUNC(
p_bmi160->dev_addr,
BMI160_USER_INTR_ENABLE_0_FLAT_ENABLE__REG, &v_data_u8,
BMI160_GEN_READ_WRITE_DATA_LENGTH);
if (com_rslt == SUCCESS) {
v_data_u8 = BMI160_SET_BITSLICE(
v_data_u8,
BMI160_USER_INTR_ENABLE_0_FLAT_ENABLE,
v_intr_enable_zero_u8);
com_rslt += p_bmi160->BMI160_BUS_WRITE_FUNC(
p_bmi160->dev_addr,
BMI160_USER_INTR_ENABLE_0_FLAT_ENABLE__REG,
&v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH);
}
break;
default:
com_rslt = E_BMI160_OUT_OF_RANGE;
break;
}
return com_rslt;
}
static int sm_init_interrupts(u8 sig_map_int_pin)
{
int ret = 0;
/*0x60 */
ret += bmi160_set_intr_any_motion_thres(0x1e);
/* 0x62(bit 3~2) 0=1.5s */
ret += bmi160_set_intr_sm_skip(0);
/* 0x62(bit 5~4) 1=0.5s */
ret += bmi160_set_intr_sm_proof(1);
/* 0x50 (bit 0, 1, 2) INT_EN_0 anymo x y z */
ret += bmi160_map_sm_intr(sig_map_int_pin);
/* 0x62 (bit 1) INT_MOTION_3 */
/*int_sig_mot_sel close the signification_motion */
ret += bmi160_set_intr_sm_select(0);
/*close the anymotion interrupt */
ret += bmi160_set_intr_enable_0(BMI160_ANY_MOTION_X_ENABLE, 0);
ret += bmi160_set_intr_enable_0(BMI160_ANY_MOTION_Y_ENABLE, 0);
ret += bmi160_set_intr_enable_0(BMI160_ANY_MOTION_Z_ENABLE, 0);
if (ret)
pr_err("bmi160 sig motion setting failed.\n");
return ret;
}
#ifdef CUSTOM_KERNEL_SIGNIFICANT_MOTION_SENSOR
static void bmi_std_interrupt_handle(struct bmi160_accelgyro_data *client_data)
{
u8 step_detect_enable = 0;
int err = 0;
err = bmi160_get_std_enable(&step_detect_enable);
if (err < 0) {
pr_err("get step detect enable failed.\n");
return;
}
if (step_detect_enable == ENABLE)
err = bmi160_step_notify(TYPE_STEP_DETECTOR);
if (err < 0)
pr_err("notify step detect failed.\n");
pr_debug("step detect enable = %d.\n", step_detect_enable);
}
static void bmi_sm_interrupt_handle(struct bmi160_accelgyro_data *client_data)
{
u8 sig_sel = 0;
int err = 0;
err = bmi160_get_intr_sm_select(&sig_sel);
if (err < 0) {
pr_err("get significant motion failed.\n");
return;
}
if (sig_sel == ENABLE) {
sig_flag = 1;
err = bmi160_step_notify(TYPE_SIGNIFICANT);
}
if (err < 0)
pr_err("notify significant motion failed.\n");
pr_debug("signification motion = %d.\n", (int)sig_sel);
}
#endif
static void bmi_irq_work_func(struct work_struct *work)
{
struct bmi160_accelgyro_data *obj = accelgyro_obj_data;
u8 int_status[4] = {0, 0, 0, 0};
BMP160_spi_read_bytes(obj->spi, BMI160_USER_INTR_STAT_0_ADDR,
int_status, 4);
#ifdef CUSTOM_KERNEL_SIGNIFICANT_MOTION_SENSOR
if (BMI160_GET_BITSLICE(int_status[0],
BMI160_USER_INTR_STAT_0_STEP_INTR))
bmi_std_interrupt_handle(client_data);
#endif
#ifdef CUSTOM_KERNEL_SIGNIFICANT_MOTION_SENSOR
if (BMI160_GET_BITSLICE(int_status[0],
BMI160_USER_INTR_STAT_0_SIGNIFICANT_INTR))
bmi_sm_interrupt_handle(client_data);
#endif
}
static irqreturn_t bmi_irq_handler(int irq, void *handle)
{
struct bmi160_accelgyro_data *client_data = accelgyro_obj_data;
if (client_data == NULL)
return IRQ_HANDLED;
schedule_work(&client_data->accel_irq_work);
return IRQ_HANDLED;
}
#ifdef MTK_NEW_ARCH_ACCEL
static int bmi160acc_probe(struct platform_device *pdev)
{
accelPltFmDev = pdev;
return 0;
}
static int bmi160acc_remove(struct platform_device *pdev)
{
return 0;
}
#ifdef CONFIG_OF
static const struct of_device_id bmi160_of_match[] = {
{
.compatible = "mediatek,st_step_counter",
},
{},
};
#endif
static struct platform_driver bmi160acc_driver = {
.probe = bmi160acc_probe,
.remove = bmi160acc_remove,
.driver = {
.name = "stepcounter",
/* .owner = THIS_MODULE, */
#ifdef CONFIG_OF
.of_match_table = bmi160_of_match,
#endif
}
};
static int bmi160acc_setup_eint(struct spi_device *spi)
{
int ret;
struct device_node *node = NULL;
struct pinctrl *pinctrl;
struct pinctrl_state *pins_default;
struct pinctrl_state *pins_cfg;
u32 ints[2] = {0, 0};
struct bmi160_accelgyro_data *obj = accelgyro_obj_data;
/* gpio setting */
pinctrl = devm_pinctrl_get(&spi->dev);
if (IS_ERR(pinctrl)) {
ret = PTR_ERR(pinctrl);
pr_err("Cannot find step pinctrl!\n");
return ret;
}
pins_default = pinctrl_lookup_state(pinctrl, "pin_default");
if (IS_ERR(pins_default)) {
ret = PTR_ERR(pins_default);
pr_err("Cannot find step pinctrl default!\n");
return ret;
}
pins_cfg = pinctrl_lookup_state(pinctrl, "pin_cfg");
if (IS_ERR(pins_cfg)) {
ret = PTR_ERR(pins_cfg);
pr_err("Cannot find step pinctrl pin_cfg!\n");
return ret;
}
pinctrl_select_state(pinctrl, pins_cfg);
node = of_find_compatible_node(NULL, NULL, "mediatek,ACC_1-eint");
/* eint request */
if (node) {
pr_debug("irq node is ok!");
of_property_read_u32_array(node, "debounce", ints,
ARRAY_SIZE(ints));
gpio_set_debounce(ints[0], ints[1]);
pr_debug("ints[0] = %d, ints[1] = %d!!\n", ints[0], ints[1]);
obj->IRQ = irq_of_parse_and_map(node, 0);
pr_debug("obj->IRQ = %d\n", obj->IRQ);
if (!obj->IRQ) {
pr_err("irq_of_parse_and_map fail!!\n");
return -EINVAL;
}
if (request_irq(obj->IRQ, bmi_irq_handler, IRQF_TRIGGER_RISING,
"mediatek,ACC_1-eint", NULL)) {
pr_err("IRQ LINE NOT AVAILABLE!!\n");
return -EINVAL;
}
enable_irq(obj->IRQ);
} else {
pr_err("null irq node!!\n");
return -EINVAL;
}
return 0;
}
#endif
static int bmg_factory_enable_sensor(bool enabledisable,
int64_t sample_periods_ms)
{
int err = 0;
err = bmi160_gyro_enable_nodata(enabledisable == true ? 1 : 0);
if (err) {
pr_err("%s enable failed!\n", __func__);
return -1;
}
err = bmi160_gyro_batch(0, sample_periods_ms * 1000000, 0);
if (err) {
pr_err("%s set batch failed!\n", __func__);
return -1;
}
return 0;
}
static int bmg_factory_get_data(int32_t data[3], int *status)
{
return bmi160_gyro_get_data(&data[0], &data[1], &data[2], status);
}
static int bmg_factory_get_raw_data(int32_t data[3])
{
pr_debug("%s don't support!\n", __func__);
return 0;
}
static int bmg_factory_enable_calibration(void)
{
return 0;
}
static int bmg_factory_clear_cali(void)
{
int err = 0;
err = bmg_reset_calibration(gyro_obj_data);
if (err) {
pr_err("bmg_ResetCalibration failed!\n");
return -1;
}
return 0;
}
static int bmg_factory_set_cali(int32_t data[3])
{
int err = 0;
int cali[3] = {0};
cali[BMG_AXIS_X] =
data[0] * gyro_obj_data->gyro_sensitivity / BMI160_FS_250_LSB;
cali[BMG_AXIS_Y] =
data[1] * gyro_obj_data->gyro_sensitivity / BMI160_FS_250_LSB;
cali[BMG_AXIS_Z] =
data[2] * gyro_obj_data->gyro_sensitivity / BMI160_FS_250_LSB;
err = bmg_write_calibration(gyro_obj_data, cali);
if (err) {
pr_err("bmg_WriteCalibration failed!\n");
return -1;
}
return 0;
}
static int bmg_factory_get_cali(int32_t data[3])
{
int err = 0;
int cali[3] = {0};
int raw_offset[BMG_BUFSIZE] = {0};
err = bmg_read_calibration(NULL, cali, raw_offset);
if (err) {
pr_err("bmg_ReadCalibration failed!\n");
return -1;
}
data[0] = cali[BMG_AXIS_X] * BMI160_FS_250_LSB /
gyro_obj_data->gyro_sensitivity;
data[1] = cali[BMG_AXIS_Y] * BMI160_FS_250_LSB /
gyro_obj_data->gyro_sensitivity;
data[2] = cali[BMG_AXIS_Z] * BMI160_FS_250_LSB /
gyro_obj_data->gyro_sensitivity;
return 0;
}
static int bmg_factory_do_self_test(void)
{
return 0;
}
static struct gyro_factory_fops bmg_factory_fops = {
.enable_sensor = bmg_factory_enable_sensor,
.get_data = bmg_factory_get_data,
.get_raw_data = bmg_factory_get_raw_data,
.enable_calibration = bmg_factory_enable_calibration,
.clear_cali = bmg_factory_clear_cali,
.set_cali = bmg_factory_set_cali,
.get_cali = bmg_factory_get_cali,
.do_self_test = bmg_factory_do_self_test,
};
static struct gyro_factory_public bmg_factory_device = {
.gain = 1, .sensitivity = 1, .fops = &bmg_factory_fops,
};
static int bmi160_accelgyro_spi_probe(struct spi_device *spi)
{
int err = 0;
/* accel sensor */
struct bmi160_accelgyro_data *obj;
struct acc_control_path accel_ctl = {0};
struct acc_data_path accel_data = {0};
struct gyro_control_path gyro_ctl = {0};
struct gyro_data_path gyro_data = {0};
pr_debug("%s enter\n", __func__);
obj = kzalloc(sizeof(*obj), GFP_KERNEL);
if (!obj) {
err = -ENOMEM;
goto exit;
}
err = get_accelgyro_dts_func(spi->dev.of_node, &obj->hw);
if (err < 0) {
pr_err("device tree configuration error\n");
return 0;
}
/* map direction */
err = hwmsen_get_convert(obj->hw.direction, &obj->cvt);
if (err) {
pr_err("invalid direction: %d\n", obj->hw.direction);
goto exit;
}
/* Spi start,Initialize the driver data */
obj->spi = spi;
/* setup SPI parameters */
/* CPOL=CPHA=0, speed 1MHz */
obj->spi->mode = SPI_MODE_0;
obj->spi->bits_per_word = 8;
obj->spi->max_speed_hz = 1 * 1000 * 1000;
spi_set_drvdata(spi, obj);
/* allocate buffer for SPI transfer */
obj->spi_buffer = kzalloc(bufsiz, GFP_KERNEL);
if (obj->spi_buffer == NULL)
goto err_buf;
/*Spi end*/
/* acc */
accelgyro_obj_data = obj;
atomic_set(&obj->accel_trace, 0);
atomic_set(&obj->accel_suspend, 0);
mutex_init(&obj->accel_lock);
/* gyro */
gyro_obj_data = obj;
atomic_set(&obj->gyro_trace, 0);
atomic_set(&obj->gyro_suspend, 0);
obj->gyro_power_mode = BMG_UNDEFINED_POWERMODE;
obj->gyro_range = BMG_UNDEFINED_RANGE;
obj->gyro_datarate = BMI160_GYRO_ODR_RESERVED;
mutex_init(&obj->gyro_lock);
#ifdef CONFIG_BMG_LOWPASS
if (obj->hw.gyro_firlen > C_MAX_FIR_LENGTH)
atomic_set(&obj->gyro_firlen, C_MAX_FIR_LENGTH);
else
atomic_set(&obj->gyro_firlen, obj->hw.gyro_firlen);
if (atomic_read(&obj->gyro_firlen) > 0)
atomic_set(&obj->gyro_fir_en, 1);
#endif
/*gyro end*/
mutex_init(&obj->spi_lock);
err = bmi160_acc_init_client(obj, 1);
if (err)
goto exit_init_failed;
err = bmg_init_client(obj, 1);
if (err)
goto exit_init_client_failed;
#ifdef MTK_NEW_ARCH_ACCEL
platform_driver_register(&bmi160acc_driver);
#endif
#ifdef FIFO_READ_USE_DMA_MODE_I2C
gpDMABuf_va = (u8 *)dma_alloc_coherent(
NULL, GTP_DMA_MAX_TRANSACTION_LENGTH, &gpDMABuf_pa, GFP_KERNEL);
memset(gpDMABuf_va, 0, GTP_DMA_MAX_TRANSACTION_LENGTH);
#endif
#ifndef MTK_NEW_ARCH_ACCEL
obj->accel_gpio_pin = 94;
obj->accel_IRQ = gpio_to_irq(obj->accel_gpio_pin);
err = request_irq(obj->accel_IRQ, bmi_irq_handler, IRQF_TRIGGER_RISING,
"bmi160", obj);
if (err)
pr_err("could not request accel_IRQ\n");
#else
err = bmi160acc_setup_eint(spi);
if (err)
pr_err("could not request accel_IRQ\n");
#endif
/* acc factory */
err = accel_factory_device_register(&bmi160_accel_factory_device);
if (err) {
pr_err("acc_factory register failed.\n");
goto exit_misc_device_register_failed;
}
/* gyro factory */
/* err = misc_register(&bmg_device); */
err = gyro_factory_device_register(&bmg_factory_device);
if (err) {
pr_err("misc device register failed, err = %d\n", err);
goto exit_misc_device_register_failed;
}
err = bmi160_accelgyro_create_attr(
&(bmi160_accelgyro_spi_driver.driver));
if (err) {
pr_err("create attribute failed.\n");
goto exit_create_attr_failed;
}
/* Init control path,acc */
accel_ctl.enable_nodata = bmi160_acc_enable_nodata;
accel_ctl.batch = bmi160_acc_batch;
accel_ctl.flush = bmi160_acc_flush;
accel_ctl.is_support_batch = false; /* using customization info */
accel_ctl.is_report_input_direct = false;
err = acc_register_control_path(&accel_ctl);
if (err) {
pr_err("register acc control path error.\n");
goto exit_kfree;
}
/* gyro */
gyro_ctl.open_report_data = bmi160_gyro_open_report_data;
gyro_ctl.enable_nodata = bmi160_gyro_enable_nodata;
gyro_ctl.batch = bmi160_gyro_batch;
gyro_ctl.flush = bmi160_gyro_flush;
gyro_ctl.is_report_input_direct = false;
gyro_ctl.is_support_batch = obj->hw.gyro_is_batch_supported;
pr_debug(">>gyro_register_control_path\n");
err = gyro_register_control_path(&gyro_ctl);
if (err) {
pr_err("register gyro control path err\n");
goto exit_create_attr_failed;
}
/* Init data path,acc */
accel_data.get_data = bmi160_acc_get_data;
accel_data.vender_div = 1000;
err = acc_register_data_path(&accel_data);
if (err) {
pr_err("register acc data path error.\n");
goto exit_kfree;
}
/* gyro */
gyro_data.get_data = bmi160_gyro_get_data;
gyro_data.vender_div = DEGREE_TO_RAD;
err = gyro_register_data_path(&gyro_data);
if (err) {
pr_err("gyro_register_data_path fail = %d\n", err);
goto exit_create_attr_failed;
}
/* acc and gyro */
#ifdef CONFIG_PM
err = register_pm_notifier(&pm_notifier_func);
if (err) {
pr_err("Failed to register PM notifier.\n");
goto exit_kfree;
}
#endif /* CONFIG_PM */
/* h/w init */
obj->device.bus_read = bmi_read_wrapper;
obj->device.bus_write = bmi_write_wrapper;
obj->device.delay_msec = bmi_delay;
bmi160_init(&obj->device);
/* soft reset */
bmi160_set_command_register(0xB6);
mdelay(3);
/* maps interrupt to INT1 pin, set interrupt trigger level way */
bmi160_set_intr_edge_ctrl(BMI_INT0, BMI_INT_LEVEL);
udelay(500);
bmi160_set_intr_fifo_wm(BMI_INT0, ENABLE);
udelay(500);
bmi160_set_intr_level(BMI_INT0, ENABLE);
udelay(500);
bmi160_set_output_enable(BMI160_INTR1_OUTPUT_ENABLE, ENABLE);
udelay(500);
sm_init_interrupts(BMI160_MAP_INTR1);
mdelay(3);
bmi160_map_std_intr(BMI160_MAP_INTR1);
mdelay(3);
bmi160_set_std_enable(DISABLE);
mdelay(3);
/* fifo setting */
bmi160_set_fifo_header_enable(ENABLE);
udelay(500);
bmi160_set_fifo_time_enable(DISABLE);
udelay(500);
bmi160_acc_init_client(obj, 1);
INIT_WORK(&obj->accel_irq_work, bmi_irq_work_func);
bmi160_acc_init_flag = 0;
bmi160_gyro_init_flag = 0;
pr_debug("%s: is ok.\n", __func__);
return 0;
exit_create_attr_failed:
/* misc_deregister(&bmi160_acc_device); */
/* misc_deregister(&bmg_device); */
exit_misc_device_register_failed:
exit_init_failed:
err_buf:
kfree(obj->spi_buffer);
spi_set_drvdata(spi, NULL);
obj->spi = NULL;
exit_kfree:
exit_init_client_failed:
kfree(obj);
exit:
pr_err("%s: err = %d\n", __func__, err);
bmi160_acc_init_flag = -1;
bmi160_gyro_init_flag = -1;
return err;
}
static int bmi160_accelgyro_spi_remove(struct spi_device *spi)
{
struct bmi160_accelgyro_data *obj = spi_get_drvdata(spi);
int err = 0;
err = bmi160_accelgyro_delete_attr(
&(bmi160_accelgyro_spi_driver.driver));
if (err)
pr_err("delete device attribute failed.\n");
if (obj->spi_buffer != NULL) {
kfree(obj->spi_buffer);
obj->spi_buffer = NULL;
}
spi_set_drvdata(spi, NULL);
obj->spi = NULL;
/* misc_deregister(&bmi160_acc_device); */
accel_factory_device_deregister(&bmi160_accel_factory_device);
gyro_factory_device_deregister(&bmg_factory_device);
kfree(accelgyro_obj_data);
return 0;
}
static int bmi160_accelgyro_local_init(void)
{
pr_debug("%s start.\n", __func__);
if (spi_register_driver(&bmi160_accelgyro_spi_driver))
return -1;
if ((-1 == bmi160_acc_init_flag) || (-1 == bmi160_gyro_init_flag))
return -1;
pr_debug("%s end.\n", __func__);
return 0;
}
static int bmi160_accelgyro_remove(void)
{
pr_debug("%s\n", __func__);
spi_unregister_driver(&bmi160_accelgyro_spi_driver);
return 0;
}
static struct accelgyro_init_info bmi160_accelgyro_init_info = {
.name = BMI160_ACCELGYRO_DEV_NAME,
.init = bmi160_accelgyro_local_init,
.uninit = bmi160_accelgyro_remove,
};
static int __init bmi160_accelgyro_init(void)
{
pr_debug("%s\n", __func__);
accelgyro_driver_add(&bmi160_accelgyro_init_info);
return 0;
}
static void __exit bmi160_accelgyro_exit(void)
{
pr_debug("%s\n", __func__);
}
module_init(bmi160_accelgyro_init);
module_exit(bmi160_accelgyro_exit);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("BMI160_ACC_GYRO SPI driver");
MODULE_AUTHOR("ruixue.su@mediatek.com");