diff options
author | Samu Onkalo <samu.p.onkalo@nokia.com> | 2010-10-22 07:57:32 -0400 |
---|---|---|
committer | Guenter Roeck <guenter.roeck@ericsson.com> | 2010-10-25 17:11:39 -0400 |
commit | 029756d0b8856f52d83dee81c01dd3af786cadff (patch) | |
tree | 573ac19fe3461f1ffece64fd42af8573c011fa5d /drivers/hwmon/lis3lv02d.c | |
parent | f10a5407b58603fb3b084d7fbdbd50f47d010c82 (diff) |
hwmon: lis3: Enhance lis3 selftest with IRQ line test
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>
Diffstat (limited to 'drivers/hwmon/lis3lv02d.c')
-rw-r--r-- | drivers/hwmon/lis3lv02d.c | 88 |
1 files changed, 80 insertions, 8 deletions
diff --git a/drivers/hwmon/lis3lv02d.c b/drivers/hwmon/lis3lv02d.c index 0780de0550df..0cee73a6124e 100644 --- a/drivers/hwmon/lis3lv02d.c +++ b/drivers/hwmon/lis3lv02d.c | |||
@@ -48,6 +48,13 @@ | |||
48 | 48 | ||
49 | #define LIS3_SYSFS_POWERDOWN_DELAY 5000 /* In milliseconds */ | 49 | #define LIS3_SYSFS_POWERDOWN_DELAY 5000 /* In milliseconds */ |
50 | 50 | ||
51 | #define SELFTEST_OK 0 | ||
52 | #define SELFTEST_FAIL -1 | ||
53 | #define SELFTEST_IRQ -2 | ||
54 | |||
55 | #define IRQ_LINE0 0 | ||
56 | #define IRQ_LINE1 1 | ||
57 | |||
51 | /* | 58 | /* |
52 | * The sensor can also generate interrupts (DRDY) but it's pretty pointless | 59 | * The sensor can also generate interrupts (DRDY) but it's pretty pointless |
53 | * because they are generated even if the data do not change. So it's better | 60 | * 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]) | |||
226 | s16 x, y, z; | 233 | s16 x, y, z; |
227 | u8 selftest; | 234 | u8 selftest; |
228 | int ret; | 235 | int ret; |
236 | u8 ctrl_reg_data; | ||
237 | unsigned char irq_cfg; | ||
229 | 238 | ||
230 | mutex_lock(&lis3->mutex); | 239 | mutex_lock(&lis3->mutex); |
240 | |||
241 | irq_cfg = lis3->irq_cfg; | ||
242 | if (lis3_dev.whoami == WAI_8B) { | ||
243 | lis3->data_ready_count[IRQ_LINE0] = 0; | ||
244 | lis3->data_ready_count[IRQ_LINE1] = 0; | ||
245 | |||
246 | /* Change interrupt cfg to data ready for selftest */ | ||
247 | atomic_inc(&lis3_dev.wake_thread); | ||
248 | lis3->irq_cfg = LIS3_IRQ1_DATA_READY | LIS3_IRQ2_DATA_READY; | ||
249 | lis3->read(lis3, CTRL_REG3, &ctrl_reg_data); | ||
250 | lis3->write(lis3, CTRL_REG3, (ctrl_reg_data & | ||
251 | ~(LIS3_IRQ1_MASK | LIS3_IRQ2_MASK)) | | ||
252 | (LIS3_IRQ1_DATA_READY | LIS3_IRQ2_DATA_READY)); | ||
253 | } | ||
254 | |||
231 | if (lis3_dev.whoami == WAI_3DC) { | 255 | if (lis3_dev.whoami == WAI_3DC) { |
232 | ctlreg = CTRL_REG4; | 256 | ctlreg = CTRL_REG4; |
233 | selftest = CTRL4_ST0; | 257 | selftest = CTRL4_ST0; |
@@ -257,13 +281,33 @@ static int lis3lv02d_selftest(struct lis3lv02d *lis3, s16 results[3]) | |||
257 | results[2] = z - lis3->read_data(lis3, OUTZ); | 281 | results[2] = z - lis3->read_data(lis3, OUTZ); |
258 | 282 | ||
259 | ret = 0; | 283 | ret = 0; |
284 | |||
285 | if (lis3_dev.whoami == WAI_8B) { | ||
286 | /* Restore original interrupt configuration */ | ||
287 | atomic_dec(&lis3_dev.wake_thread); | ||
288 | lis3->write(lis3, CTRL_REG3, ctrl_reg_data); | ||
289 | lis3->irq_cfg = irq_cfg; | ||
290 | |||
291 | if ((irq_cfg & LIS3_IRQ1_MASK) && | ||
292 | lis3->data_ready_count[IRQ_LINE0] < 2) { | ||
293 | ret = SELFTEST_IRQ; | ||
294 | goto fail; | ||
295 | } | ||
296 | |||
297 | if ((irq_cfg & LIS3_IRQ2_MASK) && | ||
298 | lis3->data_ready_count[IRQ_LINE1] < 2) { | ||
299 | ret = SELFTEST_IRQ; | ||
300 | goto fail; | ||
301 | } | ||
302 | } | ||
303 | |||
260 | if (lis3->pdata) { | 304 | if (lis3->pdata) { |
261 | int i; | 305 | int i; |
262 | for (i = 0; i < 3; i++) { | 306 | for (i = 0; i < 3; i++) { |
263 | /* Check against selftest acceptance limits */ | 307 | /* Check against selftest acceptance limits */ |
264 | if ((results[i] < lis3->pdata->st_min_limits[i]) || | 308 | if ((results[i] < lis3->pdata->st_min_limits[i]) || |
265 | (results[i] > lis3->pdata->st_max_limits[i])) { | 309 | (results[i] > lis3->pdata->st_max_limits[i])) { |
266 | ret = -EIO; | 310 | ret = SELFTEST_FAIL; |
267 | goto fail; | 311 | goto fail; |
268 | } | 312 | } |
269 | } | 313 | } |
@@ -426,13 +470,24 @@ static void lis302dl_interrupt_handle_click(struct lis3lv02d *lis3) | |||
426 | mutex_unlock(&lis3->mutex); | 470 | mutex_unlock(&lis3->mutex); |
427 | } | 471 | } |
428 | 472 | ||
429 | static irqreturn_t lis302dl_interrupt_thread1_8b(int irq, void *data) | 473 | static inline void lis302dl_data_ready(struct lis3lv02d *lis3, int index) |
430 | { | 474 | { |
475 | int dummy; | ||
476 | |||
477 | /* Dummy read to ack interrupt */ | ||
478 | lis3lv02d_get_xyz(lis3, &dummy, &dummy, &dummy); | ||
479 | lis3->data_ready_count[index]++; | ||
480 | } | ||
431 | 481 | ||
482 | static irqreturn_t lis302dl_interrupt_thread1_8b(int irq, void *data) | ||
483 | { | ||
432 | struct lis3lv02d *lis3 = data; | 484 | struct lis3lv02d *lis3 = data; |
485 | u8 irq_cfg = lis3->irq_cfg & LIS3_IRQ1_MASK; | ||
433 | 486 | ||
434 | if ((lis3->irq_cfg & LIS3_IRQ1_MASK) == LIS3_IRQ1_CLICK) | 487 | if (irq_cfg == LIS3_IRQ1_CLICK) |
435 | lis302dl_interrupt_handle_click(lis3); | 488 | lis302dl_interrupt_handle_click(lis3); |
489 | else if (unlikely(irq_cfg == LIS3_IRQ1_DATA_READY)) | ||
490 | lis302dl_data_ready(lis3, IRQ_LINE0); | ||
436 | else | 491 | else |
437 | lis3lv02d_joystick_poll(lis3->idev); | 492 | lis3lv02d_joystick_poll(lis3->idev); |
438 | 493 | ||
@@ -441,11 +496,13 @@ static irqreturn_t lis302dl_interrupt_thread1_8b(int irq, void *data) | |||
441 | 496 | ||
442 | static irqreturn_t lis302dl_interrupt_thread2_8b(int irq, void *data) | 497 | static irqreturn_t lis302dl_interrupt_thread2_8b(int irq, void *data) |
443 | { | 498 | { |
444 | |||
445 | struct lis3lv02d *lis3 = data; | 499 | struct lis3lv02d *lis3 = data; |
500 | u8 irq_cfg = lis3->irq_cfg & LIS3_IRQ2_MASK; | ||
446 | 501 | ||
447 | if ((lis3->irq_cfg & LIS3_IRQ2_MASK) == LIS3_IRQ2_CLICK) | 502 | if (irq_cfg == LIS3_IRQ2_CLICK) |
448 | lis302dl_interrupt_handle_click(lis3); | 503 | lis302dl_interrupt_handle_click(lis3); |
504 | else if (unlikely(irq_cfg == LIS3_IRQ2_DATA_READY)) | ||
505 | lis302dl_data_ready(lis3, IRQ_LINE1); | ||
449 | else | 506 | else |
450 | lis3lv02d_joystick_poll(lis3->idev); | 507 | lis3lv02d_joystick_poll(lis3->idev); |
451 | 508 | ||
@@ -648,12 +705,27 @@ static void lis3lv02d_sysfs_poweron(struct lis3lv02d *lis3) | |||
648 | static ssize_t lis3lv02d_selftest_show(struct device *dev, | 705 | static ssize_t lis3lv02d_selftest_show(struct device *dev, |
649 | struct device_attribute *attr, char *buf) | 706 | struct device_attribute *attr, char *buf) |
650 | { | 707 | { |
651 | int result; | ||
652 | s16 values[3]; | 708 | s16 values[3]; |
653 | 709 | ||
710 | static const char ok[] = "OK"; | ||
711 | static const char fail[] = "FAIL"; | ||
712 | static const char irq[] = "FAIL_IRQ"; | ||
713 | const char *res; | ||
714 | |||
654 | lis3lv02d_sysfs_poweron(&lis3_dev); | 715 | lis3lv02d_sysfs_poweron(&lis3_dev); |
655 | result = lis3lv02d_selftest(&lis3_dev, values); | 716 | switch (lis3lv02d_selftest(&lis3_dev, values)) { |
656 | return sprintf(buf, "%s %d %d %d\n", result == 0 ? "OK" : "FAIL", | 717 | case SELFTEST_FAIL: |
718 | res = fail; | ||
719 | break; | ||
720 | case SELFTEST_IRQ: | ||
721 | res = irq; | ||
722 | break; | ||
723 | case SELFTEST_OK: | ||
724 | default: | ||
725 | res = ok; | ||
726 | break; | ||
727 | } | ||
728 | return sprintf(buf, "%s %d %d %d\n", res, | ||
657 | values[0], values[1], values[2]); | 729 | values[0], values[1], values[2]); |
658 | } | 730 | } |
659 | 731 | ||