PATCH/RFC [3/3]: lis302dl-correct-wakeup-sysfs-interface.patch

Simon Kagstrom simon.kagstrom at gmail.com
Sat Nov 15 09:53:41 CET 2008


Correct the sysfs interface for wakeups.

From: Simon Kagstrom <simon.kagstrom at gmail.com>

Modify the interface of the wakeup feature to provide single-value
writes to the sysfs files. The new interface only allows the threshold
and duration values to be set, and always enable wakeups for X, Y, and Z
in OR-mode, i.e., if acceleration in any direction exceeds the
threshold, an interrupt will be generated.

In summary, wakeup is now enabled by doing

   cd /sys/.../lis302dl.1
   echo 200 > wakeup_threshold

the duration parameter is optional and only setting wakeup_theshold will
actually enable wakeup.

***Note***: As before, the freerunner will wakeup immediately after
being suspended, stil not sure what causes this.

Signed-off-by: Simon Kagstrom <simon.kagstrom at gmail.com>
---

 drivers/input/misc/lis302dl.c |  114 ++++++++++++++++++++++-------------------
 include/linux/lis302dl.h      |    2 -
 2 files changed, 62 insertions(+), 54 deletions(-)

diff --git a/drivers/input/misc/lis302dl.c b/drivers/input/misc/lis302dl.c
index fa3dc15..4b4edaf 100644
--- a/drivers/input/misc/lis302dl.c
+++ b/drivers/input/misc/lis302dl.c
@@ -136,9 +136,11 @@ static void __lis302dl_int_mode(struct device *dev, int int_pin,
 
 static void __enable_wakeup(struct lis302dl_info *lis)
 {
+	__reg_write(lis, LIS302DL_REG_CTRL1, 0);
+
 	/* First zero to get to a known state */
-	__reg_write(lis, LIS302DL_REG_FF_WU_CFG_1,
-			lis->wakeup.cfg);
+	__reg_write(lis, LIS302DL_REG_FF_WU_CFG_1, LIS302DL_FFWUCFG_XHIE |
+			LIS302DL_FFWUCFG_YHIE | LIS302DL_FFWUCFG_ZHIE);
 	__reg_write(lis, LIS302DL_REG_FF_WU_THS_1,
 			__mg_to_threshold(lis, lis->wakeup.threshold));
 	__reg_write(lis, LIS302DL_REG_FF_WU_DURATION_1,
@@ -148,7 +150,14 @@ static void __enable_wakeup(struct lis302dl_info *lis)
 	__lis302dl_int_mode(lis->dev, 1,
 			LIS302DL_INTMODE_FF_WU_1);
 
-	__reg_write(lis, LIS302DL_REG_CTRL1, LIS302DL_CTRL1_PD);
+	__reg_read(lis, LIS302DL_REG_HP_FILTER_RESET);
+	__reg_read(lis, LIS302DL_REG_OUT_X);
+	__reg_read(lis, LIS302DL_REG_OUT_Y);
+	__reg_read(lis, LIS302DL_REG_OUT_Z);
+	__reg_read(lis, LIS302DL_REG_STATUS);
+	__reg_read(lis, LIS302DL_REG_FF_WU_SRC_1);
+	__reg_read(lis, LIS302DL_REG_FF_WU_SRC_2);
+	__reg_write(lis, LIS302DL_REG_CTRL1, LIS302DL_CTRL1_PD | 7);
 }
 
 static void __enable_data_collection(struct lis302dl_info *lis)
@@ -414,19 +423,20 @@ static ssize_t lis302dl_dump(struct device *dev, struct device_attribute *attr,
 static DEVICE_ATTR(dump, S_IRUGO, lis302dl_dump, NULL);
 
 /* Configure freefall/wakeup interrupts */
-static ssize_t set_wakeup(struct device *dev, struct device_attribute *attr,
-			 const char *buf, size_t count)
+static ssize_t set_wakeup_threshold(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t count)
 {
 	struct lis302dl_info *lis = dev_get_drvdata(dev);
-	u_int8_t x_lo, y_lo, z_lo;
-	u_int8_t x_hi, y_hi, z_hi;
-	int duration, threshold, and_events;
-	int x, y, z;
+	unsigned int threshold;
 
-	/* Zero turns the feature off */
-	if (strcmp(buf, "0\n") == 0) {
-		lis->wakeup.active = 0;
+	if (sscanf(buf, "%u\n", &threshold) != 1)
+		return -EINVAL;
+
+	if (threshold > 8000)
+		return -ERANGE;
 
+	/* Zero turns the feature off */
+	if (threshold == 0) {
 		if (lis->flags & LIS302DL_F_IRQ_WAKE) {
 			disable_irq_wake(lis->pdata->interrupt);
 			lis->flags &= ~LIS302DL_F_IRQ_WAKE;
@@ -435,63 +445,58 @@ static ssize_t set_wakeup(struct device *dev, struct device_attribute *attr,
 		return count;
 	}
 
-	if (sscanf(buf, "%d %d %d %d %d %d", &x, &y, &z, &threshold, &duration,
-			&and_events) != 6)
-		return -EINVAL;
-
-	if (duration < 0 || duration > 2550 ||
-			threshold < 0 || threshold > 8000)
-		return -ERANGE;
-
-	/* Interrupt flags */
-	x_lo = x < 0 ? LIS302DL_FFWUCFG_XLIE : 0;
-	y_lo = y < 0 ? LIS302DL_FFWUCFG_YLIE : 0;
-	z_lo = z < 0 ? LIS302DL_FFWUCFG_ZLIE : 0;
-	x_hi = x > 0 ? LIS302DL_FFWUCFG_XHIE : 0;
-	y_hi = y > 0 ? LIS302DL_FFWUCFG_YHIE : 0;
-	z_hi = z > 0 ? LIS302DL_FFWUCFG_ZHIE : 0;
-
-	lis->wakeup.duration = lis->duration;
-	lis->wakeup.threshold = lis->threshold;
-	lis->wakeup.cfg = (and_events ? LIS302DL_FFWUCFG_AOI : 0) |
-		x_lo | x_hi | y_lo | y_hi | z_lo | z_hi;
+	lis->wakeup.threshold = threshold;
 
 	if (!(lis->flags & LIS302DL_F_IRQ_WAKE)) {
 		enable_irq_wake(lis->pdata->interrupt);
 		lis->flags |= LIS302DL_F_IRQ_WAKE;
 	}
-	lis->wakeup.active = 1;
 
 	return count;
 }
 
-static ssize_t show_wakeup(struct device *dev,
+static ssize_t show_wakeup_threshold(struct device *dev,
 		struct device_attribute *attr, char *buf)
 {
 	struct lis302dl_info *lis = dev_get_drvdata(dev);
-	u8 config;
 
 	/* All events off? */
-	if (!lis->wakeup.active)
+	if (lis->wakeup.threshold == 0)
 		return sprintf(buf, "off\n");
 
-	config = lis->wakeup.cfg;
+	return sprintf(buf, "%u\n", lis->wakeup.threshold);
+}
+
+static DEVICE_ATTR(wakeup_threshold, S_IRUGO | S_IWUSR, show_wakeup_threshold,
+		set_wakeup_threshold);
 
-	return sprintf(buf,
-			"%s events, duration %d, threshold %d, "
-			"enabled: %s %s %s %s %s %s\n",
-			(config & LIS302DL_FFWUCFG_AOI) == 0 ? "or" : "and",
-			lis->wakeup.duration,
-			lis->wakeup.threshold,
-			(config & LIS302DL_FFWUCFG_XLIE) == 0 ? "---" : "xlo",
-			(config & LIS302DL_FFWUCFG_XHIE) == 0 ? "---" : "xhi",
-			(config & LIS302DL_FFWUCFG_YLIE) == 0 ? "---" : "ylo",
-			(config & LIS302DL_FFWUCFG_YHIE) == 0 ? "---" : "yhi",
-			(config & LIS302DL_FFWUCFG_ZLIE) == 0 ? "---" : "zlo",
-			(config & LIS302DL_FFWUCFG_ZHIE) == 0 ? "---" : "zhi");
+static ssize_t set_wakeup_duration(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t count)
+{
+	struct lis302dl_info *lis = dev_get_drvdata(dev);
+	unsigned int duration;
+
+	if (sscanf(buf, "%u\n", &duration) != 1)
+		return -EINVAL;
+
+	if (duration > 2550)
+		return -ERANGE;
+
+	lis->wakeup.duration = duration;
+
+	return count;
 }
 
-static DEVICE_ATTR(wakeup, S_IRUGO | S_IWUSR, show_wakeup, set_wakeup);
+static ssize_t show_wakeup_duration(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct lis302dl_info *lis = dev_get_drvdata(dev);
+
+	return sprintf(buf, "%u\n", lis->wakeup.duration);
+}
+
+static DEVICE_ATTR(wakeup_duration, S_IRUGO | S_IWUSR, show_wakeup_duration,
+		set_wakeup_duration);
 
 static struct attribute *lis302dl_sysfs_entries[] = {
 	&dev_attr_sample_rate.attr,
@@ -499,7 +504,8 @@ static struct attribute *lis302dl_sysfs_entries[] = {
 	&dev_attr_threshold.attr,
 	&dev_attr_duration.attr,
 	&dev_attr_dump.attr,
-	&dev_attr_wakeup.attr,
+	&dev_attr_wakeup_threshold.attr,
+	&dev_attr_wakeup_duration.attr,
 	NULL
 };
 
@@ -717,6 +723,9 @@ static int __devexit lis302dl_remove(struct platform_device *pdev)
 	__reg_write(lis, LIS302DL_REG_CTRL1, 0x00);
 	local_irq_restore(flags);
 
+	if (lis->flags & LIS302DL_F_IRQ_WAKE)
+		disable_irq_wake(lis->pdata->interrupt);
+
 	/* Cleanup resources */
 	free_irq(lis->pdata->interrupt, lis);
 	sysfs_remove_group(&pdev->dev.kobj, &lis302dl_attr_group);
@@ -779,7 +788,8 @@ static int lis302dl_suspend(struct platform_device *pdev, pm_message_t state)
 			__reg_read(lis, regs_to_save[n]);
 
 	/* power down or enable wakeup */
-	if (!lis->wakeup.active) {
+
+	if (lis->wakeup.threshold == 0) {
 		tmp = __reg_read(lis, LIS302DL_REG_CTRL1);
 		tmp &= ~LIS302DL_CTRL1_PD;
 		__reg_write(lis, LIS302DL_REG_CTRL1, tmp);
diff --git a/include/linux/lis302dl.h b/include/linux/lis302dl.h
index a255c76..3064446 100644
--- a/include/linux/lis302dl.h
+++ b/include/linux/lis302dl.h
@@ -33,10 +33,8 @@ struct lis302dl_info {
 	unsigned int threshold;
 	unsigned int duration;
 	struct {
-		u8 cfg;
 		unsigned int threshold; /* mg */
 		unsigned int duration;  /* ms */
-		int active;
 	} wakeup;
 	u_int8_t regs[0x40];
 	struct work_struct work;



More information about the openmoko-kernel mailing list