Re: [PATCH 01/12] hwmon: lis3: pm_runtime support
Op 22-10-10 13:57, Samu Onkalo schreef: Add pm_runtime support to lis3 core driver. Add pm_runtime support to lis3 i2c driver. spi and hp_accel drivers are not yet supported. Old always on functionality remains for those. For sysfs there is 5 second delay before turning off the chip to avoid long ramp up delay. Signed-off-by: Samu Onkalosamu.p.onk...@nokia.com Acked-by: Eric Piel eric.p...@tremplin-utc.net --- drivers/hwmon/lis3lv02d.c | 60 + drivers/hwmon/lis3lv02d.h |1 + drivers/hwmon/lis3lv02d_i2c.c | 54 - 3 files changed, 102 insertions(+), 13 deletions(-) diff --git a/drivers/hwmon/lis3lv02d.c b/drivers/hwmon/lis3lv02d.c index fc591ae..412ddc3 100644 --- a/drivers/hwmon/lis3lv02d.c +++ b/drivers/hwmon/lis3lv02d.c @@ -34,6 +34,7 @@ #includelinux/freezer.h #includelinux/uaccess.h #includelinux/miscdevice.h +#includelinux/pm_runtime.h #includeasm/atomic.h #include lis3lv02d.h @@ -43,6 +44,9 @@ #define MDPS_POLL_INTERVAL 50 #define MDPS_POLL_MIN0 #define MDPS_POLL_MAX2000 + +#define LIS3_SYSFS_POWERDOWN_DELAY 5000 /* In milliseconds */ + /* * The sensor can also generate interrupts (DRDY) but it's pretty pointless * because they are generated even if the data do not change. So it's better @@ -262,6 +266,18 @@ static void lis3lv02d_joystick_poll(struct input_polled_dev *pidev) mutex_unlock(lis3_dev.mutex); } +static void lis3lv02d_joystick_open(struct input_polled_dev *pidev) +{ + if (lis3_dev.pm_dev) + pm_runtime_get_sync(lis3_dev.pm_dev); +} + +static void lis3lv02d_joystick_close(struct input_polled_dev *pidev) +{ + if (lis3_dev.pm_dev) + pm_runtime_put(lis3_dev.pm_dev); +} + static irqreturn_t lis302dl_interrupt(int irq, void *dummy) { if (!test_bit(0,lis3_dev.misc_opened)) @@ -356,6 +372,9 @@ static int lis3lv02d_misc_open(struct inode *inode, struct file *file) if (test_and_set_bit(0,lis3_dev.misc_opened)) return -EBUSY; /* already open */ + if (lis3_dev.pm_dev) + pm_runtime_get_sync(lis3_dev.pm_dev); + atomic_set(lis3_dev.count, 0); return 0; } @@ -364,6 +383,8 @@ static int lis3lv02d_misc_release(struct inode *inode, struct file *file) { fasync_helper(-1, file, 0,lis3_dev.async_queue); clear_bit(0,lis3_dev.misc_opened); /* release the device */ + if (lis3_dev.pm_dev) + pm_runtime_put(lis3_dev.pm_dev); return 0; } @@ -460,6 +481,8 @@ int lis3lv02d_joystick_enable(void) return -ENOMEM; lis3_dev.idev-poll = lis3lv02d_joystick_poll; + lis3_dev.idev-open = lis3lv02d_joystick_open; + lis3_dev.idev-close = lis3lv02d_joystick_close; lis3_dev.idev-poll_interval = MDPS_POLL_INTERVAL; lis3_dev.idev-poll_interval_min = MDPS_POLL_MIN; lis3_dev.idev-poll_interval_max = MDPS_POLL_MAX; @@ -512,12 +535,30 @@ void lis3lv02d_joystick_disable(void) EXPORT_SYMBOL_GPL(lis3lv02d_joystick_disable); /* Sysfs stuff */ +static void lis3lv02d_sysfs_poweron(struct lis3lv02d *lis3) +{ + /* +* SYSFS functions are fast visitors so put-call +* immediately after the get-call. However, keep +* chip running for a while and schedule delayed +* suspend. This way periodic sysfs calls doesn't +* suffer from relatively long power up time. +*/ + + if (lis3-pm_dev) { + pm_runtime_get_sync(lis3-pm_dev); + pm_runtime_put_noidle(lis3-pm_dev); + pm_schedule_suspend(lis3-pm_dev, LIS3_SYSFS_POWERDOWN_DELAY); + } +} + static ssize_t lis3lv02d_selftest_show(struct device *dev, struct device_attribute *attr, char *buf) { int result; s16 values[3]; + lis3lv02d_sysfs_poweron(lis3_dev); result = lis3lv02d_selftest(lis3_dev, values); return sprintf(buf, %s %d %d %d\n, result == 0 ? OK : FAIL, values[0], values[1], values[2]); @@ -528,6 +569,7 @@ static ssize_t lis3lv02d_position_show(struct device *dev, { int x, y, z; + lis3lv02d_sysfs_poweron(lis3_dev); mutex_lock(lis3_dev.mutex); lis3lv02d_get_xyz(lis3_dev,x,y,z); mutex_unlock(lis3_dev.mutex); @@ -537,6 +579,7 @@ static ssize_t lis3lv02d_position_show(struct device *dev, static ssize_t lis3lv02d_rate_show(struct device *dev, struct device_attribute *attr, char *buf) { + lis3lv02d_sysfs_poweron(lis3_dev); return sprintf(buf, %d\n, lis3lv02d_get_odr()); } @@ -549,6 +592,7 @@ static ssize_t lis3lv02d_rate_set(struct device *dev, if (strict_strtoul(buf, 0,rate)) return -EINVAL; + lis3lv02d_sysfs_poweron(lis3_dev); if (lis3lv02d_set_odr(rate)) return -EINVAL; @@ -585,6 +629,17 @@ int
Re: [PATCH 01/12] hwmon: lis3: pm_runtime support
On 10/22/10 12:57, Samu Onkalo wrote: Add pm_runtime support to lis3 core driver. Add pm_runtime support to lis3 i2c driver. spi and hp_accel drivers are not yet supported. Old always on functionality remains for those. For sysfs there is 5 second delay before turning off the chip to avoid long ramp up delay. I acked this last time around (after Samu answered some queries I had) and I don't think it has changed. Signed-off-by: Samu Onkalo samu.p.onk...@nokia.com Acked-by: Jonathan Cameron ji...@cam.ac.uk --- drivers/hwmon/lis3lv02d.c | 60 + drivers/hwmon/lis3lv02d.h |1 + drivers/hwmon/lis3lv02d_i2c.c | 54 - 3 files changed, 102 insertions(+), 13 deletions(-) diff --git a/drivers/hwmon/lis3lv02d.c b/drivers/hwmon/lis3lv02d.c index fc591ae..412ddc3 100644 --- a/drivers/hwmon/lis3lv02d.c +++ b/drivers/hwmon/lis3lv02d.c @@ -34,6 +34,7 @@ #include linux/freezer.h #include linux/uaccess.h #include linux/miscdevice.h +#include linux/pm_runtime.h #include asm/atomic.h #include lis3lv02d.h @@ -43,6 +44,9 @@ #define MDPS_POLL_INTERVAL 50 #define MDPS_POLL_MIN 0 #define MDPS_POLL_MAX 2000 + +#define LIS3_SYSFS_POWERDOWN_DELAY 5000 /* In milliseconds */ + /* * The sensor can also generate interrupts (DRDY) but it's pretty pointless * because they are generated even if the data do not change. So it's better @@ -262,6 +266,18 @@ static void lis3lv02d_joystick_poll(struct input_polled_dev *pidev) mutex_unlock(lis3_dev.mutex); } +static void lis3lv02d_joystick_open(struct input_polled_dev *pidev) +{ + if (lis3_dev.pm_dev) + pm_runtime_get_sync(lis3_dev.pm_dev); +} + +static void lis3lv02d_joystick_close(struct input_polled_dev *pidev) +{ + if (lis3_dev.pm_dev) + pm_runtime_put(lis3_dev.pm_dev); +} + static irqreturn_t lis302dl_interrupt(int irq, void *dummy) { if (!test_bit(0, lis3_dev.misc_opened)) @@ -356,6 +372,9 @@ static int lis3lv02d_misc_open(struct inode *inode, struct file *file) if (test_and_set_bit(0, lis3_dev.misc_opened)) return -EBUSY; /* already open */ + if (lis3_dev.pm_dev) + pm_runtime_get_sync(lis3_dev.pm_dev); + atomic_set(lis3_dev.count, 0); return 0; } @@ -364,6 +383,8 @@ static int lis3lv02d_misc_release(struct inode *inode, struct file *file) { fasync_helper(-1, file, 0, lis3_dev.async_queue); clear_bit(0, lis3_dev.misc_opened); /* release the device */ + if (lis3_dev.pm_dev) + pm_runtime_put(lis3_dev.pm_dev); return 0; } @@ -460,6 +481,8 @@ int lis3lv02d_joystick_enable(void) return -ENOMEM; lis3_dev.idev-poll = lis3lv02d_joystick_poll; + lis3_dev.idev-open = lis3lv02d_joystick_open; + lis3_dev.idev-close = lis3lv02d_joystick_close; lis3_dev.idev-poll_interval = MDPS_POLL_INTERVAL; lis3_dev.idev-poll_interval_min = MDPS_POLL_MIN; lis3_dev.idev-poll_interval_max = MDPS_POLL_MAX; @@ -512,12 +535,30 @@ void lis3lv02d_joystick_disable(void) EXPORT_SYMBOL_GPL(lis3lv02d_joystick_disable); /* Sysfs stuff */ +static void lis3lv02d_sysfs_poweron(struct lis3lv02d *lis3) +{ + /* + * SYSFS functions are fast visitors so put-call + * immediately after the get-call. However, keep + * chip running for a while and schedule delayed + * suspend. This way periodic sysfs calls doesn't + * suffer from relatively long power up time. + */ + + if (lis3-pm_dev) { + pm_runtime_get_sync(lis3-pm_dev); + pm_runtime_put_noidle(lis3-pm_dev); + pm_schedule_suspend(lis3-pm_dev, LIS3_SYSFS_POWERDOWN_DELAY); + } +} + static ssize_t lis3lv02d_selftest_show(struct device *dev, struct device_attribute *attr, char *buf) { int result; s16 values[3]; + lis3lv02d_sysfs_poweron(lis3_dev); result = lis3lv02d_selftest(lis3_dev, values); return sprintf(buf, %s %d %d %d\n, result == 0 ? OK : FAIL, values[0], values[1], values[2]); @@ -528,6 +569,7 @@ static ssize_t lis3lv02d_position_show(struct device *dev, { int x, y, z; + lis3lv02d_sysfs_poweron(lis3_dev); mutex_lock(lis3_dev.mutex); lis3lv02d_get_xyz(lis3_dev, x, y, z); mutex_unlock(lis3_dev.mutex); @@ -537,6 +579,7 @@ static ssize_t lis3lv02d_position_show(struct device *dev, static ssize_t lis3lv02d_rate_show(struct device *dev, struct device_attribute *attr, char *buf) { + lis3lv02d_sysfs_poweron(lis3_dev); return sprintf(buf, %d\n, lis3lv02d_get_odr()); } @@ -549,6 +592,7 @@ static ssize_t lis3lv02d_rate_set(struct device *dev, if (strict_strtoul(buf, 0, rate)) return -EINVAL; +