From 251dfdebd87f676eaeb173b6cafe78da0bfbf455 Mon Sep 17 00:00:00 2001 From: Jie Cheng Date: Fri, 20 Dec 2013 16:41:21 +0800 Subject: [PATCH] sensors: add enable and poll_delay handle for kxtj9 sensor drver Add enable and poll_delay handle functions for the kxtj9 accelerometer driver. The system will create the general enable and poll_delay handles in the "/sys/class/sensors/xxx/" for each sensor drvier which is using the sensor class driver. Change-Id: I7ff71bd554f864c62b642791222c7d575d4c6b7f Signed-off-by: Jie Cheng --- drivers/input/misc/kxtj9.c | 120 ++++++++++++++++++++++++------------- 1 file changed, 77 insertions(+), 43 deletions(-) diff --git a/drivers/input/misc/kxtj9.c b/drivers/input/misc/kxtj9.c index f5d84417b69..0883ac55349 100644 --- a/drivers/input/misc/kxtj9.c +++ b/drivers/input/misc/kxtj9.c @@ -90,9 +90,13 @@ static struct sensors_classdev sensors_cdev = { .max_range = "19.6", .resolution = "0.01", .sensor_power = "0.2", - .min_delay = 2000, + .min_delay = 2000, /* microsecond */ .fifo_reserved_event_count = 0, .fifo_max_event_count = 0, + .enabled = 0, + .delay_msec = 200, /* millisecond */ + .sensors_enable = NULL, + .sensors_poll_delay = NULL, }; static const struct { @@ -124,6 +128,7 @@ struct kxtj9_data { bool power_enabled; struct regulator *vdd; struct regulator *vio; + struct sensors_classdev cdev; }; static int kxtj9_i2c_read(struct kxtj9_data *tj9, u8 addr, u8 *data, int len) @@ -486,6 +491,36 @@ static int __devinit kxtj9_setup_input_device(struct kxtj9_data *tj9) return 0; } +static int kxtj9_enable_set(struct sensors_classdev *sensors_cdev, + unsigned int enabled) +{ + struct kxtj9_data *tj9 = container_of(sensors_cdev, + struct kxtj9_data, cdev); + struct input_dev *input_dev = tj9->input_dev; + + mutex_lock(&input_dev->mutex); + + if (enabled == 0) { + disable_irq(tj9->client->irq); + kxtj9_disable(tj9); + tj9->enable = false; + } else if (enabled == 1) { + if (!kxtj9_enable(tj9)) { + enable_irq(tj9->client->irq); + tj9->enable = true; + } + } else { + dev_err(&tj9->client->dev, + "Invalid value of input, input=%d\n", enabled); + mutex_unlock(&input_dev->mutex); + return -EINVAL; + } + + mutex_unlock(&input_dev->mutex); + + return 0; +} + static ssize_t kxtj9_enable_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -501,31 +536,16 @@ static ssize_t kxtj9_enable_store(struct device *dev, { struct i2c_client *client = to_i2c_client(dev); struct kxtj9_data *tj9 = i2c_get_clientdata(client); - struct input_dev *input_dev = tj9->input_dev; unsigned long data; int error; error = kstrtoul(buf, 10, &data); - if (error) + if (error < 0) return error; - mutex_lock(&input_dev->mutex); - - if (data == 0) { - disable_irq(client->irq); - kxtj9_disable(tj9); - tj9->enable = false; - } else if (data == 1) { - if (!kxtj9_enable(tj9)) { - enable_irq(client->irq); - tj9->enable = true; - } - } else { - dev_err(&tj9->client->dev, - "Invalid value of input, input=%ld\n", data); - } - - mutex_unlock(&input_dev->mutex); + error = kxtj9_enable_set(&tj9->cdev, data); + if (error < 0) + return error; return count; } @@ -542,6 +562,29 @@ static DEVICE_ATTR(enable, S_IRUGO|S_IWUSR|S_IWGRP, * will be responsible for retrieving data from the input node at the desired * interval. */ +static int kxtj9_poll_delay_set(struct sensors_classdev *sensors_cdev, + unsigned int delay_msec) +{ + struct kxtj9_data *tj9 = container_of(sensors_cdev, + struct kxtj9_data, cdev); + struct input_dev *input_dev = tj9->input_dev; + + /* Lock the device to prevent races with open/close (and itself) */ + mutex_lock(&input_dev->mutex); + + if (tj9->enable) + disable_irq(tj9->client->irq); + + tj9->last_poll_interval = max(delay_msec, tj9->pdata.min_interval); + + if (tj9->enable) { + kxtj9_update_odr(tj9, tj9->last_poll_interval); + enable_irq(tj9->client->irq); + } + mutex_unlock(&input_dev->mutex); + + return 0; +} /* Returns currently selected poll interval (in ms) */ static ssize_t kxtj9_get_poll_delay(struct device *dev, @@ -560,7 +603,6 @@ static ssize_t kxtj9_set_poll_delay(struct device *dev, { struct i2c_client *client = to_i2c_client(dev); struct kxtj9_data *tj9 = i2c_get_clientdata(client); - struct input_dev *input_dev = tj9->input_dev; unsigned int interval; int error; @@ -568,24 +610,9 @@ static ssize_t kxtj9_set_poll_delay(struct device *dev, if (error < 0) return error; - /* Lock the device to prevent races with open/close (and itself) */ - mutex_lock(&input_dev->mutex); - - if (tj9->enable) - disable_irq(client->irq); - - /* - * Set current interval to the greater of the minimum interval or - * the requested interval - */ - tj9->last_poll_interval = max(interval, tj9->pdata.min_interval); - - if (tj9->enable) { - kxtj9_update_odr(tj9, tj9->last_poll_interval); - enable_irq(client->irq); - } - mutex_unlock(&input_dev->mutex); - + error = kxtj9_poll_delay_set(&tj9->cdev, interval); + if (error < 0) + return error; return count; } @@ -602,7 +629,6 @@ static struct attribute_group kxtj9_attribute_group = { .attrs = kxtj9_attributes }; - #ifdef CONFIG_INPUT_KXTJ9_POLLED_MODE static void kxtj9_poll(struct input_polled_dev *dev) { @@ -858,7 +884,13 @@ static int __devinit kxtj9_probe(struct i2c_client *client, tj9->ctrl_reg1 = tj9->pdata.res_ctl | tj9->pdata.g_range; tj9->last_poll_interval = tj9->pdata.init_interval; - err = sensors_classdev_register(&client->dev, &sensors_cdev); + tj9->cdev = sensors_cdev; + /* The min_delay is used by userspace and the unit is microsecond. */ + tj9->cdev.min_delay = tj9->pdata.min_interval * 1000; + tj9->cdev.delay_msec = tj9->pdata.init_interval; + tj9->cdev.sensors_enable = kxtj9_enable_set; + tj9->cdev.sensors_poll_delay = kxtj9_poll_delay_set; + err = sensors_classdev_register(&client->dev, &tj9->cdev); if (err) { dev_err(&client->dev, "class device create failed: %d\n", err); goto err_power_off; @@ -871,7 +903,7 @@ static int __devinit kxtj9_probe(struct i2c_client *client, err = kxtj9_setup_input_device(tj9); if (err) - goto err_power_off; + goto err_class_sysfs; err = request_threaded_irq(client->irq, NULL, kxtj9_isr, IRQF_TRIGGER_RISING | IRQF_ONESHOT, @@ -892,7 +924,7 @@ static int __devinit kxtj9_probe(struct i2c_client *client, } else { err = kxtj9_setup_polled_device(tj9); if (err) - goto err_power_off; + goto err_class_sysfs; } dev_dbg(&client->dev, "%s: kxtj9_probe OK.\n", __func__); @@ -903,6 +935,8 @@ err_free_irq: free_irq(client->irq, tj9); err_destroy_input: input_unregister_device(tj9->input_dev); +err_class_sysfs: + sensors_classdev_unregister(&tj9->cdev); err_power_off: kxtj9_device_power_off(tj9); err_power_deinit: