diff options
author | Akio Idehara <zbe64533@gmail.com> | 2012-04-05 12:46:43 -0400 |
---|---|---|
committer | Matthew Garrett <mjg@redhat.com> | 2012-05-31 14:26:39 -0400 |
commit | 121b7b0d2976c4b915434ae8005f0dde6e05e440 (patch) | |
tree | b453eb6290586bcc6ef4fc717b98acebe6510fc6 /drivers/platform/x86/toshiba_acpi.c | |
parent | 62cce7526629e164513d3c67a06845953910f818 (diff) |
toshiba_acpi: Add support for transflective LCD
Some Toshiba laptops have the transflective LCD and toshset
can control its backlight state. I brought this feature to the
mainline. To support transflective LCD, it's implemented by
adding an extra level to the backlight and having 0 change to
transflective mode. It was tested on a Toshiba Portege R500.
Signed-off-by: Akio Idehara <zbe64533@gmail.com>
Signed-off-by: Matthew Garrett <mjg@redhat.com>
Diffstat (limited to 'drivers/platform/x86/toshiba_acpi.c')
-rw-r--r-- | drivers/platform/x86/toshiba_acpi.c | 61 |
1 files changed, 57 insertions, 4 deletions
diff --git a/drivers/platform/x86/toshiba_acpi.c b/drivers/platform/x86/toshiba_acpi.c index 1bb128bbcfc9..f88b9d22f39e 100644 --- a/drivers/platform/x86/toshiba_acpi.c +++ b/drivers/platform/x86/toshiba_acpi.c | |||
@@ -95,6 +95,7 @@ MODULE_LICENSE("GPL"); | |||
95 | 95 | ||
96 | /* registers */ | 96 | /* registers */ |
97 | #define HCI_FAN 0x0004 | 97 | #define HCI_FAN 0x0004 |
98 | #define HCI_TR_BACKLIGHT 0x0005 | ||
98 | #define HCI_SYSTEM_EVENT 0x0016 | 99 | #define HCI_SYSTEM_EVENT 0x0016 |
99 | #define HCI_VIDEO_OUT 0x001c | 100 | #define HCI_VIDEO_OUT 0x001c |
100 | #define HCI_HOTKEY_EVENT 0x001e | 101 | #define HCI_HOTKEY_EVENT 0x001e |
@@ -134,6 +135,7 @@ struct toshiba_acpi_dev { | |||
134 | unsigned int system_event_supported:1; | 135 | unsigned int system_event_supported:1; |
135 | unsigned int ntfy_supported:1; | 136 | unsigned int ntfy_supported:1; |
136 | unsigned int info_supported:1; | 137 | unsigned int info_supported:1; |
138 | unsigned int tr_backlight_supported:1; | ||
137 | 139 | ||
138 | struct mutex mutex; | 140 | struct mutex mutex; |
139 | }; | 141 | }; |
@@ -478,16 +480,46 @@ static const struct rfkill_ops toshiba_rfk_ops = { | |||
478 | .poll = bt_rfkill_poll, | 480 | .poll = bt_rfkill_poll, |
479 | }; | 481 | }; |
480 | 482 | ||
483 | static int get_tr_backlight_status(struct toshiba_acpi_dev *dev, bool *enabled) | ||
484 | { | ||
485 | u32 hci_result; | ||
486 | u32 status; | ||
487 | |||
488 | hci_read1(dev, HCI_TR_BACKLIGHT, &status, &hci_result); | ||
489 | *enabled = !status; | ||
490 | return hci_result == HCI_SUCCESS ? 0 : -EIO; | ||
491 | } | ||
492 | |||
493 | static int set_tr_backlight_status(struct toshiba_acpi_dev *dev, bool enable) | ||
494 | { | ||
495 | u32 hci_result; | ||
496 | u32 value = !enable; | ||
497 | |||
498 | hci_write1(dev, HCI_TR_BACKLIGHT, value, &hci_result); | ||
499 | return hci_result == HCI_SUCCESS ? 0 : -EIO; | ||
500 | } | ||
501 | |||
481 | static struct proc_dir_entry *toshiba_proc_dir /*= 0*/ ; | 502 | static struct proc_dir_entry *toshiba_proc_dir /*= 0*/ ; |
482 | 503 | ||
483 | static int __get_lcd_brightness(struct toshiba_acpi_dev *dev) | 504 | static int __get_lcd_brightness(struct toshiba_acpi_dev *dev) |
484 | { | 505 | { |
485 | u32 hci_result; | 506 | u32 hci_result; |
486 | u32 value; | 507 | u32 value; |
508 | int brightness = 0; | ||
509 | |||
510 | if (dev->tr_backlight_supported) { | ||
511 | bool enabled; | ||
512 | int ret = get_tr_backlight_status(dev, &enabled); | ||
513 | if (ret) | ||
514 | return ret; | ||
515 | if (enabled) | ||
516 | return 0; | ||
517 | brightness++; | ||
518 | } | ||
487 | 519 | ||
488 | hci_read1(dev, HCI_LCD_BRIGHTNESS, &value, &hci_result); | 520 | hci_read1(dev, HCI_LCD_BRIGHTNESS, &value, &hci_result); |
489 | if (hci_result == HCI_SUCCESS) | 521 | if (hci_result == HCI_SUCCESS) |
490 | return (value >> HCI_LCD_BRIGHTNESS_SHIFT); | 522 | return brightness + (value >> HCI_LCD_BRIGHTNESS_SHIFT); |
491 | 523 | ||
492 | return -EIO; | 524 | return -EIO; |
493 | } | 525 | } |
@@ -502,15 +534,16 @@ static int lcd_proc_show(struct seq_file *m, void *v) | |||
502 | { | 534 | { |
503 | struct toshiba_acpi_dev *dev = m->private; | 535 | struct toshiba_acpi_dev *dev = m->private; |
504 | int value; | 536 | int value; |
537 | int levels; | ||
505 | 538 | ||
506 | if (!dev->backlight_dev) | 539 | if (!dev->backlight_dev) |
507 | return -ENODEV; | 540 | return -ENODEV; |
508 | 541 | ||
542 | levels = dev->backlight_dev->props.max_brightness + 1; | ||
509 | value = get_lcd_brightness(dev->backlight_dev); | 543 | value = get_lcd_brightness(dev->backlight_dev); |
510 | if (value >= 0) { | 544 | if (value >= 0) { |
511 | seq_printf(m, "brightness: %d\n", value); | 545 | seq_printf(m, "brightness: %d\n", value); |
512 | seq_printf(m, "brightness_levels: %d\n", | 546 | seq_printf(m, "brightness_levels: %d\n", levels); |
513 | HCI_LCD_BRIGHTNESS_LEVELS); | ||
514 | return 0; | 547 | return 0; |
515 | } | 548 | } |
516 | 549 | ||
@@ -527,6 +560,15 @@ static int set_lcd_brightness(struct toshiba_acpi_dev *dev, int value) | |||
527 | { | 560 | { |
528 | u32 hci_result; | 561 | u32 hci_result; |
529 | 562 | ||
563 | if (dev->tr_backlight_supported) { | ||
564 | bool enable = !value; | ||
565 | int ret = set_tr_backlight_status(dev, enable); | ||
566 | if (ret) | ||
567 | return ret; | ||
568 | if (value) | ||
569 | value--; | ||
570 | } | ||
571 | |||
530 | value = value << HCI_LCD_BRIGHTNESS_SHIFT; | 572 | value = value << HCI_LCD_BRIGHTNESS_SHIFT; |
531 | hci_write1(dev, HCI_LCD_BRIGHTNESS, value, &hci_result); | 573 | hci_write1(dev, HCI_LCD_BRIGHTNESS, value, &hci_result); |
532 | return hci_result == HCI_SUCCESS ? 0 : -EIO; | 574 | return hci_result == HCI_SUCCESS ? 0 : -EIO; |
@@ -546,6 +588,7 @@ static ssize_t lcd_proc_write(struct file *file, const char __user *buf, | |||
546 | size_t len; | 588 | size_t len; |
547 | int value; | 589 | int value; |
548 | int ret; | 590 | int ret; |
591 | int levels = dev->backlight_dev->props.max_brightness + 1; | ||
549 | 592 | ||
550 | len = min(count, sizeof(cmd) - 1); | 593 | len = min(count, sizeof(cmd) - 1); |
551 | if (copy_from_user(cmd, buf, len)) | 594 | if (copy_from_user(cmd, buf, len)) |
@@ -553,7 +596,7 @@ static ssize_t lcd_proc_write(struct file *file, const char __user *buf, | |||
553 | cmd[len] = '\0'; | 596 | cmd[len] = '\0'; |
554 | 597 | ||
555 | if (sscanf(cmd, " brightness : %i", &value) == 1 && | 598 | if (sscanf(cmd, " brightness : %i", &value) == 1 && |
556 | value >= 0 && value < HCI_LCD_BRIGHTNESS_LEVELS) { | 599 | value >= 0 && value < levels) { |
557 | ret = set_lcd_brightness(dev, value); | 600 | ret = set_lcd_brightness(dev, value); |
558 | if (ret == 0) | 601 | if (ret == 0) |
559 | ret = count; | 602 | ret = count; |
@@ -865,6 +908,7 @@ static void remove_toshiba_proc_entries(struct toshiba_acpi_dev *dev) | |||
865 | } | 908 | } |
866 | 909 | ||
867 | static const struct backlight_ops toshiba_backlight_data = { | 910 | static const struct backlight_ops toshiba_backlight_data = { |
911 | .options = BL_CORE_SUSPENDRESUME, | ||
868 | .get_brightness = get_lcd_brightness, | 912 | .get_brightness = get_lcd_brightness, |
869 | .update_status = set_lcd_status, | 913 | .update_status = set_lcd_status, |
870 | }; | 914 | }; |
@@ -1030,6 +1074,7 @@ static int __devinit toshiba_acpi_setup_backlight(struct toshiba_acpi_dev *dev) | |||
1030 | struct backlight_properties props; | 1074 | struct backlight_properties props; |
1031 | int brightness; | 1075 | int brightness; |
1032 | int ret; | 1076 | int ret; |
1077 | bool enabled; | ||
1033 | 1078 | ||
1034 | /* | 1079 | /* |
1035 | * Some machines don't support the backlight methods at all, and | 1080 | * Some machines don't support the backlight methods at all, and |
@@ -1046,10 +1091,18 @@ static int __devinit toshiba_acpi_setup_backlight(struct toshiba_acpi_dev *dev) | |||
1046 | return 0; | 1091 | return 0; |
1047 | } | 1092 | } |
1048 | 1093 | ||
1094 | /* Determine whether or not BIOS supports transflective backlight */ | ||
1095 | ret = get_tr_backlight_status(dev, &enabled); | ||
1096 | dev->tr_backlight_supported = !ret; | ||
1097 | |||
1049 | props.type = BACKLIGHT_PLATFORM; | 1098 | props.type = BACKLIGHT_PLATFORM; |
1050 | props.max_brightness = HCI_LCD_BRIGHTNESS_LEVELS - 1; | 1099 | props.max_brightness = HCI_LCD_BRIGHTNESS_LEVELS - 1; |
1051 | memset(&props, 0, sizeof(props)); | 1100 | memset(&props, 0, sizeof(props)); |
1052 | 1101 | ||
1102 | /* adding an extra level and having 0 change to transflective mode */ | ||
1103 | if (dev->tr_backlight_supported) | ||
1104 | props.max_brightness++; | ||
1105 | |||
1053 | dev->backlight_dev = backlight_device_register("toshiba", | 1106 | dev->backlight_dev = backlight_device_register("toshiba", |
1054 | &dev->acpi_dev->dev, | 1107 | &dev->acpi_dev->dev, |
1055 | dev, | 1108 | dev, |