summaryrefslogtreecommitdiff
path: root/target/linux/s3c24xx/patches-2.6.24/1310--lis302dl-wakeup-configuration.patch.patch
diff options
context:
space:
mode:
Diffstat (limited to 'target/linux/s3c24xx/patches-2.6.24/1310--lis302dl-wakeup-configuration.patch.patch')
-rw-r--r--target/linux/s3c24xx/patches-2.6.24/1310--lis302dl-wakeup-configuration.patch.patch366
1 files changed, 366 insertions, 0 deletions
diff --git a/target/linux/s3c24xx/patches-2.6.24/1310--lis302dl-wakeup-configuration.patch.patch b/target/linux/s3c24xx/patches-2.6.24/1310--lis302dl-wakeup-configuration.patch.patch
new file mode 100644
index 0000000000..bea01b99c5
--- /dev/null
+++ b/target/linux/s3c24xx/patches-2.6.24/1310--lis302dl-wakeup-configuration.patch.patch
@@ -0,0 +1,366 @@
+From 933f18caaf8f96d1094f064312d416a2fe0b4337 Mon Sep 17 00:00:00 2001
+From: Simon Kagstrom <simon.kagstrom@gmail.com>
+Date: Thu, 16 Oct 2008 01:19:56 +0100
+Subject: [PATCH] : lis302dl-wakeup-configuration.patch
+
+Setup accelerometer interrupt to wake the device up
+
+From: Simon Kagstrom <simon.kagstrom@gmail.com>
+
+The threshold implementation recently broke this functionality. This
+patch reinstates it again and simplifies the code a bit. It only
+supports one of the two lis302dl interrupt sources now (which is the
+only connected one on the openmoko). If you need to configure both, buy
+an Iphone!
+
+(Or flame this patch)
+
+
+Note that, as before, the device immediately wakes up when put to sleep
+with the wakeup configured. The interface is therefore not currently
+very useful, but to use it do e.g.,
+
+ echo 1 1 1 180 0 1 > wakeup
+
+The value is of the form
+
+ X Y Z THRESHOLD DURATION SPEC
+
+X, Y and Z are threshold values, given as a value > 0, < 0 or 0 to
+specify if an interrupt should be generated for high or low thresholds
+or neither (off). THRESHOLD specifies the threshold that must be
+exceeded, in mg. DURATION specifies the time in milliseconds for which
+the acceleration should be measured. SPEC is either '1' or '0' and
+specifies if the thresholds should be taken all together or one at a
+time ('and' or 'or' mode).
+
+Echoing '0' to the file turns off the interrupts.
+
+Signed-off-by: Simon Kagstrom <simon.kagstrom@gmail.com>
+---
+ drivers/input/misc/lis302dl.c | 204 ++++++++++++-----------------------------
+ include/linux/lis302dl.h | 6 +
+ 2 files changed, 63 insertions(+), 147 deletions(-)
+
+diff --git a/drivers/input/misc/lis302dl.c b/drivers/input/misc/lis302dl.c
+index e404a45..f743a24 100644
+--- a/drivers/input/misc/lis302dl.c
++++ b/drivers/input/misc/lis302dl.c
+@@ -133,6 +133,23 @@ static void __lis302dl_int_mode(struct device *dev, int int_pin,
+ }
+ }
+
++static void __enable_wakeup(struct lis302dl_info *lis)
++{
++ /* 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_THS_1,
++ lis->wakeup.threshold);
++ __reg_write(lis, LIS302DL_REG_FF_WU_DURATION_1,
++ lis->wakeup.duration);
++
++ /* Route the interrupt for wakeup */
++ __lis302dl_int_mode(lis->dev, 1,
++ LIS302DL_INTMODE_FF_WU_1);
++
++ __reg_write(lis, LIS302DL_REG_CTRL1, LIS302DL_CTRL1_PD);
++}
++
+ static void __enable_data_collection(struct lis302dl_info *lis)
+ {
+ u_int8_t ctrl1 = LIS302DL_CTRL1_PD | LIS302DL_CTRL1_Xen |
+@@ -395,73 +412,33 @@ 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_freefall_common(int which, struct device *dev,
+- struct device_attribute *attr, const char *buf, size_t count)
++static ssize_t set_wakeup(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;
+- int threshold;
+- int and_events;
+- int r_ths = LIS302DL_REG_FF_WU_THS_1; /* registers, assume first pin */
+- int r_duration = LIS302DL_REG_FF_WU_DURATION_1;
+- int r_cfg = LIS302DL_REG_FF_WU_CFG_1;
+- int flag_mask = LIS302DL_F_WUP_FF_1;
+- int intmode = LIS302DL_INTMODE_FF_WU_1;
++ int duration, threshold, and_events;
+ int x, y, z;
+- int ms;
+- unsigned long flags;
+-
+- /* Configure for second freefall/wakeup pin */
+- if (which == 2) {
+- r_ths = LIS302DL_REG_FF_WU_THS_2;
+- r_duration = LIS302DL_REG_FF_WU_DURATION_2;
+- r_cfg = LIS302DL_REG_FF_WU_CFG_2;
+- flag_mask = LIS302DL_F_WUP_FF_2;
+- intmode = LIS302DL_INTMODE_FF_WU_2;
+
+- printk(KERN_WARNING
+- "Configuring second freefall / wakeup interrupt\n");
+- }
+-
+- /* Parse the input */
++ /* Zero turns the feature off */
+ if (strcmp(buf, "0\n") == 0) {
+- /* Turn off the interrupt */
+- local_irq_save(flags);
+- if (lis->flags & LIS302DL_F_IRQ_WAKE)
+- disable_irq_wake(lis->pdata->interrupt);
+- __lis302dl_int_mode(lis->dev, which,
+- LIS302DL_INTMODE_DATA_READY);
+- lis->flags &= ~(flag_mask | LIS302DL_F_IRQ_WAKE);
+-
+- __reg_write(lis, r_cfg, 0);
+- __reg_write(lis, r_ths, 0);
+- __reg_write(lis, r_duration, 0);
++ lis->wakeup.active = 0;
+
+- /* Power off unless the input subsystem is using the device */
+- if (!(lis->flags & LIS302DL_F_INPUT_OPEN))
+- __reg_set_bit_mask(lis, LIS302DL_REG_CTRL1,
+- LIS302DL_CTRL1_PD, 0);
+-
+- local_irq_restore(flags);
++ if (lis->flags & LIS302DL_F_IRQ_WAKE) {
++ disable_irq_wake(lis->pdata->interrupt);
++ lis->flags &= ~LIS302DL_F_IRQ_WAKE;
++ }
+
+ return count;
+ }
+
+- if (sscanf(buf, "%d %d %d %d %d %d", &x, &y, &z, &threshold, &ms,
+- &and_events) != 6)
++ if (sscanf(buf, "%d %d %d %d %d %d", &x, &y, &z, &threshold, &duration,
++ &and_events) != 6)
+ return -EINVAL;
+
+- local_irq_save(flags);
+- duration = __ms_to_duration(lis, ms);
+- local_irq_save(flags);
+-
+- if (duration < 0)
+- return -ERANGE;
+-
+- /* 7 bits */
+- if (threshold < 0 || threshold > 127)
++ if (duration < 0 || duration > 2550 ||
++ threshold < 0 || threshold > 8000)
+ return -ERANGE;
+
+ /* Interrupt flags */
+@@ -472,91 +449,38 @@ static ssize_t set_freefall_common(int which, struct device *dev,
+ y_hi = y > 0 ? LIS302DL_FFWUCFG_YHIE : 0;
+ z_hi = z > 0 ? LIS302DL_FFWUCFG_ZHIE : 0;
+
+- /* Setup the configuration registers */
+- local_irq_save(flags);
+- /* First zero to get to a known state */
+- __reg_write(lis, r_cfg, 0);
+- __reg_write(lis, r_cfg,
+- (and_events ? LIS302DL_FFWUCFG_AOI : 0) |
+- x_lo | x_hi | y_lo | y_hi | z_lo | z_hi);
+- __reg_write(lis, r_ths, threshold & ~LIS302DL_FFWUTHS_DCRM);
+- __reg_write(lis, r_duration, duration);
++ lis->wakeup.duration = __ms_to_duration(lis, duration);
++ lis->wakeup.threshold = __mg_to_threshold(lis, threshold);
++ lis->wakeup.cfg = (and_events ? LIS302DL_FFWUCFG_AOI : 0) |
++ x_lo | x_hi | y_lo | y_hi | z_lo | z_hi;
+
+- /* Route the interrupt for wakeup */
+- __lis302dl_int_mode(lis->dev, which, intmode);
+-
+- /* Power up the device and note that we want to wake up from
+- * this interrupt */
+- if (!(lis->flags & LIS302DL_F_IRQ_WAKE))
++ if (!(lis->flags & LIS302DL_F_IRQ_WAKE)) {
+ enable_irq_wake(lis->pdata->interrupt);
+-
+- lis->flags |= flag_mask | LIS302DL_F_IRQ_WAKE;
+- __reg_set_bit_mask(lis, LIS302DL_REG_CTRL1, LIS302DL_CTRL1_PD,
+- LIS302DL_CTRL1_PD);
+- local_irq_restore(flags);
++ lis->flags |= LIS302DL_F_IRQ_WAKE;
++ }
++ lis->wakeup.active = 1;
+
+ return count;
+ }
+
+-static ssize_t set_freefall_1(struct device *dev, struct device_attribute *attr,
+- const char *buf, size_t count)
+-{
+- return set_freefall_common(1, dev, attr, buf, count);
+-}
+-static ssize_t set_freefall_2(struct device *dev, struct device_attribute *attr,
+- const char *buf, size_t count)
+-{
+- return set_freefall_common(2, dev, attr, buf, count);
+-}
+-
+-
+-static ssize_t show_freefall_common(int which, struct device *dev,
++static ssize_t show_wakeup(struct device *dev,
+ struct device_attribute *attr, char *buf)
+ {
+ struct lis302dl_info *lis = dev_get_drvdata(dev);
+- u_int8_t duration;
+- u_int8_t threshold;
+- u_int8_t config;
+- u_int8_t r4;
+- u_int8_t r5;
+- int r_ths = LIS302DL_REG_FF_WU_THS_1; /* registers, assume first pin */
+- int r_duration = LIS302DL_REG_FF_WU_DURATION_1;
+- int r_cfg = LIS302DL_REG_FF_WU_CFG_1;
+- int r_src = LIS302DL_REG_FF_WU_SRC_1;
+- unsigned long flags;
+- int ms;
+-
+- /* Configure second freefall/wakeup pin */
+- if (which == 2) {
+- r_ths = LIS302DL_REG_FF_WU_THS_2;
+- r_duration = LIS302DL_REG_FF_WU_DURATION_2;
+- r_cfg = LIS302DL_REG_FF_WU_CFG_2;
+- r_src = LIS302DL_REG_FF_WU_SRC_2;
+- }
+-
+- local_irq_save(flags);
+- config = __reg_read(lis, r_cfg);
+- threshold = __reg_read(lis, r_ths);
+- duration = __reg_read(lis, r_duration);
+- r4 = __reg_read(lis, r_src);
+- r5 = __reg_read(lis, LIS302DL_REG_CTRL3);
+- ms = __duration_to_ms(lis, duration);
+- local_irq_restore(flags);
++ u8 config;
+
+ /* All events off? */
+- if ((config & (LIS302DL_FFWUCFG_XLIE | LIS302DL_FFWUCFG_XHIE |
+- LIS302DL_FFWUCFG_YLIE | LIS302DL_FFWUCFG_YHIE |
+- LIS302DL_FFWUCFG_ZLIE | LIS302DL_FFWUCFG_ZHIE)) == 0)
++ if (!lis->wakeup.active)
+ return sprintf(buf, "off\n");
+
++ config = lis->wakeup.cfg;
+
+ return sprintf(buf,
+- "%s events, %s interrupt, duration %d, threshold %d, "
++ "%s events, duration %d, threshold %d, "
+ "enabled: %s %s %s %s %s %s\n",
+ (config & LIS302DL_FFWUCFG_AOI) == 0 ? "or" : "and",
+- (config & LIS302DL_FFWUCFG_LIR) == 0 ?
+- "don't latch" : "latch",
+- ms, threshold,
++ __duration_to_ms(lis, lis->wakeup.duration),
++ __threshold_to_mg(lis, lis->wakeup.threshold),
+ (config & LIS302DL_FFWUCFG_XLIE) == 0 ? "---" : "xlo",
+ (config & LIS302DL_FFWUCFG_XHIE) == 0 ? "---" : "xhi",
+ (config & LIS302DL_FFWUCFG_YLIE) == 0 ? "---" : "ylo",
+@@ -565,22 +489,7 @@ static ssize_t show_freefall_common(int which, struct device *dev,
+ (config & LIS302DL_FFWUCFG_ZHIE) == 0 ? "---" : "zhi");
+ }
+
+-static ssize_t show_freefall_1(struct device *dev,
+- struct device_attribute *attr, char *buf)
+-{
+- return show_freefall_common(1, dev, attr, buf);
+-}
+-
+-static ssize_t show_freefall_2(struct device *dev,
+- struct device_attribute *attr, char *buf)
+-{
+- return show_freefall_common(2, dev, attr, buf);
+-}
+-
+-static DEVICE_ATTR(freefall_wakeup_1, S_IRUGO | S_IWUSR, show_freefall_1,
+- set_freefall_1);
+-static DEVICE_ATTR(freefall_wakeup_2, S_IRUGO | S_IWUSR, show_freefall_2,
+- set_freefall_2);
++static DEVICE_ATTR(wakeup, S_IRUGO | S_IWUSR, show_wakeup, set_wakeup);
+
+ static struct attribute *lis302dl_sysfs_entries[] = {
+ &dev_attr_sample_rate.attr,
+@@ -588,8 +497,7 @@ static struct attribute *lis302dl_sysfs_entries[] = {
+ &dev_attr_threshold.attr,
+ &dev_attr_duration.attr,
+ &dev_attr_dump.attr,
+- &dev_attr_freefall_wakeup_1.attr,
+- &dev_attr_freefall_wakeup_2.attr,
++ &dev_attr_wakeup.attr,
+ NULL
+ };
+
+@@ -715,6 +623,7 @@ static int __devinit lis302dl_probe(struct platform_device *pdev)
+ */
+ lis->threshold = 1;
+ lis->duration = 0;
++ memset(&lis->wakeup, 0, sizeof(lis->wakeup));
+
+ lis->input_dev->private = lis;
+ lis->input_dev->name = pdata->name;
+@@ -845,8 +754,7 @@ static int lis302dl_suspend(struct platform_device *pdev, pm_message_t state)
+ int n;
+
+ /* determine if we want to wake up from the accel. */
+- if (lis->flags & LIS302DL_F_WUP_FF ||
+- lis->flags & LIS302DL_F_WUP_CLICK)
++ if (lis->flags & LIS302DL_F_WUP_CLICK)
+ return 0;
+
+ disable_irq(lis->pdata->interrupt);
+@@ -866,10 +774,13 @@ static int lis302dl_suspend(struct platform_device *pdev, pm_message_t state)
+ lis->regs[regs_to_save[n]] =
+ __reg_read(lis, regs_to_save[n]);
+
+- /* power down */
+- tmp = __reg_read(lis, LIS302DL_REG_CTRL1);
+- tmp &= ~LIS302DL_CTRL1_PD;
+- __reg_write(lis, LIS302DL_REG_CTRL1, tmp);
++ /* power down or enable wakeup */
++ if (!lis->wakeup.active) {
++ tmp = __reg_read(lis, LIS302DL_REG_CTRL1);
++ tmp &= ~LIS302DL_CTRL1_PD;
++ __reg_write(lis, LIS302DL_REG_CTRL1, tmp);
++ } else
++ __enable_wakeup(lis);
+
+ /* place our IO to the device in sleep-compatible states */
+ (lis->pdata->lis302dl_suspend_io)(lis, 0);
+@@ -885,8 +796,7 @@ static int lis302dl_resume(struct platform_device *pdev)
+ unsigned long flags;
+ int n;
+
+- if (lis->flags & LIS302DL_F_WUP_FF ||
+- lis->flags & LIS302DL_F_WUP_CLICK)
++ if (lis->flags & LIS302DL_F_WUP_CLICK)
+ return 0;
+
+ local_irq_save(flags);
+diff --git a/include/linux/lis302dl.h b/include/linux/lis302dl.h
+index f7aa956..f4121d9 100644
+--- a/include/linux/lis302dl.h
++++ b/include/linux/lis302dl.h
+@@ -31,6 +31,12 @@ struct lis302dl_info {
+ unsigned int flags;
+ unsigned int threshold;
+ unsigned int duration;
++ struct {
++ u8 cfg;
++ u8 threshold;
++ u8 duration;
++ int active;
++ } wakeup;
+ u_int8_t regs[0x40];
+ };
+
+--
+1.5.6.5
+