aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndy Green <andy@openmoko.com>2009-02-03 09:45:18 +0000
committerAndy Green <agreen@octopus.localdomain>2009-02-03 09:45:18 +0000
commitfd8dc272391ad245fffb43cb97120ffe09f25396 (patch)
tree8efd999691ab6ef7bbb81fcdf29f5150fe7bfeed
parent6910248623f49e2e7040f8adc0feea8af8759568 (diff)
fix-lis302dl-get-status-confirm-data-ready.patch
Level interrupts solve the sticky loss of service from accels issue. But currently, we get two service actions per one interrupt, leading to information getting read and sent to the input subsystem twice. This patch makes the ISR confirm with the lis302dl status register that there is fresh data before accepting it, it works around the issue and allows use of the other information in the status reg by another patch. Signed-off-by: Andy Green <andy@openmoko.com>
-rw-r--r--drivers/input/misc/lis302dl.c44
1 files changed, 37 insertions, 7 deletions
diff --git a/drivers/input/misc/lis302dl.c b/drivers/input/misc/lis302dl.c
index a7fb86a2504..2e3d92decab 100644
--- a/drivers/input/misc/lis302dl.c
+++ b/drivers/input/misc/lis302dl.c
@@ -213,23 +213,42 @@ static void _report_btn_double(struct input_dev *inp, int btn)
static void lis302dl_bitbang_read_sample(struct lis302dl_info *lis)
{
- u8 data = 0xc0 | LIS302DL_REG_OUT_X; /* read, autoincrement */
- u8 read[5];
+ u8 data = 0xc0 | LIS302DL_REG_STATUS; /* read, autoincrement */
+ u8 read[(LIS302DL_REG_OUT_Z - LIS302DL_REG_STATUS) + 1];
unsigned long flags;
int mg_per_sample;
local_irq_save(flags);
mg_per_sample = __threshold_to_mg(lis, 1);
- (lis->pdata->lis302dl_bitbang)(lis, &data, 1, &read[0], 5);
+ (lis->pdata->lis302dl_bitbang)(lis, &data, 1, &read[0], sizeof(read));
local_irq_restore(flags);
- input_report_rel(lis->input_dev, REL_X, mg_per_sample * (s8)read[0]);
- input_report_rel(lis->input_dev, REL_Y, mg_per_sample * (s8)read[2]);
- input_report_rel(lis->input_dev, REL_Z, mg_per_sample * (s8)read[4]);
+ /*
+ * at the minute the test below fails 50% of the time due to
+ * a problem with level interrupts causing ISRs to get called twice.
+ * This is a workaround for that, but actually this test is still
+ * valid and the information can be used for overrrun stats.
+ */
- input_sync(lis->input_dev);
+ /* has any kind of overrun been observed by the lis302dl? */
+ if (read[0] & (LIS302DL_STATUS_XOR |
+ LIS302DL_STATUS_YOR |
+ LIS302DL_STATUS_ZOR))
+ lis->overruns++;
+
+ /* we have a valid sample set? */
+ if (read[0] & LIS302DL_STATUS_XYZDA) {
+ input_report_rel(lis->input_dev, REL_X, mg_per_sample *
+ (s8)read[LIS302DL_REG_OUT_X - LIS302DL_REG_STATUS]);
+ input_report_rel(lis->input_dev, REL_Y, mg_per_sample *
+ (s8)read[LIS302DL_REG_OUT_Y - LIS302DL_REG_STATUS]);
+ input_report_rel(lis->input_dev, REL_Z, mg_per_sample *
+ (s8)read[LIS302DL_REG_OUT_Z - LIS302DL_REG_STATUS]);
+
+ input_sync(lis->input_dev);
+ }
/* Reset the HP filter */
__reg_read(lis, LIS302DL_REG_HP_FILTER_RESET);
@@ -246,6 +265,16 @@ static irqreturn_t lis302dl_interrupt(int irq, void *_lis)
/* sysfs */
+static ssize_t show_overruns(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct lis302dl_info *lis = dev_get_drvdata(dev);
+
+ return sprintf(buf, "%u\n", lis->overruns);
+}
+
+static DEVICE_ATTR(overruns, S_IRUGO, show_overruns, NULL);
+
static ssize_t show_rate(struct device *dev, struct device_attribute *attr,
char *buf)
{
@@ -505,6 +534,7 @@ static struct attribute *lis302dl_sysfs_entries[] = {
&dev_attr_dump.attr,
&dev_attr_wakeup_threshold.attr,
&dev_attr_wakeup_duration.attr,
+ &dev_attr_overruns.attr,
NULL
};