diff options
author | Ike Panhc <ike.pan@canonical.com> | 2011-06-30 07:50:52 -0400 |
---|---|---|
committer | Matthew Garrett <mjg@redhat.com> | 2011-08-05 14:45:45 -0400 |
commit | a4ecbb8ae7be16497db2f984ee7a3ffec0f164c3 (patch) | |
tree | a35d723223e7144f8b828b3e5be48667caad36b9 /drivers/platform | |
parent | a84511f7fbeb37e26aacb9c72f5a21ffc24e909e (diff) |
ideapad: add backlight driver
When acpi_backlight=vendor in cmdline or no backlight support in acpi video
device, ideapad-laptop will register backlight device and control brightness
and backlight power via the command in VPC2004.
Signed-off-by: Ike Panhc <ike.pan@canonical.com>
Signed-off-by: Matthew Garrett <mjg@redhat.com>
Diffstat (limited to 'drivers/platform')
-rw-r--r-- | drivers/platform/x86/ideapad-laptop.c | 123 |
1 files changed, 117 insertions, 6 deletions
diff --git a/drivers/platform/x86/ideapad-laptop.c b/drivers/platform/x86/ideapad-laptop.c index 1612abde5188..8811c68f809d 100644 --- a/drivers/platform/x86/ideapad-laptop.c +++ b/drivers/platform/x86/ideapad-laptop.c | |||
@@ -32,6 +32,8 @@ | |||
32 | #include <linux/platform_device.h> | 32 | #include <linux/platform_device.h> |
33 | #include <linux/input.h> | 33 | #include <linux/input.h> |
34 | #include <linux/input/sparse-keymap.h> | 34 | #include <linux/input/sparse-keymap.h> |
35 | #include <linux/backlight.h> | ||
36 | #include <linux/fb.h> | ||
35 | 37 | ||
36 | #define IDEAPAD_RFKILL_DEV_NUM (3) | 38 | #define IDEAPAD_RFKILL_DEV_NUM (3) |
37 | 39 | ||
@@ -44,6 +46,7 @@ struct ideapad_private { | |||
44 | struct rfkill *rfk[IDEAPAD_RFKILL_DEV_NUM]; | 46 | struct rfkill *rfk[IDEAPAD_RFKILL_DEV_NUM]; |
45 | struct platform_device *platform_device; | 47 | struct platform_device *platform_device; |
46 | struct input_dev *inputdev; | 48 | struct input_dev *inputdev; |
49 | struct backlight_device *blightdev; | ||
47 | unsigned long cfg; | 50 | unsigned long cfg; |
48 | }; | 51 | }; |
49 | 52 | ||
@@ -309,8 +312,7 @@ static int __devinit ideapad_register_rfkill(struct acpi_device *adevice, | |||
309 | return 0; | 312 | return 0; |
310 | } | 313 | } |
311 | 314 | ||
312 | static void __devexit ideapad_unregister_rfkill(struct acpi_device *adevice, | 315 | static void ideapad_unregister_rfkill(struct acpi_device *adevice, int dev) |
313 | int dev) | ||
314 | { | 316 | { |
315 | struct ideapad_private *priv = dev_get_drvdata(&adevice->dev); | 317 | struct ideapad_private *priv = dev_get_drvdata(&adevice->dev); |
316 | 318 | ||
@@ -418,6 +420,98 @@ static void ideapad_input_report(struct ideapad_private *priv, | |||
418 | } | 420 | } |
419 | 421 | ||
420 | /* | 422 | /* |
423 | * backlight | ||
424 | */ | ||
425 | static int ideapad_backlight_get_brightness(struct backlight_device *blightdev) | ||
426 | { | ||
427 | unsigned long now; | ||
428 | |||
429 | if (read_ec_data(ideapad_handle, 0x12, &now)) | ||
430 | return -EIO; | ||
431 | return now; | ||
432 | } | ||
433 | |||
434 | static int ideapad_backlight_update_status(struct backlight_device *blightdev) | ||
435 | { | ||
436 | if (write_ec_cmd(ideapad_handle, 0x13, blightdev->props.brightness)) | ||
437 | return -EIO; | ||
438 | if (write_ec_cmd(ideapad_handle, 0x33, | ||
439 | blightdev->props.power == FB_BLANK_POWERDOWN ? 0 : 1)) | ||
440 | return -EIO; | ||
441 | |||
442 | return 0; | ||
443 | } | ||
444 | |||
445 | static const struct backlight_ops ideapad_backlight_ops = { | ||
446 | .get_brightness = ideapad_backlight_get_brightness, | ||
447 | .update_status = ideapad_backlight_update_status, | ||
448 | }; | ||
449 | |||
450 | static int ideapad_backlight_init(struct ideapad_private *priv) | ||
451 | { | ||
452 | struct backlight_device *blightdev; | ||
453 | struct backlight_properties props; | ||
454 | unsigned long max, now, power; | ||
455 | |||
456 | if (read_ec_data(ideapad_handle, 0x11, &max)) | ||
457 | return -EIO; | ||
458 | if (read_ec_data(ideapad_handle, 0x12, &now)) | ||
459 | return -EIO; | ||
460 | if (read_ec_data(ideapad_handle, 0x18, &power)) | ||
461 | return -EIO; | ||
462 | |||
463 | memset(&props, 0, sizeof(struct backlight_properties)); | ||
464 | props.max_brightness = max; | ||
465 | props.type = BACKLIGHT_PLATFORM; | ||
466 | blightdev = backlight_device_register("ideapad", | ||
467 | &priv->platform_device->dev, | ||
468 | priv, | ||
469 | &ideapad_backlight_ops, | ||
470 | &props); | ||
471 | if (IS_ERR(blightdev)) { | ||
472 | pr_err("Could not register backlight device\n"); | ||
473 | return PTR_ERR(blightdev); | ||
474 | } | ||
475 | |||
476 | priv->blightdev = blightdev; | ||
477 | blightdev->props.brightness = now; | ||
478 | blightdev->props.power = power ? FB_BLANK_UNBLANK : FB_BLANK_POWERDOWN; | ||
479 | backlight_update_status(blightdev); | ||
480 | |||
481 | return 0; | ||
482 | } | ||
483 | |||
484 | static void ideapad_backlight_exit(struct ideapad_private *priv) | ||
485 | { | ||
486 | if (priv->blightdev) | ||
487 | backlight_device_unregister(priv->blightdev); | ||
488 | priv->blightdev = NULL; | ||
489 | } | ||
490 | |||
491 | static void ideapad_backlight_notify_power(struct ideapad_private *priv) | ||
492 | { | ||
493 | unsigned long power; | ||
494 | struct backlight_device *blightdev = priv->blightdev; | ||
495 | |||
496 | if (read_ec_data(ideapad_handle, 0x18, &power)) | ||
497 | return; | ||
498 | blightdev->props.power = power ? FB_BLANK_UNBLANK : FB_BLANK_POWERDOWN; | ||
499 | } | ||
500 | |||
501 | static void ideapad_backlight_notify_brightness(struct ideapad_private *priv) | ||
502 | { | ||
503 | unsigned long now; | ||
504 | |||
505 | /* if we control brightness via acpi video driver */ | ||
506 | if (priv->blightdev == NULL) { | ||
507 | read_ec_data(ideapad_handle, 0x12, &now); | ||
508 | return; | ||
509 | } | ||
510 | |||
511 | backlight_force_update(priv->blightdev, BACKLIGHT_UPDATE_HOTKEY); | ||
512 | } | ||
513 | |||
514 | /* | ||
421 | * module init/exit | 515 | * module init/exit |
422 | */ | 516 | */ |
423 | static const struct acpi_device_id ideapad_device_ids[] = { | 517 | static const struct acpi_device_id ideapad_device_ids[] = { |
@@ -458,8 +552,17 @@ static int __devinit ideapad_acpi_add(struct acpi_device *adevice) | |||
458 | } | 552 | } |
459 | ideapad_sync_rfk_state(adevice); | 553 | ideapad_sync_rfk_state(adevice); |
460 | 554 | ||
555 | if (!acpi_video_backlight_support()) { | ||
556 | ret = ideapad_backlight_init(priv); | ||
557 | if (ret && ret != -ENODEV) | ||
558 | goto backlight_failed; | ||
559 | } | ||
560 | |||
461 | return 0; | 561 | return 0; |
462 | 562 | ||
563 | backlight_failed: | ||
564 | for (i = 0; i < IDEAPAD_RFKILL_DEV_NUM; i++) | ||
565 | ideapad_unregister_rfkill(adevice, i); | ||
463 | input_failed: | 566 | input_failed: |
464 | ideapad_platform_exit(priv); | 567 | ideapad_platform_exit(priv); |
465 | platform_failed: | 568 | platform_failed: |
@@ -472,6 +575,7 @@ static int __devexit ideapad_acpi_remove(struct acpi_device *adevice, int type) | |||
472 | struct ideapad_private *priv = dev_get_drvdata(&adevice->dev); | 575 | struct ideapad_private *priv = dev_get_drvdata(&adevice->dev); |
473 | int i; | 576 | int i; |
474 | 577 | ||
578 | ideapad_backlight_exit(priv); | ||
475 | for (i = 0; i < IDEAPAD_RFKILL_DEV_NUM; i++) | 579 | for (i = 0; i < IDEAPAD_RFKILL_DEV_NUM; i++) |
476 | ideapad_unregister_rfkill(adevice, i); | 580 | ideapad_unregister_rfkill(adevice, i); |
477 | ideapad_input_exit(priv); | 581 | ideapad_input_exit(priv); |
@@ -496,12 +600,19 @@ static void ideapad_acpi_notify(struct acpi_device *adevice, u32 event) | |||
496 | vpc1 = (vpc2 << 8) | vpc1; | 600 | vpc1 = (vpc2 << 8) | vpc1; |
497 | for (vpc_bit = 0; vpc_bit < 16; vpc_bit++) { | 601 | for (vpc_bit = 0; vpc_bit < 16; vpc_bit++) { |
498 | if (test_bit(vpc_bit, &vpc1)) { | 602 | if (test_bit(vpc_bit, &vpc1)) { |
499 | if (vpc_bit == 9) | 603 | switch (vpc_bit) { |
604 | case 9: | ||
500 | ideapad_sync_rfk_state(adevice); | 605 | ideapad_sync_rfk_state(adevice); |
501 | else if (vpc_bit == 4) | 606 | break; |
502 | read_ec_data(handle, 0x12, &vpc2); | 607 | case 4: |
503 | else | 608 | ideapad_backlight_notify_brightness(priv); |
609 | break; | ||
610 | case 2: | ||
611 | ideapad_backlight_notify_power(priv); | ||
612 | break; | ||
613 | default: | ||
504 | ideapad_input_report(priv, vpc_bit); | 614 | ideapad_input_report(priv, vpc_bit); |
615 | } | ||
505 | } | 616 | } |
506 | } | 617 | } |
507 | } | 618 | } |