diff options
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.patch | 366 |
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 + |