diff options
| -rw-r--r-- | drivers/hwmon/lis3lv02d.c | 88 | ||||
| -rw-r--r-- | drivers/hwmon/lis3lv02d.h | 3 |
2 files changed, 82 insertions, 9 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 | ||
diff --git a/drivers/hwmon/lis3lv02d.h b/drivers/hwmon/lis3lv02d.h index fdbe899a7f14..a1939589eb2c 100644 --- a/drivers/hwmon/lis3lv02d.h +++ b/drivers/hwmon/lis3lv02d.h | |||
| @@ -273,7 +273,8 @@ struct lis3lv02d { | |||
| 273 | struct fasync_struct *async_queue; /* queue for the misc device */ | 273 | struct fasync_struct *async_queue; /* queue for the misc device */ |
| 274 | wait_queue_head_t misc_wait; /* Wait queue for the misc device */ | 274 | wait_queue_head_t misc_wait; /* Wait queue for the misc device */ |
| 275 | unsigned long misc_opened; /* bit0: whether the device is open */ | 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 | unsigned char irq_cfg; | 278 | unsigned char irq_cfg; |
| 278 | 279 | ||
| 279 | struct lis3lv02d_platform_data *pdata; /* for passing board config */ | 280 | struct lis3lv02d_platform_data *pdata; /* for passing board config */ |
