Commit 029756d0b8856f52d83dee81c01dd3af786cadff
Committed by
Guenter Roeck
1 parent
f10a5407b5
Exists in
master
and in
7 other branches
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>
Showing 2 changed files with 82 additions and 9 deletions Side-by-side Diff
drivers/hwmon/lis3lv02d.c
... | ... | @@ -48,6 +48,13 @@ |
48 | 48 | |
49 | 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 | 59 | * The sensor can also generate interrupts (DRDY) but it's pretty pointless |
53 | 60 | * because they are generated even if the data do not change. So it's better |
54 | 61 | |
... | ... | @@ -226,8 +233,25 @@ |
226 | 233 | s16 x, y, z; |
227 | 234 | u8 selftest; |
228 | 235 | int ret; |
236 | + u8 ctrl_reg_data; | |
237 | + unsigned char irq_cfg; | |
229 | 238 | |
230 | 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 | 255 | if (lis3_dev.whoami == WAI_3DC) { |
232 | 256 | ctlreg = CTRL_REG4; |
233 | 257 | selftest = CTRL4_ST0; |
234 | 258 | |
... | ... | @@ -257,13 +281,33 @@ |
257 | 281 | results[2] = z - lis3->read_data(lis3, OUTZ); |
258 | 282 | |
259 | 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 | 304 | if (lis3->pdata) { |
261 | 305 | int i; |
262 | 306 | for (i = 0; i < 3; i++) { |
263 | 307 | /* Check against selftest acceptance limits */ |
264 | 308 | if ((results[i] < lis3->pdata->st_min_limits[i]) || |
265 | 309 | (results[i] > lis3->pdata->st_max_limits[i])) { |
266 | - ret = -EIO; | |
310 | + ret = SELFTEST_FAIL; | |
267 | 311 | goto fail; |
268 | 312 | } |
269 | 313 | } |
270 | 314 | |
271 | 315 | |
272 | 316 | |
273 | 317 | |
274 | 318 | |
... | ... | @@ -426,13 +470,24 @@ |
426 | 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; | |
431 | 476 | |
477 | + /* Dummy read to ack interrupt */ | |
478 | + lis3lv02d_get_xyz(lis3, &dummy, &dummy, &dummy); | |
479 | + lis3->data_ready_count[index]++; | |
480 | +} | |
481 | + | |
482 | +static irqreturn_t lis302dl_interrupt_thread1_8b(int irq, void *data) | |
483 | +{ | |
432 | 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 | 488 | lis302dl_interrupt_handle_click(lis3); |
489 | + else if (unlikely(irq_cfg == LIS3_IRQ1_DATA_READY)) | |
490 | + lis302dl_data_ready(lis3, IRQ_LINE0); | |
436 | 491 | else |
437 | 492 | lis3lv02d_joystick_poll(lis3->idev); |
438 | 493 | |
439 | 494 | |
440 | 495 | |
441 | 496 | |
... | ... | @@ -441,11 +496,13 @@ |
441 | 496 | |
442 | 497 | static irqreturn_t lis302dl_interrupt_thread2_8b(int irq, void *data) |
443 | 498 | { |
444 | - | |
445 | 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 | 503 | lis302dl_interrupt_handle_click(lis3); |
504 | + else if (unlikely(irq_cfg == LIS3_IRQ2_DATA_READY)) | |
505 | + lis302dl_data_ready(lis3, IRQ_LINE1); | |
449 | 506 | else |
450 | 507 | lis3lv02d_joystick_poll(lis3->idev); |
451 | 508 | |
452 | 509 | |
453 | 510 | |
... | ... | @@ -648,12 +705,27 @@ |
648 | 705 | static ssize_t lis3lv02d_selftest_show(struct device *dev, |
649 | 706 | struct device_attribute *attr, char *buf) |
650 | 707 | { |
651 | - int result; | |
652 | 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 | 715 | lis3lv02d_sysfs_poweron(&lis3_dev); |
655 | - result = lis3lv02d_selftest(&lis3_dev, values); | |
656 | - return sprintf(buf, "%s %d %d %d\n", result == 0 ? "OK" : "FAIL", | |
716 | + switch (lis3lv02d_selftest(&lis3_dev, values)) { | |
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 | 729 | values[0], values[1], values[2]); |
658 | 730 | } |
659 | 731 |
drivers/hwmon/lis3lv02d.h
... | ... | @@ -273,7 +273,8 @@ |
273 | 273 | struct fasync_struct *async_queue; /* queue for the misc device */ |
274 | 274 | wait_queue_head_t misc_wait; /* Wait queue for the misc device */ |
275 | 275 | unsigned long misc_opened; /* bit0: whether the device is open */ |
276 | - atomic_t wake_thread; | |
276 | + int data_ready_count[2]; | |
277 | + atomic_t wake_thread; | |
277 | 278 | unsigned char irq_cfg; |
278 | 279 | |
279 | 280 | struct lis3lv02d_platform_data *pdata; /* for passing board config */ |