/*!
 * @section LICENSE
 * (C) Copyright 2011~2016 Bosch Sensortec GmbH All Rights Reserved
 *
 * (C) Modification Copyright 2018 Robert Bosch Kft  All Rights Reserved
 *
 * This software program is licensed subject to the GNU General
 * Public License (GPL).Version 2,June 1991,
 * available at http://www.fsf.org/copyleft/gpl.html
 *
 * Special: Description of the Software:
 *
 * This software module (hereinafter called "Software") and any
 * information on application-sheets (hereinafter called "Information") is
 * provided free of charge for the sole purpose to support your application
 * work. 
 *
 * As such, the Software is merely an experimental software, not tested for
 * safety in the field and only intended for inspiration for further development 
 * and testing. Any usage in a safety-relevant field of use (like automotive,
 * seafaring, spacefaring, industrial plants etc.) was not intended, so there are
 * no precautions for such usage incorporated in the Software.
 * 
 * The Software is specifically designed for the exclusive use for Bosch
 * Sensortec products by personnel who have special experience and training. Do
 * not use this Software if you do not have the proper experience or training.
 * 
 * This Software package is provided as is and without any expressed or
 * implied warranties, including without limitation, the implied warranties of
 * merchantability and fitness for a particular purpose.
 * 
 * Bosch Sensortec and their representatives and agents deny any liability for
 * the functional impairment of this Software in terms of fitness, performance
 * and safety. Bosch Sensortec and their representatives and agents shall not be
 * liable for any direct or indirect damages or injury, except as otherwise
 * stipulated in mandatory applicable law.
 * The Information provided is believed to be accurate and reliable. Bosch
 * Sensortec assumes no responsibility for the consequences of use of such
 * Information nor for any infringement of patents or other rights of third
 * parties which may result from its use.
 * 
 *------------------------------------------------------------------------------
 * The following Product Disclaimer does not apply to the BSX4-HAL-4.1NoFusion Software 
 * which is licensed under the Apache License, Version 2.0 as stated above.  
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Product Disclaimer
 *
 * Common:
 *
 * Assessment of Products Returned from Field
 *
 * Returned products are considered good if they fulfill the specifications / 
 * test data for 0-mileage and field listed in this document.
 *
 * Engineering Samples
 * 
 * Engineering samples are marked with (e) or (E). Samples may vary from the
 * valid technical specifications of the series product contained in this
 * data sheet. Therefore, they are not intended or fit for resale to
 * third parties or for use in end products. Their sole purpose is internal
 * client testing. The testing of an engineering sample may in no way replace
 * the testing of a series product. Bosch assumes no liability for the use
 * of engineering samples. The purchaser shall indemnify Bosch from all claims
 * arising from the use of engineering samples.
 *
 * Intended use
 *
 * Provided that SMI130 is used within the conditions (environment, application,
 * installation, loads) as described in this TCD and the corresponding
 * agreed upon documents, Bosch ensures that the product complies with
 * the agreed properties. Agreements beyond this require
 * the written approval by Bosch. The product is considered fit for the intended
 * use when the product successfully has passed the tests
 * in accordance with the TCD and agreed upon documents.
 *
 * It is the responsibility of the customer to ensure the proper application
 * of the product in the overall system/vehicle.
 *
 * Bosch does not assume any responsibility for changes to the environment
 * of the product that deviate from the TCD and the agreed upon documents 
 * as well as all applications not released by Bosch
  *
 * The resale and/or use of products are at the purchaser’s own risk and 
 * responsibility. The examination and testing of the SMI130 
 * is the sole responsibility of the purchaser.
 *
 * The purchaser shall indemnify Bosch from all third party claims 
 * arising from any product use not covered by the parameters of 
 * this product data sheet or not approved by Bosch and reimburse Bosch 
 * for all costs and damages in connection with such claims.
 *
 * The purchaser must monitor the market for the purchased products,
 * particularly with regard to product safety, and inform Bosch without delay
 * of all security relevant incidents.
 *
 * Application Examples and Hints
 *
 * With respect to any application examples, advice, normal values
 * and/or any information regarding the application of the device,
 * Bosch hereby disclaims any and all warranties and liabilities of any kind,
 * including without limitation warranties of
 * non-infringement of intellectual property rights or copyrights
 * of any third party.
 * The information given in this document shall in no event be regarded 
 * as a guarantee of conditions or characteristics. They are provided
 * for illustrative purposes only and no evaluation regarding infringement
 * of intellectual property rights or copyrights or regarding functionality,
 * performance or error has been made.
 *
 * @filename smi130_driver.c
 * @date     2016/08/01 14:40
 * @Modification Date 2018/08/28 18:20
 * @id       "b5ff23a"
 * @version  1.3
 *
 * @brief
 * The core code of SMI130 device driver
 *
 * @detail
 * This file implements the core code of SMI130 device driver,
 * which includes hardware related functions, input device register,
 * device attribute files, etc.
*/

#include "smi130.h"
#include "smi130_driver.h"
#include <linux/device.h>
#include <linux/gpio.h>
#include <linux/of_gpio.h>
#include <linux/of_irq.h>


#define DRIVER_VERSION "0.0.53.0"
#define I2C_BURST_READ_MAX_LEN      (256)
#define SMI130_STORE_COUNT  (6000)
#define LMADA     (1)
uint64_t g_current_apts_us_mbl;


enum SMI_SENSOR_INT_T {
	/* Interrupt enable0*/
	SMI_ANYMO_X_INT = 0,
	SMI_ANYMO_Y_INT,
	SMI_ANYMO_Z_INT,
	SMI_D_TAP_INT,
	SMI_S_TAP_INT,
	SMI_ORIENT_INT,
	SMI_FLAT_INT,
	/* Interrupt enable1*/
	SMI_HIGH_X_INT,
	SMI_HIGH_Y_INT,
	SMI_HIGH_Z_INT,
	SMI_LOW_INT,
	SMI_DRDY_INT,
	SMI_FFULL_INT,
	SMI_FWM_INT,
	/* Interrupt enable2 */
	SMI_NOMOTION_X_INT,
	SMI_NOMOTION_Y_INT,
	SMI_NOMOTION_Z_INT,
	SMI_STEP_DETECTOR_INT,
	INT_TYPE_MAX
};

/*smi fifo sensor type combination*/
enum SMI_SENSOR_FIFO_COMBINATION {
	SMI_FIFO_A = 0,
	SMI_FIFO_G,
	SMI_FIFO_M,
	SMI_FIFO_G_A,
	SMI_FIFO_M_A,
	SMI_FIFO_M_G,
	SMI_FIFO_M_G_A,
	SMI_FIFO_COM_MAX
};

/*smi fifo analyse return err status*/
enum SMI_FIFO_ANALYSE_RETURN_T {
	FIFO_OVER_READ_RETURN = -10,
	FIFO_SENSORTIME_RETURN = -9,
	FIFO_SKIP_OVER_LEN = -8,
	FIFO_M_G_A_OVER_LEN = -7,
	FIFO_M_G_OVER_LEN = -6,
	FIFO_M_A_OVER_LEN = -5,
	FIFO_G_A_OVER_LEN = -4,
	FIFO_M_OVER_LEN = -3,
	FIFO_G_OVER_LEN = -2,
	FIFO_A_OVER_LEN = -1
};

/*!smi sensor generic power mode enum */
enum SMI_DEV_OP_MODE {
	SENSOR_PM_NORMAL = 0,
	SENSOR_PM_LP1,
	SENSOR_PM_SUSPEND,
	SENSOR_PM_LP2
};

/*! smi acc sensor power mode enum */
enum SMI_ACC_PM_TYPE {
	SMI_ACC_PM_NORMAL = 0,
	SMI_ACC_PM_LP1,
	SMI_ACC_PM_SUSPEND,
	SMI_ACC_PM_LP2,
	SMI_ACC_PM_MAX
};

/*! smi gyro sensor power mode enum */
enum SMI_GYRO_PM_TYPE {
	SMI_GYRO_PM_NORMAL = 0,
	SMI_GYRO_PM_FAST_START,
	SMI_GYRO_PM_SUSPEND,
	SMI_GYRO_PM_MAX
};

/*! smi mag sensor power mode enum */
enum SMI_MAG_PM_TYPE {
	SMI_MAG_PM_NORMAL = 0,
	SMI_MAG_PM_LP1,
	SMI_MAG_PM_SUSPEND,
	SMI_MAG_PM_LP2,
	SMI_MAG_PM_MAX
};


/*! smi sensor support type*/
enum SMI_SENSOR_TYPE {
	SMI_ACC_SENSOR,
	SMI_GYRO_SENSOR,
	SMI_MAG_SENSOR,
	SMI_SENSOR_TYPE_MAX
};

/*!smi sensor generic power mode enum */
enum SMI_AXIS_TYPE {
	X_AXIS = 0,
	Y_AXIS,
	Z_AXIS,
	AXIS_MAX
};

/*!smi sensor generic intterrupt enum */
enum SMI_INT_TYPE {
	SMI130_INT0 = 0,
	SMI130_INT1,
	SMI130_INT_MAX
};

/*! smi sensor time resolution definition*/
enum SMI_SENSOR_TIME_RS_TYPE {
	TS_0_78_HZ = 1,/*0.78HZ*/
	TS_1_56_HZ,/*1.56HZ*/
	TS_3_125_HZ,/*3.125HZ*/
	TS_6_25_HZ,/*6.25HZ*/
	TS_12_5_HZ,/*12.5HZ*/
	TS_25_HZ,/*25HZ, odr=6*/
	TS_50_HZ,/*50HZ*/
	TS_100_HZ,/*100HZ*/
	TS_200_HZ,/*200HZ*/
	TS_400_HZ,/*400HZ*/
	TS_800_HZ,/*800HZ*/
	TS_1600_HZ,/*1600HZ*/
	TS_MAX_HZ
};

/*! smi sensor interface mode */
enum SMI_SENSOR_IF_MODE_TYPE {
	/*primary interface:autoconfig/secondary interface off*/
	P_AUTO_S_OFF = 0,
	/*primary interface:I2C/secondary interface:OIS*/
	P_I2C_S_OIS,
	/*primary interface:autoconfig/secondary interface:Magnetometer*/
	P_AUTO_S_MAG,
	/*interface mode reseved*/
	IF_MODE_RESEVED

};

/*! smi130 acc/gyro calibration status in H/W layer */
enum SMI_CALIBRATION_STATUS_TYPE {
	/*SMI FAST Calibration ready x/y/z status*/
	SMI_ACC_X_FAST_CALI_RDY = 0,
	SMI_ACC_Y_FAST_CALI_RDY,
	SMI_ACC_Z_FAST_CALI_RDY
};

unsigned int reg_op_addr_mbl;

static const int smi_pmu_cmd_acc_arr[SMI_ACC_PM_MAX] = {
	/*!smi pmu for acc normal, low power1,
	 * suspend, low power2 mode command */
	CMD_PMU_ACC_NORMAL,
	CMD_PMU_ACC_LP1,
	CMD_PMU_ACC_SUSPEND,
	CMD_PMU_ACC_LP2
};

static const int smi_pmu_cmd_gyro_arr[SMI_GYRO_PM_MAX] = {
	/*!smi pmu for gyro normal, fast startup,
	 * suspend mode command */
	CMD_PMU_GYRO_NORMAL,
	CMD_PMU_GYRO_FASTSTART,
	CMD_PMU_GYRO_SUSPEND
};

static const int smi_pmu_cmd_mag_arr[SMI_MAG_PM_MAX] = {
	/*!smi pmu for mag normal, low power1,
	 * suspend, low power2 mode command */
	CMD_PMU_MAG_NORMAL,
	CMD_PMU_MAG_LP1,
	CMD_PMU_MAG_SUSPEND,
	CMD_PMU_MAG_LP2
};

static const char *smi_axis_name[AXIS_MAX] = {"x", "y", "z"};

static const int smi_interrupt_type[] = {
	/*!smi interrupt type */
	/* Interrupt enable0 , index=0~6*/
	SMI130_ANY_MOTION_X_ENABLE,
	SMI130_ANY_MOTION_Y_ENABLE,
	SMI130_ANY_MOTION_Z_ENABLE,
	SMI130_DOUBLE_TAP_ENABLE,
	SMI130_SINGLE_TAP_ENABLE,
	SMI130_ORIENT_ENABLE,
	SMI130_FLAT_ENABLE,
	/* Interrupt enable1, index=7~13*/
	SMI130_HIGH_G_X_ENABLE,
	SMI130_HIGH_G_Y_ENABLE,
	SMI130_HIGH_G_Z_ENABLE,
	SMI130_LOW_G_ENABLE,
	SMI130_DATA_RDY_ENABLE,
	SMI130_FIFO_FULL_ENABLE,
	SMI130_FIFO_WM_ENABLE,
	/* Interrupt enable2, index = 14~17*/
	SMI130_NOMOTION_X_ENABLE,
	SMI130_NOMOTION_Y_ENABLE,
	SMI130_NOMOTION_Z_ENABLE,
	SMI130_STEP_DETECTOR_EN
};

/*! smi sensor time depend on ODR*/
struct smi_sensor_time_odr_tbl {
	u32 ts_duration_lsb;
	u32 ts_duration_us;
	u32 ts_delat;/*sub current delat fifo_time*/
};

struct smi130_axis_data_t {
	s16 x;
	s16 y;
	s16 z;
};

struct smi130_type_mapping_type {

	/*! smi16x sensor chip id */
	uint16_t chip_id;

	/*! smi16x chip revision code */
	uint16_t revision_id;

	/*! smi130_acc sensor name */
	const char *sensor_name;
};

struct smi130_store_info_t {
	uint8_t current_frm_cnt;
	uint64_t current_apts_us[2];
	uint8_t fifo_ts_total_frmcnt;
	uint64_t fifo_time;
};

uint64_t get_current_timestamp_mbl(void)
{
	uint64_t ts_ap;
	struct timespec tmp_time;
	get_monotonic_boottime(&tmp_time);
	ts_ap = (uint64_t)tmp_time.tv_sec * 1000000000 + tmp_time.tv_nsec;
	return ts_ap;

}

/*! sensor support type map */
static const struct smi130_type_mapping_type sensor_type_map[] = {

	{SENSOR_CHIP_ID_SMI, SENSOR_CHIP_REV_ID_SMI, "SMI130/162AB"},
	{SENSOR_CHIP_ID_SMI_C2, SENSOR_CHIP_REV_ID_SMI, "SMI130C2"},
	{SENSOR_CHIP_ID_SMI_C3, SENSOR_CHIP_REV_ID_SMI, "SMI130C3"},

};

/*!smi130 sensor time depends on ODR */
static const struct smi_sensor_time_odr_tbl
		sensortime_duration_tbl[TS_MAX_HZ] = {
	{0x010000, 2560000, 0x00ffff},/*2560ms, 0.39hz, odr=resver*/
	{0x008000, 1280000, 0x007fff},/*1280ms, 0.78hz, odr_acc=1*/
	{0x004000, 640000, 0x003fff},/*640ms, 1.56hz, odr_acc=2*/
	{0x002000, 320000, 0x001fff},/*320ms, 3.125hz, odr_acc=3*/
	{0x001000, 160000, 0x000fff},/*160ms, 6.25hz, odr_acc=4*/
	{0x000800, 80000,  0x0007ff},/*80ms, 12.5hz*/
	{0x000400, 40000, 0x0003ff},/*40ms, 25hz, odr_acc = odr_gyro =6*/
	{0x000200, 20000, 0x0001ff},/*20ms, 50hz, odr = 7*/
	{0x000100, 10000, 0x0000ff},/*10ms, 100hz, odr=8*/
	{0x000080, 5000, 0x00007f},/*5ms, 200hz, odr=9*/
	{0x000040, 2500, 0x00003f},/*2.5ms, 400hz, odr=10*/
	{0x000020, 1250, 0x00001f},/*1.25ms, 800hz, odr=11*/
	{0x000010, 625, 0x00000f},/*0.625ms, 1600hz, odr=12*/

};

#if defined(CONFIG_USE_QUALCOMM_HAL)
#define POLL_INTERVAL_MIN_MS	10
#define POLL_INTERVAL_MAX_MS	4000
#define POLL_DEFAULT_INTERVAL_MS 200
#define SMI130_ACCEL_MIN_VALUE	-32768
#define SMI130_ACCEL_MAX_VALUE	32767
#define SMI130_GYRO_MIN_VALUE	-32768
#define SMI130_GYRO_MAX_VALUE	32767
#define SMI130_ACCEL_DEFAULT_POLL_INTERVAL_MS	200
#define SMI130_GYRO_DEFAULT_POLL_INTERVAL_MS	200
#define SMI130_ACCEL_MIN_POLL_INTERVAL_MS	10
#define SMI130_ACCEL_MAX_POLL_INTERVAL_MS	5000
#define SMI130_GYRO_MIN_POLL_INTERVAL_MS	10
#define SMI130_GYRO_MAX_POLL_INTERVAL_MS	5000
static struct sensors_classdev smi130_accel_cdev = {
		.name = "smi130-accel",
		.vendor = "bosch",
		.version = 1,
		.handle = SENSORS_ACCELERATION_HANDLE,
		.type = SENSOR_TYPE_ACCELEROMETER,
		.max_range = "156.8",	/* 16g */
		.resolution = "0.153125",	/* 15.6mg */
		.sensor_power = "0.13",	/* typical value */
		.min_delay = POLL_INTERVAL_MIN_MS * 1000, /* in microseconds */
		.max_delay = POLL_INTERVAL_MAX_MS,
		.delay_msec = POLL_DEFAULT_INTERVAL_MS, /* in millisecond */
		.fifo_reserved_event_count = 0,
		.fifo_max_event_count = 0,
		.enabled = 0,
		.max_latency = 0,
		.flags = 0,
		.sensors_enable = NULL,
		.sensors_poll_delay = NULL,
		.sensors_set_latency = NULL,
		.sensors_flush = NULL,
		.sensors_self_test = NULL,
};
static struct sensors_classdev smi130_gyro_cdev = {
	.name = "smi130-gyro",
	.vendor = "bosch",
	.version = 1,
	.handle = SENSORS_GYROSCOPE_HANDLE,
	.type = SENSOR_TYPE_GYROSCOPE,
	.max_range = "34.906586",	/* rad/s */
	.resolution = "0.0010681152",	/* rad/s */
	.sensor_power = "3.6",	/* 3.6 mA */
	.min_delay = SMI130_GYRO_MIN_POLL_INTERVAL_MS * 1000,
	.max_delay = SMI130_GYRO_MAX_POLL_INTERVAL_MS,
	.delay_msec = SMI130_GYRO_DEFAULT_POLL_INTERVAL_MS,
	.fifo_reserved_event_count = 0,
	.fifo_max_event_count = 0,
	.enabled = 0,
	.max_latency = 0,
	.flags = 0, /* SENSOR_FLAG_CONTINUOUS_MODE */
	.sensors_enable = NULL,
	.sensors_poll_delay = NULL,
	.sensors_enable_wakeup = NULL,
	.sensors_set_latency = NULL,
	.sensors_flush = NULL,
};
#endif
static void smi_delay(u32 msec)
{
	if (msec <= 20)
		usleep_range(msec * 1000, msec * 1000);
	else
		msleep(msec);
}

static void smi_dump_reg(struct smi_client_data *client_data)
{
	#define REG_MAX0 0x24
	#define REG_MAX1 0x56
	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] = "";

	dev_notice(client_data->dev, "\nFrom 0x00:\n");

	client_data->device.bus_read(client_data->device.dev_addr,
			SMI_REG_NAME(USER_CHIP_ID), dbg_buf0, REG_MAX0);
	for (i = 0; i < REG_MAX0; i++) {
		snprintf(dbg_buf_str0 + i * 3, 16, "%02x%c", dbg_buf0[i],
				(((i + 1) % BYTES_PER_LINE == 0) ? '\n' : ' '));
	}
	dev_notice(client_data->dev, "%s\n", dbg_buf_str0);

	client_data->device.bus_read(client_data->device.dev_addr,
			SMI130_USER_ACCEL_CONFIG_ADDR, dbg_buf1, REG_MAX1);
	dev_notice(client_data->dev, "\nFrom 0x40:\n");
	for (i = 0; i < REG_MAX1; i++) {
		snprintf(dbg_buf_str1 + i * 3, 16, "%02x%c", dbg_buf1[i],
				(((i + 1) % BYTES_PER_LINE == 0) ? '\n' : ' '));
	}
	dev_notice(client_data->dev, "\n%s\n", dbg_buf_str1);
	}


void smi_fifo_frame_bytes_extend_calc(
	struct smi_client_data *client_data,
	unsigned int *fifo_frmbytes_extend)
{

	switch (client_data->fifo_data_sel) {
	case SMI_FIFO_A_SEL:
	case SMI_FIFO_G_SEL:
		*fifo_frmbytes_extend = 7;
		break;
	case SMI_FIFO_G_A_SEL:
		*fifo_frmbytes_extend = 13;
		break;
	case SMI_FIFO_M_SEL:
		*fifo_frmbytes_extend = 9;
		break;
	case SMI_FIFO_M_A_SEL:
	case SMI_FIFO_M_G_SEL:
		/*8(mag) + 6(gyro or acc) +1(head) = 15*/
		*fifo_frmbytes_extend = 15;
		break;
	case SMI_FIFO_M_G_A_SEL:
		/*8(mag) + 6(gyro or acc) + 6 + 1 = 21*/
		*fifo_frmbytes_extend = 21;
		break;
	default:
		*fifo_frmbytes_extend = 0;
		break;

	};

}

static int smi_input_init(struct smi_client_data *client_data)
{
	struct input_dev *dev;
	int err = 0;

	dev = input_allocate_device();
	if (NULL == dev)
		return -ENOMEM;
#if defined(CONFIG_USE_QUALCOMM_HAL)
	dev->name = "smi130-accel";
#else
	dev->name = SENSOR_NAME;
#endif
	dev->id.bustype = BUS_I2C;

	input_set_capability(dev, EV_MSC, MSC_GESTURE);
	input_set_capability(dev, EV_MSC, INPUT_EVENT_SGM);

	input_set_capability(dev, EV_MSC, INPUT_EVENT_FAST_GYRO_CALIB_DONE);
	input_set_capability(dev, EV_MSC, INPUT_EVENT_STEP_DETECTOR);
	input_set_capability(dev, EV_MSC, INPUT_EVENT_FAST_ACC_CALIB_DONE);


	input_set_capability(dev, EV_REL, REL_X);
	input_set_capability(dev, EV_REL, REL_Y);
	input_set_capability(dev, EV_REL, REL_Z);
	#if defined(CONFIG_USE_QUALCOMM_HAL)
	input_set_capability(dev, EV_ABS, ABS_MISC);
	input_set_abs_params(dev, ABS_X,
	SMI130_ACCEL_MIN_VALUE, SMI130_ACCEL_MAX_VALUE,
	0, 0);
	input_set_abs_params(dev, ABS_Y,
	SMI130_ACCEL_MIN_VALUE, SMI130_ACCEL_MAX_VALUE,
	0, 0);
	input_set_abs_params(dev, ABS_Z,
	SMI130_ACCEL_MIN_VALUE, SMI130_ACCEL_MAX_VALUE,
	0, 0);
	#endif
	input_set_drvdata(dev, client_data);

	err = input_register_device(dev);
	if (err < 0) {
		input_free_device(dev);
		dev_notice(client_data->dev, "smi130 input free!\n");
		return err;
	}
	client_data->input = dev;
	dev_notice(client_data->dev,
		"smi130 input register successfully, %s!\n",
		client_data->input->name);
	return err;
}

//#if defined(CONFIG_USE_QUALCOMM_HAL)
static int smi_gyro_input_init(struct smi_client_data *client_data)
{
	struct input_dev *dev;
	int err = 0;

	dev = input_allocate_device();
	if (NULL == dev)
		return -ENOMEM;
	dev->name = "smi130-gyro";
	dev->id.bustype = BUS_I2C;
	input_set_capability(dev, EV_ABS, ABS_MISC);
	input_set_capability(dev, EV_MSC, MSC_GESTURE);
	input_set_capability(dev, EV_MSC, INPUT_EVENT_SGM);
	
	input_set_capability(dev, EV_MSC, INPUT_EVENT_FAST_GYRO_CALIB_DONE);
	input_set_capability(dev, EV_MSC, INPUT_EVENT_STEP_DETECTOR);
	input_set_capability(dev, EV_MSC, INPUT_EVENT_FAST_ACC_CALIB_DONE);
	#if defined(CONFIG_USE_QUALCOMM_HAL)
	input_set_abs_params(dev, ABS_RX,
	SMI130_ACCEL_MIN_VALUE, SMI130_ACCEL_MAX_VALUE,
	0, 0);
	input_set_abs_params(dev, ABS_RY,
	SMI130_ACCEL_MIN_VALUE, SMI130_ACCEL_MAX_VALUE,
	0, 0);
	input_set_abs_params(dev, ABS_RZ,
	SMI130_ACCEL_MIN_VALUE, SMI130_ACCEL_MAX_VALUE,
	0, 0);
	#endif
	input_set_drvdata(dev, client_data);
	err = input_register_device(dev);
	if (err < 0) {
		input_free_device(dev);
		dev_notice(client_data->dev, "smi130 input free!\n");
		return err;
	}
	client_data->gyro_input = dev;
	dev_notice(client_data->dev,
		"smi130 input register successfully, %s!\n",
		client_data->gyro_input->name);
	return err;
}
//#endif
static void smi_input_destroy(struct smi_client_data *client_data)
{
	struct input_dev *dev = client_data->input;

	input_unregister_device(dev);
	input_free_device(dev);
}

static int smi_check_chip_id(struct smi_client_data *client_data)
{
	int8_t err = 0;
	int8_t i = 0;
	uint8_t chip_id = 0;
	uint8_t read_count = 0;
	u8 smi_sensor_cnt = sizeof(sensor_type_map)
				/ sizeof(struct smi130_type_mapping_type);
	/* read and check chip id */
	while (read_count++ < CHECK_CHIP_ID_TIME_MAX) {
		if (client_data->device.bus_read(client_data->device.dev_addr,
				SMI_REG_NAME(USER_CHIP_ID), &chip_id, 1) < 0) {

			dev_err(client_data->dev,
					"Bosch Sensortec Device not found"
						"read chip_id:%d\n", chip_id);
			continue;
		} else {
			for (i = 0; i < smi_sensor_cnt; i++) {
				if (sensor_type_map[i].chip_id == chip_id) {
					client_data->chip_id = chip_id;
					dev_notice(client_data->dev,
					"Bosch Sensortec Device detected, "
			"HW IC name: %s\n", sensor_type_map[i].sensor_name);
					break;
				}
			}
			if (i < smi_sensor_cnt)
				break;
			else {
				if (read_count == CHECK_CHIP_ID_TIME_MAX) {
					dev_err(client_data->dev,
				"Failed!Bosch Sensortec Device not found"
					" mismatch chip_id:%d\n", chip_id);
					err = -ENODEV;
					return err;
				}
			}
			smi_delay(1);
		}
	}
	return err;

}

static int smi_pmu_set_suspend(struct smi_client_data *client_data)
{
	int err = 0;
	if (client_data == NULL)
		return -EINVAL;
	else {
		err += SMI_CALL_API(set_command_register)
				(smi_pmu_cmd_acc_arr[SENSOR_PM_SUSPEND]);
		err += SMI_CALL_API(set_command_register)
				(smi_pmu_cmd_gyro_arr[SENSOR_PM_SUSPEND]);
		err += SMI_CALL_API(set_command_register)
				(smi_pmu_cmd_mag_arr[SENSOR_PM_SUSPEND]);
		client_data->pw.acc_pm = SMI_ACC_PM_SUSPEND;
		client_data->pw.gyro_pm = SMI_GYRO_PM_SUSPEND;
		client_data->pw.mag_pm = SMI_MAG_PM_SUSPEND;
	}

	return err;
}

static int smi_get_err_status(struct smi_client_data *client_data)
{
	int err = 0;

	err = SMI_CALL_API(get_error_status)(&client_data->err_st.fatal_err,
		&client_data->err_st.err_code, &client_data->err_st.i2c_fail,
	&client_data->err_st.drop_cmd, &client_data->err_st.mag_drdy_err);
	return err;
}

static void smi_work_func(struct work_struct *work)
{
	struct smi_client_data *client_data =
		container_of((struct delayed_work *)work,
			struct smi_client_data, work);
	unsigned long delay =
		msecs_to_jiffies(atomic_read(&client_data->delay));
	struct smi130_accel_t data;
	int err;

	err = SMI_CALL_API(read_accel_xyz)(&data);
	if (err < 0)
		return;

	/*report current frame via input event*/
	input_event(client_data->input, EV_REL, REL_X, data.x);
	input_event(client_data->input, EV_REL, REL_Y, data.y);
	input_event(client_data->input, EV_REL, REL_Z, data.z);
	input_sync(client_data->input);

	schedule_delayed_work(&client_data->work, delay);
}

static ssize_t smi130_chip_id_show(struct device *dev,
		struct device_attribute *attr, char *buf)
{
	struct input_dev *input = to_input_dev(dev);
	struct smi_client_data *client_data = input_get_drvdata(input);

	return snprintf(buf, 16, "0x%x\n", client_data->chip_id);
}

static ssize_t smi130_err_st_show(struct device *dev,
		struct device_attribute *attr, char *buf)
{
	struct input_dev *input = to_input_dev(dev);
	struct smi_client_data *client_data = input_get_drvdata(input);
	int err = 0;
	err = smi_get_err_status(client_data);
	if (err)
		return err;
	else {
		return snprintf(buf, 128, "fatal_err:0x%x, err_code:%d,\n\n"
			"i2c_fail_err:%d, drop_cmd_err:%d, mag_drdy_err:%d\n",
			client_data->err_st.fatal_err,
			client_data->err_st.err_code,
			client_data->err_st.i2c_fail,
			client_data->err_st.drop_cmd,
			client_data->err_st.mag_drdy_err);

	}
}

static ssize_t smi130_sensor_time_show(struct device *dev,
		struct device_attribute *attr, char *buf)
{
	int err = 0;
	u32 sensor_time;
	err = SMI_CALL_API(get_sensor_time)(&sensor_time);
	if (err)
		return err;
	else
		return snprintf(buf, 16, "0x%x\n", (unsigned int)sensor_time);
}

static ssize_t smi130_fifo_flush_store(struct device *dev,
		struct device_attribute *attr,
		const char *buf, size_t count)
{
	int err;
	unsigned long enable;
	struct input_dev *input = to_input_dev(dev);
	struct smi_client_data *client_data = input_get_drvdata(input);

	err = kstrtoul(buf, 10, &enable);
	if (err)
		return err;
	if (enable)
		err = SMI_CALL_API(set_command_register)(CMD_CLR_FIFO_DATA);

	if (err)
		dev_err(client_data->dev, "fifo flush failed!\n");

	return count;

}


static ssize_t smi130_fifo_bytecount_show(struct device *dev,
		struct device_attribute *attr, char *buf)
{
	int err;
	unsigned int fifo_bytecount = 0;

	SMI_CALL_API(fifo_length)(&fifo_bytecount);
	err = snprintf(buf, 16, "%u\n", fifo_bytecount);
	return err;
}

static ssize_t smi130_fifo_bytecount_store(struct device *dev,
		struct device_attribute *attr,
		const char *buf, size_t count)
{
	struct input_dev *input = to_input_dev(dev);
	struct smi_client_data *client_data = input_get_drvdata(input);
	int err;
	unsigned long data;
	err = kstrtoul(buf, 10, &data);
	if (err)
		return err;
	client_data->fifo_bytecount = (unsigned int) data;

	return count;
}

int smi130_fifo_data_sel_get(struct smi_client_data *client_data)
{
	int err = 0;
	unsigned char fifo_acc_en, fifo_gyro_en, fifo_mag_en;
	unsigned char fifo_datasel;

	err += SMI_CALL_API(get_fifo_accel_enable)(&fifo_acc_en);
	err += SMI_CALL_API(get_fifo_gyro_enable)(&fifo_gyro_en);
	err += SMI_CALL_API(get_fifo_mag_enable)(&fifo_mag_en);

	if (err)
		return err;

	fifo_datasel = (fifo_acc_en << SMI_ACC_SENSOR) |
			(fifo_gyro_en << SMI_GYRO_SENSOR) |
				(fifo_mag_en << SMI_MAG_SENSOR);

	client_data->fifo_data_sel = fifo_datasel;

	return err;


}

static ssize_t smi130_fifo_data_sel_show(struct device *dev,
		struct device_attribute *attr, char *buf)
{
	int err = 0;
	struct input_dev *input = to_input_dev(dev);
	struct smi_client_data *client_data = input_get_drvdata(input);
	err = smi130_fifo_data_sel_get(client_data);
	if (err) {
		dev_err(client_data->dev, "get fifo_sel failed!\n");
		return -EINVAL;
	}
	return snprintf(buf, 16, "%d\n", client_data->fifo_data_sel);
}

/* write any value to clear all the fifo data. */
static ssize_t smi130_fifo_data_sel_store(struct device *dev,
		struct device_attribute *attr,
		const char *buf, size_t count)
{
	struct input_dev *input = to_input_dev(dev);
	struct smi_client_data *client_data = input_get_drvdata(input);
	int err;
	unsigned long data;
	unsigned char fifo_datasel;

	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;


	err += SMI_CALL_API(set_fifo_accel_enable)
			((fifo_datasel & (1 << SMI_ACC_SENSOR)) ? 1 :  0);
	err += SMI_CALL_API(set_fifo_gyro_enable)
			(fifo_datasel & (1 << SMI_GYRO_SENSOR) ? 1 : 0);
	err += SMI_CALL_API(set_fifo_mag_enable)
			((fifo_datasel & (1 << SMI_MAG_SENSOR)) ? 1 : 0);

	err += SMI_CALL_API(set_command_register)(CMD_CLR_FIFO_DATA);
	if (err)
		return -EIO;
	else {
		dev_notice(client_data->dev, "FIFO A_en:%d, G_en:%d, M_en:%d\n",
			(fifo_datasel & (1 << SMI_ACC_SENSOR)) ? 1 :  0,
			(fifo_datasel & (1 << SMI_GYRO_SENSOR) ? 1 : 0),
			((fifo_datasel & (1 << SMI_MAG_SENSOR)) ? 1 : 0));
		client_data->fifo_data_sel = fifo_datasel;
	}
	return count;
}

static ssize_t smi130_fifo_data_out_frame_show(struct device *dev,
		struct device_attribute *attr, char *buf)
{
	struct input_dev *input = to_input_dev(dev);
	struct smi_client_data *client_data = input_get_drvdata(input);

	int err = 0;
	uint32_t fifo_bytecount = 0;

	err = SMI_CALL_API(fifo_length)(&fifo_bytecount);
	if (err < 0) {
		dev_err(client_data->dev, "read fifo_length err");
		return -EINVAL;
	}
	if (fifo_bytecount == 0)
		return 0;
	err = smi_burst_read_wrapper(client_data->device.dev_addr,
		SMI130_USER_FIFO_DATA__REG, buf,
		fifo_bytecount);
	if (err) {
		dev_err(client_data->dev, "read fifo err");
		SMI_CALL_API(set_command_register)(CMD_CLR_FIFO_DATA);
		return -EINVAL;
	}
	return fifo_bytecount;

}

static ssize_t smi130_fifo_watermark_show(struct device *dev,
		struct device_attribute *attr, char *buf)
{
	int err;
	unsigned char data = 0xff;

	err = SMI_CALL_API(get_fifo_wm)(&data);

	if (err)
		return err;
	return snprintf(buf, 16, "%d\n", data);
}

static ssize_t smi130_fifo_watermark_store(struct device *dev,
		struct device_attribute *attr,
		const char *buf, size_t count)
{
	int err;
	unsigned long data;
	unsigned char fifo_watermark;

	err = kstrtoul(buf, 10, &data);
	if (err)
		return err;

	fifo_watermark = (unsigned char)data;
	err = SMI_CALL_API(set_fifo_wm)(fifo_watermark);
	if (err)
		return -EIO;

	return count;
}


static ssize_t smi130_fifo_header_en_show(struct device *dev,
		struct device_attribute *attr, char *buf)
{
	int err;
	unsigned char data = 0xff;

	err = SMI_CALL_API(get_fifo_header_enable)(&data);

	if (err)
		return err;
	return snprintf(buf, 16, "%d\n", data);
}

static ssize_t smi130_fifo_header_en_store(struct device *dev,
		struct device_attribute *attr,
		const char *buf, size_t count)
{
	struct input_dev *input = to_input_dev(dev);
	struct smi_client_data *client_data = input_get_drvdata(input);
	int err;
	unsigned long data;
	unsigned char fifo_header_en;

	err = kstrtoul(buf, 10, &data);
	if (err)
		return err;
	if (data > 1)
		return -ENOENT;

	fifo_header_en = (unsigned char)data;
	err = SMI_CALL_API(set_fifo_header_enable)(fifo_header_en);
	if (err)
		return -EIO;

	client_data->fifo_head_en = fifo_header_en;

	return count;
}

static ssize_t smi130_fifo_time_en_show(struct device *dev,
		struct device_attribute *attr, char *buf)
{
	int err;
	unsigned char data = 0;

	err = SMI_CALL_API(get_fifo_time_enable)(&data);

	if (!err)
		err = snprintf(buf, 16, "%d\n", data);

	return err;
}

static ssize_t smi130_fifo_time_en_store(struct device *dev,
		struct device_attribute *attr,
		const char *buf, size_t count)
{
	int err;
	unsigned long data;
	unsigned char fifo_ts_en;

	err = kstrtoul(buf, 10, &data);
	if (err)
		return err;

	fifo_ts_en = (unsigned char)data;

	err = SMI_CALL_API(set_fifo_time_enable)(fifo_ts_en);
	if (err)
		return -EIO;

	return count;
}

static ssize_t smi130_fifo_int_tag_en_show(struct device *dev,
		struct device_attribute *attr, char *buf)
{
	int err = 0;
	unsigned char fifo_tag_int1 = 0;
	unsigned char fifo_tag_int2 = 0;
	unsigned char fifo_tag_int;

	err += SMI_CALL_API(get_fifo_tag_intr1_enable)(&fifo_tag_int1);
	err += SMI_CALL_API(get_fifo_tag_intr2_enable)(&fifo_tag_int2);

	fifo_tag_int = (fifo_tag_int1 << SMI130_INT0) |
			(fifo_tag_int2 << SMI130_INT1);

	if (!err)
		err = snprintf(buf, 16, "%d\n", fifo_tag_int);

	return err;
}

static ssize_t smi130_fifo_int_tag_en_store(struct device *dev,
		struct device_attribute *attr,
		const char *buf, size_t count)
{
	struct input_dev *input = to_input_dev(dev);
	struct smi_client_data *client_data = input_get_drvdata(input);
	int err;
	unsigned long data;
	unsigned char fifo_tag_int_en;

	err = kstrtoul(buf, 10, &data);
	if (err)
		return err;
	if (data > 3)
		return -EINVAL;

	fifo_tag_int_en = (unsigned char)data;

	err += SMI_CALL_API(set_fifo_tag_intr1_enable)
			((fifo_tag_int_en & (1 << SMI130_INT0)) ? 1 :  0);
	err += SMI_CALL_API(set_fifo_tag_intr2_enable)
			((fifo_tag_int_en & (1 << SMI130_INT1)) ? 1 :  0);

	if (err) {
		dev_err(client_data->dev, "fifo int tag en err:%d\n", err);
		return -EIO;
	}
	client_data->fifo_int_tag_en = fifo_tag_int_en;

	return count;
}

static int smi130_set_acc_op_mode(struct smi_client_data *client_data,
							unsigned long op_mode)
{
	int err = 0;
	unsigned char stc_enable;
	unsigned char std_enable;
	mutex_lock(&client_data->mutex_op_mode);

	if (op_mode < SMI_ACC_PM_MAX) {
		switch (op_mode) {
		case SMI_ACC_PM_NORMAL:
			err = SMI_CALL_API(set_command_register)
			(smi_pmu_cmd_acc_arr[SMI_ACC_PM_NORMAL]);
			client_data->pw.acc_pm = SMI_ACC_PM_NORMAL;
			smi_delay(10);
			break;
		case SMI_ACC_PM_LP1:
			err = SMI_CALL_API(set_command_register)
			(smi_pmu_cmd_acc_arr[SMI_ACC_PM_LP1]);
			client_data->pw.acc_pm = SMI_ACC_PM_LP1;
			smi_delay(3);
			break;
		case SMI_ACC_PM_SUSPEND:
			SMI_CALL_API(get_step_counter_enable)(&stc_enable);
			SMI_CALL_API(get_step_detector_enable)(&std_enable);
			if ((stc_enable == 0) && (std_enable == 0) &&
				(client_data->sig_flag == 0)) {
				err = SMI_CALL_API(set_command_register)
				(smi_pmu_cmd_acc_arr[SMI_ACC_PM_SUSPEND]);
				client_data->pw.acc_pm = SMI_ACC_PM_SUSPEND;
				smi_delay(10);
			}
			break;
		case SMI_ACC_PM_LP2:
			err = SMI_CALL_API(set_command_register)
			(smi_pmu_cmd_acc_arr[SMI_ACC_PM_LP2]);
			client_data->pw.acc_pm = SMI_ACC_PM_LP2;
			smi_delay(3);
			break;
		default:
			mutex_unlock(&client_data->mutex_op_mode);
			return -EINVAL;
		}
	} else {
		mutex_unlock(&client_data->mutex_op_mode);
		return -EINVAL;
	}

	mutex_unlock(&client_data->mutex_op_mode);

	return err;


}

static ssize_t smi130_temperature_show(struct device *dev,
		struct device_attribute *attr, char *buf)
{
	int err;
	s16 temp = 0xff;

	err = SMI_CALL_API(get_temp)(&temp);

	if (!err)
		err = snprintf(buf, 16, "0x%x\n", temp);

	return err;
}

static ssize_t smi130_place_show(struct device *dev,
		struct device_attribute *attr, char *buf)
{
	struct input_dev *input = to_input_dev(dev);
	struct smi_client_data *client_data = input_get_drvdata(input);
	int place = BOSCH_SENSOR_PLACE_UNKNOWN;

	if (NULL != client_data->bosch_pd)
		place = client_data->bosch_pd->place;

	return snprintf(buf, 16, "%d\n", place);
}

static ssize_t smi130_delay_show(struct device *dev,
		struct device_attribute *attr, char *buf)
{
	struct input_dev *input = to_input_dev(dev);
	struct smi_client_data *client_data = input_get_drvdata(input);

	return snprintf(buf, 16, "%d\n", atomic_read(&client_data->delay));

}

static ssize_t smi130_delay_store(struct device *dev,
		struct device_attribute *attr,
		const char *buf, size_t count)
{
	struct input_dev *input = to_input_dev(dev);
	struct smi_client_data *client_data = input_get_drvdata(input);
	int err;
	unsigned long data;

	err = kstrtoul(buf, 10, &data);
	if (err)
		return err;

	if (data == 0) {
		err = -EINVAL;
		return err;
	}

	if (data < SMI_DELAY_MIN)
		data = SMI_DELAY_MIN;

	atomic_set(&client_data->delay, (unsigned int)data);

	return count;
}

static ssize_t smi130_enable_show(struct device *dev,
		struct device_attribute *attr, char *buf)
{
	struct input_dev *input = to_input_dev(dev);
	struct smi_client_data *client_data = input_get_drvdata(input);

	return snprintf(buf, 16, "%d\n", atomic_read(&client_data->wkqueue_en));

}

static ssize_t smi130_enable_store(struct device *dev,
		struct device_attribute *attr,
		const char *buf, size_t count)
{
	struct input_dev *input = to_input_dev(dev);
	struct smi_client_data *client_data = input_get_drvdata(input);
	int err;
	unsigned long enable;
	int pre_enable = atomic_read(&client_data->wkqueue_en);

	err = kstrtoul(buf, 10, &enable);
	if (err)
		return err;

	enable = enable ? 1 : 0;
	mutex_lock(&client_data->mutex_enable);
	if (enable) {
		if (pre_enable == 0) {
			smi130_set_acc_op_mode(client_data,
							SMI_ACC_PM_NORMAL);
			schedule_delayed_work(&client_data->work,
			msecs_to_jiffies(atomic_read(&client_data->delay)));
			atomic_set(&client_data->wkqueue_en, 1);
		}

	} else {
		if (pre_enable == 1) {
			smi130_set_acc_op_mode(client_data,
							SMI_ACC_PM_SUSPEND);

			cancel_delayed_work_sync(&client_data->work);
			atomic_set(&client_data->wkqueue_en, 0);
		}
	}

	mutex_unlock(&client_data->mutex_enable);

	return count;
}

#if defined(SMI130_ENABLE_INT1) || defined(SMI130_ENABLE_INT2)
/* accel sensor part */
static ssize_t smi130_anymot_duration_show(struct device *dev,
		struct device_attribute *attr, char *buf)
{
	int err;
	unsigned char data;

	err = SMI_CALL_API(get_intr_any_motion_durn)(&data);

	if (err < 0)
		return err;
	return snprintf(buf, 16, "%d\n", data);
}

static ssize_t smi130_anymot_duration_store(struct device *dev,
		struct device_attribute *attr, const char *buf, size_t count)
{
	unsigned long data;
	int err;

	err = kstrtoul(buf, 10, &data);
	if (err)
		return err;

	err = SMI_CALL_API(set_intr_any_motion_durn)((unsigned char)data);
	if (err < 0)
		return -EIO;

	return count;
}

static ssize_t smi130_anymot_threshold_show(struct device *dev,
		struct device_attribute *attr, char *buf)
{
	unsigned char data;
	int err;

	err = SMI_CALL_API(get_intr_any_motion_thres)(&data);

	if (err < 0)
		return err;
	return snprintf(buf, 16, "%d\n", data);
}

static ssize_t smi130_anymot_threshold_store(struct device *dev,
		struct device_attribute *attr,
		const char *buf, size_t count)
{
	unsigned long data;
	int err;

	err = kstrtoul(buf, 10, &data);
	if (err)
		return err;

	err = SMI_CALL_API(set_intr_any_motion_thres)((unsigned char)data);

	if (err < 0)
		return -EIO;
	return count;
}

static ssize_t smi130_step_detector_status_show(struct device *dev,
		struct device_attribute *attr, char *buf)
{
	u8 data = 0;
	u8 step_det;
	int err;
	struct input_dev *input = to_input_dev(dev);
	struct smi_client_data *client_data = input_get_drvdata(input);
	err = SMI_CALL_API(get_step_detector_enable)(&step_det);
	/*smi130_get_status0_step_int*/
	if (err < 0)
		return err;
/*client_data->std will be updated in smi_stepdetector_interrupt_handle */
	if ((step_det == 1) && (client_data->std == 1)) {
		data = 1;
		client_data->std = 0;
		}
	else {
		data = 0;
		}
	return snprintf(buf, 16, "%d\n", data);
}

static ssize_t smi130_step_detector_enable_show(struct device *dev,
		struct device_attribute *attr, char *buf)
{
	unsigned char data;
	int err;

	err = SMI_CALL_API(get_step_detector_enable)(&data);

	if (err < 0)
		return err;
	return snprintf(buf, 16, "%d\n", data);
}

static ssize_t smi130_step_detector_enable_store(struct device *dev,
		struct device_attribute *attr,
		const char *buf, size_t count)
{
	unsigned long data;
	int err;
	struct input_dev *input = to_input_dev(dev);
	struct smi_client_data *client_data = input_get_drvdata(input);

	err = kstrtoul(buf, 10, &data);
	if (err)
		return err;

	err = SMI_CALL_API(set_step_detector_enable)((unsigned char)data);
	if (err < 0)
		return -EIO;
	if (data == 0)
		client_data->pedo_data.wkar_step_detector_status = 0;
	return count;
}

static ssize_t smi130_signification_motion_enable_store(
	struct device *dev, struct device_attribute *attr,
	const char *buf, size_t count)
{
	unsigned long data;
	int err;
	struct input_dev *input = to_input_dev(dev);
	struct smi_client_data *client_data = input_get_drvdata(input);

	err = kstrtoul(buf, 10, &data);
	if (err)
		return err;
	/*0x62 (bit 1) INT_MOTION_3 int_sig_mot_sel*/
	err = SMI_CALL_API(set_intr_significant_motion_select)(
		(unsigned char)data);
	if (err < 0)
		return -EIO;
	if (data == 1) {
		err = SMI_CALL_API(set_intr_enable_0)
					(SMI130_ANY_MOTION_X_ENABLE, 1);
		err += SMI_CALL_API(set_intr_enable_0)
					(SMI130_ANY_MOTION_Y_ENABLE, 1);
		err += SMI_CALL_API(set_intr_enable_0)
					(SMI130_ANY_MOTION_Z_ENABLE, 1);
		if (err < 0)
			return -EIO;
		enable_irq_wake(client_data->IRQ);
		client_data->sig_flag = 1;
	} else {
		err = SMI_CALL_API(set_intr_enable_0)
					(SMI130_ANY_MOTION_X_ENABLE, 0);
		err += SMI_CALL_API(set_intr_enable_0)
					(SMI130_ANY_MOTION_Y_ENABLE, 0);
		err += SMI_CALL_API(set_intr_enable_0)
					(SMI130_ANY_MOTION_Z_ENABLE, 0);
		if (err < 0)
			return -EIO;
		disable_irq_wake(client_data->IRQ);
		client_data->sig_flag = 0;
	}
	return count;
}

static ssize_t smi130_signification_motion_enable_show(
	struct device *dev, struct device_attribute *attr, char *buf)
{
	unsigned char data;
	int err;
	/*0x62 (bit 1) INT_MOTION_3 int_sig_mot_sel*/
	err = SMI_CALL_API(get_intr_significant_motion_select)(&data);

	if (err < 0)
		return err;
	return snprintf(buf, 16, "%d\n", data);
}

static int sigmotion_init_interrupts(u8 sig_map_int_pin)
{
	int ret = 0;
/*0x60  */
	ret += smi130_set_intr_any_motion_thres(0x1e);
/* 0x62(bit 3~2)	0=1.5s */
	ret += smi130_set_intr_significant_motion_skip(0);
/*0x62(bit 5~4)	1=0.5s*/
	ret += smi130_set_intr_significant_motion_proof(1);
/*0x50 (bit 0, 1, 2)  INT_EN_0 anymo x y z*/
	ret += smi130_map_significant_motion_intr(sig_map_int_pin);
/*0x62 (bit 1) INT_MOTION_3	int_sig_mot_sel
close the signification_motion*/
	ret += smi130_set_intr_significant_motion_select(0);
/*close the anymotion interrupt*/
	ret += SMI_CALL_API(set_intr_enable_0)
					(SMI130_ANY_MOTION_X_ENABLE, 0);
	ret += SMI_CALL_API(set_intr_enable_0)
					(SMI130_ANY_MOTION_Y_ENABLE, 0);
	ret += SMI_CALL_API(set_intr_enable_0)
					(SMI130_ANY_MOTION_Z_ENABLE, 0);
	if (ret)
		printk(KERN_ERR "smi130 sig motion failed setting,%d!\n", ret);
	return ret;

}
#endif

static ssize_t smi130_acc_range_show(struct device *dev,
		struct device_attribute *attr, char *buf)
{
	int err;
	unsigned char range;
	struct input_dev *input = to_input_dev(dev);
	struct smi_client_data *client_data = input_get_drvdata(input);

	err = SMI_CALL_API(get_accel_range)(&range);
	if (err)
		return err;

	client_data->range.acc_range = range;
	return snprintf(buf, 16, "%d\n", range);
}

static ssize_t smi130_acc_range_store(struct device *dev,
		struct device_attribute *attr,
		const char *buf, size_t count)
{
	int err;
	unsigned long range;
	struct input_dev *input = to_input_dev(dev);
	struct smi_client_data *client_data = input_get_drvdata(input);


	err = kstrtoul(buf, 10, &range);
	if (err)
		return err;

	err = SMI_CALL_API(set_accel_range)(range);
	if (err)
		return -EIO;

	client_data->range.acc_range = range;
	return count;
}

static ssize_t smi130_acc_odr_show(struct device *dev,
		struct device_attribute *attr, char *buf)
{
	int err;
	unsigned char acc_odr;
	struct input_dev *input = to_input_dev(dev);
	struct smi_client_data *client_data = input_get_drvdata(input);

	err = SMI_CALL_API(get_accel_output_data_rate)(&acc_odr);
	if (err)
		return err;

	client_data->odr.acc_odr = acc_odr;
	return snprintf(buf, 16, "%d\n", acc_odr);
}

static ssize_t smi130_acc_odr_store(struct device *dev,
		struct device_attribute *attr,
		const char *buf, size_t count)
{
	int err;
	unsigned long acc_odr;
	struct input_dev *input = to_input_dev(dev);
	struct smi_client_data *client_data = input_get_drvdata(input);

	err = kstrtoul(buf, 10, &acc_odr);
	if (err)
		return err;

	if (acc_odr < 1 || acc_odr > 12)
		return -EIO;

	if (acc_odr < 5)
		err = SMI_CALL_API(set_accel_under_sampling_parameter)(1);
	else
		err = SMI_CALL_API(set_accel_under_sampling_parameter)(0);

	if (err)
		return err;

	err = SMI_CALL_API(set_accel_output_data_rate)(acc_odr);
	if (err)
		return -EIO;
	client_data->odr.acc_odr = acc_odr;
	return count;
}

static ssize_t smi130_acc_op_mode_show(struct device *dev,
		struct device_attribute *attr, char *buf)
{
	struct input_dev *input = to_input_dev(dev);
	struct smi_client_data *client_data = input_get_drvdata(input);
	int err = 0;
	u8 accel_pmu_status = 0;
	err = SMI_CALL_API(get_accel_power_mode_stat)(
		&accel_pmu_status);

	if (err)
		return err;
	else
	return snprintf(buf, 32, "reg:%d, val:%d\n", accel_pmu_status,
			client_data->pw.acc_pm);
}

static ssize_t smi130_acc_op_mode_store(struct device *dev,
		struct device_attribute *attr,
		const char *buf, size_t count)
{
	struct input_dev *input = to_input_dev(dev);
	struct smi_client_data *client_data = input_get_drvdata(input);
	int err;
	unsigned long op_mode;
	err = kstrtoul(buf, 10, &op_mode);
	if (err)
		return err;

	err = smi130_set_acc_op_mode(client_data, op_mode);
	if (err)
		return err;
	else
		return count;

}

static ssize_t smi130_acc_value_show(struct device *dev,
		struct device_attribute *attr, char *buf)
{
	struct smi130_accel_t data;

	int err;

	err = SMI_CALL_API(read_accel_xyz)(&data);
	if (err < 0)
		return err;

	return snprintf(buf, 48, "%hd %hd %hd\n",
			data.x, data.y, data.z);
}

static ssize_t smi130_acc_fast_calibration_x_show(struct device *dev,
		struct device_attribute *attr, char *buf)
{
	unsigned char data;
	int err;

	err = SMI_CALL_API(get_foc_accel_x)(&data);

	if (err < 0)
		return err;
	return snprintf(buf, 16, "%d\n", data);
}

static ssize_t smi130_acc_fast_calibration_x_store(struct device *dev,
		struct device_attribute *attr,
		const char *buf, size_t count)
{
	unsigned long data;
	int err;
	s8 accel_offset_x = 0;
	struct input_dev *input = to_input_dev(dev);
	struct smi_client_data *client_data = input_get_drvdata(input);

	err = kstrtoul(buf, 10, &data);
	if (err)
		return err;
	/* 0: disable, 1: +1g, 2: -1g, 3: 0g */
	if (data > 3)
		return -EINVAL;

	err = SMI_CALL_API(set_accel_foc_trigger)(X_AXIS,
					data, &accel_offset_x);
	if (err)
		return -EIO;
	else
		client_data->calib_status |=
			SMI_FAST_CALI_TRUE << SMI_ACC_X_FAST_CALI_RDY;
	return count;
}

static ssize_t smi130_acc_fast_calibration_y_show(struct device *dev,
		struct device_attribute *attr, char *buf)
{
	unsigned char data;
	int err;

	err = SMI_CALL_API(get_foc_accel_y)(&data);

	if (err < 0)
		return err;
	return snprintf(buf, 16, "%d\n", data);
}

static ssize_t smi130_acc_fast_calibration_y_store(struct device *dev,
		struct device_attribute *attr,
		const char *buf, size_t count)
{
	unsigned long data;
	int err;
	s8 accel_offset_y = 0;
	struct input_dev *input = to_input_dev(dev);
	struct smi_client_data *client_data = input_get_drvdata(input);

	err = kstrtoul(buf, 10, &data);
	if (err)
		return err;
	/* 0: disable, 1: +1g, 2: -1g, 3: 0g */
	if (data > 3)
		return -EINVAL;

	err = SMI_CALL_API(set_accel_foc_trigger)(Y_AXIS,
				data, &accel_offset_y);
	if (err)
		return -EIO;
	else
		client_data->calib_status |=
			SMI_FAST_CALI_TRUE << SMI_ACC_Y_FAST_CALI_RDY;
	return count;
}

static ssize_t smi130_acc_fast_calibration_z_show(struct device *dev,
		struct device_attribute *attr, char *buf)
{
	unsigned char data;
	int err;

	err = SMI_CALL_API(get_foc_accel_z)(&data);

	if (err < 0)
		return err;
	return snprintf(buf, 16, "%d\n", data);
}

static ssize_t smi130_acc_fast_calibration_z_store(struct device *dev,
		struct device_attribute *attr,
		const char *buf, size_t count)
{
	unsigned long data;
	int err;
	s8 accel_offset_z = 0;
	struct input_dev *input = to_input_dev(dev);
	struct smi_client_data *client_data = input_get_drvdata(input);
	unsigned char data1[3] = {0};
	err = kstrtoul(buf, 10, &data);
	if (err)
		return err;
	/* 0: disable, 1: +1g, 2: -1g, 3: 0g */
	if (data > 3)
		return -EINVAL;

	err = SMI_CALL_API(set_accel_foc_trigger)(Z_AXIS,
			data, &accel_offset_z);
	if (err)
		return -EIO;
	else
		client_data->calib_status |=
			SMI_FAST_CALI_TRUE << SMI_ACC_Z_FAST_CALI_RDY;

	if (client_data->calib_status == SMI_FAST_CALI_ALL_RDY) {
		err = SMI_CALL_API(get_accel_offset_compensation_xaxis)(
			&data1[0]);
		err += SMI_CALL_API(get_accel_offset_compensation_yaxis)(
			&data1[1]);
		err += SMI_CALL_API(get_accel_offset_compensation_zaxis)(
			&data1[2]);
		dev_info(client_data->dev, "accx %d, accy %d, accz %d\n",
			data1[0], data1[1], data1[2]);
		if (err)
			return -EIO;
		input_event(client_data->input, EV_MSC,
		INPUT_EVENT_FAST_ACC_CALIB_DONE,
		(data1[0] | (data1[1] << 8) | (data1[2] << 16)));
		input_sync(client_data->input);
		client_data->calib_status = 0;
	}

	return count;
}

static ssize_t smi130_acc_offset_x_show(struct device *dev,
		struct device_attribute *attr, char *buf)
{
	unsigned char data;
	int err;

	err = SMI_CALL_API(get_accel_offset_compensation_xaxis)(&data);

	if (err < 0)
		return err;
	return snprintf(buf, 16, "%d\n", data);
}


static ssize_t smi130_acc_offset_x_store(struct device *dev,
		struct device_attribute *attr,
		const char *buf, size_t count)
{
	unsigned long data;
	int err;

	err = kstrtoul(buf, 10, &data);
	if (err)
		return err;

	err = SMI_CALL_API(set_accel_offset_compensation_xaxis)
						((unsigned char)data);

	if (err < 0)
		return -EIO;
	return count;
}

static ssize_t smi130_acc_offset_y_show(struct device *dev,
		struct device_attribute *attr, char *buf)
{
	unsigned char data;
	int err;

	err = SMI_CALL_API(get_accel_offset_compensation_yaxis)(&data);

	if (err < 0)
		return err;
	return snprintf(buf, 16, "%d\n", data);
}

static ssize_t smi130_acc_offset_y_store(struct device *dev,
		struct device_attribute *attr,
		const char *buf, size_t count)
{
	unsigned long data;
	int err;

	err = kstrtoul(buf, 10, &data);
	if (err)
		return err;

	err = SMI_CALL_API(set_accel_offset_compensation_yaxis)
						((unsigned char)data);

	if (err < 0)
		return -EIO;
	return count;
}

static ssize_t smi130_acc_offset_z_show(struct device *dev,
		struct device_attribute *attr, char *buf)
{
	unsigned char data;
	int err;

	err = SMI_CALL_API(get_accel_offset_compensation_zaxis)(&data);

	if (err < 0)
		return err;
	return snprintf(buf, 16, "%d\n", data);
}

static ssize_t smi130_acc_offset_z_store(struct device *dev,
		struct device_attribute *attr,
		const char *buf, size_t count)
{
	unsigned long data;
	int err;

	err = kstrtoul(buf, 10, &data);
	if (err)
		return err;

	err = SMI_CALL_API(set_accel_offset_compensation_zaxis)
						((unsigned char)data);

	if (err < 0)
		return -EIO;
	return count;
}

static ssize_t smi130_test_show(struct device *dev,
		struct device_attribute *attr, char *buf)
{
	struct input_dev *input = to_input_dev(dev);
	struct smi_client_data *client_data = input_get_drvdata(input);
	u8 raw_data[15] = {0};
	unsigned int sensor_time = 0;

	int err;
	memset(raw_data, 0, sizeof(raw_data));

	err = client_data->device.bus_read(client_data->device.dev_addr,
			SMI130_USER_DATA_8_GYRO_X_LSB__REG, raw_data, 15);
	if (err)
		return err;

	udelay(10);
	sensor_time = (u32)(raw_data[14] << 16 | raw_data[13] << 8
						| raw_data[12]);

	return snprintf(buf, 128, "%d %d %d %d %d %d %u",
					(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]),
				sensor_time);

}

static ssize_t smi130_step_counter_enable_show(struct device *dev,
		struct device_attribute *attr, char *buf)
{
	unsigned char data;
	int err;
	struct input_dev *input = to_input_dev(dev);
	struct smi_client_data *client_data = input_get_drvdata(input);

	err = SMI_CALL_API(get_step_counter_enable)(&data);

	client_data->stc_enable = data;

	if (err < 0)
		return err;
	return snprintf(buf, 16, "%d\n", data);
}

static ssize_t smi130_step_counter_enable_store(struct device *dev,
		struct device_attribute *attr,
		const char *buf, size_t count)
{
	unsigned long data;
	int err;
	struct input_dev *input = to_input_dev(dev);
	struct smi_client_data *client_data = input_get_drvdata(input);

	err = kstrtoul(buf, 10, &data);
	if (err)
		return err;

	err = SMI_CALL_API(set_step_counter_enable)((unsigned char)data);

	client_data->stc_enable = data;

	if (err < 0)
		return -EIO;
	return count;
}


static ssize_t smi130_step_counter_mode_store(struct device *dev,
		struct device_attribute *attr,
		const char *buf, size_t count)
{
	unsigned long data;
	int err;

	err = kstrtoul(buf, 10, &data);
	if (err)
		return err;

	err = SMI_CALL_API(set_step_mode)((unsigned char)data);

	if (err < 0)
		return -EIO;
	return count;
}

static ssize_t smi130_step_counter_clc_store(struct device *dev,
		struct device_attribute *attr,
		const char *buf, size_t count)
{
	unsigned long data;
	int err;

	err = kstrtoul(buf, 10, &data);
	if (err)
		return err;

	err = smi130_clear_step_counter();

	if (err < 0)
		return -EIO;
	return count;
}

static ssize_t smi130_step_counter_value_show(struct device *dev,
		struct device_attribute *attr, char *buf)
{
	u16 data;
	int err;
	static u16 last_stc_value;

	struct input_dev *input = to_input_dev(dev);
	struct smi_client_data *client_data = input_get_drvdata(input);

	err = SMI_CALL_API(read_step_count)(&data);

	if (err < 0)
		return err;
	if (data >= last_stc_value) {
		client_data->pedo_data.last_step_counter_value += (
			data - last_stc_value);
		last_stc_value = data;
	} else
		last_stc_value = data;
	return snprintf(buf, 16, "%d\n",
		client_data->pedo_data.last_step_counter_value);
}

static ssize_t smi130_smi_value_show(struct device *dev,
		struct device_attribute *attr, char *buf)
{
	struct input_dev *input = to_input_dev(dev);
	struct smi_client_data *client_data = input_get_drvdata(input);
	u8 raw_data[12] = {0};

	int err;
	memset(raw_data, 0, sizeof(raw_data));

	err = client_data->device.bus_read(client_data->device.dev_addr,
			SMI130_USER_DATA_8_GYRO_X_LSB__REG, raw_data, 12);
	if (err)
		return err;
	/*output:gyro x y z acc x y z*/
	return snprintf(buf, 96, "%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 ssize_t smi130_selftest_show(struct device *dev,
		struct device_attribute *attr, char *buf)
{
	struct input_dev *input = to_input_dev(dev);
	struct smi_client_data *client_data = input_get_drvdata(input);

	return snprintf(buf, 16, "0x%x\n",
				atomic_read(&client_data->selftest_result));
}

static int smi_restore_hw_cfg(struct smi_client_data *client);

/*!
 * @brief store selftest result which make up of acc and gyro
 * format: 0b 0000 xxxx  x:1 failed, 0 success
 * bit3:     gyro_self
 * bit2..0: acc_self z y x
 */
static ssize_t smi130_selftest_store(struct device *dev,
		struct device_attribute *attr,
		const char *buf, size_t count)
{
	struct input_dev *input = to_input_dev(dev);
	struct smi_client_data *client_data = input_get_drvdata(input);
	int err = 0;
	int i = 0;

	u8 acc_selftest = 0;
	u8 gyro_selftest = 0;
	u8 smi_selftest = 0;
	s16 axis_p_value, axis_n_value;
	u16 diff_axis[3] = {0xff, 0xff, 0xff};
	u8 acc_odr, range, acc_selftest_amp, acc_selftest_sign;

	dev_notice(client_data->dev, "Selftest for SMI16x starting.\n");

	client_data->selftest = 1;

	/*soft reset*/
	err = SMI_CALL_API(set_command_register)(CMD_RESET_USER_REG);
	msleep(70);
	err += SMI_CALL_API(set_command_register)
				(smi_pmu_cmd_acc_arr[SMI_ACC_PM_NORMAL]);
	err += SMI_CALL_API(set_command_register)
				(smi_pmu_cmd_gyro_arr[SMI_GYRO_PM_NORMAL]);
	err += SMI_CALL_API(set_accel_under_sampling_parameter)(0);
	err += SMI_CALL_API(set_accel_output_data_rate)(
	SMI130_ACCEL_OUTPUT_DATA_RATE_1600HZ);

	/* set to 8G range*/
	err += SMI_CALL_API(set_accel_range)(SMI130_ACCEL_RANGE_8G);
	/* set to self amp high */
	err += SMI_CALL_API(set_accel_selftest_amp)(SMI_SELFTEST_AMP_HIGH);


	err += SMI_CALL_API(get_accel_output_data_rate)(&acc_odr);
	err += SMI_CALL_API(get_accel_range)(&range);
	err += SMI_CALL_API(get_accel_selftest_amp)(&acc_selftest_amp);
	err += SMI_CALL_API(read_accel_x)(&axis_n_value);

	dev_info(client_data->dev,
			"acc_odr:%d, acc_range:%d, acc_selftest_amp:%d, acc_x:%d\n",
				acc_odr, range, acc_selftest_amp, axis_n_value);

	for (i = X_AXIS; i < AXIS_MAX; i++) {
		axis_n_value = 0;
		axis_p_value = 0;
		/* set every selftest axis */
		/*set_acc_selftest_axis(param),param x:1, y:2, z:3
		* but X_AXIS:0, Y_AXIS:1, Z_AXIS:2
		* so we need to +1*/
		err += SMI_CALL_API(set_accel_selftest_axis)(i + 1);
		msleep(50);
		switch (i) {
		case X_AXIS:
			/* set negative sign */
			err += SMI_CALL_API(set_accel_selftest_sign)(0);
			err += SMI_CALL_API(get_accel_selftest_sign)(
				&acc_selftest_sign);

			msleep(60);
			err += SMI_CALL_API(read_accel_x)(&axis_n_value);
			dev_info(client_data->dev,
			"acc_x_selftest_sign:%d, axis_n_value:%d\n",
			acc_selftest_sign, axis_n_value);

			/* set postive sign */
			err += SMI_CALL_API(set_accel_selftest_sign)(1);
			err += SMI_CALL_API(get_accel_selftest_sign)(
				&acc_selftest_sign);

			msleep(60);
			err += SMI_CALL_API(read_accel_x)(&axis_p_value);
			dev_info(client_data->dev,
			"acc_x_selftest_sign:%d, axis_p_value:%d\n",
			acc_selftest_sign, axis_p_value);
			diff_axis[i] = abs(axis_p_value - axis_n_value);
			break;

		case Y_AXIS:
			/* set negative sign */
			err += SMI_CALL_API(set_accel_selftest_sign)(0);
			msleep(60);
			err += SMI_CALL_API(read_accel_y)(&axis_n_value);
			/* set postive sign */
			err += SMI_CALL_API(set_accel_selftest_sign)(1);
			msleep(60);
			err += SMI_CALL_API(read_accel_y)(&axis_p_value);
			diff_axis[i] = abs(axis_p_value - axis_n_value);
			break;

		case Z_AXIS:
			/* set negative sign */
			err += SMI_CALL_API(set_accel_selftest_sign)(0);
			msleep(60);
			err += SMI_CALL_API(read_accel_z)(&axis_n_value);
			/* set postive sign */
			err += SMI_CALL_API(set_accel_selftest_sign)(1);
			msleep(60);
			err += SMI_CALL_API(read_accel_z)(&axis_p_value);
			/* also start gyro self test */
			err += SMI_CALL_API(set_gyro_selftest_start)(1);
			msleep(60);
			err += SMI_CALL_API(get_gyro_selftest)(&gyro_selftest);

			diff_axis[i] = abs(axis_p_value - axis_n_value);
			break;
		default:
			err += -EINVAL;
			break;
		}
		if (err) {
			dev_err(client_data->dev,
				"Failed selftest axis:%s, p_val=%d, n_val=%d\n",
				smi_axis_name[i], axis_p_value, axis_n_value);
			client_data->selftest = 0;
			return -EINVAL;
		}

		/*400mg for acc z axis*/
		if (Z_AXIS == i) {
			if (diff_axis[i] < 1639) {
				acc_selftest |= 1 << i;
				dev_err(client_data->dev,
					"Over selftest minimum for "
					"axis:%s,diff=%d,p_val=%d, n_val=%d\n",
					smi_axis_name[i], diff_axis[i],
						axis_p_value, axis_n_value);
			}
		} else {
			/*800mg for x or y axis*/
			if (diff_axis[i] < 3277) {
				acc_selftest |= 1 << i;

				if (smi_get_err_status(client_data) < 0)
					return err;
				dev_err(client_data->dev,
					"Over selftest minimum for "
					"axis:%s,diff=%d, p_val=%d, n_val=%d\n",
					smi_axis_name[i], diff_axis[i],
						axis_p_value, axis_n_value);
				dev_err(client_data->dev, "err_st:0x%x\n",
						client_data->err_st.err_st_all);

			}
		}

	}
	/* gyro_selftest==1,gyro selftest successfully,
	* but smi_result bit4 0 is successful, 1 is failed*/
	smi_selftest = (acc_selftest & 0x0f) | ((!gyro_selftest) << AXIS_MAX);
	atomic_set(&client_data->selftest_result, smi_selftest);
	/*soft reset*/
	err = SMI_CALL_API(set_command_register)(CMD_RESET_USER_REG);
	if (err) {
		client_data->selftest = 0;
		return err;
	}
	msleep(50);

	smi_restore_hw_cfg(client_data);

	client_data->selftest = 0;
	dev_notice(client_data->dev, "Selftest for SMI16x finished\n");

	return count;
}

/* gyro sensor part */
static ssize_t smi130_gyro_op_mode_show(struct device *dev,
		struct device_attribute *attr, char *buf)
{
	struct input_dev *input = to_input_dev(dev);
	struct smi_client_data *client_data = input_get_drvdata(input);
	int err = 0;
	u8 gyro_pmu_status = 0;

	err = SMI_CALL_API(get_gyro_power_mode_stat)(
		&gyro_pmu_status);

	if (err)
		return err;
	else
	return snprintf(buf, 32, "reg:%d, val:%d\n", gyro_pmu_status,
				client_data->pw.gyro_pm);
}

static ssize_t smi130_gyro_op_mode_store(struct device *dev,
		struct device_attribute *attr,
		const char *buf, size_t count)
{
	struct input_dev *input = to_input_dev(dev);
	struct smi_client_data *client_data = input_get_drvdata(input);
	unsigned long op_mode;
	int err;

	err = kstrtoul(buf, 10, &op_mode);
	if (err)
		return err;

	mutex_lock(&client_data->mutex_op_mode);

	if (op_mode < SMI_GYRO_PM_MAX) {
		switch (op_mode) {
		case SMI_GYRO_PM_NORMAL:
			err = SMI_CALL_API(set_command_register)
				(smi_pmu_cmd_gyro_arr[SMI_GYRO_PM_NORMAL]);
			client_data->pw.gyro_pm = SMI_GYRO_PM_NORMAL;
			smi_delay(60);
			break;
		case SMI_GYRO_PM_FAST_START:
			err = SMI_CALL_API(set_command_register)
				(smi_pmu_cmd_gyro_arr[SMI_GYRO_PM_FAST_START]);
			client_data->pw.gyro_pm = SMI_GYRO_PM_FAST_START;
			smi_delay(60);
			break;
		case SMI_GYRO_PM_SUSPEND:
			err = SMI_CALL_API(set_command_register)
				(smi_pmu_cmd_gyro_arr[SMI_GYRO_PM_SUSPEND]);
			client_data->pw.gyro_pm = SMI_GYRO_PM_SUSPEND;
			smi_delay(60);
			break;
		default:
			mutex_unlock(&client_data->mutex_op_mode);
			return -EINVAL;
		}
	} else {
		mutex_unlock(&client_data->mutex_op_mode);
		return -EINVAL;
	}

	mutex_unlock(&client_data->mutex_op_mode);

	if (err)
		return err;
	else
		return count;

}

static ssize_t smi130_gyro_value_show(struct device *dev,
		struct device_attribute *attr, char *buf)
{
	struct smi130_gyro_t data;
	int err;

	err = SMI_CALL_API(read_gyro_xyz)(&data);
	if (err < 0)
		return err;


	return snprintf(buf, 48, "%hd %hd %hd\n", data.x,
				data.y, data.z);
}

static ssize_t smi130_gyro_range_show(struct device *dev,
		struct device_attribute *attr, char *buf)
{
	int err;
	unsigned char range;
	struct input_dev *input = to_input_dev(dev);
	struct smi_client_data *client_data = input_get_drvdata(input);

	err = SMI_CALL_API(get_gyro_range)(&range);
	if (err)
		return err;

	client_data->range.gyro_range = range;
	return snprintf(buf, 16, "%d\n", range);
}

static ssize_t smi130_gyro_range_store(struct device *dev,
		struct device_attribute *attr,
		const char *buf, size_t count)
{
	int err;
	unsigned long range;
	struct input_dev *input = to_input_dev(dev);
	struct smi_client_data *client_data = input_get_drvdata(input);

	err = kstrtoul(buf, 10, &range);
	if (err)
		return err;

	err = SMI_CALL_API(set_gyro_range)(range);
	if (err)
		return -EIO;

	client_data->range.gyro_range = range;
	return count;
}

static ssize_t smi130_gyro_odr_show(struct device *dev,
		struct device_attribute *attr, char *buf)
{
	int err;
	unsigned char gyro_odr;
	struct input_dev *input = to_input_dev(dev);
	struct smi_client_data *client_data = input_get_drvdata(input);

	err = SMI_CALL_API(get_gyro_output_data_rate)(&gyro_odr);
	if (err)
		return err;

	client_data->odr.gyro_odr = gyro_odr;
	return snprintf(buf, 16, "%d\n", gyro_odr);
}

static ssize_t smi130_gyro_odr_store(struct device *dev,
		struct device_attribute *attr,
		const char *buf, size_t count)
{
	int err;
	unsigned long gyro_odr;
	struct input_dev *input = to_input_dev(dev);
	struct smi_client_data *client_data = input_get_drvdata(input);

	err = kstrtoul(buf, 10, &gyro_odr);
	if (err)
		return err;

	if (gyro_odr < 6 || gyro_odr > 13)
		return -EIO;

	err = SMI_CALL_API(set_gyro_output_data_rate)(gyro_odr);
	if (err)
		return -EIO;

	client_data->odr.gyro_odr = gyro_odr;
	return count;
}

static ssize_t smi130_gyro_fast_calibration_en_show(struct device *dev,
		struct device_attribute *attr, char *buf)
{
	unsigned char data;
	int err;

	err = SMI_CALL_API(get_foc_gyro_enable)(&data);

	if (err < 0)
		return err;
	return snprintf(buf, 16, "%d\n", data);
}

static ssize_t smi130_gyro_fast_calibration_en_store(struct device *dev,
		struct device_attribute *attr,
		const char *buf, size_t count)
{
	unsigned long enable;
	s8 err;
	s16 gyr_off_x;
	s16 gyr_off_y;
	s16 gyr_off_z;
	struct input_dev *input = to_input_dev(dev);
	struct smi_client_data *client_data = input_get_drvdata(input);

	err = kstrtoul(buf, 10, &enable);
	if (err)
		return err;

	err = SMI_CALL_API(set_foc_gyro_enable)((u8)enable,
				&gyr_off_x, &gyr_off_y, &gyr_off_z);

	if (err < 0)
		return -EIO;
	else {
		input_event(client_data->input, EV_MSC,
			INPUT_EVENT_FAST_GYRO_CALIB_DONE, 1);
		input_sync(client_data->input);
	}
	return count;
}

static ssize_t smi130_gyro_offset_x_show(struct device *dev,
		struct device_attribute *attr, char *buf)
{
	s16 data = 0;
	s8 err = 0;

	err = SMI_CALL_API(get_gyro_offset_compensation_xaxis)(&data);

	if (err < 0)
		return err;
	return snprintf(buf, 16, "%d\n", data);
}

static ssize_t smi130_gyro_offset_x_store(struct device *dev,
		struct device_attribute *attr,
		const char *buf, size_t count)
{
	unsigned long data;
	s8 err;

	err = kstrtoul(buf, 10, &data);
	if (err)
		return err;

	err = SMI_CALL_API(set_gyro_offset_compensation_xaxis)((s16)data);

	if (err < 0)
		return -EIO;
	return count;
}

static ssize_t smi130_gyro_offset_y_show(struct device *dev,
		struct device_attribute *attr, char *buf)
{
	s16 data = 0;
	s8 err = 0;

	err = SMI_CALL_API(get_gyro_offset_compensation_yaxis)(&data);

	if (err < 0)
		return err;
	return snprintf(buf, 16, "%d\n", data);
}

static ssize_t smi130_gyro_offset_y_store(struct device *dev,
		struct device_attribute *attr,
		const char *buf, size_t count)
{
	unsigned long data;
	s8 err;

	err = kstrtoul(buf, 10, &data);
	if (err)
		return err;

	err = SMI_CALL_API(set_gyro_offset_compensation_yaxis)((s16)data);

	if (err < 0)
		return -EIO;
	return count;
}

static ssize_t smi130_gyro_offset_z_show(struct device *dev,
		struct device_attribute *attr, char *buf)
{
	s16 data = 0;
	int err = 0;

	err = SMI_CALL_API(get_gyro_offset_compensation_zaxis)(&data);

	if (err < 0)
		return err;
	return snprintf(buf, 16, "%d\n", data);
}

static ssize_t smi130_gyro_offset_z_store(struct device *dev,
		struct device_attribute *attr,
		const char *buf, size_t count)
{
	unsigned long data;
	int err;

	err = kstrtoul(buf, 10, &data);
	if (err)
		return err;

	err = SMI_CALL_API(set_gyro_offset_compensation_zaxis)((s16)data);

	if (err < 0)
		return -EIO;
	return count;
}


/* mag sensor part */
#ifdef SMI130_MAG_INTERFACE_SUPPORT
static ssize_t smi130_mag_op_mode_show(struct device *dev,
		struct device_attribute *attr, char *buf)
{
	struct input_dev *input = to_input_dev(dev);
	struct smi_client_data *client_data = input_get_drvdata(input);
	u8 mag_op_mode;
	s8 err;
	err = smi130_get_mag_power_mode_stat(&mag_op_mode);
	if (err) {
		dev_err(client_data->dev,
			"Failed to get SMI130 mag power mode:%d\n", err);
		return err;
	} else
		return snprintf(buf, 32, "%d, reg:%d\n",
					client_data->pw.mag_pm, mag_op_mode);
}

static ssize_t smi130_mag_op_mode_store(struct device *dev,
		struct device_attribute *attr,
		const char *buf, size_t count)
{
	struct input_dev *input = to_input_dev(dev);
	struct smi_client_data *client_data = input_get_drvdata(input);
	unsigned long op_mode;
	int err;

	err = kstrtoul(buf, 10, &op_mode);
	if (err)
		return err;

	if (op_mode == client_data->pw.mag_pm)
		return count;

	mutex_lock(&client_data->mutex_op_mode);


	if (op_mode < SMI_MAG_PM_MAX) {
		switch (op_mode) {
		case SMI_MAG_PM_NORMAL:
			/* need to modify as mag sensor connected,
			 * set write address to 0x4c and triggers
			 * write operation
			 * 0x4c(op mode control reg)
			 * enables normal mode in magnetometer */
#if defined(SMI130_AKM09912_SUPPORT)
			err = smi130_set_bosch_akm_and_secondary_if_powermode(
			SMI130_MAG_FORCE_MODE);
#else
			err = smi130_set_bmm150_mag_and_secondary_if_power_mode(
			SMI130_MAG_FORCE_MODE);
#endif
			client_data->pw.mag_pm = SMI_MAG_PM_NORMAL;
			smi_delay(5);
			break;
		case SMI_MAG_PM_LP1:
			/* need to modify as mag sensor connected,
			 * set write address to 0x4 band triggers
			 * write operation
			 * 0x4b(bmm150, power control reg, bit0)
			 * enables power in magnetometer*/
#if defined(SMI130_AKM09912_SUPPORT)
			err = smi130_set_bosch_akm_and_secondary_if_powermode(
			SMI130_MAG_FORCE_MODE);
#else
			err = smi130_set_bmm150_mag_and_secondary_if_power_mode(
			SMI130_MAG_FORCE_MODE);
#endif
			client_data->pw.mag_pm = SMI_MAG_PM_LP1;
			smi_delay(5);
			break;
		case SMI_MAG_PM_SUSPEND:
		case SMI_MAG_PM_LP2:
#if defined(SMI130_AKM09912_SUPPORT)
		err = smi130_set_bosch_akm_and_secondary_if_powermode(
		SMI130_MAG_SUSPEND_MODE);
#else
		err = smi130_set_bmm150_mag_and_secondary_if_power_mode(
		SMI130_MAG_SUSPEND_MODE);
#endif
			client_data->pw.mag_pm = op_mode;
			smi_delay(5);
			break;
		default:
			mutex_unlock(&client_data->mutex_op_mode);
			return -EINVAL;
		}
	} else {
		mutex_unlock(&client_data->mutex_op_mode);
		return -EINVAL;
	}

	mutex_unlock(&client_data->mutex_op_mode);

	if (err) {
		dev_err(client_data->dev,
			"Failed to switch SMI130 mag power mode:%d\n",
			client_data->pw.mag_pm);
		return err;
	} else
		return count;

}

static ssize_t smi130_mag_odr_show(struct device *dev,
		struct device_attribute *attr, char *buf)
{
	int err = 0;
	unsigned char mag_odr = 0;
	struct input_dev *input = to_input_dev(dev);
	struct smi_client_data *client_data = input_get_drvdata(input);

	err = SMI_CALL_API(get_mag_output_data_rate)(&mag_odr);
	if (err)
		return err;

	client_data->odr.mag_odr = mag_odr;
	return snprintf(buf, 16, "%d\n", mag_odr);
}

static ssize_t smi130_mag_odr_store(struct device *dev,
		struct device_attribute *attr,
		const char *buf, size_t count)
{
	int err;
	unsigned long mag_odr;
	struct input_dev *input = to_input_dev(dev);
	struct smi_client_data *client_data = input_get_drvdata(input);

	err = kstrtoul(buf, 10, &mag_odr);
	if (err)
		return err;
	/*1~25/32hz,..6(25hz),7(50hz),... */
	err = SMI_CALL_API(set_mag_output_data_rate)(mag_odr);
	if (err)
		return -EIO;

	client_data->odr.mag_odr = mag_odr;
	return count;
}

static ssize_t smi130_mag_i2c_address_show(struct device *dev,
		struct device_attribute *attr, char *buf)
{
	u8 data;
	s8 err;

	err = SMI_CALL_API(set_mag_manual_enable)(1);
	err += SMI_CALL_API(get_i2c_device_addr)(&data);
	err += SMI_CALL_API(set_mag_manual_enable)(0);

	if (err < 0)
		return err;
	return snprintf(buf, 16, "0x%x\n", data);
}

static ssize_t smi130_mag_i2c_address_store(struct device *dev,
		struct device_attribute *attr,
		const char *buf, size_t count)
{
	unsigned long data;
	int err;

	err = kstrtoul(buf, 10, &data);
	if (err)
		return err;

	err += SMI_CALL_API(set_mag_manual_enable)(1);
	if (!err)
		err += SMI_CALL_API(set_i2c_device_addr)((unsigned char)data);
	err += SMI_CALL_API(set_mag_manual_enable)(0);

	if (err < 0)
		return -EIO;
	return count;
}

static ssize_t smi130_mag_value_show(struct device *dev,
		struct device_attribute *attr, char *buf)
{
	struct input_dev *input = to_input_dev(dev);
	struct smi_client_data *client_data = input_get_drvdata(input);
	struct smi130_mag_xyz_s32_t data;
	int err;
	/* raw data with compensation */
#if defined(SMI130_AKM09912_SUPPORT)
	err = smi130_bosch_akm09912_compensate_xyz(&data);
#else
	err = smi130_bmm150_mag_compensate_xyz(&data);
#endif

	if (err < 0) {
		memset(&data, 0, sizeof(data));
		dev_err(client_data->dev, "mag not ready!\n");
	}
	return snprintf(buf, 48, "%hd %hd %hd\n", data.x,
				data.y, data.z);
}
static ssize_t smi130_mag_offset_show(struct device *dev,
		struct device_attribute *attr, char *buf)
{
	int err = 0;
	unsigned char mag_offset;
	err = SMI_CALL_API(get_mag_offset)(&mag_offset);
	if (err)
		return err;

	return snprintf(buf, 16, "%d\n", mag_offset);

}

static ssize_t smi130_mag_offset_store(struct device *dev,
		struct device_attribute *attr,
		const char *buf, size_t count)
{
	unsigned long data;
	int err;

	err = kstrtoul(buf, 10, &data);
	if (err)
		return err;

	err += SMI_CALL_API(set_mag_manual_enable)(1);
	if (err == 0)
		err += SMI_CALL_API(set_mag_offset)((unsigned char)data);
	err += SMI_CALL_API(set_mag_manual_enable)(0);

	if (err < 0)
		return -EIO;
	return count;
}

static ssize_t smi130_mag_chip_id_show(struct device *dev,
		struct device_attribute *attr, char *buf)
{
	s8 err = 0;
	u8 mag_chipid;

	err = smi130_set_mag_manual_enable(0x01);
	/* read mag chip_id value */
#if defined(SMI130_AKM09912_SUPPORT)
	err += smi130_set_mag_read_addr(AKM09912_CHIP_ID_REG);
		/* 0x04 is mag_x lsb register */
	err += smi130_read_reg(SMI130_USER_DATA_0_MAG_X_LSB__REG,
							&mag_chipid, 1);

	/* Must add this commands to re-set data register addr of mag sensor */
	err += smi130_set_mag_read_addr(AKM_DATA_REGISTER);
#else
	err += smi130_set_mag_read_addr(SMI130_BMM150_CHIP_ID);
	/* 0x04 is mag_x lsb register */
	err += smi130_read_reg(SMI130_USER_DATA_0_MAG_X_LSB__REG,
							&mag_chipid, 1);

	/* Must add this commands to re-set data register addr of mag sensor */
	/* 0x42 is  bmm150 data register address */
	err += smi130_set_mag_read_addr(SMI130_BMM150_DATA_REG);
#endif

	err += smi130_set_mag_manual_enable(0x00);

	if (err)
		return err;

	return snprintf(buf, 16, "%x\n", mag_chipid);

}

static ssize_t smi130_mag_chip_name_show(struct device *dev,
		struct device_attribute *attr, char *buf)
{
	u8 mag_chipid = 0;
#if defined(SMI130_AKM09912_SUPPORT)
	mag_chipid = 15;
#else
	mag_chipid = 150;
#endif
	return snprintf(buf, 16, "%d\n", mag_chipid);
}

struct smi130_mag_xyz_s32_t mag_compensate;
static ssize_t smi130_mag_compensate_xyz_show(struct device *dev,
	struct device_attribute *attr, char *buf)
{
	memcpy(buf, &mag_compensate, sizeof(mag_compensate));
	return sizeof(mag_compensate);
}
static ssize_t smi130_mag_compensate_xyz_store(struct device *dev,
	struct device_attribute *attr, const char *buf, size_t count)
{
	struct smi130_mag_xyzr_t mag_raw;
	memset(&mag_compensate, 0, sizeof(mag_compensate));
	memset(&mag_raw, 0, sizeof(mag_raw));
	mag_raw.x = (buf[1] << 8 | buf[0]);
	mag_raw.y = (buf[3] << 8 | buf[2]);
	mag_raw.z = (buf[5] << 8 | buf[4]);
	mag_raw.r = (buf[7] << 8 | buf[6]);
	mag_raw.x = mag_raw.x >> 3;
	mag_raw.y = mag_raw.y >> 3;
	mag_raw.z = mag_raw.z >> 1;
	mag_raw.r = mag_raw.r >> 2;
	smi130_bmm150_mag_compensate_xyz_raw(
	&mag_compensate, mag_raw);
	return count;
}

#endif

#if defined(SMI130_ENABLE_INT1) || defined(SMI130_ENABLE_INT2)
static ssize_t smi_enable_int_store(struct device *dev,
		struct device_attribute *attr,
		const char *buf, size_t count)
{
	int interrupt_type, value;

	sscanf(buf, "%3d %3d", &interrupt_type, &value);

	if (interrupt_type < 0 || interrupt_type > 16)
		return -EINVAL;

	if (interrupt_type <= SMI_FLAT_INT) {
		if (SMI_CALL_API(set_intr_enable_0)
				(smi_interrupt_type[interrupt_type], value) < 0)
			return -EINVAL;
	} else if (interrupt_type <= SMI_FWM_INT) {
		if (SMI_CALL_API(set_intr_enable_1)
			(smi_interrupt_type[interrupt_type], value) < 0)
			return -EINVAL;
	} else {
		if (SMI_CALL_API(set_intr_enable_2)
			(smi_interrupt_type[interrupt_type], value) < 0)
			return -EINVAL;
	}

	return count;
}

#endif

static ssize_t smi130_show_reg_sel(struct device *dev
		, struct device_attribute *attr, char *buf)
{
	struct input_dev *input = to_input_dev(dev);
	struct smi_client_data *client_data = input_get_drvdata(input);

	if (client_data == NULL) {
		printk(KERN_ERR "Invalid client_data pointer");
		return -ENODEV;
	}

	return snprintf(buf, 64, "reg=0X%02X, len=%d\n",
		client_data->reg_sel, client_data->reg_len);
}

static ssize_t smi130_store_reg_sel(struct device *dev
		, struct device_attribute *attr,
		const char *buf, size_t count)
{
	struct input_dev *input = to_input_dev(dev);
	struct smi_client_data *client_data = input_get_drvdata(input);
	ssize_t ret;

	if (client_data == NULL) {
		printk(KERN_ERR "Invalid client_data pointer");
		return -ENODEV;
	}
	ret = sscanf(buf, "%11X %11d",
		&client_data->reg_sel, &client_data->reg_len);
	if (ret != 2) {
		dev_err(client_data->dev, "Invalid argument");
		return -EINVAL;
	}

	return count;
}

static ssize_t smi130_show_reg_val(struct device *dev
		, struct device_attribute *attr, char *buf)
{
	struct input_dev *input = to_input_dev(dev);
	struct smi_client_data *client_data = input_get_drvdata(input);

	ssize_t ret;
	u8 reg_data[128], i;
	int pos;

	if (client_data == NULL) {
		printk(KERN_ERR "Invalid client_data pointer");
		return -ENODEV;
	}

	ret = smi_burst_read_wrapper(client_data->device.dev_addr,
		client_data->reg_sel,
		reg_data, client_data->reg_len);
	if (ret < 0) {
		dev_err(client_data->dev, "Reg op failed");
		return ret;
	}

	pos = 0;
	for (i = 0; i < client_data->reg_len; ++i) {
		pos += snprintf(buf + pos, 16, "%02X", reg_data[i]);
		buf[pos++] = (i + 1) % 16 == 0 ? '\n' : ' ';
	}
	if (buf[pos - 1] == ' ')
		buf[pos - 1] = '\n';

	return pos;
}

static ssize_t smi130_store_reg_val(struct device *dev
		, struct device_attribute *attr,
		const char *buf, size_t count)
{
	struct input_dev *input = to_input_dev(dev);
	struct smi_client_data *client_data = input_get_drvdata(input);
	ssize_t ret;
	u8 reg_data[32];
	int i, j, status, digit;

	if (client_data == NULL) {
		printk(KERN_ERR "Invalid client_data pointer");
		return -ENODEV;
	}
	status = 0;
	for (i = j = 0; i < count && j < client_data->reg_len; ++i) {
		if (buf[i] == ' ' || buf[i] == '\n' || buf[i] == '\t' ||
			buf[i] == '\r') {
			status = 0;
			++j;
			continue;
		}
		digit = buf[i] & 0x10 ? (buf[i] & 0xF) : ((buf[i] & 0xF) + 9);
		printk(KERN_INFO "digit is %d", digit);
		switch (status) {
		case 2:
			++j; /* Fall thru */
		case 0:
			reg_data[j] = digit;
			status = 1;
			break;
		case 1:
			reg_data[j] = reg_data[j] * 16 + digit;
			status = 2;
			break;
		}
	}
	if (status > 0)
		++j;
	if (j > client_data->reg_len)
		j = client_data->reg_len;
	else if (j < client_data->reg_len) {
		dev_err(client_data->dev, "Invalid argument");
		return -EINVAL;
	}
	printk(KERN_INFO "Reg data read as");
	for (i = 0; i < j; ++i)
		printk(KERN_INFO "%d", reg_data[i]);

	ret = SMI_CALL_API(write_reg)(
		client_data->reg_sel,
		reg_data, client_data->reg_len);
	if (ret < 0) {
		dev_err(client_data->dev, "Reg op failed");
		return ret;
	}

	return count;
}

static ssize_t smi130_driver_version_show(struct device *dev
		, struct device_attribute *attr, char *buf)
{
	struct input_dev *input = to_input_dev(dev);
	struct smi_client_data *client_data = input_get_drvdata(input);
	int ret;

	if (client_data == NULL) {
		printk(KERN_ERR "Invalid client_data pointer");
		return -ENODEV;
	}

	ret = snprintf(buf, 128, "Driver version: %s\n",
			DRIVER_VERSION);

	return ret;
}
static DEVICE_ATTR(chip_id, S_IRUGO,
		smi130_chip_id_show, NULL);
static DEVICE_ATTR(err_st, S_IRUGO,
		smi130_err_st_show, NULL);
static DEVICE_ATTR(sensor_time, S_IRUGO,
		smi130_sensor_time_show, NULL);

static DEVICE_ATTR(selftest, S_IRUGO | S_IWUSR,
		smi130_selftest_show, smi130_selftest_store);
static DEVICE_ATTR(fifo_flush, S_IRUGO | S_IWUSR,
		NULL, smi130_fifo_flush_store);
static DEVICE_ATTR(fifo_bytecount, S_IRUGO | S_IWUSR,
		smi130_fifo_bytecount_show, smi130_fifo_bytecount_store);
static DEVICE_ATTR(fifo_data_sel, S_IRUGO | S_IWUSR,
		smi130_fifo_data_sel_show, smi130_fifo_data_sel_store);
static DEVICE_ATTR(fifo_data_frame, S_IRUGO,
		smi130_fifo_data_out_frame_show, NULL);

static DEVICE_ATTR(fifo_watermark, S_IRUGO | S_IWUSR,
		smi130_fifo_watermark_show, smi130_fifo_watermark_store);

static DEVICE_ATTR(fifo_header_en, S_IRUGO | S_IWUSR,
		smi130_fifo_header_en_show, smi130_fifo_header_en_store);
static DEVICE_ATTR(fifo_time_en, S_IRUGO | S_IWUSR,
		smi130_fifo_time_en_show, smi130_fifo_time_en_store);
static DEVICE_ATTR(fifo_int_tag_en, S_IRUGO | S_IWUSR,
		smi130_fifo_int_tag_en_show, smi130_fifo_int_tag_en_store);

static DEVICE_ATTR(temperature, S_IRUGO,
		smi130_temperature_show, NULL);
static DEVICE_ATTR(place, S_IRUGO,
		smi130_place_show, NULL);
static DEVICE_ATTR(delay, S_IRUGO | S_IWUSR,
		smi130_delay_show, smi130_delay_store);
static DEVICE_ATTR(enable, S_IRUGO | S_IWUSR,
		smi130_enable_show, smi130_enable_store);
static DEVICE_ATTR(acc_range, S_IRUGO | S_IWUSR,
		smi130_acc_range_show, smi130_acc_range_store);
static DEVICE_ATTR(acc_odr, S_IRUGO | S_IWUSR,
		smi130_acc_odr_show, smi130_acc_odr_store);
static DEVICE_ATTR(acc_op_mode, S_IRUGO | S_IWUSR,
		smi130_acc_op_mode_show, smi130_acc_op_mode_store);
static DEVICE_ATTR(acc_value, S_IRUGO,
		smi130_acc_value_show, NULL);
static DEVICE_ATTR(acc_fast_calibration_x, S_IRUGO | S_IWUSR,
		smi130_acc_fast_calibration_x_show,
		smi130_acc_fast_calibration_x_store);
static DEVICE_ATTR(acc_fast_calibration_y, S_IRUGO | S_IWUSR,
		smi130_acc_fast_calibration_y_show,
		smi130_acc_fast_calibration_y_store);
static DEVICE_ATTR(acc_fast_calibration_z, S_IRUGO | S_IWUSR,
		smi130_acc_fast_calibration_z_show,
		smi130_acc_fast_calibration_z_store);
static DEVICE_ATTR(acc_offset_x, S_IRUGO | S_IWUSR,
		smi130_acc_offset_x_show,
		smi130_acc_offset_x_store);
static DEVICE_ATTR(acc_offset_y, S_IRUGO | S_IWUSR,
		smi130_acc_offset_y_show,
		smi130_acc_offset_y_store);
static DEVICE_ATTR(acc_offset_z, S_IRUGO | S_IWUSR,
		smi130_acc_offset_z_show,
		smi130_acc_offset_z_store);
static DEVICE_ATTR(test, S_IRUGO,
		smi130_test_show, NULL);
static DEVICE_ATTR(stc_enable, S_IRUGO | S_IWUSR,
		smi130_step_counter_enable_show,
		smi130_step_counter_enable_store);
static DEVICE_ATTR(stc_mode, S_IRUGO | S_IWUSR,
		NULL, smi130_step_counter_mode_store);
static DEVICE_ATTR(stc_clc, S_IRUGO | S_IWUSR,
		NULL, smi130_step_counter_clc_store);
static DEVICE_ATTR(stc_value, S_IRUGO,
		smi130_step_counter_value_show, NULL);
static DEVICE_ATTR(reg_sel, S_IRUGO | S_IWUSR,
		smi130_show_reg_sel, smi130_store_reg_sel);
static DEVICE_ATTR(reg_val, S_IRUGO | S_IWUSR,
		smi130_show_reg_val, smi130_store_reg_val);
static DEVICE_ATTR(driver_version, S_IRUGO,
		smi130_driver_version_show, NULL);
/* gyro part */
static DEVICE_ATTR(gyro_op_mode, S_IRUGO | S_IWUSR,
		smi130_gyro_op_mode_show, smi130_gyro_op_mode_store);
static DEVICE_ATTR(gyro_value, S_IRUGO,
		smi130_gyro_value_show, NULL);
static DEVICE_ATTR(gyro_range, S_IRUGO | S_IWUSR,
		smi130_gyro_range_show, smi130_gyro_range_store);
static DEVICE_ATTR(gyro_odr, S_IRUGO | S_IWUSR,
		smi130_gyro_odr_show, smi130_gyro_odr_store);
static DEVICE_ATTR(gyro_fast_calibration_en, S_IRUGO | S_IWUSR,
smi130_gyro_fast_calibration_en_show, smi130_gyro_fast_calibration_en_store);
static DEVICE_ATTR(gyro_offset_x, S_IRUGO | S_IWUSR,
smi130_gyro_offset_x_show, smi130_gyro_offset_x_store);
static DEVICE_ATTR(gyro_offset_y, S_IRUGO | S_IWUSR,
smi130_gyro_offset_y_show, smi130_gyro_offset_y_store);
static DEVICE_ATTR(gyro_offset_z, S_IRUGO | S_IWUSR,
smi130_gyro_offset_z_show, smi130_gyro_offset_z_store);

#ifdef SMI130_MAG_INTERFACE_SUPPORT
static DEVICE_ATTR(mag_op_mode, S_IRUGO | S_IWUSR,
		smi130_mag_op_mode_show, smi130_mag_op_mode_store);
static DEVICE_ATTR(mag_odr, S_IRUGO | S_IWUSR,
		smi130_mag_odr_show, smi130_mag_odr_store);
static DEVICE_ATTR(mag_i2c_addr, S_IRUGO | S_IWUSR,
		smi130_mag_i2c_address_show, smi130_mag_i2c_address_store);
static DEVICE_ATTR(mag_value, S_IRUGO,
		smi130_mag_value_show, NULL);
static DEVICE_ATTR(mag_offset, S_IRUGO | S_IWUSR,
		smi130_mag_offset_show, smi130_mag_offset_store);
static DEVICE_ATTR(mag_chip_id, S_IRUGO,
		smi130_mag_chip_id_show, NULL);
static DEVICE_ATTR(mag_chip_name, S_IRUGO,
		smi130_mag_chip_name_show, NULL);
static DEVICE_ATTR(mag_compensate, S_IRUGO | S_IWUSR,
		smi130_mag_compensate_xyz_show,
		smi130_mag_compensate_xyz_store);
#endif


#if defined(SMI130_ENABLE_INT1) || defined(SMI130_ENABLE_INT2)
static DEVICE_ATTR(enable_int, S_IRUGO | S_IWUSR,
		NULL, smi_enable_int_store);
static DEVICE_ATTR(anymot_duration, S_IRUGO | S_IWUSR,
		smi130_anymot_duration_show, smi130_anymot_duration_store);
static DEVICE_ATTR(anymot_threshold, S_IRUGO | S_IWUSR,
		smi130_anymot_threshold_show, smi130_anymot_threshold_store);
static DEVICE_ATTR(std_stu, S_IRUGO,
		smi130_step_detector_status_show, NULL);
static DEVICE_ATTR(std_en, S_IRUGO | S_IWUSR,
		smi130_step_detector_enable_show,
		smi130_step_detector_enable_store);
static DEVICE_ATTR(sig_en, S_IRUGO | S_IWUSR,
		smi130_signification_motion_enable_show,
		smi130_signification_motion_enable_store);

#endif



static DEVICE_ATTR(smi_value, S_IRUGO,
		smi130_smi_value_show, NULL);


static struct attribute *smi130_attributes[] = {
	&dev_attr_chip_id.attr,
	&dev_attr_err_st.attr,
	&dev_attr_sensor_time.attr,
	&dev_attr_selftest.attr,
	&dev_attr_driver_version.attr,
	&dev_attr_test.attr,
	&dev_attr_fifo_flush.attr,
	&dev_attr_fifo_header_en.attr,
	&dev_attr_fifo_time_en.attr,
	&dev_attr_fifo_int_tag_en.attr,
	&dev_attr_fifo_bytecount.attr,
	&dev_attr_fifo_data_sel.attr,
	&dev_attr_fifo_data_frame.attr,

	&dev_attr_fifo_watermark.attr,

	&dev_attr_enable.attr,
	&dev_attr_delay.attr,
	&dev_attr_temperature.attr,
	&dev_attr_place.attr,

	&dev_attr_acc_range.attr,
	&dev_attr_acc_odr.attr,
	&dev_attr_acc_op_mode.attr,
	&dev_attr_acc_value.attr,

	&dev_attr_acc_fast_calibration_x.attr,
	&dev_attr_acc_fast_calibration_y.attr,
	&dev_attr_acc_fast_calibration_z.attr,
	&dev_attr_acc_offset_x.attr,
	&dev_attr_acc_offset_y.attr,
	&dev_attr_acc_offset_z.attr,

	&dev_attr_stc_enable.attr,
	&dev_attr_stc_mode.attr,
	&dev_attr_stc_clc.attr,
	&dev_attr_stc_value.attr,

	&dev_attr_gyro_op_mode.attr,
	&dev_attr_gyro_value.attr,
	&dev_attr_gyro_range.attr,
	&dev_attr_gyro_odr.attr,
	&dev_attr_gyro_fast_calibration_en.attr,
	&dev_attr_gyro_offset_x.attr,
	&dev_attr_gyro_offset_y.attr,
	&dev_attr_gyro_offset_z.attr,

#ifdef SMI130_MAG_INTERFACE_SUPPORT
	&dev_attr_mag_chip_id.attr,
	&dev_attr_mag_op_mode.attr,
	&dev_attr_mag_odr.attr,
	&dev_attr_mag_i2c_addr.attr,
	&dev_attr_mag_chip_name.attr,
	&dev_attr_mag_value.attr,
	&dev_attr_mag_offset.attr,
	&dev_attr_mag_compensate.attr,
#endif

#if defined(SMI130_ENABLE_INT1) || defined(SMI130_ENABLE_INT2)
	&dev_attr_enable_int.attr,

	&dev_attr_anymot_duration.attr,
	&dev_attr_anymot_threshold.attr,
	&dev_attr_std_stu.attr,
	&dev_attr_std_en.attr,
	&dev_attr_sig_en.attr,

#endif
	&dev_attr_reg_sel.attr,
	&dev_attr_reg_val.attr,
	&dev_attr_smi_value.attr,
	NULL
};

static struct attribute_group smi130_attribute_group = {
	.attrs = smi130_attributes
};

#if defined(SMI130_ENABLE_INT1) || defined(SMI130_ENABLE_INT2)
static void smi_slope_interrupt_handle(struct smi_client_data *client_data)
{
	/* anym_first[0..2]: x, y, z */
	u8 anym_first[3] = {0};
	u8 status2;
	u8 anym_sign;
	u8 i = 0;

	client_data->device.bus_read(client_data->device.dev_addr,
				SMI130_USER_INTR_STAT_2_ADDR, &status2, 1);
	anym_first[0] = SMI130_GET_BITSLICE(status2,
				SMI130_USER_INTR_STAT_2_ANY_MOTION_FIRST_X);
	anym_first[1] = SMI130_GET_BITSLICE(status2,
				SMI130_USER_INTR_STAT_2_ANY_MOTION_FIRST_Y);
	anym_first[2] = SMI130_GET_BITSLICE(status2,
				SMI130_USER_INTR_STAT_2_ANY_MOTION_FIRST_Z);
	anym_sign = SMI130_GET_BITSLICE(status2,
				SMI130_USER_INTR_STAT_2_ANY_MOTION_SIGN);

	for (i = 0; i < 3; i++) {
		if (anym_first[i]) {
			/*1: negative*/
			if (anym_sign)
				dev_notice(client_data->dev,
				"Anymotion interrupt happend!"
				"%s axis, negative sign\n", smi_axis_name[i]);
			else
				dev_notice(client_data->dev,
				"Anymotion interrupt happend!"
				"%s axis, postive sign\n", smi_axis_name[i]);
		}
	}


}

static void smi_fifo_watermark_interrupt_handle
				(struct smi_client_data *client_data)
{
	int err = 0;
	unsigned int fifo_len0 = 0;
	unsigned int  fifo_frmbytes_ext = 0;
	unsigned char *fifo_data = NULL;
	fifo_data = kzalloc(FIFO_DATA_BUFSIZE, GFP_KERNEL);
	/*TO DO*/
	if (NULL == fifo_data) {
			dev_err(client_data->dev, "no memory available");
			err = -ENOMEM;
	}
	smi_fifo_frame_bytes_extend_calc(client_data, &fifo_frmbytes_ext);

	if (client_data->pw.acc_pm == 2 && client_data->pw.gyro_pm == 2
					&& client_data->pw.mag_pm == 2)
		printk(KERN_INFO "pw_acc: %d, pw_gyro: %d\n",
			client_data->pw.acc_pm, client_data->pw.gyro_pm);
	if (!client_data->fifo_data_sel)
		printk(KERN_INFO "no selsect sensor fifo, fifo_data_sel:%d\n",
						client_data->fifo_data_sel);

	err = SMI_CALL_API(fifo_length)(&fifo_len0);
	client_data->fifo_bytecount = fifo_len0;

	if (client_data->fifo_bytecount == 0 || err)
		return;

	if (client_data->fifo_bytecount + fifo_frmbytes_ext > FIFO_DATA_BUFSIZE)
		client_data->fifo_bytecount = FIFO_DATA_BUFSIZE;
	/* need give attention for the time of burst read*/
	if (!err) {
		err = smi_burst_read_wrapper(client_data->device.dev_addr,
			SMI130_USER_FIFO_DATA__REG, fifo_data,
			client_data->fifo_bytecount + fifo_frmbytes_ext);
	} else
		dev_err(client_data->dev, "read fifo leght err");

	if (err)
		dev_err(client_data->dev, "brust read fifo err\n");
	/*err = smi_fifo_analysis_handle(client_data, fifo_data,
			client_data->fifo_bytecount + 20, fifo_out_data);*/
	if (fifo_data != NULL) {
		kfree(fifo_data);
		fifo_data = NULL;
	}

}
static void smi_data_ready_interrupt_handle(
	struct smi_client_data *client_data, uint8_t status)
{
	uint8_t data12[12] = {0};
	struct smi130_accel_t accel;
	struct smi130_gyro_t gyro;
	struct timespec ts;
	client_data->device.bus_read(client_data->device.dev_addr,
	SMI130_USER_DATA_8_ADDR, data12, 12);
	if (status & 0x80)
	{
		/*report acc data*/
		/* Data X */
		accel.x = (s16)((((s32)((s8)data12[7])) << SMI130_SHIFT_BIT_POSITION_BY_08_BITS) | (data12[6]));
		/* Data Y */
		accel.y = (s16)((((s32)((s8)data12[9])) << SMI130_SHIFT_BIT_POSITION_BY_08_BITS) | (data12[8]));
		/* Data Z */
		accel.z = (s16)((((s32)((s8)data12[11]))<< SMI130_SHIFT_BIT_POSITION_BY_08_BITS) | (data12[10]));
		ts = ns_to_timespec(client_data->timestamp);
		input_event(client_data->input, EV_MSC, 6, ts.tv_sec);
		input_event(client_data->input, EV_MSC, 6, ts.tv_nsec);
		input_event(client_data->input, EV_MSC, MSC_GESTURE, accel.x);
		input_event(client_data->input, EV_MSC, MSC_RAW, accel.y);
		input_event(client_data->input, EV_MSC, MSC_SCAN, accel.z);
		input_sync(client_data->input);
	}
	if (status & 0x40)
	{
		/*report gyro data*/
		/* Data X */
		gyro.x = (s16)((((s32)((s8)data12[1])) << SMI130_SHIFT_BIT_POSITION_BY_08_BITS) | (data12[0]));
		/* Data Y */
		gyro.y = (s16)((((s32)((s8)data12[3])) << SMI130_SHIFT_BIT_POSITION_BY_08_BITS) | (data12[2]));
		/* Data Z */
		gyro.z = (s16)((((s32)((s8)data12[5]))<< SMI130_SHIFT_BIT_POSITION_BY_08_BITS) | (data12[4]));
		ts = ns_to_timespec(client_data->timestamp);
		input_event(client_data->gyro_input, EV_MSC, 6, ts.tv_sec);
		input_event(client_data->gyro_input, EV_MSC, 6, ts.tv_nsec);
		input_event(client_data->gyro_input, EV_MSC, MSC_GESTURE, gyro.x);
		input_event(client_data->gyro_input, EV_MSC, MSC_RAW, gyro.y);
		input_event(client_data->gyro_input, EV_MSC, MSC_SCAN, gyro.z);
		input_sync(client_data->gyro_input);
	}
}

static void smi_signification_motion_interrupt_handle(
		struct smi_client_data *client_data)
{
	printk(KERN_INFO "smi_signification_motion_interrupt_handle\n");
	input_event(client_data->input, EV_MSC, INPUT_EVENT_SGM, 1);
/*input_report_rel(client_data->input,INPUT_EVENT_SGM,1);*/
	input_sync(client_data->input);
	smi130_set_command_register(CMD_RESET_INT_ENGINE);

}
static void smi_stepdetector_interrupt_handle(
	struct smi_client_data *client_data)
{
	u8 current_step_dector_st = 0;
	client_data->pedo_data.wkar_step_detector_status++;
	current_step_dector_st =
		client_data->pedo_data.wkar_step_detector_status;
	client_data->std = ((current_step_dector_st == 1) ? 0 : 1);

	input_event(client_data->input, EV_MSC, INPUT_EVENT_STEP_DETECTOR, 1);
	input_sync(client_data->input);
}

static void smi_irq_work_func(struct work_struct *work)
{
	struct smi_client_data *client_data =
		container_of((struct work_struct *)work,
			struct smi_client_data, irq_work);

	unsigned char int_status[4] = {0, 0, 0, 0};
	uint8_t status = 0;

	//client_data->device.bus_read(client_data->device.dev_addr,
	//			SMI130_USER_INTR_STAT_0_ADDR, int_status, 4);
	client_data->device.bus_read(client_data->device.dev_addr,
	SMI130_USER_STAT_ADDR, &status, 1);
	printk("status = 0x%x", status);
	if (SMI130_GET_BITSLICE(int_status[0],
					SMI130_USER_INTR_STAT_0_ANY_MOTION))
		smi_slope_interrupt_handle(client_data);

	if (SMI130_GET_BITSLICE(int_status[0],
			SMI130_USER_INTR_STAT_0_STEP_INTR))
		smi_stepdetector_interrupt_handle(client_data);
	if (SMI130_GET_BITSLICE(int_status[1],
			SMI130_USER_INTR_STAT_1_FIFO_WM_INTR))
		smi_fifo_watermark_interrupt_handle(client_data);
	if ((status & 0x80) || (status & 0x40))
		smi_data_ready_interrupt_handle(client_data, status);
	/* Clear ALL inputerrupt status after handler sig mition*/
	/* Put this commads intot the last one*/
	if (SMI130_GET_BITSLICE(int_status[0],
		SMI130_USER_INTR_STAT_0_SIGNIFICANT_INTR))
		smi_signification_motion_interrupt_handle(client_data);

}

static void smi130_delay_sigmo_work_func(struct work_struct *work)
{
	struct smi_client_data *client_data =
	container_of(work, struct smi_client_data,
	delay_work_sig.work);
	unsigned char int_status[4] = {0, 0, 0, 0};

	client_data->device.bus_read(client_data->device.dev_addr,
				SMI130_USER_INTR_STAT_0_ADDR, int_status, 4);
	if (SMI130_GET_BITSLICE(int_status[0],
		SMI130_USER_INTR_STAT_0_SIGNIFICANT_INTR))
		smi_signification_motion_interrupt_handle(client_data);
}

static irqreturn_t smi_irq_handler(int irq, void *handle)
{
	struct smi_client_data *client_data = handle;
	int in_suspend_copy;
	in_suspend_copy = atomic_read(&client_data->in_suspend);

	if (client_data == NULL)
		return IRQ_HANDLED;
	if (client_data->dev == NULL)
		return IRQ_HANDLED;
		/*this only deal with SIG_motion CTS test*/
	if ((in_suspend_copy == 1) &&
		(client_data->sig_flag == 1)) {
		/*wake_lock_timeout(&client_data->wakelock, HZ);*/
		schedule_delayed_work(&client_data->delay_work_sig,
			msecs_to_jiffies(50));
	}
	schedule_work(&client_data->irq_work);

	return IRQ_HANDLED;
}
#endif /* defined(SMI_ENABLE_INT1)||defined(SMI_ENABLE_INT2) */

static int smi_restore_hw_cfg(struct smi_client_data *client)
{
	int err = 0;

	if ((client->fifo_data_sel) & (1 << SMI_ACC_SENSOR)) {
		err += SMI_CALL_API(set_accel_range)(client->range.acc_range);
		err += SMI_CALL_API(set_accel_output_data_rate)
				(client->odr.acc_odr);
		err += SMI_CALL_API(set_fifo_accel_enable)(1);
	}
	if ((client->fifo_data_sel) & (1 << SMI_GYRO_SENSOR)) {
		err += SMI_CALL_API(set_gyro_range)(client->range.gyro_range);
		err += SMI_CALL_API(set_gyro_output_data_rate)
				(client->odr.gyro_odr);
		err += SMI_CALL_API(set_fifo_gyro_enable)(1);
	}
	if ((client->fifo_data_sel) & (1 << SMI_MAG_SENSOR)) {
		err += SMI_CALL_API(set_mag_output_data_rate)
				(client->odr.mag_odr);
		err += SMI_CALL_API(set_fifo_mag_enable)(1);
	}
	err += SMI_CALL_API(set_command_register)(CMD_CLR_FIFO_DATA);

	mutex_lock(&client->mutex_op_mode);
	if (client->pw.acc_pm != SMI_ACC_PM_SUSPEND) {
		err += SMI_CALL_API(set_command_register)
				(smi_pmu_cmd_acc_arr[SMI_ACC_PM_NORMAL]);
		smi_delay(3);
	}
	mutex_unlock(&client->mutex_op_mode);

	mutex_lock(&client->mutex_op_mode);
	if (client->pw.gyro_pm != SMI_GYRO_PM_SUSPEND) {
		err += SMI_CALL_API(set_command_register)
				(smi_pmu_cmd_gyro_arr[SMI_GYRO_PM_NORMAL]);
		smi_delay(3);
	}
	mutex_unlock(&client->mutex_op_mode);

	mutex_lock(&client->mutex_op_mode);

	if (client->pw.mag_pm != SMI_MAG_PM_SUSPEND) {
#ifdef SMI130_AKM09912_SUPPORT
		err += smi130_set_bosch_akm_and_secondary_if_powermode
					(SMI130_MAG_FORCE_MODE);
#else
		err += smi130_set_bmm150_mag_and_secondary_if_power_mode
					(SMI130_MAG_FORCE_MODE);
#endif
		smi_delay(3);
	}
	mutex_unlock(&client->mutex_op_mode);

	return err;
}

#if defined(CONFIG_USE_QUALCOMM_HAL)
static void smi130_accel_work_fn(struct work_struct *work)
{
	struct smi_client_data *sensor;
	ktime_t timestamp;
	struct smi130_accel_t data;
	int err;
	sensor = container_of((struct delayed_work *)work,
				struct smi_client_data, accel_poll_work);
	timestamp = ktime_get();
	err = SMI_CALL_API(read_accel_xyz)(&data);
	if (err)
		dev_err(sensor->dev, "read data err");
	input_report_abs(sensor->input, ABS_X,
		(data.x));
	input_report_abs(sensor->input, ABS_Y,
		(data.y));
	input_report_abs(sensor->input, ABS_Z,
		(data.z));
	input_event(sensor->input,
			EV_SYN, SYN_TIME_SEC,
			ktime_to_timespec(timestamp).tv_sec);
	input_event(sensor->input, EV_SYN,
		SYN_TIME_NSEC,
		ktime_to_timespec(timestamp).tv_nsec);
	input_sync(sensor->input);
	if (atomic_read(&sensor->accel_en))
		queue_delayed_work(sensor->data_wq,
			&sensor->accel_poll_work,
			msecs_to_jiffies(sensor->accel_poll_ms));
}
static void smi130_gyro_work_fn(struct work_struct *work)
{
	struct smi_client_data *sensor;
	ktime_t timestamp;
	struct smi130_gyro_t data;
	int err;
	sensor = container_of((struct delayed_work *)work,
				struct smi_client_data, gyro_poll_work);
	timestamp = ktime_get();
	err = SMI_CALL_API(read_gyro_xyz)(&data);
	if (err)
		dev_err(sensor->dev, "read data err");
	input_report_abs(sensor->gyro_input, ABS_RX,
		(data.x));
	input_report_abs(sensor->gyro_input, ABS_RY,
		(data.y));
	input_report_abs(sensor->gyro_input, ABS_RZ,
		(data.z));
	input_event(sensor->gyro_input,
			EV_SYN, SYN_TIME_SEC,
			ktime_to_timespec(timestamp).tv_sec);
	input_event(sensor->gyro_input, EV_SYN,
		SYN_TIME_NSEC,
		ktime_to_timespec(timestamp).tv_nsec);
	input_sync(sensor->gyro_input);
	if (atomic_read(&sensor->gyro_en))
		queue_delayed_work(sensor->data_wq,
			&sensor->gyro_poll_work,
			msecs_to_jiffies(sensor->gyro_poll_ms));
}
static int smi130_set_gyro_op_mode(struct smi_client_data *client_data,
							unsigned long op_mode)
{
	int err = 0;
	mutex_lock(&client_data->mutex_op_mode);
	if (op_mode < SMI_GYRO_PM_MAX) {
		switch (op_mode) {
		case SMI_GYRO_PM_NORMAL:
			err = SMI_CALL_API(set_command_register)
				(smi_pmu_cmd_gyro_arr[SMI_GYRO_PM_NORMAL]);
			client_data->pw.gyro_pm = SMI_GYRO_PM_NORMAL;
			smi_delay(60);
			break;
		case SMI_GYRO_PM_FAST_START:
			err = SMI_CALL_API(set_command_register)
				(smi_pmu_cmd_gyro_arr[SMI_GYRO_PM_FAST_START]);
			client_data->pw.gyro_pm = SMI_GYRO_PM_FAST_START;
			smi_delay(60);
			break;
		case SMI_GYRO_PM_SUSPEND:
			err = SMI_CALL_API(set_command_register)
				(smi_pmu_cmd_gyro_arr[SMI_GYRO_PM_SUSPEND]);
			client_data->pw.gyro_pm = SMI_GYRO_PM_SUSPEND;
			smi_delay(60);
			break;
		default:
			mutex_unlock(&client_data->mutex_op_mode);
			return -EINVAL;
		}
	} else {
		mutex_unlock(&client_data->mutex_op_mode);
		return -EINVAL;
	}
	mutex_unlock(&client_data->mutex_op_mode);
	return err;
}
static int smi130_accel_set_enable(
	struct smi_client_data *client_data, bool enable)
{
	int ret = 0;
	dev_notice(client_data->dev,
		"smi130_accel_set_enable enable=%d\n", enable);
	if (enable) {
		ret = smi130_set_acc_op_mode(client_data, 0);
		if (ret) {
			dev_err(client_data->dev,
				"Fail to enable accel engine ret=%d\n", ret);
			ret = -EBUSY;
			goto exit;
		}
		queue_delayed_work(client_data->data_wq,
				&client_data->accel_poll_work,
				msecs_to_jiffies(client_data->accel_poll_ms));
		atomic_set(&client_data->accel_en, 1);
	} else {
		atomic_set(&client_data->accel_en, 0);
		cancel_delayed_work_sync(&client_data->accel_poll_work);
		ret = smi130_set_acc_op_mode(client_data, 2);
		if (ret) {
			dev_err(client_data->dev,
				"Fail to disable accel engine ret=%d\n", ret);
			ret = -EBUSY;
			goto exit;
		}
	}
exit:
	return ret;
}
static int smi130_accel_set_poll_delay(struct smi_client_data *client_data,
					unsigned long delay)
{
	dev_info(client_data->dev,
		"smi130_accel_set_poll_delay delay_ms=%ld\n", delay);
	if (delay < SMI130_ACCEL_MIN_POLL_INTERVAL_MS)
		delay = SMI130_ACCEL_MIN_POLL_INTERVAL_MS;
	if (delay > SMI130_ACCEL_MAX_POLL_INTERVAL_MS)
		delay = SMI130_ACCEL_MAX_POLL_INTERVAL_MS;
	client_data->accel_poll_ms = delay;
	if (!atomic_read(&client_data->accel_en))
		goto exit;
	cancel_delayed_work_sync(&client_data->accel_poll_work);
	queue_delayed_work(client_data->data_wq,
			&client_data->accel_poll_work,
			msecs_to_jiffies(client_data->accel_poll_ms));
exit:
	return 0;
}
static int smi130_gyro_set_enable(
	struct smi_client_data *client_data, bool enable)
{
	int ret = 0;
	dev_notice(client_data->dev,
		"smi130_gyro_set_enable enable=%d\n", enable);
	if (enable) {
		ret = smi130_set_gyro_op_mode(client_data, 0);
		if (ret) {
			dev_err(client_data->dev,
				"Fail to enable gyro engine ret=%d\n", ret);
			ret = -EBUSY;
			goto exit;
		}
		queue_delayed_work(client_data->data_wq,
				&client_data->gyro_poll_work,
				msecs_to_jiffies(client_data->gyro_poll_ms));
		atomic_set(&client_data->gyro_en, 1);
	} else {
		atomic_set(&client_data->gyro_en, 0);
		cancel_delayed_work_sync(&client_data->gyro_poll_work);
		ret = smi130_set_gyro_op_mode(client_data, 2);
		if (ret) {
			dev_err(client_data->dev,
				"Fail to disable accel engine ret=%d\n", ret);
			ret = -EBUSY;
			goto exit;
		}
	}
exit:
	return ret;
}
static int smi130_gyro_set_poll_delay(struct smi_client_data *client_data,
					unsigned long delay)
{
	dev_info(client_data->dev,
		"smi130_accel_set_poll_delay delay_ms=%ld\n", delay);
	if (delay < SMI130_GYRO_MIN_POLL_INTERVAL_MS)
		delay = SMI130_GYRO_MIN_POLL_INTERVAL_MS;
	if (delay > SMI130_GYRO_MAX_POLL_INTERVAL_MS)
		delay = SMI130_GYRO_MAX_POLL_INTERVAL_MS;
	client_data->gyro_poll_ms = delay;
	if (!atomic_read(&client_data->gyro_en))
		goto exit;
	cancel_delayed_work_sync(&client_data->gyro_poll_work);
	queue_delayed_work(client_data->data_wq,
			&client_data->gyro_poll_work,
			msecs_to_jiffies(client_data->gyro_poll_ms));
exit:
	return 0;
}
static int smi130_accel_cdev_enable(struct sensors_classdev *sensors_cdev,
			unsigned int enable)
{
	struct smi_client_data *sensor = container_of(sensors_cdev,
			struct smi_client_data, accel_cdev);
	return smi130_accel_set_enable(sensor, enable);
}
static int smi130_accel_cdev_poll_delay(struct sensors_classdev *sensors_cdev,
			unsigned int delay_ms)
{
	struct smi_client_data *sensor = container_of(sensors_cdev,
			struct smi_client_data, accel_cdev);

	return smi130_accel_set_poll_delay(sensor, delay_ms);
}

static int smi130_gyro_cdev_enable(struct sensors_classdev *sensors_cdev,
			unsigned int enable)
{
	struct smi_client_data *sensor = container_of(sensors_cdev,
			struct smi_client_data, gyro_cdev);

	return smi130_gyro_set_enable(sensor, enable);
}

static int smi130_gyro_cdev_poll_delay(struct sensors_classdev *sensors_cdev,
			unsigned int delay_ms)
{
	struct smi_client_data *sensor = container_of(sensors_cdev,
			struct smi_client_data, gyro_cdev);

	return	smi130_gyro_set_poll_delay(sensor, delay_ms);
}
#endif

int smi_probe(struct smi_client_data *client_data, struct device *dev)
{
	int err = 0;
#ifdef SMI130_MAG_INTERFACE_SUPPORT
	u8 mag_dev_addr;
	u8 mag_urst_len;
	u8 mag_op_mode;
#endif
	/* check chip id */
	err = smi_check_chip_id(client_data);
	if (err)
		goto exit_err_clean;

	dev_set_drvdata(dev, client_data);
	client_data->dev = dev;

	mutex_init(&client_data->mutex_enable);
	mutex_init(&client_data->mutex_op_mode);

	/* input device init */
	err = smi_input_init(client_data);
	if (err < 0)
		goto exit_err_clean;

	/* sysfs node creation */
	err = sysfs_create_group(&client_data->input->dev.kobj,
			&smi130_attribute_group);

	if (err < 0)
		goto exit_err_sysfs;

	if (NULL != dev->platform_data) {
		client_data->bosch_pd = kzalloc(sizeof(*client_data->bosch_pd),
				GFP_KERNEL);

		if (NULL != client_data->bosch_pd) {
			memcpy(client_data->bosch_pd, dev->platform_data,
					sizeof(*client_data->bosch_pd));
			dev_notice(dev, "%s sensor driver set place: p%d\n",
					client_data->bosch_pd->name,
					client_data->bosch_pd->place);
		}
	}

	if (NULL != client_data->bosch_pd) {
			memcpy(client_data->bosch_pd, dev->platform_data,
					sizeof(*client_data->bosch_pd));
			dev_notice(dev, "%s sensor driver set place: p%d\n",
					client_data->bosch_pd->name,
					client_data->bosch_pd->place);
		}


	/* workqueue init */
	INIT_DELAYED_WORK(&client_data->work, smi_work_func);
	atomic_set(&client_data->delay, SMI_DELAY_DEFAULT);
	atomic_set(&client_data->wkqueue_en, 0);

	/* h/w init */
	client_data->device.delay_msec = smi_delay;
	err = SMI_CALL_API(init)(&client_data->device);

	smi_dump_reg(client_data);

	/*power on detected*/
	/*or softrest(cmd 0xB6) */
	/*fatal err check*/
	/*soft reset*/
	err += SMI_CALL_API(set_command_register)(CMD_RESET_USER_REG);
	smi_delay(3);
	if (err)
		dev_err(dev, "Failed soft reset, er=%d", err);
	/*usr data config page*/
	err += SMI_CALL_API(set_target_page)(USER_DAT_CFG_PAGE);
	if (err)
		dev_err(dev, "Failed cffg page, er=%d", err);
	err += smi_get_err_status(client_data);
	if (err) {
		dev_err(dev, "Failed to smi16x init!err_st=0x%x\n",
				client_data->err_st.err_st_all);
		goto exit_err_sysfs;
	}

#ifdef SMI130_MAG_INTERFACE_SUPPORT
	err += smi130_set_command_register(MAG_MODE_NORMAL);
	smi_delay(2);
	err += smi130_get_mag_power_mode_stat(&mag_op_mode);
	smi_delay(2);
	err += SMI_CALL_API(get_i2c_device_addr)(&mag_dev_addr);
	smi_delay(2);
#if defined(SMI130_AKM09912_SUPPORT)
	err += SMI_CALL_API(set_i2c_device_addr)(SMI130_AKM09912_I2C_ADDRESS);
	smi130_bosch_akm_mag_interface_init(SMI130_AKM09912_I2C_ADDRESS);
#else
	err += SMI_CALL_API(set_i2c_device_addr)(
		SMI130_AUX_BMM150_I2C_ADDRESS);
	smi130_bmm150_mag_interface_init();
#endif

	err += smi130_set_mag_burst(3);
	err += smi130_get_mag_burst(&mag_urst_len);
	if (err)
		dev_err(client_data->dev, "Failed cffg mag, er=%d", err);
	dev_info(client_data->dev,
		"SMI130 mag_urst_len:%d, mag_add:0x%x, mag_op_mode:%d\n",
		mag_urst_len, mag_dev_addr, mag_op_mode);
#endif
	if (err < 0)
		goto exit_err_sysfs;


#if defined(SMI130_ENABLE_INT1) || defined(SMI130_ENABLE_INT2)
		/*wake_lock_init(&client_data->wakelock,
			WAKE_LOCK_SUSPEND, "smi130");*/
		client_data->gpio_pin = of_get_named_gpio_flags(dev->of_node,
					"smi,gpio_irq", 0, NULL);
		dev_info(client_data->dev, "SMI130 qpio number:%d\n",
					client_data->gpio_pin);
		err += gpio_request_one(client_data->gpio_pin,
					GPIOF_IN, "smi130_int");
		err += gpio_direction_input(client_data->gpio_pin);
		client_data->IRQ = gpio_to_irq(client_data->gpio_pin);
		if (err) {
			dev_err(client_data->dev,
				"can not request gpio to irq number\n");
			client_data->gpio_pin = 0;
		}
		INIT_DELAYED_WORK(&client_data->delay_work_sig,
			smi130_delay_sigmo_work_func);
#ifdef SMI130_ENABLE_INT1
		/* maps interrupt to INT1/InT2 pin */
		SMI_CALL_API(set_intr_any_motion)(SMI_INT0, ENABLE);
		SMI_CALL_API(set_intr_fifo_wm)(SMI_INT0, ENABLE);
		SMI_CALL_API(set_intr_data_rdy)(SMI_INT0, ENABLE);

		/*Set interrupt trige level way */
		SMI_CALL_API(set_intr_edge_ctrl)(SMI_INT0, SMI_INT_LEVEL);
		smi130_set_intr_level(SMI_INT0, 1);
		/*set interrupt latch temporary, 5 ms*/
		/*smi130_set_latch_int(5);*/

		SMI_CALL_API(set_output_enable)(
		SMI130_INTR1_OUTPUT_ENABLE, ENABLE);
		sigmotion_init_interrupts(SMI130_MAP_INTR1);
		SMI_CALL_API(map_step_detector_intr)(SMI130_MAP_INTR1);
		/*close step_detector in init function*/
		SMI_CALL_API(set_step_detector_enable)(0);
#endif

#ifdef SMI130_ENABLE_INT2
		/* maps interrupt to INT1/InT2 pin */
		SMI_CALL_API(set_intr_any_motion)(SMI_INT1, ENABLE);
		SMI_CALL_API(set_intr_fifo_wm)(SMI_INT1, ENABLE);
		SMI_CALL_API(set_intr_data_rdy)(SMI_INT1, ENABLE);

		/*Set interrupt trige level way */
		SMI_CALL_API(set_intr_edge_ctrl)(SMI_INT1, SMI_INT_LEVEL);
		smi130_set_intr_level(SMI_INT1, 1);
		/*set interrupt latch temporary, 5 ms*/
		/*smi130_set_latch_int(5);*/

		SMI_CALL_API(set_output_enable)(
		SMI130_INTR2_OUTPUT_ENABLE, ENABLE);
		sigmotion_init_interrupts(SMI130_MAP_INTR2);
		SMI_CALL_API(map_step_detector_intr)(SMI130_MAP_INTR2);
		/*close step_detector in init function*/
		SMI_CALL_API(set_step_detector_enable)(0);
#endif
		err = request_irq(client_data->IRQ, smi_irq_handler,
				IRQF_TRIGGER_RISING, "smi130", client_data);
		if (err)
			dev_err(client_data->dev, "could not request irq\n");

		INIT_WORK(&client_data->irq_work, smi_irq_work_func);
#endif

	client_data->selftest = 0;

	client_data->fifo_data_sel = 0;
	#if defined(CONFIG_USE_QUALCOMM_HAL)
	SMI_CALL_API(set_accel_output_data_rate)(9);/*defalut odr 200HZ*/
	SMI_CALL_API(set_gyro_output_data_rate)(9);/*defalut odr 200HZ*/
	#endif
	SMI_CALL_API(get_accel_output_data_rate)(&client_data->odr.acc_odr);
	SMI_CALL_API(get_gyro_output_data_rate)(&client_data->odr.gyro_odr);
	SMI_CALL_API(get_mag_output_data_rate)(&client_data->odr.mag_odr);
	SMI_CALL_API(set_fifo_time_enable)(1);
	SMI_CALL_API(get_accel_range)(&client_data->range.acc_range);
	SMI_CALL_API(get_gyro_range)(&client_data->range.gyro_range);
	/* now it's power on which is considered as resuming from suspend */
	
	/* gyro input device init */
	err = smi_gyro_input_init(client_data);
	#if defined(CONFIG_USE_QUALCOMM_HAL)
	/* gyro input device init */
	err = smi_gyro_input_init(client_data);
	if (err < 0)
		goto exit_err_clean;
	client_data->accel_poll_ms = SMI130_ACCEL_DEFAULT_POLL_INTERVAL_MS;
	client_data->gyro_poll_ms = SMI130_GYRO_DEFAULT_POLL_INTERVAL_MS;
	client_data->data_wq = create_freezable_workqueue("smi130_data_work");
	if (!client_data->data_wq) {
		dev_err(dev, "Cannot create workqueue!\n");
		goto exit_err_clean;
	}
	INIT_DELAYED_WORK(&client_data->accel_poll_work,
		smi130_accel_work_fn);
	client_data->accel_cdev = smi130_accel_cdev;
	client_data->accel_cdev.delay_msec = client_data->accel_poll_ms;
	client_data->accel_cdev.sensors_enable = smi130_accel_cdev_enable;
	client_data->accel_cdev.sensors_poll_delay =
	smi130_accel_cdev_poll_delay;
	err = sensors_classdev_register(dev, &client_data->accel_cdev);
	if (err) {
		dev_err(dev,
			"create accel class device file failed!\n");
		goto exit_err_clean;
	}
	INIT_DELAYED_WORK(&client_data->gyro_poll_work, smi130_gyro_work_fn);
	client_data->gyro_cdev = smi130_gyro_cdev;
	client_data->gyro_cdev.delay_msec = client_data->gyro_poll_ms;
	client_data->gyro_cdev.sensors_enable = smi130_gyro_cdev_enable;
	client_data->gyro_cdev.sensors_poll_delay = smi130_gyro_cdev_poll_delay;
	err = sensors_classdev_register(dev, &client_data->gyro_cdev);
	if (err) {
		dev_err(dev,
			"create accel class device file failed!\n");
		goto exit_err_clean;
	}
	#endif
	/* set sensor PMU into suspend power mode for all */
	if (smi_pmu_set_suspend(client_data) < 0) {
		dev_err(dev, "Failed to set SMI130 to suspend power mode\n");
		goto exit_err_sysfs;
	}
	/*enable the data ready interrupt*/
	SMI_CALL_API(set_intr_enable_1)(SMI130_DATA_RDY_ENABLE, 1);
	dev_notice(dev, "sensor_time:%d, %d, %d",
		sensortime_duration_tbl[0].ts_delat,
		sensortime_duration_tbl[0].ts_duration_lsb,
		sensortime_duration_tbl[0].ts_duration_us);
	dev_notice(dev, "sensor %s probed successfully", SENSOR_NAME);

	return 0;

exit_err_sysfs:
	if (err)
		smi_input_destroy(client_data);

exit_err_clean:
	if (err) {
		if (client_data != NULL) {
			if (NULL != client_data->bosch_pd) {
				kfree(client_data->bosch_pd);
				client_data->bosch_pd = NULL;
			}
		}
	}
	return err;
}
EXPORT_SYMBOL(smi_probe);

/*!
 * @brief remove smi client
 *
 * @param dev the pointer of device
 *
 * @return zero
 * @retval zero
*/
int smi_remove(struct device *dev)
{
	int err = 0;
	struct smi_client_data *client_data = dev_get_drvdata(dev);

	if (NULL != client_data) {
#ifdef CONFIG_HAS_EARLYSUSPEND
		unregister_early_suspend(&client_data->early_suspend_handler);
#endif
		mutex_lock(&client_data->mutex_enable);
		if (SMI_ACC_PM_NORMAL == client_data->pw.acc_pm ||
			SMI_GYRO_PM_NORMAL == client_data->pw.gyro_pm ||
				SMI_MAG_PM_NORMAL == client_data->pw.mag_pm) {
			cancel_delayed_work_sync(&client_data->work);
		}
		mutex_unlock(&client_data->mutex_enable);

		err = smi_pmu_set_suspend(client_data);

		smi_delay(5);

		sysfs_remove_group(&client_data->input->dev.kobj,
				&smi130_attribute_group);
		smi_input_destroy(client_data);

		if (NULL != client_data->bosch_pd) {
			kfree(client_data->bosch_pd);
			client_data->bosch_pd = NULL;
		}
		kfree(client_data);
	}

	return err;
}
EXPORT_SYMBOL(smi_remove);

static int smi_post_resume(struct smi_client_data *client_data)
{
	int err = 0;

	mutex_lock(&client_data->mutex_enable);

	if (atomic_read(&client_data->wkqueue_en) == 1) {
		smi130_set_acc_op_mode(client_data, SMI_ACC_PM_NORMAL);
		schedule_delayed_work(&client_data->work,
				msecs_to_jiffies(
					atomic_read(&client_data->delay)));
	}
	mutex_unlock(&client_data->mutex_enable);

	return err;
}


int smi_suspend(struct device *dev)
{
	int err = 0;
	struct smi_client_data *client_data = dev_get_drvdata(dev);
	unsigned char stc_enable;
	unsigned char std_enable;
	dev_err(client_data->dev, "smi suspend function entrance");

	atomic_set(&client_data->in_suspend, 1);
	if (atomic_read(&client_data->wkqueue_en) == 1) {
		smi130_set_acc_op_mode(client_data, SMI_ACC_PM_SUSPEND);
		cancel_delayed_work_sync(&client_data->work);
	}
	SMI_CALL_API(get_step_counter_enable)(&stc_enable);
	SMI_CALL_API(get_step_detector_enable)(&std_enable);
	if (client_data->pw.acc_pm != SMI_ACC_PM_SUSPEND &&
		(stc_enable != 1) && (std_enable != 1) &&
		(client_data->sig_flag != 1)) {
		err += SMI_CALL_API(set_command_register)
				(smi_pmu_cmd_acc_arr[SMI_ACC_PM_SUSPEND]);
		smi_delay(3);
	}
	if (client_data->pw.gyro_pm != SMI_GYRO_PM_SUSPEND) {
		err += SMI_CALL_API(set_command_register)
				(smi_pmu_cmd_gyro_arr[SMI_GYRO_PM_SUSPEND]);
		smi_delay(3);
	}

	if (client_data->pw.mag_pm != SMI_MAG_PM_SUSPEND) {
#if defined(SMI130_AKM09912_SUPPORT)
		err += smi130_set_bosch_akm_and_secondary_if_powermode(
		SMI130_MAG_SUSPEND_MODE);
#else
		err += smi130_set_bmm150_mag_and_secondary_if_power_mode(
		SMI130_MAG_SUSPEND_MODE);
#endif
		smi_delay(3);
	}

	return err;
}
EXPORT_SYMBOL(smi_suspend);

int smi_resume(struct device *dev)
{
	int err = 0;
	struct smi_client_data *client_data = dev_get_drvdata(dev);
	atomic_set(&client_data->in_suspend, 0);
	if (client_data->pw.acc_pm != SMI_ACC_PM_SUSPEND) {
		err += SMI_CALL_API(set_command_register)
				(smi_pmu_cmd_acc_arr[SMI_ACC_PM_NORMAL]);
		smi_delay(3);
	}
	if (client_data->pw.gyro_pm != SMI_GYRO_PM_SUSPEND) {
		err += SMI_CALL_API(set_command_register)
				(smi_pmu_cmd_gyro_arr[SMI_GYRO_PM_NORMAL]);
		smi_delay(3);
	}

	if (client_data->pw.mag_pm != SMI_MAG_PM_SUSPEND) {
#if defined(SMI130_AKM09912_SUPPORT)
		err += smi130_set_bosch_akm_and_secondary_if_powermode
					(SMI130_MAG_FORCE_MODE);
#else
		err += smi130_set_bmm150_mag_and_secondary_if_power_mode
					(SMI130_MAG_FORCE_MODE);
#endif
		smi_delay(3);
	}
	/* post resume operation */
	err += smi_post_resume(client_data);

	return err;
}
EXPORT_SYMBOL(smi_resume);

