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