Correct the sysfs interface for wakeups.

From: Simon Kagstrom <[EMAIL PROTECTED]>

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 <[EMAIL PROTECTED]>
---

 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;

Reply via email to