diff options
Diffstat (limited to 'drivers/hwmon/lis3lv02d.c')
| -rw-r--r-- | drivers/hwmon/lis3lv02d.c | 245 |
1 files changed, 190 insertions, 55 deletions
diff --git a/drivers/hwmon/lis3lv02d.c b/drivers/hwmon/lis3lv02d.c index b2f2277cad3c..6138f036b159 100644 --- a/drivers/hwmon/lis3lv02d.c +++ b/drivers/hwmon/lis3lv02d.c | |||
| @@ -41,6 +41,8 @@ | |||
| 41 | 41 | ||
| 42 | /* joystick device poll interval in milliseconds */ | 42 | /* joystick device poll interval in milliseconds */ |
| 43 | #define MDPS_POLL_INTERVAL 50 | 43 | #define MDPS_POLL_INTERVAL 50 |
| 44 | #define MDPS_POLL_MIN 0 | ||
| 45 | #define MDPS_POLL_MAX 2000 | ||
| 44 | /* | 46 | /* |
| 45 | * The sensor can also generate interrupts (DRDY) but it's pretty pointless | 47 | * The sensor can also generate interrupts (DRDY) but it's pretty pointless |
| 46 | * because they are generated even if the data do not change. So it's better | 48 | * because they are generated even if the data do not change. So it's better |
| @@ -121,11 +123,9 @@ static void lis3lv02d_get_xyz(struct lis3lv02d *lis3, int *x, int *y, int *z) | |||
| 121 | int position[3]; | 123 | int position[3]; |
| 122 | int i; | 124 | int i; |
| 123 | 125 | ||
| 124 | mutex_lock(&lis3->mutex); | ||
| 125 | position[0] = lis3->read_data(lis3, OUTX); | 126 | position[0] = lis3->read_data(lis3, OUTX); |
| 126 | position[1] = lis3->read_data(lis3, OUTY); | 127 | position[1] = lis3->read_data(lis3, OUTY); |
| 127 | position[2] = lis3->read_data(lis3, OUTZ); | 128 | position[2] = lis3->read_data(lis3, OUTZ); |
| 128 | mutex_unlock(&lis3->mutex); | ||
| 129 | 129 | ||
| 130 | for (i = 0; i < 3; i++) | 130 | for (i = 0; i < 3; i++) |
| 131 | position[i] = (position[i] * lis3->scale) / LIS3_ACCURACY; | 131 | position[i] = (position[i] * lis3->scale) / LIS3_ACCURACY; |
| @@ -249,8 +249,24 @@ void lis3lv02d_poweron(struct lis3lv02d *lis3) | |||
| 249 | EXPORT_SYMBOL_GPL(lis3lv02d_poweron); | 249 | EXPORT_SYMBOL_GPL(lis3lv02d_poweron); |
| 250 | 250 | ||
| 251 | 251 | ||
| 252 | static void lis3lv02d_joystick_poll(struct input_polled_dev *pidev) | ||
| 253 | { | ||
| 254 | int x, y, z; | ||
| 255 | |||
| 256 | mutex_lock(&lis3_dev.mutex); | ||
| 257 | lis3lv02d_get_xyz(&lis3_dev, &x, &y, &z); | ||
| 258 | input_report_abs(pidev->input, ABS_X, x); | ||
| 259 | input_report_abs(pidev->input, ABS_Y, y); | ||
| 260 | input_report_abs(pidev->input, ABS_Z, z); | ||
| 261 | input_sync(pidev->input); | ||
| 262 | mutex_unlock(&lis3_dev.mutex); | ||
| 263 | } | ||
| 264 | |||
| 252 | static irqreturn_t lis302dl_interrupt(int irq, void *dummy) | 265 | static irqreturn_t lis302dl_interrupt(int irq, void *dummy) |
| 253 | { | 266 | { |
| 267 | if (!test_bit(0, &lis3_dev.misc_opened)) | ||
| 268 | goto out; | ||
| 269 | |||
| 254 | /* | 270 | /* |
| 255 | * Be careful: on some HP laptops the bios force DD when on battery and | 271 | * Be careful: on some HP laptops the bios force DD when on battery and |
| 256 | * the lid is closed. This leads to interrupts as soon as a little move | 272 | * the lid is closed. This leads to interrupts as soon as a little move |
| @@ -260,44 +276,93 @@ static irqreturn_t lis302dl_interrupt(int irq, void *dummy) | |||
| 260 | 276 | ||
| 261 | wake_up_interruptible(&lis3_dev.misc_wait); | 277 | wake_up_interruptible(&lis3_dev.misc_wait); |
| 262 | kill_fasync(&lis3_dev.async_queue, SIGIO, POLL_IN); | 278 | kill_fasync(&lis3_dev.async_queue, SIGIO, POLL_IN); |
| 279 | out: | ||
| 280 | if (lis3_dev.whoami == WAI_8B && lis3_dev.idev && | ||
| 281 | lis3_dev.idev->input->users) | ||
| 282 | return IRQ_WAKE_THREAD; | ||
| 263 | return IRQ_HANDLED; | 283 | return IRQ_HANDLED; |
| 264 | } | 284 | } |
| 265 | 285 | ||
| 266 | static int lis3lv02d_misc_open(struct inode *inode, struct file *file) | 286 | static void lis302dl_interrupt_handle_click(struct lis3lv02d *lis3) |
| 267 | { | 287 | { |
| 268 | int ret; | 288 | struct input_dev *dev = lis3->idev->input; |
| 289 | u8 click_src; | ||
| 269 | 290 | ||
| 270 | if (test_and_set_bit(0, &lis3_dev.misc_opened)) | 291 | mutex_lock(&lis3->mutex); |
| 271 | return -EBUSY; /* already open */ | 292 | lis3->read(lis3, CLICK_SRC, &click_src); |
| 272 | 293 | ||
| 273 | atomic_set(&lis3_dev.count, 0); | 294 | if (click_src & CLICK_SINGLE_X) { |
| 295 | input_report_key(dev, lis3->mapped_btns[0], 1); | ||
| 296 | input_report_key(dev, lis3->mapped_btns[0], 0); | ||
| 297 | } | ||
| 274 | 298 | ||
| 275 | /* | 299 | if (click_src & CLICK_SINGLE_Y) { |
| 276 | * The sensor can generate interrupts for free-fall and direction | 300 | input_report_key(dev, lis3->mapped_btns[1], 1); |
| 277 | * detection (distinguishable with FF_WU_SRC and DD_SRC) but to keep | 301 | input_report_key(dev, lis3->mapped_btns[1], 0); |
| 278 | * the things simple and _fast_ we activate it only for free-fall, so | 302 | } |
| 279 | * no need to read register (very slow with ACPI). For the same reason, | ||
| 280 | * we forbid shared interrupts. | ||
| 281 | * | ||
| 282 | * IRQF_TRIGGER_RISING seems pointless on HP laptops because the | ||
| 283 | * io-apic is not configurable (and generates a warning) but I keep it | ||
| 284 | * in case of support for other hardware. | ||
| 285 | */ | ||
| 286 | ret = request_irq(lis3_dev.irq, lis302dl_interrupt, IRQF_TRIGGER_RISING, | ||
| 287 | DRIVER_NAME, &lis3_dev); | ||
| 288 | 303 | ||
| 289 | if (ret) { | 304 | if (click_src & CLICK_SINGLE_Z) { |
| 290 | clear_bit(0, &lis3_dev.misc_opened); | 305 | input_report_key(dev, lis3->mapped_btns[2], 1); |
| 291 | printk(KERN_ERR DRIVER_NAME ": IRQ%d allocation failed\n", lis3_dev.irq); | 306 | input_report_key(dev, lis3->mapped_btns[2], 0); |
| 292 | return -EBUSY; | ||
| 293 | } | 307 | } |
| 308 | input_sync(dev); | ||
| 309 | mutex_unlock(&lis3->mutex); | ||
| 310 | } | ||
| 311 | |||
| 312 | static void lis302dl_interrupt_handle_ff_wu(struct lis3lv02d *lis3) | ||
| 313 | { | ||
| 314 | u8 wu1_src; | ||
| 315 | u8 wu2_src; | ||
| 316 | |||
| 317 | lis3->read(lis3, FF_WU_SRC_1, &wu1_src); | ||
| 318 | lis3->read(lis3, FF_WU_SRC_2, &wu2_src); | ||
| 319 | |||
| 320 | wu1_src = wu1_src & FF_WU_SRC_IA ? wu1_src : 0; | ||
| 321 | wu2_src = wu2_src & FF_WU_SRC_IA ? wu2_src : 0; | ||
| 322 | |||
| 323 | /* joystick poll is internally protected by the lis3->mutex. */ | ||
| 324 | if (wu1_src || wu2_src) | ||
| 325 | lis3lv02d_joystick_poll(lis3_dev.idev); | ||
| 326 | } | ||
| 327 | |||
| 328 | static irqreturn_t lis302dl_interrupt_thread1_8b(int irq, void *data) | ||
| 329 | { | ||
| 330 | |||
| 331 | struct lis3lv02d *lis3 = data; | ||
| 332 | |||
| 333 | if ((lis3->pdata->irq_cfg & LIS3_IRQ1_MASK) == LIS3_IRQ1_CLICK) | ||
| 334 | lis302dl_interrupt_handle_click(lis3); | ||
| 335 | else | ||
| 336 | lis302dl_interrupt_handle_ff_wu(lis3); | ||
| 337 | |||
| 338 | return IRQ_HANDLED; | ||
| 339 | } | ||
| 340 | |||
| 341 | static irqreturn_t lis302dl_interrupt_thread2_8b(int irq, void *data) | ||
| 342 | { | ||
| 343 | |||
| 344 | struct lis3lv02d *lis3 = data; | ||
| 345 | |||
| 346 | if ((lis3->pdata->irq_cfg & LIS3_IRQ2_MASK) == LIS3_IRQ2_CLICK) | ||
| 347 | lis302dl_interrupt_handle_click(lis3); | ||
| 348 | else | ||
| 349 | lis302dl_interrupt_handle_ff_wu(lis3); | ||
| 350 | |||
| 351 | return IRQ_HANDLED; | ||
| 352 | } | ||
| 353 | |||
| 354 | static int lis3lv02d_misc_open(struct inode *inode, struct file *file) | ||
| 355 | { | ||
| 356 | if (test_and_set_bit(0, &lis3_dev.misc_opened)) | ||
| 357 | return -EBUSY; /* already open */ | ||
| 358 | |||
| 359 | atomic_set(&lis3_dev.count, 0); | ||
| 294 | return 0; | 360 | return 0; |
| 295 | } | 361 | } |
| 296 | 362 | ||
| 297 | static int lis3lv02d_misc_release(struct inode *inode, struct file *file) | 363 | static int lis3lv02d_misc_release(struct inode *inode, struct file *file) |
| 298 | { | 364 | { |
| 299 | fasync_helper(-1, file, 0, &lis3_dev.async_queue); | 365 | fasync_helper(-1, file, 0, &lis3_dev.async_queue); |
| 300 | free_irq(lis3_dev.irq, &lis3_dev); | ||
| 301 | clear_bit(0, &lis3_dev.misc_opened); /* release the device */ | 366 | clear_bit(0, &lis3_dev.misc_opened); /* release the device */ |
| 302 | return 0; | 367 | return 0; |
| 303 | } | 368 | } |
| @@ -380,22 +445,12 @@ static struct miscdevice lis3lv02d_misc_device = { | |||
| 380 | .fops = &lis3lv02d_misc_fops, | 445 | .fops = &lis3lv02d_misc_fops, |
| 381 | }; | 446 | }; |
| 382 | 447 | ||
| 383 | static void lis3lv02d_joystick_poll(struct input_polled_dev *pidev) | ||
| 384 | { | ||
| 385 | int x, y, z; | ||
| 386 | |||
| 387 | lis3lv02d_get_xyz(&lis3_dev, &x, &y, &z); | ||
| 388 | input_report_abs(pidev->input, ABS_X, x); | ||
| 389 | input_report_abs(pidev->input, ABS_Y, y); | ||
| 390 | input_report_abs(pidev->input, ABS_Z, z); | ||
| 391 | input_sync(pidev->input); | ||
| 392 | } | ||
| 393 | |||
| 394 | int lis3lv02d_joystick_enable(void) | 448 | int lis3lv02d_joystick_enable(void) |
| 395 | { | 449 | { |
| 396 | struct input_dev *input_dev; | 450 | struct input_dev *input_dev; |
| 397 | int err; | 451 | int err; |
| 398 | int max_val, fuzz, flat; | 452 | int max_val, fuzz, flat; |
| 453 | int btns[] = {BTN_X, BTN_Y, BTN_Z}; | ||
| 399 | 454 | ||
| 400 | if (lis3_dev.idev) | 455 | if (lis3_dev.idev) |
| 401 | return -EINVAL; | 456 | return -EINVAL; |
| @@ -406,6 +461,8 @@ int lis3lv02d_joystick_enable(void) | |||
| 406 | 461 | ||
| 407 | lis3_dev.idev->poll = lis3lv02d_joystick_poll; | 462 | lis3_dev.idev->poll = lis3lv02d_joystick_poll; |
| 408 | lis3_dev.idev->poll_interval = MDPS_POLL_INTERVAL; | 463 | lis3_dev.idev->poll_interval = MDPS_POLL_INTERVAL; |
| 464 | lis3_dev.idev->poll_interval_min = MDPS_POLL_MIN; | ||
| 465 | lis3_dev.idev->poll_interval_max = MDPS_POLL_MAX; | ||
| 409 | input_dev = lis3_dev.idev->input; | 466 | input_dev = lis3_dev.idev->input; |
| 410 | 467 | ||
| 411 | input_dev->name = "ST LIS3LV02DL Accelerometer"; | 468 | input_dev->name = "ST LIS3LV02DL Accelerometer"; |
| @@ -422,6 +479,10 @@ int lis3lv02d_joystick_enable(void) | |||
| 422 | input_set_abs_params(input_dev, ABS_Y, -max_val, max_val, fuzz, flat); | 479 | input_set_abs_params(input_dev, ABS_Y, -max_val, max_val, fuzz, flat); |
| 423 | input_set_abs_params(input_dev, ABS_Z, -max_val, max_val, fuzz, flat); | 480 | input_set_abs_params(input_dev, ABS_Z, -max_val, max_val, fuzz, flat); |
| 424 | 481 | ||
| 482 | lis3_dev.mapped_btns[0] = lis3lv02d_get_axis(abs(lis3_dev.ac.x), btns); | ||
| 483 | lis3_dev.mapped_btns[1] = lis3lv02d_get_axis(abs(lis3_dev.ac.y), btns); | ||
| 484 | lis3_dev.mapped_btns[2] = lis3lv02d_get_axis(abs(lis3_dev.ac.z), btns); | ||
| 485 | |||
| 425 | err = input_register_polled_device(lis3_dev.idev); | 486 | err = input_register_polled_device(lis3_dev.idev); |
| 426 | if (err) { | 487 | if (err) { |
| 427 | input_free_polled_device(lis3_dev.idev); | 488 | input_free_polled_device(lis3_dev.idev); |
| @@ -434,6 +495,11 @@ EXPORT_SYMBOL_GPL(lis3lv02d_joystick_enable); | |||
| 434 | 495 | ||
| 435 | void lis3lv02d_joystick_disable(void) | 496 | void lis3lv02d_joystick_disable(void) |
| 436 | { | 497 | { |
| 498 | if (lis3_dev.irq) | ||
| 499 | free_irq(lis3_dev.irq, &lis3_dev); | ||
| 500 | if (lis3_dev.pdata && lis3_dev.pdata->irq2) | ||
| 501 | free_irq(lis3_dev.pdata->irq2, &lis3_dev); | ||
| 502 | |||
| 437 | if (!lis3_dev.idev) | 503 | if (!lis3_dev.idev) |
| 438 | return; | 504 | return; |
| 439 | 505 | ||
| @@ -462,7 +528,9 @@ static ssize_t lis3lv02d_position_show(struct device *dev, | |||
| 462 | { | 528 | { |
| 463 | int x, y, z; | 529 | int x, y, z; |
| 464 | 530 | ||
| 531 | mutex_lock(&lis3_dev.mutex); | ||
| 465 | lis3lv02d_get_xyz(&lis3_dev, &x, &y, &z); | 532 | lis3lv02d_get_xyz(&lis3_dev, &x, &y, &z); |
| 533 | mutex_unlock(&lis3_dev.mutex); | ||
| 466 | return sprintf(buf, "(%d,%d,%d)\n", x, y, z); | 534 | return sprintf(buf, "(%d,%d,%d)\n", x, y, z); |
| 467 | } | 535 | } |
| 468 | 536 | ||
| @@ -521,12 +589,70 @@ int lis3lv02d_remove_fs(struct lis3lv02d *lis3) | |||
| 521 | } | 589 | } |
| 522 | EXPORT_SYMBOL_GPL(lis3lv02d_remove_fs); | 590 | EXPORT_SYMBOL_GPL(lis3lv02d_remove_fs); |
| 523 | 591 | ||
| 592 | static void lis3lv02d_8b_configure(struct lis3lv02d *dev, | ||
| 593 | struct lis3lv02d_platform_data *p) | ||
| 594 | { | ||
| 595 | int err; | ||
| 596 | int ctrl2 = p->hipass_ctrl; | ||
| 597 | |||
| 598 | if (p->click_flags) { | ||
| 599 | dev->write(dev, CLICK_CFG, p->click_flags); | ||
| 600 | dev->write(dev, CLICK_TIMELIMIT, p->click_time_limit); | ||
| 601 | dev->write(dev, CLICK_LATENCY, p->click_latency); | ||
| 602 | dev->write(dev, CLICK_WINDOW, p->click_window); | ||
| 603 | dev->write(dev, CLICK_THSZ, p->click_thresh_z & 0xf); | ||
| 604 | dev->write(dev, CLICK_THSY_X, | ||
| 605 | (p->click_thresh_x & 0xf) | | ||
| 606 | (p->click_thresh_y << 4)); | ||
| 607 | |||
| 608 | if (dev->idev) { | ||
| 609 | struct input_dev *input_dev = lis3_dev.idev->input; | ||
| 610 | input_set_capability(input_dev, EV_KEY, BTN_X); | ||
| 611 | input_set_capability(input_dev, EV_KEY, BTN_Y); | ||
| 612 | input_set_capability(input_dev, EV_KEY, BTN_Z); | ||
| 613 | } | ||
| 614 | } | ||
| 615 | |||
| 616 | if (p->wakeup_flags) { | ||
| 617 | dev->write(dev, FF_WU_CFG_1, p->wakeup_flags); | ||
| 618 | dev->write(dev, FF_WU_THS_1, p->wakeup_thresh & 0x7f); | ||
| 619 | /* default to 2.5ms for now */ | ||
| 620 | dev->write(dev, FF_WU_DURATION_1, 1); | ||
| 621 | ctrl2 ^= HP_FF_WU1; /* Xor to keep compatible with old pdata*/ | ||
| 622 | } | ||
| 623 | |||
| 624 | if (p->wakeup_flags2) { | ||
| 625 | dev->write(dev, FF_WU_CFG_2, p->wakeup_flags2); | ||
| 626 | dev->write(dev, FF_WU_THS_2, p->wakeup_thresh2 & 0x7f); | ||
| 627 | /* default to 2.5ms for now */ | ||
| 628 | dev->write(dev, FF_WU_DURATION_2, 1); | ||
| 629 | ctrl2 ^= HP_FF_WU2; /* Xor to keep compatible with old pdata*/ | ||
| 630 | } | ||
| 631 | /* Configure hipass filters */ | ||
| 632 | dev->write(dev, CTRL_REG2, ctrl2); | ||
| 633 | |||
| 634 | if (p->irq2) { | ||
| 635 | err = request_threaded_irq(p->irq2, | ||
| 636 | NULL, | ||
| 637 | lis302dl_interrupt_thread2_8b, | ||
| 638 | IRQF_TRIGGER_RISING | | ||
| 639 | IRQF_ONESHOT, | ||
| 640 | DRIVER_NAME, &lis3_dev); | ||
| 641 | if (err < 0) | ||
| 642 | printk(KERN_ERR DRIVER_NAME | ||
| 643 | "No second IRQ. Limited functionality\n"); | ||
| 644 | } | ||
| 645 | } | ||
| 646 | |||
| 524 | /* | 647 | /* |
| 525 | * Initialise the accelerometer and the various subsystems. | 648 | * Initialise the accelerometer and the various subsystems. |
| 526 | * Should be rather independent of the bus system. | 649 | * Should be rather independent of the bus system. |
| 527 | */ | 650 | */ |
| 528 | int lis3lv02d_init_device(struct lis3lv02d *dev) | 651 | int lis3lv02d_init_device(struct lis3lv02d *dev) |
| 529 | { | 652 | { |
| 653 | int err; | ||
| 654 | irq_handler_t thread_fn; | ||
| 655 | |||
| 530 | dev->whoami = lis3lv02d_read_8(dev, WHO_AM_I); | 656 | dev->whoami = lis3lv02d_read_8(dev, WHO_AM_I); |
| 531 | 657 | ||
| 532 | switch (dev->whoami) { | 658 | switch (dev->whoami) { |
| @@ -567,25 +693,8 @@ int lis3lv02d_init_device(struct lis3lv02d *dev) | |||
| 567 | if (dev->pdata) { | 693 | if (dev->pdata) { |
| 568 | struct lis3lv02d_platform_data *p = dev->pdata; | 694 | struct lis3lv02d_platform_data *p = dev->pdata; |
| 569 | 695 | ||
| 570 | if (p->click_flags && (dev->whoami == WAI_8B)) { | 696 | if (dev->whoami == WAI_8B) |
| 571 | dev->write(dev, CLICK_CFG, p->click_flags); | 697 | lis3lv02d_8b_configure(dev, p); |
| 572 | dev->write(dev, CLICK_TIMELIMIT, p->click_time_limit); | ||
| 573 | dev->write(dev, CLICK_LATENCY, p->click_latency); | ||
| 574 | dev->write(dev, CLICK_WINDOW, p->click_window); | ||
| 575 | dev->write(dev, CLICK_THSZ, p->click_thresh_z & 0xf); | ||
| 576 | dev->write(dev, CLICK_THSY_X, | ||
| 577 | (p->click_thresh_x & 0xf) | | ||
| 578 | (p->click_thresh_y << 4)); | ||
| 579 | } | ||
| 580 | |||
| 581 | if (p->wakeup_flags && (dev->whoami == WAI_8B)) { | ||
| 582 | dev->write(dev, FF_WU_CFG_1, p->wakeup_flags); | ||
| 583 | dev->write(dev, FF_WU_THS_1, p->wakeup_thresh & 0x7f); | ||
| 584 | /* default to 2.5ms for now */ | ||
| 585 | dev->write(dev, FF_WU_DURATION_1, 1); | ||
| 586 | /* enable high pass filter for both free-fall units */ | ||
| 587 | dev->write(dev, CTRL_REG2, HP_FF_WU1 | HP_FF_WU2); | ||
| 588 | } | ||
| 589 | 698 | ||
| 590 | if (p->irq_cfg) | 699 | if (p->irq_cfg) |
| 591 | dev->write(dev, CTRL_REG3, p->irq_cfg); | 700 | dev->write(dev, CTRL_REG3, p->irq_cfg); |
| @@ -598,6 +707,32 @@ int lis3lv02d_init_device(struct lis3lv02d *dev) | |||
| 598 | goto out; | 707 | goto out; |
| 599 | } | 708 | } |
| 600 | 709 | ||
| 710 | /* | ||
| 711 | * The sensor can generate interrupts for free-fall and direction | ||
| 712 | * detection (distinguishable with FF_WU_SRC and DD_SRC) but to keep | ||
| 713 | * the things simple and _fast_ we activate it only for free-fall, so | ||
| 714 | * no need to read register (very slow with ACPI). For the same reason, | ||
| 715 | * we forbid shared interrupts. | ||
| 716 | * | ||
| 717 | * IRQF_TRIGGER_RISING seems pointless on HP laptops because the | ||
| 718 | * io-apic is not configurable (and generates a warning) but I keep it | ||
| 719 | * in case of support for other hardware. | ||
| 720 | */ | ||
| 721 | if (dev->whoami == WAI_8B) | ||
| 722 | thread_fn = lis302dl_interrupt_thread1_8b; | ||
| 723 | else | ||
| 724 | thread_fn = NULL; | ||
| 725 | |||
| 726 | err = request_threaded_irq(dev->irq, lis302dl_interrupt, | ||
| 727 | thread_fn, | ||
| 728 | IRQF_TRIGGER_RISING | IRQF_ONESHOT, | ||
| 729 | DRIVER_NAME, &lis3_dev); | ||
| 730 | |||
| 731 | if (err < 0) { | ||
| 732 | printk(KERN_ERR DRIVER_NAME "Cannot get IRQ\n"); | ||
| 733 | goto out; | ||
| 734 | } | ||
| 735 | |||
| 601 | if (misc_register(&lis3lv02d_misc_device)) | 736 | if (misc_register(&lis3lv02d_misc_device)) |
| 602 | printk(KERN_ERR DRIVER_NAME ": misc_register failed\n"); | 737 | printk(KERN_ERR DRIVER_NAME ": misc_register failed\n"); |
| 603 | out: | 738 | out: |
