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

Commit ca23a3a8 authored by Bingzhe Cai's avatar Bingzhe Cai
Browse files

input: sensors: use work queue for mma8x5x data polling



Accelerometer mma8x5x driver register polling device for data
polling, but polling device only update polling interval on
new polling cycle, this will cause delay on change polling
interval in some case.

Change-Id: I391dc5507a40e6bfc7e8127a0db89cb685eaf192
Signed-off-by: default avatarBingzhe Cai <bingzhec@codeaurora.org>
parent ce42a34f
Loading
Loading
Loading
Loading
+74 −96
Original line number Diff line number Diff line
@@ -26,8 +26,8 @@
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/i2c.h>
#include <linux/input-polldev.h>
#include <linux/sensors.h>
#include <linux/input.h>
#include <linux/regulator/consumer.h>
#include <linux/of_gpio.h>
#include <linux/irq.h>
@@ -44,8 +44,6 @@
#define POLL_INTERVAL_MAX	10000
#define POLL_INTERVAL		100 /* msecs */

/* if sensor is standby ,set POLL_STOP_TIME to slow down the poll */
#define POLL_STOP_TIME		10000
#define INPUT_FUZZ			32
#define INPUT_FLAT			32
#define INPUT_DATA_DIVIDER	16
@@ -189,7 +187,7 @@ struct mma8x5x_data_axis {
};
struct mma8x5x_data {
	struct i2c_client *client;
	struct input_polled_dev *poll_dev;
	struct delayed_work dwork;
	struct input_dev *idev;
	struct mutex data_lock;
	struct sensors_classdev cdev;
@@ -229,7 +227,6 @@ static int mma8x5x_position_setting[8][3][3] = {
	{{ 0,  1,  0}, { 1,  0,	0}, {0, 0,  -1} },
	{{ 1,  0,  0}, { 0, -1,	0}, {0, 0,  -1} },
};
static struct mma8x5x_data *drv_data;
static int mma8x5x_config_regulator(struct i2c_client *client, bool on)
{
	int rc = 0, i;
@@ -487,32 +484,27 @@ static int mma8x5x_read_data(struct i2c_client *client,

static void mma8x5x_report_data(struct mma8x5x_data *pdata)
{
	struct input_polled_dev *poll_dev = pdata->poll_dev;
	struct mma8x5x_data_axis data;

	mutex_lock(&pdata->data_lock);
	if ((pdata->active & MMA_STATE_MASK) == MMA_STANDBY) {
		poll_dev->poll_interval = POLL_STOP_TIME;
		/* if standby ,set as 10s to slow the poll. */
		goto out;
	} else {
		if (poll_dev->poll_interval == POLL_STOP_TIME)
			poll_dev->poll_interval = pdata->poll_delay;
	}
	if (mma8x5x_read_data(pdata->client, &data) != 0)
		goto out;
	mma8x5x_data_convert(pdata, &data);
	input_report_abs(poll_dev->input, ABS_X, data.x);
	input_report_abs(poll_dev->input, ABS_Y, data.y);
	input_report_abs(poll_dev->input, ABS_Z, data.z);
	input_sync(poll_dev->input);
	input_report_abs(pdata->idev, ABS_X, data.x);
	input_report_abs(pdata->idev, ABS_Y, data.y);
	input_report_abs(pdata->idev, ABS_Z, data.z);
	input_sync(pdata->idev);
out:
	mutex_unlock(&pdata->data_lock);
}

static void mma8x5x_dev_poll(struct input_polled_dev *dev)
static void mma8x5x_dev_poll(struct work_struct *work)
{
	struct mma8x5x_data *pdata = (struct mma8x5x_data *)dev->private;
	struct mma8x5x_data *pdata = container_of((struct delayed_work *)work,
				struct mma8x5x_data, dwork);
	mma8x5x_report_data(pdata);
	schedule_delayed_work(&pdata->dwork,
				msecs_to_jiffies(pdata->poll_delay));
}

static irqreturn_t mma8x5x_interrupt(int vec, void *data)
@@ -577,12 +569,18 @@ static int mma8x5x_enable_set(struct sensors_classdev *sensors_cdev,
				dev_err(&client->dev, "change device state failed!");
				goto err_failed;
			}

			schedule_delayed_work(&pdata->dwork,
				msecs_to_jiffies(pdata->poll_delay));

			pdata->active = MMA_ACTIVED;
			dev_dbg(&client->dev, "%s:mma enable setting active.\n",
					__func__);
		}
	} else if (enable == 0) {
		if (pdata->active == MMA_ACTIVED) {
			cancel_delayed_work_sync(&pdata->dwork);

			val = i2c_smbus_read_byte_data(client,
					MMA8X5X_CTRL_REG1);
			if (val < 0) {
@@ -616,7 +614,7 @@ err_failed:
static ssize_t mma8x5x_enable_show(struct device *dev,
				   struct device_attribute *attr, char *buf)
{
	struct mma8x5x_data *pdata = drv_data;
	struct mma8x5x_data *pdata = dev_get_drvdata(dev);
	struct i2c_client *client;
	u8 val;
	int enable;
@@ -641,7 +639,7 @@ static ssize_t mma8x5x_enable_store(struct device *dev,
				    struct device_attribute *attr,
				    const char *buf, size_t count)
{
	struct mma8x5x_data *pdata = drv_data;
	struct mma8x5x_data *pdata = dev_get_drvdata(dev);
	struct i2c_client *client;
	int ret;
	unsigned long enable;
@@ -663,7 +661,7 @@ static ssize_t mma8x5x_enable_store(struct device *dev,
static ssize_t mma8x5x_position_show(struct device *dev,
				   struct device_attribute *attr, char *buf)
{
	struct mma8x5x_data *pdata = drv_data;
	struct mma8x5x_data *pdata = dev_get_drvdata(dev);
	int position = 0;

	if (!pdata) {
@@ -680,7 +678,7 @@ static ssize_t mma8x5x_position_store(struct device *dev,
				    struct device_attribute *attr,
				    const char *buf, size_t count)
{
	struct mma8x5x_data *pdata = drv_data;
	struct mma8x5x_data *pdata = dev_get_drvdata(dev);
	int position;
	int ret;

@@ -714,7 +712,6 @@ static int mma8x5x_poll_delay_set(struct sensors_classdev *sensors_cdev,
	} else {
		mutex_lock(&pdata->data_lock);
		pdata->poll_delay = delay_ms;
		pdata->poll_dev->poll_interval = pdata->poll_delay;
		mutex_unlock(&pdata->data_lock);
	}

@@ -724,7 +721,7 @@ static int mma8x5x_poll_delay_set(struct sensors_classdev *sensors_cdev,
static ssize_t mma8x5x_poll_delay_show(struct device *dev,
				   struct device_attribute *attr, char *buf)
{
	struct mma8x5x_data *pdata = drv_data;
	struct mma8x5x_data *pdata = dev_get_drvdata(dev);

	if (!pdata) {
		dev_err(dev, "Invalid driver private data!");
@@ -738,7 +735,7 @@ static ssize_t mma8x5x_poll_delay_store(struct device *dev,
				    struct device_attribute *attr,
				    const char *buf, size_t count)
{
	struct mma8x5x_data *pdata = drv_data;
	struct mma8x5x_data *pdata = dev_get_drvdata(dev);
	int delay;
	int ret;

@@ -825,7 +822,6 @@ static int mma8x5x_probe(struct i2c_client *client,
	struct input_dev *idev;
	struct mma8x5x_data *pdata;
	struct i2c_adapter *adapter;
	struct input_polled_dev *poll_dev;
	adapter = to_i2c_adapter(client->dev.parent);
	/* power on the device */
	result = mma8x5x_config_regulator(client, 1);
@@ -836,7 +832,7 @@ static int mma8x5x_probe(struct i2c_client *client,
					 I2C_FUNC_SMBUS_BYTE |
					 I2C_FUNC_SMBUS_BYTE_DATA);
	if (!result)
		goto err_out;
		goto err_check_id;

	chip_id = i2c_smbus_read_byte_data(client, MMA8X5X_WHO_AM_I);

@@ -846,14 +842,14 @@ static int mma8x5x_probe(struct i2c_client *client,
			chip_id, MMA8451_ID, MMA8452_ID, MMA8453_ID,
			MMA8652_ID, MMA8653_ID);
		result = -EINVAL;
		goto err_out;
		goto err_check_id;
	}
	/* set the private data */
	pdata = kzalloc(sizeof(struct mma8x5x_data), GFP_KERNEL);
	if (!pdata) {
		result = -ENOMEM;
		dev_err(&client->dev, "alloc data memory error!\n");
		goto err_out;
		goto err_check_id;
	}

	if (client->dev.of_node) {
@@ -867,12 +863,10 @@ static int mma8x5x_probe(struct i2c_client *client,
	}

	/* Initialize the MMA8X5X chip */
	drv_data = pdata;
	pdata->client = client;
	pdata->chip_id = chip_id;
	pdata->mode = MODE_2G;
	pdata->poll_delay = POLL_STOP_TIME;
	pdata->poll_dev = NULL;
	pdata->poll_delay = POLL_INTERVAL;

	mutex_init(&pdata->data_lock);
	i2c_set_clientdata(client, pdata);
@@ -894,29 +888,9 @@ static int mma8x5x_probe(struct i2c_client *client,
			if (result) {
				dev_err(&client->dev,
					"set_direction for irq gpio failed\n");
				goto err_set_direction;
			}
		}
		idev = input_allocate_device();
		if (!idev) {
			result = -ENOMEM;
			dev_err(&client->dev, "alloc input device failed!\n");
			goto err_alloc_poll_device;
				goto err_set_gpio_direction;
			}
		input_set_drvdata(idev, pdata);
		idev->name = ACCEL_INPUT_DEV_NAME;
		idev->uniq = mma8x5x_id2name(pdata->chip_id);
		idev->id.bustype = BUS_I2C;
		idev->evbit[0] = BIT_MASK(EV_ABS);
		input_set_abs_params(idev, ABS_X, -0x7fff, 0x7fff, 0, 0);
		input_set_abs_params(idev, ABS_Y, -0x7fff, 0x7fff, 0, 0);
		input_set_abs_params(idev, ABS_Z, -0x7fff, 0x7fff, 0, 0);
		result = input_register_device(idev);
		if (result) {
			dev_err(&client->dev, "register input device failed!\n");
			goto err_register_device;
		}
		pdata->idev = idev;
		device_init_wakeup(&client->dev, true);
		enable_irq_wake(client->irq);
		result = request_threaded_irq(client->irq, NULL,
@@ -930,21 +904,15 @@ static int mma8x5x_probe(struct i2c_client *client,
		}
		mma8x5x_device_int_init(client);
	} else {
		/* create the input poll device */
		poll_dev = input_allocate_polled_device();
		if (!poll_dev) {
		INIT_DELAYED_WORK(&pdata->dwork, mma8x5x_dev_poll);
	}
	idev = input_allocate_device();
	if (!idev) {
		result = -ENOMEM;
			dev_err(&client->dev, "alloc poll device failed!\n");
		dev_err(&client->dev, "alloc input device failed!\n");
		goto err_alloc_poll_device;
	}
		pdata->poll_dev = poll_dev;
		pdata->idev = NULL;
		poll_dev->poll = mma8x5x_dev_poll;
		poll_dev->poll_interval = POLL_STOP_TIME;
		poll_dev->poll_interval_min = POLL_INTERVAL_MIN;
		poll_dev->poll_interval_max = POLL_INTERVAL_MAX;
		poll_dev->private = pdata;
		idev = poll_dev->input;
	input_set_drvdata(idev, pdata);
	idev->name = ACCEL_INPUT_DEV_NAME;
	idev->uniq = mma8x5x_id2name(pdata->chip_id);
	idev->id.bustype = BUS_I2C;
@@ -952,12 +920,13 @@ static int mma8x5x_probe(struct i2c_client *client,
	input_set_abs_params(idev, ABS_X, -0x7fff, 0x7fff, 0, 0);
	input_set_abs_params(idev, ABS_Y, -0x7fff, 0x7fff, 0, 0);
	input_set_abs_params(idev, ABS_Z, -0x7fff, 0x7fff, 0, 0);
		result = input_register_polled_device(pdata->poll_dev);
	result = input_register_device(idev);
	if (result) {
			dev_err(&client->dev, "register poll device failed!\n");
		dev_err(&client->dev, "register input device failed!\n");
		goto err_register_device;
	}
	}
	pdata->idev = idev;

	result = sysfs_create_group(&idev->dev.kobj, &mma8x5x_attr_group);
	if (result) {
		dev_err(&client->dev, "create device file failed!\n");
@@ -983,23 +952,20 @@ static int mma8x5x_probe(struct i2c_client *client,
err_create_class_sysfs:
	sysfs_remove_group(&idev->dev.kobj, &mma8x5x_attr_group);
err_create_sysfs:
	input_unregister_polled_device(pdata->poll_dev);
err_register_irq:
	if (pdata->use_int)
		device_init_wakeup(&client->dev, false);
	input_unregister_device(idev);
err_register_device:
	if (pdata->use_int)
	input_free_device(idev);
	else
		input_free_polled_device(pdata->poll_dev);
err_alloc_poll_device:
err_set_direction:
err_register_irq:
	if (pdata->use_int)
		device_init_wakeup(&client->dev, false);
err_set_gpio_direction:
	if (gpio_is_valid(pdata->int_pin) && pdata->use_int)
		gpio_free(pdata->int_pin);
err_request_gpio:
err_parse_dt:
	kfree(pdata);
err_out:
err_check_id:
	mma8x5x_config_regulator(client, 0);
err_power_on:
	return result;
@@ -1007,14 +973,22 @@ err_power_on:
static int mma8x5x_remove(struct i2c_client *client)
{
	struct mma8x5x_data *pdata = i2c_get_clientdata(client);
	struct input_polled_dev *poll_dev;
	struct input_dev *idev;

	mma8x5x_device_stop(client);
	if (pdata) {
		poll_dev = pdata->poll_dev;
		input_unregister_polled_device(poll_dev);
		input_free_polled_device(poll_dev);
		idev = pdata->idev;
		sysfs_remove_group(&idev->dev.kobj, &mma8x5x_attr_group);
		if (pdata->use_int) {
			device_init_wakeup(&client->dev, false);
			if (gpio_is_valid(pdata->int_pin))
				gpio_free(pdata->int_pin);
		}
		input_unregister_device(idev);
		input_free_device(idev);
		kfree(pdata);
	}
	mma8x5x_config_regulator(client, 0);
	return 0;
}

@@ -1026,8 +1000,10 @@ static int mma8x5x_suspend(struct device *dev)

	if (pdata->use_int && pdata->active == MMA_ACTIVED)
		return 0;
	if (pdata->active == MMA_ACTIVED)
	if (pdata->active == MMA_ACTIVED) {
		mma8x5x_device_stop(client);
		cancel_delayed_work_sync(&pdata->dwork);
	}
	if (pdata->active & MMA_SHUTTEDDOWN)
		return 0;
	if (!mma8x5x_config_regulator(client, 0))
@@ -1058,6 +1034,8 @@ static int mma8x5x_resume(struct device *dev)
	if (pdata->active == MMA_ACTIVED) {
		val = i2c_smbus_read_byte_data(client, MMA8X5X_CTRL_REG1);
		i2c_smbus_write_byte_data(client, MMA8X5X_CTRL_REG1, val|0x01);
		schedule_delayed_work(&pdata->dwork,
				msecs_to_jiffies(pdata->poll_delay));
	}

	return 0;