aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHenrique de Moraes Holschuh <hmh@hmh.eng.br>2007-07-18 22:45:43 -0400
committerLen Brown <len.brown@intel.com>2007-07-21 23:49:03 -0400
commit24d3b77467b6aaf59e38dce4aa86d05541858195 (patch)
tree92975c9c2d4b37922d25782bd02d7076d77e817e
parentd5a2f2f1d68e2da538ac28540cddd9ccc733b001 (diff)
ACPI: thinkpad-acpi: allow use of CMOS NVRAM for brightness control
It appears that Lenovo decided to break the EC brightness control interface in a weird way in their latest BIOSes. Fortunately, the old CMOS NVRAM interface works just fine in such BIOSes. Add a module parameter that allows the user to select which strategy to use for brightness control: EC, NVRAM, or both. By default, do both (which is the way thinkpad-acpi used to work until now) on IBM ThinkPads, and use NVRAM only on Lenovo ThinkPads. Signed-off-by: Henrique de Moraes Holschuh <hmh@hmh.eng.br> Signed-off-by: Len Brown <len.brown@intel.com>
-rw-r--r--Documentation/thinkpad-acpi.txt6
-rw-r--r--drivers/misc/Kconfig1
-rw-r--r--drivers/misc/thinkpad_acpi.c62
-rw-r--r--drivers/misc/thinkpad_acpi.h7
4 files changed, 67 insertions, 9 deletions
diff --git a/Documentation/thinkpad-acpi.txt b/Documentation/thinkpad-acpi.txt
index c670363cf5a4..c145bcce2339 100644
--- a/Documentation/thinkpad-acpi.txt
+++ b/Documentation/thinkpad-acpi.txt
@@ -860,6 +860,12 @@ cannot be controlled.
860The backlight control has eight levels, ranging from 0 to 7. Some of the 860The backlight control has eight levels, ranging from 0 to 7. Some of the
861levels may not be distinct. 861levels may not be distinct.
862 862
863There are two interfaces to the firmware for brightness control, EC and CMOS.
864To select which one should be used, use the brightness_mode module parameter:
865brightness_mode=1 selects EC mode, brightness_mode=2 selects CMOS mode,
866brightness_mode=3 selects both EC and CMOS. The driver tries to autodetect
867which interface to use.
868
863Procfs notes: 869Procfs notes:
864 870
865 The available commands are: 871 The available commands are:
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index 5197f9b9b65d..aaaa61ea4217 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -150,6 +150,7 @@ config THINKPAD_ACPI
150 depends on X86 && ACPI 150 depends on X86 && ACPI
151 select BACKLIGHT_CLASS_DEVICE 151 select BACKLIGHT_CLASS_DEVICE
152 select HWMON 152 select HWMON
153 select NVRAM
153 ---help--- 154 ---help---
154 This is a driver for the IBM and Lenovo ThinkPad laptops. It adds 155 This is a driver for the IBM and Lenovo ThinkPad laptops. It adds
155 support for Fn-Fx key combinations, Bluetooth control, video 156 support for Fn-Fx key combinations, Bluetooth control, video
diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c
index 99500af651c1..5318eb272c61 100644
--- a/drivers/misc/thinkpad_acpi.c
+++ b/drivers/misc/thinkpad_acpi.c
@@ -2953,9 +2953,22 @@ static int __init brightness_init(struct ibm_init_struct *iibm)
2953 2953
2954 vdbg_printk(TPACPI_DBG_INIT, "initializing brightness subdriver\n"); 2954 vdbg_printk(TPACPI_DBG_INIT, "initializing brightness subdriver\n");
2955 2955
2956 if (!brightness_mode) {
2957 if (thinkpad_id.vendor == PCI_VENDOR_ID_LENOVO)
2958 brightness_mode = 2;
2959 else
2960 brightness_mode = 3;
2961
2962 dbg_printk(TPACPI_DBG_INIT, "selected brightness_mode=%d\n",
2963 brightness_mode);
2964 }
2965
2966 if (brightness_mode > 3)
2967 return -EINVAL;
2968
2956 b = brightness_get(NULL); 2969 b = brightness_get(NULL);
2957 if (b < 0) 2970 if (b < 0)
2958 return b; 2971 return 1;
2959 2972
2960 ibm_backlight_device = backlight_device_register( 2973 ibm_backlight_device = backlight_device_register(
2961 TPACPI_BACKLIGHT_DEV_NAME, NULL, NULL, 2974 TPACPI_BACKLIGHT_DEV_NAME, NULL, NULL,
@@ -2991,13 +3004,35 @@ static int brightness_update_status(struct backlight_device *bd)
2991 bd->props.brightness : 0); 3004 bd->props.brightness : 0);
2992} 3005}
2993 3006
3007/*
3008 * ThinkPads can read brightness from two places: EC 0x31, or
3009 * CMOS NVRAM byte 0x5E, bits 0-3.
3010 */
2994static int brightness_get(struct backlight_device *bd) 3011static int brightness_get(struct backlight_device *bd)
2995{ 3012{
2996 u8 level; 3013 u8 lec = 0, lcmos = 0, level = 0;
2997 if (!acpi_ec_read(brightness_offset, &level))
2998 return -EIO;
2999 3014
3000 level &= 0x7; 3015 if (brightness_mode & 1) {
3016 if (!acpi_ec_read(brightness_offset, &lec))
3017 return -EIO;
3018 lec &= 7;
3019 level = lec;
3020 };
3021 if (brightness_mode & 2) {
3022 lcmos = (nvram_read_byte(TP_NVRAM_ADDR_BRIGHTNESS)
3023 & TP_NVRAM_MASK_LEVEL_BRIGHTNESS)
3024 >> TP_NVRAM_POS_LEVEL_BRIGHTNESS;
3025 level = lcmos;
3026 }
3027
3028 if (brightness_mode == 3 && lec != lcmos) {
3029 printk(IBM_ERR
3030 "CMOS NVRAM (%u) and EC (%u) do not agree "
3031 "on display brightness level\n",
3032 (unsigned int) lcmos,
3033 (unsigned int) lec);
3034 return -EIO;
3035 }
3001 3036
3002 return level; 3037 return level;
3003} 3038}
@@ -3007,14 +3042,20 @@ static int brightness_set(int value)
3007 int cmos_cmd, inc, i; 3042 int cmos_cmd, inc, i;
3008 int current_value = brightness_get(NULL); 3043 int current_value = brightness_get(NULL);
3009 3044
3010 value &= 7; 3045 if (value > 7)
3046 return -EINVAL;
3011 3047
3012 cmos_cmd = value > current_value ? TP_CMOS_BRIGHTNESS_UP : TP_CMOS_BRIGHTNESS_DOWN; 3048 cmos_cmd = value > current_value ?
3049 TP_CMOS_BRIGHTNESS_UP :
3050 TP_CMOS_BRIGHTNESS_DOWN;
3013 inc = value > current_value ? 1 : -1; 3051 inc = value > current_value ? 1 : -1;
3052
3014 for (i = current_value; i != value; i += inc) { 3053 for (i = current_value; i != value; i += inc) {
3015 if (issue_thinkpad_cmos_command(cmos_cmd)) 3054 if ((brightness_mode & 2) &&
3055 issue_thinkpad_cmos_command(cmos_cmd))
3016 return -EIO; 3056 return -EIO;
3017 if (!acpi_ec_write(brightness_offset, i + inc)) 3057 if ((brightness_mode & 1) &&
3058 !acpi_ec_write(brightness_offset, i + inc))
3018 return -EIO; 3059 return -EIO;
3019 } 3060 }
3020 3061
@@ -4485,6 +4526,9 @@ module_param(force_load, bool, 0);
4485static int fan_control_allowed; 4526static int fan_control_allowed;
4486module_param_named(fan_control, fan_control_allowed, bool, 0); 4527module_param_named(fan_control, fan_control_allowed, bool, 0);
4487 4528
4529static int brightness_mode;
4530module_param_named(brightness_mode, brightness_mode, int, 0);
4531
4488#define IBM_PARAM(feature) \ 4532#define IBM_PARAM(feature) \
4489 module_param_call(feature, set_ibm_param, NULL, NULL, 0) 4533 module_param_call(feature, set_ibm_param, NULL, NULL, 0)
4490 4534
diff --git a/drivers/misc/thinkpad_acpi.h b/drivers/misc/thinkpad_acpi.h
index 09b2282fed0b..b7a4a888cc8b 100644
--- a/drivers/misc/thinkpad_acpi.h
+++ b/drivers/misc/thinkpad_acpi.h
@@ -32,6 +32,7 @@
32#include <linux/list.h> 32#include <linux/list.h>
33#include <linux/mutex.h> 33#include <linux/mutex.h>
34 34
35#include <linux/nvram.h>
35#include <linux/proc_fs.h> 36#include <linux/proc_fs.h>
36#include <linux/sysfs.h> 37#include <linux/sysfs.h>
37#include <linux/backlight.h> 38#include <linux/backlight.h>
@@ -80,6 +81,11 @@
80#define TP_CMOS_BRIGHTNESS_UP 4 81#define TP_CMOS_BRIGHTNESS_UP 4
81#define TP_CMOS_BRIGHTNESS_DOWN 5 82#define TP_CMOS_BRIGHTNESS_DOWN 5
82 83
84/* ThinkPad CMOS NVRAM constants */
85#define TP_NVRAM_ADDR_BRIGHTNESS 0x5e
86#define TP_NVRAM_MASK_LEVEL_BRIGHTNESS 0x07
87#define TP_NVRAM_POS_LEVEL_BRIGHTNESS 0
88
83#define onoff(status,bit) ((status) & (1 << (bit)) ? "on" : "off") 89#define onoff(status,bit) ((status) & (1 << (bit)) ? "on" : "off")
84#define enabled(status,bit) ((status) & (1 << (bit)) ? "enabled" : "disabled") 90#define enabled(status,bit) ((status) & (1 << (bit)) ? "enabled" : "disabled")
85#define strlencmp(a,b) (strncmp((a), (b), strlen(b))) 91#define strlencmp(a,b) (strncmp((a), (b), strlen(b)))
@@ -323,6 +329,7 @@ static int bluetooth_write(char *buf);
323 329
324static struct backlight_device *ibm_backlight_device; 330static struct backlight_device *ibm_backlight_device;
325static int brightness_offset = 0x31; 331static int brightness_offset = 0x31;
332static int brightness_mode;
326 333
327static int brightness_init(struct ibm_init_struct *iibm); 334static int brightness_init(struct ibm_init_struct *iibm);
328static void brightness_exit(void); 335static void brightness_exit(void);