The patch titled lis3: power control for the chip has been added to the -mm tree. Its filename is lis3-power-control-for-the-chip.patch Before you just go and hit "reply", please: a) Consider who else should be cc'ed b) Prefer to cc a suitable mailing list as well c) Ideally: find the original patch on the mailing list and do a reply-to-all to that, adding suitable additional cc's *** Remember to use Documentation/SubmitChecklist when testing your code *** See http://userweb.kernel.org/~akpm/stuff/added-to-mm.txt to find out what to do about this The current -mm tree may be found at http://userweb.kernel.org/~akpm/mmotm/ ------------------------------------------------------ Subject: lis3: power control for the chip From: Samu Onkalo <samu.p.onkalo@xxxxxxxxx> Chip operational state is controlled by number of the users. When no-one is really using the chip, it is powered down. Typical saving for 8bit device is 300 uA based on chip datasheet. Not much, but in small devices everything counts. New entry is added to sysfs: active It tells when position entry in sysfs is in operational state. Initial setting is chip active to keep functionality similar as before. When "active" is set to 0, position entry return error code. Regardless of the active sysfs entry state, chip is also powered on / off according to /dev/freefall or /dev/input/eventx / /dev/input/jsx use. If some of the device handles is open, chip is on operational state. Chip is in powerdown: - sysfs active == 0 and - /dev/freefall is not open and - /dev/input/... is not open Chip is in active mode: - active == 1 or - /dev/freefall is open or - /dev/input/.... is open Initial state: active == 1 When chip is powered on, it takes 30-125 ms depending on the chip type and current sampling rate. Signed-off-by: Samu Onkalo <samu.p.onkalo@xxxxxxxxx> Cc: Eric Piel <Eric.Piel@xxxxxxxxxxxxxxxx> Cc: Pavel Machek <pavel@xxxxxx> Signed-off-by: Andrew Morton <akpm@xxxxxxxxxxxxxxxxxxxx> --- drivers/hwmon/lis3lv02d.c | 75 ++++++++++++++++++++++++++++++-- drivers/hwmon/lis3lv02d.h | 2 drivers/hwmon/lis3lv02d_i2c.c | 8 ++- drivers/hwmon/lis3lv02d_spi.c | 12 ++--- 4 files changed, 87 insertions(+), 10 deletions(-) diff -puN drivers/hwmon/lis3lv02d.c~lis3-power-control-for-the-chip drivers/hwmon/lis3lv02d.c --- a/drivers/hwmon/lis3lv02d.c~lis3-power-control-for-the-chip +++ a/drivers/hwmon/lis3lv02d.c @@ -248,6 +248,31 @@ void lis3lv02d_poweron(struct lis3lv02d } EXPORT_SYMBOL_GPL(lis3lv02d_poweron); +static void lis3lv02d_add_users(struct lis3lv02d *lis3) +{ + mutex_lock(&lis3->mutex); + if (!lis3->users++) + lis3lv02d_poweron(lis3); + mutex_unlock(&lis3->mutex); +} + +static void lis3lv02d_remove_users(struct lis3lv02d *lis3) +{ + mutex_lock(&lis3->mutex); + if (!--lis3->users) + lis3lv02d_poweroff(lis3); + mutex_unlock(&lis3->mutex); +} + +static void lis3lv02d_joystick_open(struct input_polled_dev *pidev) +{ + lis3lv02d_add_users(&lis3_dev); +} + +static void lis3lv02d_joystick_close(struct input_polled_dev *pidev) +{ + lis3lv02d_remove_users(&lis3_dev); +} static irqreturn_t lis302dl_interrupt(int irq, void *dummy) { @@ -270,6 +295,7 @@ static int lis3lv02d_misc_open(struct in if (test_and_set_bit(0, &lis3_dev.misc_opened)) return -EBUSY; /* already open */ + lis3lv02d_add_users(&lis3_dev); atomic_set(&lis3_dev.count, 0); /* @@ -299,6 +325,7 @@ static int lis3lv02d_misc_release(struct fasync_helper(-1, file, 0, &lis3_dev.async_queue); free_irq(lis3_dev.irq, &lis3_dev); clear_bit(0, &lis3_dev.misc_opened); /* release the device */ + lis3lv02d_remove_users(&lis3_dev); return 0; } @@ -404,8 +431,10 @@ int lis3lv02d_joystick_enable(void) if (!lis3_dev.idev) return -ENOMEM; - lis3_dev.idev->poll = lis3lv02d_joystick_poll; - lis3_dev.idev->poll_interval = MDPS_POLL_INTERVAL; + 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; input_dev = lis3_dev.idev->input; input_dev->name = "ST LIS3LV02DL Accelerometer"; @@ -462,6 +491,9 @@ static ssize_t lis3lv02d_position_show(s { int x, y, z; + if (lis3_dev.active == 0) + return -ENODATA; + lis3lv02d_get_xyz(&lis3_dev, &x, &y, &z); return sprintf(buf, "(%d,%d,%d)\n", x, y, z); } @@ -487,15 +519,51 @@ static ssize_t lis3lv02d_rate_set(struct return count; } +static ssize_t lis3lv02d_active_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "%d\n", lis3_dev.active); +} + +static ssize_t lis3lv02d_active_set(struct device *dev, + struct device_attribute *attr, const char *buf, + size_t count) +{ + unsigned long active; + + if (strict_strtoul(buf, 0, &active)) + return -EINVAL; + + if (active > 1) + return -EINVAL; + + mutex_lock(&lis3_dev.mutex); + if (active == lis3_dev.active) { + mutex_unlock(&lis3_dev.mutex); + return count; + } + lis3_dev.active = active; + mutex_unlock(&lis3_dev.mutex); + + if (active) + lis3lv02d_add_users(&lis3_dev); + else + lis3lv02d_remove_users(&lis3_dev); + return count; +} + static DEVICE_ATTR(selftest, S_IRUSR, lis3lv02d_selftest_show, NULL); static DEVICE_ATTR(position, S_IRUGO, lis3lv02d_position_show, NULL); static DEVICE_ATTR(rate, S_IRUGO | S_IWUSR, lis3lv02d_rate_show, lis3lv02d_rate_set); +static DEVICE_ATTR(active, S_IRUGO | S_IWUSR, lis3lv02d_active_show, + lis3lv02d_active_set); static struct attribute *lis3lv02d_attributes[] = { &dev_attr_selftest.attr, &dev_attr_position.attr, &dev_attr_rate.attr, + &dev_attr_active.attr, NULL }; @@ -592,7 +660,8 @@ int lis3lv02d_init_device(struct lis3lv0 mutex_init(&dev->mutex); lis3lv02d_add_fs(dev); - lis3lv02d_poweron(dev); + lis3lv02d_add_users(dev); + lis3_dev.active = 1; /* By default, chip is in operational state */ if (lis3lv02d_joystick_enable()) printk(KERN_ERR DRIVER_NAME ": joystick initialization failed\n"); diff -puN drivers/hwmon/lis3lv02d.h~lis3-power-control-for-the-chip drivers/hwmon/lis3lv02d.h --- a/drivers/hwmon/lis3lv02d.h~lis3-power-control-for-the-chip +++ a/drivers/hwmon/lis3lv02d.h @@ -221,9 +221,11 @@ struct lis3lv02d { int *odrs; /* Supported output data rates */ u8 odr_mask; /* ODR bit mask */ u8 whoami; /* indicates measurement precision */ + u8 active; s16 (*read_data) (struct lis3lv02d *lis3, int reg); int mdps_max_val; int pwron_delay; + int users; int scale; /* * relationship between 1 LBS and mG * (1/1000th of earth gravity) diff -puN drivers/hwmon/lis3lv02d_i2c.c~lis3-power-control-for-the-chip drivers/hwmon/lis3lv02d_i2c.c --- a/drivers/hwmon/lis3lv02d_i2c.c~lis3-power-control-for-the-chip +++ a/drivers/hwmon/lis3lv02d_i2c.c @@ -121,8 +121,10 @@ static int lis3lv02d_i2c_suspend(struct { struct lis3lv02d *lis3 = i2c_get_clientdata(client); - if (!lis3->pdata->wakeup_flags) + mutex_lock(&lis3->mutex); + if (!lis3->pdata->wakeup_flags && lis3->users) lis3lv02d_poweroff(lis3); + mutex_unlock(&lis3->mutex); return 0; } @@ -130,8 +132,10 @@ static int lis3lv02d_i2c_resume(struct i { struct lis3lv02d *lis3 = i2c_get_clientdata(client); - if (!lis3->pdata->wakeup_flags) + mutex_lock(&lis3->mutex); + if (!lis3->pdata->wakeup_flags && lis3->users) lis3lv02d_poweron(lis3); + mutex_unlock(&lis3->mutex); return 0; } diff -puN drivers/hwmon/lis3lv02d_spi.c~lis3-power-control-for-the-chip drivers/hwmon/lis3lv02d_spi.c --- a/drivers/hwmon/lis3lv02d_spi.c~lis3-power-control-for-the-chip +++ a/drivers/hwmon/lis3lv02d_spi.c @@ -92,9 +92,10 @@ static int lis3lv02d_spi_suspend(struct { struct lis3lv02d *lis3 = spi_get_drvdata(spi); - if (!lis3->pdata->wakeup_flags) - lis3lv02d_poweroff(&lis3_dev); - + mutex_lock(&lis3->mutex); + if (!lis3->pdata->wakeup_flags && lis3->users) + lis3lv02d_poweroff(lis3); + mutex_unlock(&lis3->mutex); return 0; } @@ -102,9 +103,10 @@ static int lis3lv02d_spi_resume(struct s { struct lis3lv02d *lis3 = spi_get_drvdata(spi); - if (!lis3->pdata->wakeup_flags) + mutex_lock(&lis3->mutex); + if (!lis3->pdata->wakeup_flags && lis3->users) lis3lv02d_poweron(lis3); - + mutex_unlock(&lis3->mutex); return 0; } _ Patches currently in -mm which might be from samu.p.onkalo@xxxxxxxxx are lis3-add-missing-constants-for-8bit-device.patch lis3-separate-configuration-function-for-8-bit-device.patch lis3-introduce-platform-data-for-second-ff-wu-unit.patch lis3-power-control-for-the-chip.patch lis3-add-skeletons-for-interrupt-handlers.patch lis3-interrupt-handlers-for-8bit-wakeup-and-click-events.patch -- To unsubscribe from this list: send the line "unsubscribe mm-commits" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html