Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit cfd9484c authored by Puneet Yatnal's avatar Puneet Yatnal
Browse files

driver: input: sensors: SMI130 early buffer implemented



This patch allows to buffer SMI130 accel and gyro samples from driver
up to time till user space services are up and running
(or upto nth second). Buffered samples can be retrived at any time via
input subsystem by writing to below sysfs entry.
echo 1 > /sys/class/input/input*/read_acc_boot_sample
echo 1 > /sys/class/input/input*/read_gyro_boot_sample
Use config option to enable buffering feature.

Change-Id: I25109fa17bb0bea900b07c70adcb46fad34cd5c6
Signed-off-by: default avatarPuneet Yatnal <puneet@codeaurora.org>
parent 6fde3c2d
Loading
Loading
Loading
Loading
+8 −0
Original line number Diff line number Diff line
@@ -126,4 +126,12 @@ depends on SENSORS_SMI_ACC4XY
	help
	 If you say yes here, you get support for Bosch Sensortec's
	 sensor driver of SMI_ACC4XY with mag sensor support.

config ENABLE_SMI_ACC_GYRO_BUFFERING
	bool "Enable accel & gyro  boot time sensor sample buffering"
	depends on SMI130
	help
	 Say Y here if you want to buffer boot time sensor
	 samples for ASM330 accelerometer and gyroscope

endif
+276 −0
Original line number Diff line number Diff line
@@ -1528,6 +1528,16 @@ struct bosch_sensor_data {
	};
};

#ifdef CONFIG_ENABLE_SMI_ACC_GYRO_BUFFERING
#define SMI_ACC_MAXSAMPLE        4000
#define G_MAX                    23920640
struct smi_acc_sample {
	int xyz[3];
	unsigned int tsec;
	unsigned long long tnsec;
};
#endif

struct smi130_accacc {
	s16 x;
	s16 y;
@@ -1590,6 +1600,16 @@ struct smi130_acc_data {
	struct timer_list	tap_timer;
	int tap_time_period;
#endif
#ifdef CONFIG_ENABLE_SMI_ACC_GYRO_BUFFERING
	bool read_acc_boot_sample;
	int acc_bufsample_cnt;
	bool acc_buffer_smi130_samples;
	struct kmem_cache *smi_acc_cachepool;
	struct smi_acc_sample *smi130_acc_samplist[SMI_ACC_MAXSAMPLE];
	int max_buffer_time;
	struct input_dev *accbuf_dev;
	int report_evt_cnt;
#endif
};

#ifdef CONFIG_HAS_EARLYSUSPEND
@@ -4044,6 +4064,23 @@ static int smi130_acc_read_temperature(struct i2c_client *client,
	return comres;
}

#ifdef CONFIG_ENABLE_SMI_ACC_GYRO_BUFFERING
static inline int smi130_check_acc_early_buff_enable_flag(
		struct smi130_acc_data *client_data)
{
	if (client_data->acc_buffer_smi130_samples == true)
		return 1;
	else
		return 0;
}
#else
static inline int smi130_check_acc_early_buff_enable_flag(
		struct smi130_acc_data *client_data)
{
	return 0;
}
#endif

static ssize_t smi130_acc_enable_int_store(struct device *dev,
		struct device_attribute *attr,
		const char *buf, size_t count)
@@ -5365,6 +5402,10 @@ static ssize_t smi130_acc_range_store(struct device *dev,
	struct i2c_client *client = to_i2c_client(dev);
	struct smi130_acc_data *smi130_acc = i2c_get_clientdata(client);

	error = smi130_check_acc_early_buff_enable_flag(smi130_acc);
	if (error)
		return count;

	error = kstrtoul(buf, 10, &data);
	if (error)
		return error;
@@ -5397,6 +5438,10 @@ static ssize_t smi130_acc_bandwidth_store(struct device *dev,
	struct i2c_client *client = to_i2c_client(dev);
	struct smi130_acc_data *smi130_acc = i2c_get_clientdata(client);

	error = smi130_check_acc_early_buff_enable_flag(smi130_acc);
	if (error)
		return count;

	error = kstrtoul(buf, 10, &data);
	if (error)
		return error;
@@ -5436,6 +5481,10 @@ static ssize_t smi130_acc_mode_store(struct device *dev,
	struct i2c_client *client = to_i2c_client(dev);
	struct smi130_acc_data *smi130_acc = i2c_get_clientdata(client);

	error = smi130_check_acc_early_buff_enable_flag(smi130_acc);
	if (error)
		return count;

	error = kstrtoul(buf, 10, &data);
	if (error)
		return error;
@@ -6432,10 +6481,97 @@ static void smi130_acc_tap_timeout_handle(unsigned long data)
}
#endif

#ifdef CONFIG_ENABLE_SMI_ACC_GYRO_BUFFERING
static int smi_acc_read_bootsampl(struct smi130_acc_data *client_data,
		unsigned long enable_read)
{
	int i = 0;

	if (enable_read) {
		client_data->acc_buffer_smi130_samples = false;
		for (i = 0; i < client_data->acc_bufsample_cnt; i++) {
			if (client_data->debug_level & 0x08)
				PINFO("acc=%d,x=%d,y=%d,z=%d,sec=%d,ns=%lld\n",
				i, client_data->smi130_acc_samplist[i]->xyz[0],
				client_data->smi130_acc_samplist[i]->xyz[1],
				client_data->smi130_acc_samplist[i]->xyz[2],
				client_data->smi130_acc_samplist[i]->tsec,
				client_data->smi130_acc_samplist[i]->tnsec);
			input_report_abs(client_data->accbuf_dev, ABS_X,
				client_data->smi130_acc_samplist[i]->xyz[0]);
			input_report_abs(client_data->accbuf_dev, ABS_Y,
				client_data->smi130_acc_samplist[i]->xyz[1]);
			input_report_abs(client_data->accbuf_dev, ABS_Z,
				client_data->smi130_acc_samplist[i]->xyz[2]);
			input_report_abs(client_data->accbuf_dev, ABS_RX,
				client_data->smi130_acc_samplist[i]->tsec);
			input_report_abs(client_data->accbuf_dev, ABS_RY,
				client_data->smi130_acc_samplist[i]->tnsec);
			input_sync(client_data->accbuf_dev);
		}
	} else {
		/* clean up */
		if (client_data->acc_bufsample_cnt != 0) {
			for (i = 0; i < SMI_ACC_MAXSAMPLE; i++)
				kmem_cache_free(client_data->smi_acc_cachepool,
					client_data->smi130_acc_samplist[i]);
			kmem_cache_destroy(client_data->smi_acc_cachepool);
			client_data->acc_bufsample_cnt = 0;
		}

	}
	/*SYN_CONFIG indicates end of data*/
	input_event(client_data->accbuf_dev, EV_SYN, SYN_CONFIG, 0xFFFFFFFF);
	input_sync(client_data->accbuf_dev);
	if (client_data->debug_level & 0x08)
		PINFO("End of acc samples bufsample_cnt=%d\n",
				client_data->acc_bufsample_cnt);
	return 0;
}
static ssize_t read_acc_boot_sample_show(struct device *dev,
		struct device_attribute *attr,
		char *buf)
{
	struct i2c_client *client = to_i2c_client(dev);
	struct smi130_acc_data *smi130_acc = i2c_get_clientdata(client);

	return snprintf(buf, 16, "%u\n",
			smi130_acc->read_acc_boot_sample);
}

static ssize_t read_acc_boot_sample_store(struct device *dev,
		struct device_attribute *attr,
		const char *buf, size_t count)
{
	int err;
	struct i2c_client *client = to_i2c_client(dev);
	struct smi130_acc_data *smi130_acc = i2c_get_clientdata(client);
	unsigned long enable = 0;

	err = kstrtoul(buf, 10, &enable);
	if (err)
		return err;
	if (enable > 1) {
		PERR("Invalid value of input, input=%ld\n", enable);
		return -EINVAL;
	}
	err = smi_acc_read_bootsampl(smi130_acc, enable);
	if (err)
		return err;

	smi130_acc->read_acc_boot_sample = enable;
	return count;
}
#endif

static DEVICE_ATTR(range, S_IRUGO | S_IWUSR,
		smi130_acc_range_show, smi130_acc_range_store);
static DEVICE_ATTR(bandwidth, S_IRUGO | S_IWUSR,
		smi130_acc_bandwidth_show, smi130_acc_bandwidth_store);
#ifdef CONFIG_ENABLE_SMI_ACC_GYRO_BUFFERING
static DEVICE_ATTR(read_acc_boot_sample, 0644,
		read_acc_boot_sample_show, read_acc_boot_sample_store);
#endif
static DEVICE_ATTR(op_mode, S_IRUGO | S_IWUSR,
		smi130_acc_mode_show, smi130_acc_mode_store);
static DEVICE_ATTR(value, S_IRUSR,
@@ -6555,6 +6691,9 @@ static DEVICE_ATTR(en_double_tap, S_IRUGO|S_IWUSR|S_IWGRP|S_IWOTH,
static struct attribute *smi130_acc_attributes[] = {
	&dev_attr_range.attr,
	&dev_attr_bandwidth.attr,
#ifdef CONFIG_ENABLE_SMI_ACC_GYRO_BUFFERING
	&dev_attr_read_acc_boot_sample.attr,
#endif
	&dev_attr_op_mode.attr,
	&dev_attr_value.attr,
	&dev_attr_value_cache.attr,
@@ -6752,6 +6891,136 @@ static void smi130_acc_slope_interrupt_handle(struct smi130_acc_data *smi130_acc
	}
}
#endif
#ifdef CONFIG_ENABLE_SMI_ACC_GYRO_BUFFERING
static void store_acc_boot_sample(struct smi130_acc_data *client_data,
				int x, int y, int z, struct timespec ts)
{
	if (false == client_data->acc_buffer_smi130_samples)
		return;
	if (ts.tv_sec <  client_data->max_buffer_time) {
		if (client_data->acc_bufsample_cnt < SMI_ACC_MAXSAMPLE) {
			client_data->smi130_acc_samplist[client_data->
				acc_bufsample_cnt]->xyz[0] = x;
			client_data->smi130_acc_samplist[client_data->
				acc_bufsample_cnt]->xyz[1] = y;
			client_data->smi130_acc_samplist[client_data->
				acc_bufsample_cnt]->xyz[2] = z;
			client_data->smi130_acc_samplist[client_data->
				acc_bufsample_cnt]->tsec = ts.tv_sec;
			client_data->smi130_acc_samplist[client_data->
				acc_bufsample_cnt]->tnsec = ts.tv_nsec;
			client_data->acc_bufsample_cnt++;
		}
	} else {
		PINFO("End of ACC buffering %d\n",
				client_data->acc_bufsample_cnt);
		client_data->acc_buffer_smi130_samples = false;
	}
}
#else
static void store_acc_boot_sample(struct smi130_acc_data *client_data,
		int x, int y, int z, struct timespec ts)
{
}
#endif

#ifdef CONFIG_ENABLE_SMI_ACC_GYRO_BUFFERING
static int smi130_acc_early_buff_init(struct i2c_client *client,
			struct smi130_acc_data *client_data)
{
	int i = 0, err = 0;

	client_data->acc_bufsample_cnt = 0;
	client_data->report_evt_cnt = 5;
	client_data->max_buffer_time = 40;

	client_data->smi_acc_cachepool = kmem_cache_create("acc_sensor_sample",
			sizeof(struct smi_acc_sample),
			0,
			SLAB_HWCACHE_ALIGN, NULL);
	if (!client_data->smi_acc_cachepool) {
		PERR("smi_acc_cachepool cache create failed\n");
		err = -ENOMEM;
		goto clean_exit1;
	}
	for (i = 0; i < SMI_ACC_MAXSAMPLE; i++) {
		client_data->smi130_acc_samplist[i] =
			kmem_cache_alloc(client_data->smi_acc_cachepool,
					GFP_KERNEL);
		if (!client_data->smi130_acc_samplist[i]) {
			err = -ENOMEM;
			goto clean_exit2;
		}
	}

	client_data->accbuf_dev = input_allocate_device();
	if (!client_data->accbuf_dev) {
		err = -ENOMEM;
		PERR("input device allocation failed\n");
		goto clean_exit3;
	}
	client_data->accbuf_dev->name = "smi130_accbuf";
	client_data->accbuf_dev->id.bustype = BUS_I2C;
	input_set_events_per_packet(client_data->accbuf_dev,
			client_data->report_evt_cnt * SMI_ACC_MAXSAMPLE);
	set_bit(EV_ABS, client_data->accbuf_dev->evbit);
	input_set_abs_params(client_data->accbuf_dev, ABS_X,
			-G_MAX, G_MAX, 0, 0);
	input_set_abs_params(client_data->accbuf_dev, ABS_Y,
			-G_MAX, G_MAX, 0, 0);
	input_set_abs_params(client_data->accbuf_dev, ABS_Z,
			-G_MAX, G_MAX, 0, 0);
	input_set_abs_params(client_data->accbuf_dev, ABS_RX,
			-G_MAX, G_MAX, 0, 0);
	input_set_abs_params(client_data->accbuf_dev, ABS_RY,
			-G_MAX, G_MAX, 0, 0);
	err = input_register_device(client_data->accbuf_dev);
	if (err) {
		PERR("unable to register input device %s\n",
				client_data->accbuf_dev->name);
		goto clean_exit3;
	}

	client_data->acc_buffer_smi130_samples = true;

	smi130_acc_set_mode(client, SMI_ACC2X2_MODE_NORMAL, 1);
	smi130_acc_set_bandwidth(client, SMI_ACC2X2_BW_62_50HZ);
	smi130_acc_set_range(client, SMI_ACC2X2_RANGE_2G);

	return 1;

clean_exit3:
	input_free_device(client_data->accbuf_dev);
clean_exit2:
	for (i = 0; i < SMI_ACC_MAXSAMPLE; i++)
		kmem_cache_free(client_data->smi_acc_cachepool,
				client_data->smi130_acc_samplist[i]);
clean_exit1:
	kmem_cache_destroy(client_data->smi_acc_cachepool);
	return 0;
}

static void smi130_acc_input_cleanup(struct smi130_acc_data *client_data)
{
	int i = 0;

	input_unregister_device(client_data->accbuf_dev);
	input_free_device(client_data->accbuf_dev);
	for (i = 0; i < SMI_ACC_MAXSAMPLE; i++)
		kmem_cache_free(client_data->smi_acc_cachepool,
				client_data->smi130_acc_samplist[i]);
	kmem_cache_destroy(client_data->smi_acc_cachepool);
}
#else
static int smi130_acc_early_buff_init(struct i2c_client *client,
			struct smi130_acc_data *client_data)
{
	return 1;
}
static void smi130_acc_input_cleanup(struct smi130_acc_data *client_data)
{
}
#endif

static void smi130_acc_irq_work_func(struct work_struct *work)
{
@@ -6800,6 +7069,7 @@ static void smi130_acc_irq_work_func(struct work_struct *work)
		smi130_acc->value = acc;
		mutex_unlock(&smi130_acc->value_mutex);
	}
	store_acc_boot_sample(smi130_acc, acc.x, acc.y, acc.z, ts);
#endif

	smi130_acc_get_interruptstatus1(smi130_acc->smi130_acc_client, &status);
@@ -7268,6 +7538,11 @@ static int smi130_acc_probe(struct i2c_client *client,
	PDEBUG("data->IRQ = %d", data->IRQ);
	err = request_irq(data->IRQ, smi130_acc_irq_handler, IRQF_TRIGGER_RISING,
			"smi130_acc", data);

	err = smi130_acc_early_buff_init(client, data);
	if (!err)
		goto exit;

	PINFO("SMI130_ACC driver probe successfully");

	return 0;
@@ -7379,6 +7654,7 @@ static int smi130_acc_remove(struct i2c_client *client)
	if (NULL == data)
		return 0;

	smi130_acc_input_cleanup(data);
	smi130_acc_set_enable(&client->dev, 0);
#ifdef CONFIG_HAS_EARLYSUSPEND
	unregister_early_suspend(&data->early_suspend);
+306 −3
Original line number Diff line number Diff line
@@ -249,6 +249,16 @@ struct bosch_sensor_data {
	};
};

#ifdef CONFIG_ENABLE_SMI_ACC_GYRO_BUFFERING
#define SMI_GYRO_MAXSAMPLE       4000
#define G_MAX                    23920640
struct smi_gyro_sample {
	int xyz[3];
	unsigned int tsec;
	unsigned long long tnsec;
};
#endif

struct smi_gyro_client_data {
	struct smi130_gyro_t device;
	struct i2c_client *client;
@@ -281,6 +291,16 @@ struct smi_gyro_client_data {
	uint8_t gpio_pin;
	int16_t IRQ;
	struct work_struct irq_work;
#ifdef CONFIG_ENABLE_SMI_ACC_GYRO_BUFFERING
	bool read_gyro_boot_sample;
	int gyro_bufsample_cnt;
	bool gyro_buffer_smi130_samples;
	struct kmem_cache *smi_gyro_cachepool;
	struct smi_gyro_sample *smi130_gyro_samplist[SMI_GYRO_MAXSAMPLE];
	int max_buffer_time;
	struct input_dev *gyrobuf_dev;
	int report_evt_cnt;
#endif
};

static struct i2c_client *smi_gyro_client;
@@ -831,6 +851,23 @@ static ssize_t smi_gyro_show_chip_id(struct device *dev,
	return snprintf(buf, 16, "%d\n", SENSOR_CHIP_ID_SMI_GYRO);
}

#ifdef CONFIG_ENABLE_SMI_ACC_GYRO_BUFFERING
static inline int smi130_check_gyro_early_buff_enable_flag(
		struct smi_gyro_client_data *client_data)
{
	if (client_data->gyro_buffer_smi130_samples == true)
		return 1;
	else
		return 0;
}
#else
static inline int smi130_check_gyro_early_buff_enable_flag(
		struct smi_gyro_client_data *client_data)
{
	return 0;
}
#endif

static ssize_t smi_gyro_show_op_mode(struct device *dev,
		struct device_attribute *attr, char *buf)
{
@@ -858,6 +895,10 @@ static ssize_t smi_gyro_store_op_mode(struct device *dev,

	long op_mode;

	err = smi130_check_gyro_early_buff_enable_flag(client_data);
	if (err)
		return count;

	err = kstrtoul(buf, 10, &op_mode);
	if (err)
		return err;
@@ -911,6 +952,13 @@ static ssize_t smi_gyro_store_range(struct device *dev,
{
	int err;
	unsigned long range;
	struct input_dev *input = to_input_dev(dev);
	struct smi_gyro_client_data *client_data = input_get_drvdata(input);

	err = smi130_check_gyro_early_buff_enable_flag(client_data);
	if (err)
		return count;

	err = kstrtoul(buf, 10, &range);
	if (err)
		return err;
@@ -952,6 +1000,11 @@ static ssize_t smi_gyro_store_bandwidth(struct device *dev,
	struct smi_gyro_client_data *client_data = input_get_drvdata(input);
	unsigned long bandwidth;
	u8 op_mode = 0xff;

	err = smi130_check_gyro_early_buff_enable_flag(client_data);
	if (err)
		return count;

	err = kstrtoul(buf, 10, &bandwidth);
	if (err)
		return err;
@@ -1445,8 +1498,96 @@ static ssize_t smi130_gyro_driver_version_show(struct device *dev
			DRIVER_VERSION);
	return ret;
}

#ifdef CONFIG_ENABLE_SMI_ACC_GYRO_BUFFERING
static int smi_gyro_read_bootsampl(struct smi_gyro_client_data *client_data,
		unsigned long enable_read)
{
	int i = 0;

	if (enable_read) {
		client_data->gyro_buffer_smi130_samples = false;
		for (i = 0; i < client_data->gyro_bufsample_cnt; i++) {
			if (client_data->debug_level & 0x08)
				PINFO("gyro=%d,x=%d,y=%d,z=%d,sec=%d,ns=%lld\n",
				i, client_data->smi130_gyro_samplist[i]->xyz[0],
				client_data->smi130_gyro_samplist[i]->xyz[1],
				client_data->smi130_gyro_samplist[i]->xyz[2],
				client_data->smi130_gyro_samplist[i]->tsec,
				client_data->smi130_gyro_samplist[i]->tnsec);
			input_report_abs(client_data->gyrobuf_dev, ABS_X,
				client_data->smi130_gyro_samplist[i]->xyz[0]);
			input_report_abs(client_data->gyrobuf_dev, ABS_Y,
				client_data->smi130_gyro_samplist[i]->xyz[1]);
			input_report_abs(client_data->gyrobuf_dev, ABS_Z,
				client_data->smi130_gyro_samplist[i]->xyz[2]);
			input_report_abs(client_data->gyrobuf_dev, ABS_RX,
				client_data->smi130_gyro_samplist[i]->tsec);
			input_report_abs(client_data->gyrobuf_dev, ABS_RY,
				client_data->smi130_gyro_samplist[i]->tnsec);
			input_sync(client_data->gyrobuf_dev);
		}
	} else {
		/* clean up */
		if (client_data->gyro_bufsample_cnt != 0) {
			for (i = 0; i < SMI_GYRO_MAXSAMPLE; i++)
				kmem_cache_free(client_data->smi_gyro_cachepool,
					client_data->smi130_gyro_samplist[i]);
			kmem_cache_destroy(client_data->smi_gyro_cachepool);
			client_data->gyro_bufsample_cnt = 0;
		}

	}
	/*SYN_CONFIG indicates end of data*/
	input_event(client_data->gyrobuf_dev, EV_SYN, SYN_CONFIG, 0xFFFFFFFF);
	input_sync(client_data->gyrobuf_dev);
	if (client_data->debug_level & 0x08)
		PINFO("End of gyro samples bufsample_cnt=%d\n",
				client_data->gyro_bufsample_cnt);
	return 0;
}
static ssize_t read_gyro_boot_sample_show(struct device *dev,
		struct device_attribute *attr,
		char *buf)
{
	struct input_dev *input = to_input_dev(dev);
	struct smi_gyro_client_data *client_data = input_get_drvdata(input);

	return snprintf(buf, 16, "%u\n",
			client_data->read_gyro_boot_sample);
}
static ssize_t read_gyro_boot_sample_store(struct device *dev,
		struct device_attribute *attr,
		const char *buf, size_t count)
{
	int err;
	struct input_dev *input = to_input_dev(dev);
	struct smi_gyro_client_data *client_data = input_get_drvdata(input);
	unsigned long enable = 0;

	err = kstrtoul(buf, 10, &enable);
	if (err)
		return err;
	if (enable > 1) {
		PERR("Invalid value of input, input=%ld\n", enable);
		return -EINVAL;
	}
	err = smi_gyro_read_bootsampl(client_data, enable);
	if (err)
		return err;
	client_data->read_gyro_boot_sample = enable;

	return count;
}
#endif


static DEVICE_ATTR(chip_id, S_IRUSR,
		smi_gyro_show_chip_id, NULL);
#ifdef CONFIG_ENABLE_SMI_ACC_GYRO_BUFFERING
static DEVICE_ATTR(read_gyro_boot_sample, 0644,
		read_gyro_boot_sample_show, read_gyro_boot_sample_store);
#endif
static DEVICE_ATTR(op_mode, S_IRUGO | S_IWUSR,
		smi_gyro_show_op_mode, smi_gyro_store_op_mode);
static DEVICE_ATTR(value, S_IRUSR,
@@ -1500,6 +1641,9 @@ static DEVICE_ATTR(fifo_tag, S_IRUGO | S_IWUSR,

static struct attribute *smi_gyro_attributes[] = {
	&dev_attr_chip_id.attr,
#ifdef CONFIG_ENABLE_SMI_ACC_GYRO_BUFFERING
	&dev_attr_read_gyro_boot_sample.attr,
#endif
	&dev_attr_op_mode.attr,
	&dev_attr_value.attr,
	&dev_attr_range.attr,
@@ -1574,6 +1718,159 @@ static void smi_gyro_input_destroy(struct smi_gyro_client_data *client_data)
	input_unregister_device(dev);
	input_free_device(dev);
}
#ifdef CONFIG_ENABLE_SMI_ACC_GYRO_BUFFERING
static void store_gyro_boot_sample(struct smi_gyro_client_data *client_data,
			int x, int y, int z, struct timespec ts)
{
	if (false == client_data->gyro_buffer_smi130_samples)
		return;
	if (ts.tv_sec <  client_data->max_buffer_time) {
		if (client_data->gyro_bufsample_cnt < SMI_GYRO_MAXSAMPLE) {
			client_data->smi130_gyro_samplist[client_data->
				gyro_bufsample_cnt]->xyz[0] = x;
			client_data->smi130_gyro_samplist[client_data->
				gyro_bufsample_cnt]->xyz[1] = y;
			client_data->smi130_gyro_samplist[client_data->
				gyro_bufsample_cnt]->xyz[2] = z;
			client_data->smi130_gyro_samplist[client_data->
				gyro_bufsample_cnt]->tsec = ts.tv_sec;
			client_data->smi130_gyro_samplist[client_data->
				gyro_bufsample_cnt]->tnsec = ts.tv_nsec;
			client_data->gyro_bufsample_cnt++;
		}
	} else {
		PINFO("End of GYRO buffering %d",
				client_data->gyro_bufsample_cnt);
		client_data->gyro_buffer_smi130_samples = false;
	}
}
#else
static void store_gyro_boot_sample(struct smi_gyro_client_data *client_data,
		int x, int y, int z, struct timespec ts)
{
}
#endif


#ifdef CONFIG_ENABLE_SMI_ACC_GYRO_BUFFERING
static int smi130_gyro_early_buff_init(struct smi_gyro_client_data *client_data)
{
	int i = 0, err = 0;

	client_data->gyro_bufsample_cnt = 0;
	client_data->report_evt_cnt = 5;
	client_data->max_buffer_time = 40;

	client_data->smi_gyro_cachepool = kmem_cache_create("gyro_sensor_sample"
			, sizeof(struct smi_gyro_sample), 0,
			SLAB_HWCACHE_ALIGN, NULL);
	if (!client_data->smi_gyro_cachepool) {
		PERR("smi_gyro_cachepool cache create failed\n");
		err = -ENOMEM;
		goto clean_exit1;
	}

	for (i = 0; i < SMI_GYRO_MAXSAMPLE; i++) {
		client_data->smi130_gyro_samplist[i] =
			kmem_cache_alloc(client_data->smi_gyro_cachepool,
					GFP_KERNEL);
		if (!client_data->smi130_gyro_samplist[i]) {
			err = -ENOMEM;
			goto clean_exit2;
		}
	}


	client_data->gyrobuf_dev = input_allocate_device();
	if (!client_data->gyrobuf_dev) {
		err = -ENOMEM;
		PERR("input device allocation failed\n");
		goto clean_exit3;
	}
	client_data->gyrobuf_dev->name = "smi130_gyrobuf";
	client_data->gyrobuf_dev->id.bustype = BUS_I2C;
	input_set_events_per_packet(client_data->gyrobuf_dev,
			client_data->report_evt_cnt * SMI_GYRO_MAXSAMPLE);
	set_bit(EV_ABS, client_data->gyrobuf_dev->evbit);
	input_set_abs_params(client_data->gyrobuf_dev, ABS_X,
			-G_MAX, G_MAX, 0, 0);
	input_set_abs_params(client_data->gyrobuf_dev, ABS_Y,
			-G_MAX, G_MAX, 0, 0);
	input_set_abs_params(client_data->gyrobuf_dev, ABS_Z,
			-G_MAX, G_MAX, 0, 0);
	input_set_abs_params(client_data->gyrobuf_dev, ABS_RX,
			-G_MAX, G_MAX, 0, 0);
	input_set_abs_params(client_data->gyrobuf_dev, ABS_RY,
			-G_MAX, G_MAX, 0, 0);
	err = input_register_device(client_data->gyrobuf_dev);
	if (err) {
		PERR("unable to register input device %s\n",
				client_data->gyrobuf_dev->name);
		goto clean_exit3;
	}

	client_data->gyro_buffer_smi130_samples = true;

	smi130_gyro_set_mode(SMI130_GYRO_MODE_NORMAL);
	smi130_gyro_delay(5);

	smi130_gyro_set_bw(5);
	smi130_gyro_delay(5);

	smi130_gyro_set_range_reg(4);
	smi130_gyro_delay(5);

	smi130_gyro_set_mode(SMI130_GYRO_MODE_NORMAL);
	smi130_gyro_delay(5);

	smi130_gyro_set_range_reg(4);
	smi130_gyro_delay(5);

	smi130_gyro_set_data_en(SMI130_GYRO_ENABLE);

	return 1;

clean_exit3:
	input_free_device(client_data->gyrobuf_dev);
clean_exit2:
	for (i = 0; i < SMI_GYRO_MAXSAMPLE; i++)
		kmem_cache_free(client_data->smi_gyro_cachepool,
				client_data->smi130_gyro_samplist[i]);
clean_exit1:
	kmem_cache_destroy(client_data->smi_gyro_cachepool);
	return 0;
}

static void smi130_gyro_input_cleanup(struct smi_gyro_client_data *client_data)
{
	int i = 0;

	input_unregister_device(client_data->gyrobuf_dev);
	input_free_device(client_data->gyrobuf_dev);
	for (i = 0; i < SMI_GYRO_MAXSAMPLE; i++)
		kmem_cache_free(client_data->smi_gyro_cachepool,
				client_data->smi130_gyro_samplist[i]);
	kmem_cache_destroy(client_data->smi_gyro_cachepool);
}

static int smi130_enable_int1(void)
{
	return smi130_gyro_set_data_en(SMI130_GYRO_DISABLE);
}
#else
static int smi130_gyro_early_buff_init(struct smi_gyro_client_data *client_data)
{
	return 1;
}
static void smi130_gyro_input_cleanup(struct smi_gyro_client_data *client_data)
{
}
static int smi130_enable_int1(void)
{
	return smi130_gyro_set_data_en(SMI130_GYRO_ENABLE);
}
#endif


#if defined(SMI130_GYRO_ENABLE_INT1) || defined(SMI130_GYRO_ENABLE_INT2)
static void smi130_gyro_irq_work_func(struct work_struct *work)
@@ -1598,7 +1895,8 @@ static void smi130_gyro_irq_work_func(struct work_struct *work)
	input_event(client_data->input, EV_MSC,
		MSC_SCAN, gyro_data.dataz);
	input_sync(client_data->input);

	store_gyro_boot_sample(client_data, gyro_data.datax,
			gyro_data.datay, gyro_data.dataz, ts);
}

static irqreturn_t smi_gyro_irq_handler(int irq, void *handle)
@@ -1727,7 +2025,7 @@ static int smi_gyro_probe(struct i2c_client *client, const struct i2c_device_id
	smi130_gyro_delay(5);
	err += smi130_gyro_set_int_data(SMI130_GYRO_INT1_DATA, SMI130_GYRO_ENABLE);
	smi130_gyro_delay(5);
	err += smi130_gyro_set_data_en(SMI130_GYRO_ENABLE);
	err += smi130_enable_int1();
	smi130_gyro_delay(5);
	/*default odr is 100HZ*/
	err += SMI_GYRO_CALL_API(set_bw)(7);
@@ -1786,6 +2084,11 @@ static int smi_gyro_probe(struct i2c_client *client, const struct i2c_device_id
	}
	INIT_WORK(&client_data->irq_work, smi130_gyro_irq_work_func);
#endif

	err = smi130_gyro_early_buff_init(client_data);
	if (!err)
		return err;

	PINFO("sensor %s probed successfully", SENSOR_NAME);

	dev_dbg(&client->dev,
@@ -1926,6 +2229,7 @@ static int smi_gyro_remove(struct i2c_client *client)
#ifdef CONFIG_HAS_EARLYSUSPEND
		unregister_early_suspend(&client_data->early_suspend_handler);
#endif
		smi130_gyro_input_cleanup(client_data);
		mutex_lock(&client_data->mutex_op_mode);
		SMI_GYRO_CALL_API(get_mode)(&op_mode);
		if (SMI_GYRO_VAL_NAME(MODE_NORMAL) == op_mode) {
@@ -1942,7 +2246,6 @@ static int smi_gyro_remove(struct i2c_client *client)
				&smi_gyro_attribute_group);
		smi_gyro_input_destroy(client_data);
		kfree(client_data);

		smi_gyro_client = NULL;
	}