+ lis3-power-control-for-the-chip.patch added to -mm tree

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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

[Index of Archives]     [Kernel Newbies FAQ]     [Kernel Archive]     [IETF Annouce]     [DCCP]     [Netdev]     [Networking]     [Security]     [Bugtraq]     [Photo]     [Yosemite]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux SCSI]

  Powered by Linux