input: mpu3050: add enable/disable sysfs attribute
allow sensor HAL control the power state of gyro sensor, so that sensor is
disabled when not used.
Change-Id: Ib9f8e9761ea518534ffcd06f30de4b8f1f198687
Signed-off-by: Orkhan Karimov <okarimov@codeaurora.org>
diff --git a/drivers/input/misc/mpu3050.c b/drivers/input/misc/mpu3050.c
index 6c64a57..5d6a19a 100644
--- a/drivers/input/misc/mpu3050.c
+++ b/drivers/input/misc/mpu3050.c
@@ -124,6 +124,7 @@
u32 use_poll;
u32 poll_interval;
u32 dlpf_index;
+ atomic_t enabled;
};
struct sensor_regulator {
@@ -154,6 +155,10 @@
{0, 256, 8},
};
+static void mpu3050_set_power_mode(struct i2c_client *client, u8 val);
+static int mpu3050_start(struct mpu3050_sensor *sensor);
+static void mpu3050_stop(struct mpu3050_sensor *sensor);
+
static u8 interval_to_dlpf_cfg(u32 interval)
{
u32 sample_rate = 1000 / interval;
@@ -293,13 +298,45 @@
return size;
}
+
+static ssize_t mpu3050_attr_get_enable(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct mpu3050_sensor *sensor = dev_get_drvdata(dev);
+ int val = atomic_read(&sensor->enabled);
+ return snprintf(buf, sizeof(val) + 2, "%d\n", val);
+}
+
+
+static ssize_t mpu3050_attr_set_enable(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ struct mpu3050_sensor *sensor = dev_get_drvdata(dev);
+ unsigned long val;
+
+ if (kstrtoul(buf, 10, &val))
+ return -EINVAL;
+
+ if (val)
+ mpu3050_start(sensor);
+ else
+ mpu3050_stop(sensor);
+
+ return size;
+}
+
static struct device_attribute attributes[] = {
__ATTR(pollrate_ms, 0664,
mpu3050_attr_get_polling_rate,
mpu3050_attr_set_polling_rate),
+ __ATTR(enable, 0664,
+ mpu3050_attr_get_enable,
+ mpu3050_attr_set_enable),
};
+
static int create_sysfs_interfaces(struct device *dev)
{
int i;
@@ -409,16 +446,15 @@
}
/**
- * mpu3050_input_open - called on input event open
- * @input: input dev of opened device
+ * mpu3050_start - called when sensor is enabled via sysfs
+ * @sensor: the sensor
*
- * The input layer calls this function when input event is opened. The
- * function will push the device to resume. Then, the device is ready
- * to provide data.
+ * The function gets called when the sensor is enabled via sysfs.
+ * Interrupts will be enabled and the device will be ready to provide data.
+ *
*/
-static int mpu3050_input_open(struct input_dev *input)
+static int mpu3050_start(struct mpu3050_sensor *sensor)
{
- struct mpu3050_sensor *sensor = input_get_drvdata(input);
int error;
pm_runtime_get_sync(sensor->dev);
@@ -440,16 +476,15 @@
}
/**
- * mpu3050_input_close - called on input event close
- * @input: input dev of closed device
+ * mpu3050_stop - called when sensor is disabled via sysfs
+ * @sensor: the sensor
*
- * The input layer calls this function when input event is closed. The
- * function will push the device to suspend.
+ * The function gets called when the sensor is disabled via sysfs.
+ * Device will be pushed to suspend mode.
+ *
*/
-static void mpu3050_input_close(struct input_dev *input)
+static void mpu3050_stop(struct mpu3050_sensor *sensor)
{
- struct mpu3050_sensor *sensor = input_get_drvdata(input);
-
if (sensor->use_poll)
cancel_delayed_work_sync(&sensor->input_work);
@@ -595,6 +630,7 @@
}
mpu3050_set_power_mode(client, 1);
+ atomic_set(&sensor->enabled, 1);
msleep(10);
ret = i2c_smbus_read_byte_data(client, MPU3050_CHIP_ID_REG);
@@ -614,9 +650,6 @@
idev->id.bustype = BUS_I2C;
idev->dev.parent = &client->dev;
- idev->open = mpu3050_input_open;
- idev->close = mpu3050_input_close;
-
__set_bit(EV_ABS, idev->evbit);
input_set_abs_params(idev, ABS_X,
MPU3050_MIN_VALUE, MPU3050_MAX_VALUE, 0, 0);
@@ -739,8 +772,10 @@
static int mpu3050_suspend(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
-
- mpu3050_set_power_mode(client, 0);
+ struct mpu3050_sensor *sensor = i2c_get_clientdata(client);
+ if (atomic_cmpxchg(&sensor->enabled, 1, 0)) {
+ mpu3050_set_power_mode (sensor->client, 0);
+ }
return 0;
}
@@ -754,8 +789,10 @@
static int mpu3050_resume(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
-
- mpu3050_set_power_mode(client, 1);
+ struct mpu3050_sensor *sensor = i2c_get_clientdata(client);
+ if (!atomic_cmpxchg(&sensor->enabled, 0, 1)) {
+ mpu3050_set_power_mode (sensor->client, 1);
+ }
msleep(100); /* wait for gyro chip resume */
return 0;