diff options
author | mirko <mirko@3c298f89-4303-0410-b956-a3cf2f4a3e73> | 2008-12-12 11:58:53 +0000 |
---|---|---|
committer | mirko <mirko@3c298f89-4303-0410-b956-a3cf2f4a3e73> | 2008-12-12 11:58:53 +0000 |
commit | fc54b9bf158eea9cae647ce2c58f7d9989af173a (patch) | |
tree | 54644c1229434d7ee13c5872bda4129e34337fc0 /target/linux/s3c24xx/patches-2.6.24/1280-interface-for-configuring-freefall-wakeup-interrupts.patch | |
parent | d9f49b62b28ebd245587854efa484974d90debbf (diff) |
changed Makefile and profiles, added patches for kernel 2.6.24
(stable-branch of Openmoko)
git-svn-id: svn://svn.openwrt.org/openwrt/trunk@13613 3c298f89-4303-0410-b956-a3cf2f4a3e73
Diffstat (limited to 'target/linux/s3c24xx/patches-2.6.24/1280-interface-for-configuring-freefall-wakeup-interrupts.patch')
-rw-r--r-- | target/linux/s3c24xx/patches-2.6.24/1280-interface-for-configuring-freefall-wakeup-interrupts.patch | 372 |
1 files changed, 372 insertions, 0 deletions
diff --git a/target/linux/s3c24xx/patches-2.6.24/1280-interface-for-configuring-freefall-wakeup-interrupts.patch b/target/linux/s3c24xx/patches-2.6.24/1280-interface-for-configuring-freefall-wakeup-interrupts.patch new file mode 100644 index 0000000000..38318315c4 --- /dev/null +++ b/target/linux/s3c24xx/patches-2.6.24/1280-interface-for-configuring-freefall-wakeup-interrupts.patch @@ -0,0 +1,372 @@ +From 69acbd477fb7024d2cfa3702036b92ecb6c8e7b5 Mon Sep 17 00:00:00 2001 +From: Simon Kagstrom <simon.kagstrom@gmail.com> +Date: Fri, 15 Aug 2008 11:50:56 +0100 +Subject: [PATCH] interface for configuring freefall/wakeup interrupts for the accelerometers + +Hi! + +First: Unfortunately, the freerunner currently wakes up immediately on +suspend when the accelerometer IRQ is selected as a wakeup source. I'm +posting this for comments and if someone else wants to have a look at +this problem. + +The patch should be safe to apply even though the sleep portion doesn't +work - as long as it's configured it will not disturb anything. + +// Simon +-- +lis302dl-configure-wakeup-interrupts.patch + +From: simon.kagstrom <simon.kagstrom@gmail.com> + +First: Unfortunately, the freerunner currently wakes up immediately on +suspend when the accelerometer IRQ is selected as a wakeup source. + + +Add configuration of wakeup/freefall interrupts through a sysfs +interface. Configuration is done through echoing a value of the +form + + X Y Z THRESHOLD DURATION SPEC + +to freefall_wakeup_1/2. 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. 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. + +Example: + + echo "1 1 1 60 60 0" > freefall_wakeup_1 # Turn on x,y,z, 60ms/60 threshold, or-mode + echo "0" > freefall_wakeup_1 # Turn off interrupt + +The hardware supports two simulataneous wakeup sources to be configured, +but the freerunner only connects one of the interrupt outputs. The patch +exports both. Similarly, only the "top" accelerometer can be used as a +wake-up source, and it's not possible to generate DATA_READY interrupts +while the wakeup interrupts are active. + +Signed-off-by: Simon Kagstrom <simon.kagstrom@gmail.com> +--- + drivers/input/misc/lis302dl.c | 232 +++++++++++++++++++++++++++++++++++++++-- + include/linux/lis302dl.h | 8 +- + 2 files changed, 227 insertions(+), 13 deletions(-) + +diff --git a/drivers/input/misc/lis302dl.c b/drivers/input/misc/lis302dl.c +index b97cae7..3f6d0eb 100644 +--- a/drivers/input/misc/lis302dl.c ++++ b/drivers/input/misc/lis302dl.c +@@ -248,10 +248,212 @@ static ssize_t lis302dl_dump(struct device *dev, struct device_attribute *attr, + } + static DEVICE_ATTR(dump, S_IRUGO, lis302dl_dump, NULL); + ++static int freefall_ms_to_duration(struct lis302dl_info *lis, int ms) ++{ ++ u_int8_t r = reg_read(lis, LIS302DL_REG_CTRL1); ++ ++ /* If we have 400 ms sampling rate, the stepping is 2.5 ms, ++ * on 100 ms the stepping is 10ms */ ++ if ( r & LIS302DL_CTRL1_DR ) { ++ /* Too large */ ++ if (ms > 637) ++ return -1; ++ ++ return (ms * 10) / 25; ++ } ++ ++ /* Too large value */ ++ if (ms > 2550) ++ return -1; ++ return ms / 10; ++} ++ ++static int freefall_duration_to_ms(struct lis302dl_info *lis, int duration) ++{ ++ u_int8_t r = reg_read(lis, LIS302DL_REG_CTRL1); ++ ++ if ( r & LIS302DL_CTRL1_DR ) ++ return (duration * 25) / 10; ++ ++ return duration * 10; ++} ++ ++/* 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) ++{ ++ 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 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 */ ++ if (strcmp(buf, "0\n") == 0) ++ { ++ /* Turn off the interrupt */ ++ local_save_flags(flags); ++ if ( (lis->flags & LIS302DL_F_IRQ_WAKE) != 0 ) ++ disable_irq_wake(lis->spi_dev->irq); ++ lis302dl_int_mode(lis->spi_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); ++ ++ /* Power off unless the input subsystem is using the device */ ++ if ( (lis->flags & LIS302DL_F_INPUT_OPEN) == 0 ) ++ reg_set_bit_mask(lis, LIS302DL_REG_CTRL1, LIS302DL_CTRL1_PD, 0); ++ ++ local_irq_restore(flags); ++ ++ return count; ++ } ++ ++ if (sscanf(buf, "%d %d %d %d %d %d", &x, &y, &z, &threshold, &ms, &and_events) != 6) ++ return -EINVAL; ++ ++ duration = freefall_ms_to_duration(lis, ms); ++ if (duration < 0) ++ return -ERANGE; ++ ++ /* 7 bits */ ++ if (threshold < 0 || threshold > 127) ++ 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; ++ ++ /* Setup the configuration registers */ ++ local_save_flags(flags); ++ reg_write(lis, r_cfg, 0); /* First zero to get to a known state */ ++ 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); ++ ++ /* Route the interrupt for wakeup */ ++ lis302dl_int_mode(lis->spi_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) == 0 ) ++ enable_irq_wake(lis->spi_dev->irq); ++ ++ 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); ++ ++ 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, ++ 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; ++ ++ /* 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; ++ } ++ 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); ++ ++ /* All events off? */ ++ if ((config & (LIS302DL_FFWUCFG_XLIE | LIS302DL_FFWUCFG_XHIE | ++ LIS302DL_FFWUCFG_YLIE | LIS302DL_FFWUCFG_YHIE | ++ LIS302DL_FFWUCFG_ZLIE | LIS302DL_FFWUCFG_ZHIE)) == 0) ++ return sprintf(buf, "off\n"); ++ ++ return sprintf(buf,"%s events, %s interrupt, 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", ++ freefall_duration_to_ms(lis, duration), 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 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 struct attribute *lis302dl_sysfs_entries[] = { + &dev_attr_sample_rate.attr, + &dev_attr_full_scale.attr, + &dev_attr_dump.attr, ++ &dev_attr_freefall_wakeup_1.attr, ++ &dev_attr_freefall_wakeup_2.attr, + NULL + }; + +@@ -274,6 +476,8 @@ static int lis302dl_input_open(struct input_dev *inp) + reg_set_bit_mask(lis, LIS302DL_REG_CTRL1, ctrl1, ctrl1); + local_irq_restore(flags); + ++ lis->flags |= LIS302DL_F_INPUT_OPEN; ++ + /* kick it off -- since we are edge triggered, if we missed the edge + * permanent low interrupt is death for us */ + (lis->pdata->lis302dl_bitbang_read)(lis); +@@ -294,6 +498,7 @@ static void lis302dl_input_close(struct input_dev *inp) + * only see close() for the close of the last user, we can safely + * disable the data ready events */ + reg_set_bit_mask(lis, LIS302DL_REG_CTRL1, ctrl1, 0x00); ++ lis->flags &= ~LIS302DL_F_INPUT_OPEN; + + /* however, don't power down the whole device if still needed */ + if (!(lis->flags & LIS302DL_F_WUP_FF || +@@ -406,9 +611,9 @@ static int __devinit lis302dl_probe(struct spi_device *spi) + reg_write(lis, LIS302DL_REG_CTRL2, 0); + reg_write(lis, LIS302DL_REG_CTRL3, LIS302DL_CTRL3_PP_OD | + LIS302DL_CTRL3_IHL); +- reg_write(lis, LIS302DL_REG_FF_WU_THS_1, 0x14); ++ reg_write(lis, LIS302DL_REG_FF_WU_THS_1, 0x0); + reg_write(lis, LIS302DL_REG_FF_WU_DURATION_1, 0x00); +- reg_write(lis, LIS302DL_REG_FF_WU_CFG_1, 0x95); ++ reg_write(lis, LIS302DL_REG_FF_WU_CFG_1, 0x0); + + /* start off in powered down mode; we power up when someone opens us */ + reg_write(lis, LIS302DL_REG_CTRL1, LIS302DL_CTRL1_Xen | +@@ -486,6 +691,12 @@ static int lis302dl_suspend(struct spi_device *spi, pm_message_t state) + { + struct lis302dl_info *lis = dev_get_drvdata(&spi->dev); + unsigned long flags; ++ u_int8_t tmp; ++ ++ /* determine if we want to wake up from the accel. */ ++ if (lis->flags & LIS302DL_F_WUP_FF || ++ lis->flags & LIS302DL_F_WUP_CLICK) ++ return 0; + + disable_irq(lis->spi_dev->irq); + local_save_flags(flags); +@@ -528,15 +739,10 @@ static int lis302dl_suspend(struct spi_device *spi, pm_message_t state) + lis->regs[LIS302DL_REG_CLICK_WINDOW] = + reg_read(lis, LIS302DL_REG_CLICK_WINDOW); + +- /* determine if we want to wake up from the accel. */ +- if (!(lis->flags & LIS302DL_F_WUP_FF || +- lis->flags & LIS302DL_F_WUP_CLICK)) { +- /* power down */ +- u_int8_t tmp; +- tmp = reg_read(lis, LIS302DL_REG_CTRL1); +- tmp &= ~LIS302DL_CTRL1_PD; +- reg_write(lis, LIS302DL_REG_CTRL1, tmp); +- } ++ /* power down */ ++ tmp = reg_read(lis, LIS302DL_REG_CTRL1); ++ tmp &= ~LIS302DL_CTRL1_PD; ++ reg_write(lis, LIS302DL_REG_CTRL1, tmp); + + /* place our IO to the device in sleep-compatible states */ + (lis->pdata->lis302dl_suspend_io)(lis, 0); +@@ -551,6 +757,10 @@ static int lis302dl_resume(struct spi_device *spi) + struct lis302dl_info *lis = dev_get_drvdata(&spi->dev); + unsigned long flags; + ++ if (lis->flags & LIS302DL_F_WUP_FF || ++ lis->flags & LIS302DL_F_WUP_CLICK) ++ return 0; ++ + local_save_flags(flags); + + /* get our IO to the device back in operational states */ +diff --git a/include/linux/lis302dl.h b/include/linux/lis302dl.h +index e4a44f5..7daa8b3 100644 +--- a/include/linux/lis302dl.h ++++ b/include/linux/lis302dl.h +@@ -129,10 +129,14 @@ enum lis302dl_reg_cloik_src { + + #define LIS302DL_WHO_AM_I_MAGIC 0x3b + +-#define LIS302DL_F_WUP_FF 0x0001 /* wake up from free fall */ +-#define LIS302DL_F_WUP_CLICK 0x0002 ++#define LIS302DL_F_WUP_FF_1 0x0001 /* wake up from free fall */ ++#define LIS302DL_F_WUP_FF_2 0x0002 ++#define LIS302DL_F_WUP_FF 0x0003 ++#define LIS302DL_F_WUP_CLICK 0x0004 + #define LIS302DL_F_POWER 0x0010 + #define LIS302DL_F_FS 0x0020 /* ADC full scale */ ++#define LIS302DL_F_INPUT_OPEN 0x0040 /* Set if input device is opened */ ++#define LIS302DL_F_IRQ_WAKE 0x0080 /* IRQ is setup in wake mode */ + + + #endif /* _LINUX_LIS302DL_H */ +-- +1.5.6.5 + |