aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHong Liu <hong.liu@intel.com>2010-12-09 10:37:35 +0000
committerAlan Cox <alan@linux.intel.com>2010-12-09 10:37:35 +0000
commit72dd7776dc9268c5e1095440f8b608a080c1fdf6 (patch)
tree3d827689e4d0cdcb8fd39c01d1d90634abffd632
parent83c3e30db7cf04e393f4364c572b7a449f85331d (diff)
downloadmrst-s0i3-test-72dd7776dc9268c5e1095440f8b608a080c1fdf6.tar.gz
mrst-s0i3-test-72dd7776dc9268c5e1095440f8b608a080c1fdf6.tar.xz
mrst-s0i3-test-72dd7776dc9268c5e1095440f8b608a080c1fdf6.zip
apds9802ps: add runtime PM support
Signed-off-by: Hong Liu <hong.liu@intel.com>
-rw-r--r--drivers/staging/mfld-sensors/apds9802ps.c94
1 files changed, 53 insertions, 41 deletions
diff --git a/drivers/staging/mfld-sensors/apds9802ps.c b/drivers/staging/mfld-sensors/apds9802ps.c
index 8fbd50937d4..39c55a6ca37 100644
--- a/drivers/staging/mfld-sensors/apds9802ps.c
+++ b/drivers/staging/mfld-sensors/apds9802ps.c
@@ -29,6 +29,7 @@
#include <linux/delay.h>
#include <linux/mutex.h>
#include <linux/sysfs.h>
+#include <linux/pm_runtime.h>
MODULE_AUTHOR("Anantha Narayanan <Anantha.Narayanan@intel.com");
MODULE_DESCRIPTION("Avago apds9802ps Proximity Driver");
@@ -50,9 +51,25 @@ static ssize_t ps_proximity_output_data_show(struct device *dev,
struct ps_data *data = i2c_get_clientdata(client);
int ret_val = 0;
int l, h;
+ int retry = 10;
+ pm_runtime_get_sync(dev);
mutex_lock(&data->lock);
+ /* start measurement */
+ i2c_smbus_write_byte_data(client, 0x82, 0x2d);
+
+ /* wait for data ready */
+ do {
+ msleep(5);
+ ret_val = i2c_smbus_read_byte_data(client, 0x87);
+ if (ret_val > 0 && (ret_val & 0x10))
+ break;
+ } while (retry--);
+
+ if (!retry)
+ dev_warn(dev, "timeout waiting for data ready\n");
+
l = i2c_smbus_read_byte_data(client, 0x85); /* LSB data */
if (l < 0)
dev_warn(dev, "failed proximity out read LSB\n");
@@ -61,26 +78,17 @@ static ssize_t ps_proximity_output_data_show(struct device *dev,
if (h < 0)
dev_warn(dev, "failed proximity out read MSB\n");
+ /* stop measurement and clear interrupt status */
+ i2c_smbus_write_byte_data(client, 0x82, 0x0d);
+ i2c_smbus_write_byte(client, 0x60);
+
mutex_unlock(&data->lock);
+ pm_runtime_put_sync(dev);
ret_val = (h << 8 | l);
return sprintf(buf, "%d\n", ret_val);
}
-static ssize_t ps_power_status_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct i2c_client *client = to_i2c_client(dev);
- int ret_val;
-
- ret_val = i2c_smbus_read_byte_data(client, 0x80);
- if (ret_val < 0)
- dev_warn(dev, "failed power status read\n");
-
- ret_val = ret_val & 0x01;
- return sprintf(buf, "%d\n", ret_val);
-}
-
static void ps_set_power_state(struct i2c_client *client, bool on_off)
{
char curr_val = 0;
@@ -100,33 +108,11 @@ static void ps_set_power_state(struct i2c_client *client, bool on_off)
mutex_unlock(&data->lock);
}
-static ssize_t ps_power_status_store(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count)
-{
- struct i2c_client *client = to_i2c_client(dev);
- unsigned long val = 0;
-
- if (strict_strtoul(buf, 10, &val))
- return -EINVAL;
-
- if (val == POWER_STA_ENABLE) {
- ps_set_power_state(client, true);
- } else if (val == POWER_STA_DISABLE) {
- ps_set_power_state(client, false);
- } else
- return -EINVAL;
-
- return count;
-}
-
static DEVICE_ATTR(proximity_output, S_IRUGO,
ps_proximity_output_data_show, NULL);
-static DEVICE_ATTR(power_state, S_IRUGO | S_IWUSR,
- ps_power_status_show, ps_power_status_store);
static struct attribute *mid_att_ps[] = {
&dev_attr_proximity_output.attr,
- &dev_attr_power_state.attr,
NULL
};
@@ -145,9 +131,9 @@ static void ps_set_default_config(struct i2c_client *client)
if (i2c_smbus_write_byte_data(client, 0x81, 0x86) < 0)
dev_warn(&client->dev, "failed pulse frequency write\n");
- /* Enable measurement, 100MA LED current */
- if (i2c_smbus_write_byte_data(client, 0x82, 0x28) < 0)
- dev_warn(&client->dev, "failed enable measurement write\n");
+ /* 100MA LED current, 500ms interval delay */
+ if (i2c_smbus_write_byte_data(client, 0x82, 0x0d) < 0)
+ dev_warn(&client->dev, "failed interval delay write\n");
}
static int apds9802ps_probe(struct i2c_client *client,
@@ -172,6 +158,12 @@ static int apds9802ps_probe(struct i2c_client *client,
dev_info(&client->dev, "proximity sensor chip found\n");
ps_set_default_config(client);
+ pm_runtime_enable(&client->dev);
+
+ /* toggle the power state */
+ pm_runtime_get(&client->dev);
+ pm_runtime_put(&client->dev);
+
mutex_init(&data->lock);
return res;
@@ -209,11 +201,31 @@ static struct i2c_device_id apds9802ps_id[] = {
};
MODULE_DEVICE_TABLE(i2c, apds9802ps_id);
+static int apds9802ps_runtime_suspend(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+
+ ps_set_power_state(client, false);
+ return 0;
+}
+
+static int apds9802ps_runtime_resume(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+
+ ps_set_power_state(client, true);
+ return 0;
+}
+
+static const struct dev_pm_ops apds9802ps_pm_ops = {
+ .runtime_suspend = apds9802ps_runtime_suspend,
+ .runtime_resume = apds9802ps_runtime_resume,
+};
+
static struct i2c_driver apds9802ps_driver = {
.driver = {
.name = DRIVER_NAME,
- .owner = THIS_MODULE,
- .bus = &i2c_bus_type,
+ .pm = &apds9802ps_pm_ops,
},
.probe = apds9802ps_probe,
.remove = apds9802ps_remove,