From 121b7b0d2976c4b915434ae8005f0dde6e05e440 Mon Sep 17 00:00:00 2001 From: Akio Idehara Date: Fri, 6 Apr 2012 01:46:43 +0900 Subject: [PATCH] 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 Signed-off-by: Matthew Garrett --- drivers/platform/x86/toshiba_acpi.c | 61 +++++++++++++++++++++++++++-- 1 file 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"); /* registers */ #define HCI_FAN 0x0004 +#define HCI_TR_BACKLIGHT 0x0005 #define HCI_SYSTEM_EVENT 0x0016 #define HCI_VIDEO_OUT 0x001c #define HCI_HOTKEY_EVENT 0x001e @@ -134,6 +135,7 @@ struct toshiba_acpi_dev { unsigned int system_event_supported:1; unsigned int ntfy_supported:1; unsigned int info_supported:1; + unsigned int tr_backlight_supported:1; struct mutex mutex; }; @@ -478,16 +480,46 @@ static const struct rfkill_ops toshiba_rfk_ops = { .poll = bt_rfkill_poll, }; +static int get_tr_backlight_status(struct toshiba_acpi_dev *dev, bool *enabled) +{ + u32 hci_result; + u32 status; + + hci_read1(dev, HCI_TR_BACKLIGHT, &status, &hci_result); + *enabled = !status; + return hci_result == HCI_SUCCESS ? 0 : -EIO; +} + +static int set_tr_backlight_status(struct toshiba_acpi_dev *dev, bool enable) +{ + u32 hci_result; + u32 value = !enable; + + hci_write1(dev, HCI_TR_BACKLIGHT, value, &hci_result); + return hci_result == HCI_SUCCESS ? 0 : -EIO; +} + static struct proc_dir_entry *toshiba_proc_dir /*= 0*/ ; static int __get_lcd_brightness(struct toshiba_acpi_dev *dev) { u32 hci_result; u32 value; + int brightness = 0; + + if (dev->tr_backlight_supported) { + bool enabled; + int ret = get_tr_backlight_status(dev, &enabled); + if (ret) + return ret; + if (enabled) + return 0; + brightness++; + } hci_read1(dev, HCI_LCD_BRIGHTNESS, &value, &hci_result); if (hci_result == HCI_SUCCESS) - return (value >> HCI_LCD_BRIGHTNESS_SHIFT); + return brightness + (value >> HCI_LCD_BRIGHTNESS_SHIFT); return -EIO; } @@ -502,15 +534,16 @@ static int lcd_proc_show(struct seq_file *m, void *v) { struct toshiba_acpi_dev *dev = m->private; int value; + int levels; if (!dev->backlight_dev) return -ENODEV; + levels = dev->backlight_dev->props.max_brightness + 1; value = get_lcd_brightness(dev->backlight_dev); if (value >= 0) { seq_printf(m, "brightness: %d\n", value); - seq_printf(m, "brightness_levels: %d\n", - HCI_LCD_BRIGHTNESS_LEVELS); + seq_printf(m, "brightness_levels: %d\n", levels); return 0; } @@ -527,6 +560,15 @@ static int set_lcd_brightness(struct toshiba_acpi_dev *dev, int value) { u32 hci_result; + if (dev->tr_backlight_supported) { + bool enable = !value; + int ret = set_tr_backlight_status(dev, enable); + if (ret) + return ret; + if (value) + value--; + } + value = value << HCI_LCD_BRIGHTNESS_SHIFT; hci_write1(dev, HCI_LCD_BRIGHTNESS, value, &hci_result); return hci_result == HCI_SUCCESS ? 0 : -EIO; @@ -546,6 +588,7 @@ static ssize_t lcd_proc_write(struct file *file, const char __user *buf, size_t len; int value; int ret; + int levels = dev->backlight_dev->props.max_brightness + 1; len = min(count, sizeof(cmd) - 1); if (copy_from_user(cmd, buf, len)) @@ -553,7 +596,7 @@ static ssize_t lcd_proc_write(struct file *file, const char __user *buf, cmd[len] = '\0'; if (sscanf(cmd, " brightness : %i", &value) == 1 && - value >= 0 && value < HCI_LCD_BRIGHTNESS_LEVELS) { + value >= 0 && value < levels) { ret = set_lcd_brightness(dev, value); if (ret == 0) ret = count; @@ -865,6 +908,7 @@ static void remove_toshiba_proc_entries(struct toshiba_acpi_dev *dev) } static const struct backlight_ops toshiba_backlight_data = { + .options = BL_CORE_SUSPENDRESUME, .get_brightness = get_lcd_brightness, .update_status = set_lcd_status, }; @@ -1030,6 +1074,7 @@ static int __devinit toshiba_acpi_setup_backlight(struct toshiba_acpi_dev *dev) struct backlight_properties props; int brightness; int ret; + bool enabled; /* * 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) return 0; } + /* Determine whether or not BIOS supports transflective backlight */ + ret = get_tr_backlight_status(dev, &enabled); + dev->tr_backlight_supported = !ret; + props.type = BACKLIGHT_PLATFORM; props.max_brightness = HCI_LCD_BRIGHTNESS_LEVELS - 1; memset(&props, 0, sizeof(props)); + /* adding an extra level and having 0 change to transflective mode */ + if (dev->tr_backlight_supported) + props.max_brightness++; + dev->backlight_dev = backlight_device_register("toshiba", &dev->acpi_dev->dev, dev, -- 2.20.1