aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/platform
diff options
context:
space:
mode:
authorIke Panhc <ike.pan@canonical.com>2011-06-30 07:50:52 -0400
committerMatthew Garrett <mjg@redhat.com>2011-08-05 14:45:45 -0400
commita4ecbb8ae7be16497db2f984ee7a3ffec0f164c3 (patch)
treea35d723223e7144f8b828b3e5be48667caad36b9 /drivers/platform
parenta84511f7fbeb37e26aacb9c72f5a21ffc24e909e (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.c123
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
312static void __devexit ideapad_unregister_rfkill(struct acpi_device *adevice, 315static 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 */
425static 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
434static 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
445static const struct backlight_ops ideapad_backlight_ops = {
446 .get_brightness = ideapad_backlight_get_brightness,
447 .update_status = ideapad_backlight_update_status,
448};
449
450static 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
484static 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
491static 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
501static 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 */
423static const struct acpi_device_id ideapad_device_ids[] = { 517static 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
563backlight_failed:
564 for (i = 0; i < IDEAPAD_RFKILL_DEV_NUM; i++)
565 ideapad_unregister_rfkill(adevice, i);
463input_failed: 566input_failed:
464 ideapad_platform_exit(priv); 567 ideapad_platform_exit(priv);
465platform_failed: 568platform_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}