aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/misc
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 /drivers/misc
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>
Diffstat (limited to 'drivers/misc')
-rw-r--r--drivers/misc/Kconfig1
-rw-r--r--drivers/misc/thinkpad_acpi.c62
-rw-r--r--drivers/misc/thinkpad_acpi.h7
3 files changed, 61 insertions, 9 deletions
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);