hwmon: lis3: Enhance lis3 selftest with IRQ line test
authorSamu Onkalo <samu.p.onkalo@nokia.com>
Fri, 22 Oct 2010 11:57:32 +0000 (07:57 -0400)
committerGuenter Roeck <guenter.roeck@ericsson.com>
Mon, 25 Oct 2010 21:11:39 +0000 (14:11 -0700)
Configure chip to data ready mode in selftest and count received
interrupts to see that interrupt line(s) are working.

Signed-off-by: Samu Onkalo <samu.p.onkalo@nokia.com>
Acked-by: Eric Piel <eric.piel@tremplin-utc.net>
Signed-off-by: Guenter Roeck <guenter.roeck@ericsson.com>
drivers/hwmon/lis3lv02d.c
drivers/hwmon/lis3lv02d.h

index 0780de0..0cee73a 100644 (file)
 
 #define LIS3_SYSFS_POWERDOWN_DELAY 5000 /* In milliseconds */
 
+#define SELFTEST_OK           0
+#define SELFTEST_FAIL         -1
+#define SELFTEST_IRQ          -2
+
+#define IRQ_LINE0             0
+#define IRQ_LINE1             1
+
 /*
  * The sensor can also generate interrupts (DRDY) but it's pretty pointless
  * because they are generated even if the data do not change. So it's better
@@ -226,8 +233,25 @@ static int lis3lv02d_selftest(struct lis3lv02d *lis3, s16 results[3])
        s16 x, y, z;
        u8 selftest;
        int ret;
+       u8 ctrl_reg_data;
+       unsigned char irq_cfg;
 
        mutex_lock(&lis3->mutex);
+
+       irq_cfg = lis3->irq_cfg;
+       if (lis3_dev.whoami == WAI_8B) {
+               lis3->data_ready_count[IRQ_LINE0] = 0;
+               lis3->data_ready_count[IRQ_LINE1] = 0;
+
+               /* Change interrupt cfg to data ready for selftest */
+               atomic_inc(&lis3_dev.wake_thread);
+               lis3->irq_cfg = LIS3_IRQ1_DATA_READY | LIS3_IRQ2_DATA_READY;
+               lis3->read(lis3, CTRL_REG3, &ctrl_reg_data);
+               lis3->write(lis3, CTRL_REG3, (ctrl_reg_data &
+                               ~(LIS3_IRQ1_MASK | LIS3_IRQ2_MASK)) |
+                               (LIS3_IRQ1_DATA_READY | LIS3_IRQ2_DATA_READY));
+       }
+
        if (lis3_dev.whoami == WAI_3DC) {
                ctlreg = CTRL_REG4;
                selftest = CTRL4_ST0;
@@ -257,13 +281,33 @@ static int lis3lv02d_selftest(struct lis3lv02d *lis3, s16 results[3])
        results[2] = z - lis3->read_data(lis3, OUTZ);
 
        ret = 0;
+
+       if (lis3_dev.whoami == WAI_8B) {
+               /* Restore original interrupt configuration */
+               atomic_dec(&lis3_dev.wake_thread);
+               lis3->write(lis3, CTRL_REG3, ctrl_reg_data);
+               lis3->irq_cfg = irq_cfg;
+
+               if ((irq_cfg & LIS3_IRQ1_MASK) &&
+                       lis3->data_ready_count[IRQ_LINE0] < 2) {
+                       ret = SELFTEST_IRQ;
+                       goto fail;
+               }
+
+               if ((irq_cfg & LIS3_IRQ2_MASK) &&
+                       lis3->data_ready_count[IRQ_LINE1] < 2) {
+                       ret = SELFTEST_IRQ;
+                       goto fail;
+               }
+       }
+
        if (lis3->pdata) {
                int i;
                for (i = 0; i < 3; i++) {
                        /* Check against selftest acceptance limits */
                        if ((results[i] < lis3->pdata->st_min_limits[i]) ||
                            (results[i] > lis3->pdata->st_max_limits[i])) {
-                               ret = -EIO;
+                               ret = SELFTEST_FAIL;
                                goto fail;
                        }
                }
@@ -426,13 +470,24 @@ static void lis302dl_interrupt_handle_click(struct lis3lv02d *lis3)
        mutex_unlock(&lis3->mutex);
 }
 
-static irqreturn_t lis302dl_interrupt_thread1_8b(int irq, void *data)
+static inline void lis302dl_data_ready(struct lis3lv02d *lis3, int index)
 {
+       int dummy;
+
+       /* Dummy read to ack interrupt */
+       lis3lv02d_get_xyz(lis3, &dummy, &dummy, &dummy);
+       lis3->data_ready_count[index]++;
+}
 
+static irqreturn_t lis302dl_interrupt_thread1_8b(int irq, void *data)
+{
        struct lis3lv02d *lis3 = data;
+       u8 irq_cfg = lis3->irq_cfg & LIS3_IRQ1_MASK;
 
-       if ((lis3->irq_cfg & LIS3_IRQ1_MASK) == LIS3_IRQ1_CLICK)
+       if (irq_cfg == LIS3_IRQ1_CLICK)
                lis302dl_interrupt_handle_click(lis3);
+       else if (unlikely(irq_cfg == LIS3_IRQ1_DATA_READY))
+               lis302dl_data_ready(lis3, IRQ_LINE0);
        else
                lis3lv02d_joystick_poll(lis3->idev);
 
@@ -441,11 +496,13 @@ static irqreturn_t lis302dl_interrupt_thread1_8b(int irq, void *data)
 
 static irqreturn_t lis302dl_interrupt_thread2_8b(int irq, void *data)
 {
-
        struct lis3lv02d *lis3 = data;
+       u8 irq_cfg = lis3->irq_cfg & LIS3_IRQ2_MASK;
 
-       if ((lis3->irq_cfg & LIS3_IRQ2_MASK) == LIS3_IRQ2_CLICK)
+       if (irq_cfg == LIS3_IRQ2_CLICK)
                lis302dl_interrupt_handle_click(lis3);
+       else if (unlikely(irq_cfg == LIS3_IRQ2_DATA_READY))
+               lis302dl_data_ready(lis3, IRQ_LINE1);
        else
                lis3lv02d_joystick_poll(lis3->idev);
 
@@ -648,12 +705,27 @@ static void lis3lv02d_sysfs_poweron(struct lis3lv02d *lis3)
 static ssize_t lis3lv02d_selftest_show(struct device *dev,
                                struct device_attribute *attr, char *buf)
 {
-       int result;
        s16 values[3];
 
+       static const char ok[] = "OK";
+       static const char fail[] = "FAIL";
+       static const char irq[] = "FAIL_IRQ";
+       const char *res;
+
        lis3lv02d_sysfs_poweron(&lis3_dev);
-       result = lis3lv02d_selftest(&lis3_dev, values);
-       return sprintf(buf, "%s %d %d %d\n", result == 0 ? "OK" : "FAIL",
+       switch (lis3lv02d_selftest(&lis3_dev, values)) {
+       case SELFTEST_FAIL:
+               res = fail;
+               break;
+       case SELFTEST_IRQ:
+               res = irq;
+               break;
+       case SELFTEST_OK:
+       default:
+               res = ok;
+               break;
+       }
+       return sprintf(buf, "%s %d %d %d\n", res,
                values[0], values[1], values[2]);
 }
 
index fdbe899..a193958 100644 (file)
@@ -273,7 +273,8 @@ struct lis3lv02d {
        struct fasync_struct    *async_queue; /* queue for the misc device */
        wait_queue_head_t       misc_wait; /* Wait queue for the misc device */
        unsigned long           misc_opened; /* bit0: whether the device is open */
-       atomic_t                wake_thread;
+       int                     data_ready_count[2];
+       atomic_t                wake_thread;
        unsigned char           irq_cfg;
 
        struct lis3lv02d_platform_data *pdata;  /* for passing board config */