Add patches accepted for 2.6.26-rc1
[linux-2.6/linux-acpi-2.6/ibm-acpi-2.6.git] / releases / upstream / 2.6.24-rc4 / 0002-ACPI-thinkpad-acpi-support-16-levels-of-brightness.patch
blob2c2ffa0431aa3ebda6a2b0ce783b26aed1ed6ce1
1 From a3f104c02ab842574e699186cf953551aafe2ca9 Mon Sep 17 00:00:00 2001
2 From: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
3 Date: Tue, 30 Oct 2007 17:46:20 -0200
4 Subject: [PATCH 17/23] ACPI: thinkpad-acpi: support 16 levels of brightness (v3)
6 Lenovo ThinkPads often have 16 brightness levels in EC, and not just eight
7 levels like older ThinkPads. They also have standard ACPI backlight
8 brightness control.
10 We detect the number of brightness levels by the presence of a BCLL package
11 with 16 entries. If BCLL is not there, we assume eight levels (Z6*). If
12 it is there, but it doesn't have 16 entries, we assume eight levels (T60).
13 Otherwise we assume sixteen levels (T61, X61, etc).
15 We don't use _BCL because it can have side-effects in thinkpads. Thanks to
16 Thomas Renninger <trenn@suse.de> for notifying me of this potential
17 problem.
19 Using the standard ACPI backlight brightness control *instead* of the
20 native thinkpad backlight control is a better idea, though. A different
21 patch will take care of this.
23 Signed-off-by: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
24 Cc: Thomas Renninger <trenn@suse.de>
25 Signed-off-by: Len Brown <len.brown@intel.com>
26 ---
27 Documentation/thinkpad-acpi.txt | 61 +++++++++++++++-----------
28 drivers/misc/thinkpad_acpi.c | 91 ++++++++++++++++++++++++++++++++++----
29 drivers/misc/thinkpad_acpi.h | 3 +-
30 3 files changed, 118 insertions(+), 37 deletions(-)
32 diff --git a/Documentation/thinkpad-acpi.txt b/Documentation/thinkpad-acpi.txt
33 index ec49926..a743bfa 100644
34 --- a/Documentation/thinkpad-acpi.txt
35 +++ b/Documentation/thinkpad-acpi.txt
36 @@ -923,19 +923,26 @@ sysfs backlight device "thinkpad_screen"
37 This feature allows software control of the LCD brightness on ThinkPad
38 models which don't have a hardware brightness slider.
40 -It has some limitations: the LCD backlight cannot be actually turned on or off
41 -by this interface, and in many ThinkPad models, the "dim while on battery"
42 -functionality will be enabled by the BIOS when this interface is used, and
43 -cannot be controlled.
45 -The backlight control has eight levels, ranging from 0 to 7. Some of the
46 -levels may not be distinct.
48 -There are two interfaces to the firmware for brightness control, EC and CMOS.
49 -To select which one should be used, use the brightness_mode module parameter:
50 -brightness_mode=1 selects EC mode, brightness_mode=2 selects CMOS mode,
51 -brightness_mode=3 selects both EC and CMOS. The driver tries to autodetect
52 -which interface to use.
53 +It has some limitations: the LCD backlight cannot be actually turned on or
54 +off by this interface, and in many ThinkPad models, the "dim while on
55 +battery" functionality will be enabled by the BIOS when this interface is
56 +used, and cannot be controlled.
58 +On IBM (and some of the earlier Lenovo) ThinkPads, the backlight control
59 +has eight brightness levels, ranging from 0 to 7. Some of the levels
60 +may not be distinct. Later Lenovo models that implement the ACPI
61 +display backlight brightness control methods have 16 levels, ranging
62 +from 0 to 15.
64 +There are two interfaces to the firmware for direct brightness control,
65 +EC and CMOS. To select which one should be used, use the
66 +brightness_mode module parameter: brightness_mode=1 selects EC mode,
67 +brightness_mode=2 selects CMOS mode, brightness_mode=3 selects both EC
68 +and CMOS. The driver tries to autodetect which interface to use.
70 +When display backlight brightness controls are available through the
71 +standard ACPI interface, it is best to use it instead of this direct
72 +ThinkPad-specific interface.
74 Procfs notes:
76 @@ -947,11 +954,11 @@ Procfs notes:
78 Sysfs notes:
80 -The interface is implemented through the backlight sysfs class, which is poorly
81 -documented at this time.
82 +The interface is implemented through the backlight sysfs class, which is
83 +poorly documented at this time.
85 -Locate the thinkpad_screen device under /sys/class/backlight, and inside it
86 -there will be the following attributes:
87 +Locate the thinkpad_screen device under /sys/class/backlight, and inside
88 +it there will be the following attributes:
90 max_brightness:
91 Reads the maximum brightness the hardware can be set to.
92 @@ -961,17 +968,19 @@ there will be the following attributes:
93 Reads what brightness the screen is set to at this instant.
95 brightness:
96 - Writes request the driver to change brightness to the given
97 - value. Reads will tell you what brightness the driver is trying
98 - to set the display to when "power" is set to zero and the display
99 - has not been dimmed by a kernel power management event.
100 + Writes request the driver to change brightness to the
101 + given value. Reads will tell you what brightness the
102 + driver is trying to set the display to when "power" is set
103 + to zero and the display has not been dimmed by a kernel
104 + power management event.
106 power:
107 - power management mode, where 0 is "display on", and 1 to 3 will
108 - dim the display backlight to brightness level 0 because
109 - thinkpad-acpi cannot really turn the backlight off. Kernel
110 - power management events can temporarily increase the current
111 - power management level, i.e. they can dim the display.
112 + power management mode, where 0 is "display on", and 1 to 3
113 + will dim the display backlight to brightness level 0
114 + because thinkpad-acpi cannot really turn the backlight
115 + off. Kernel power management events can temporarily
116 + increase the current power management level, i.e. they can
117 + dim the display.
120 Volume control -- /proc/acpi/ibm/volume
121 diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c
122 index 63b1e26..322ba25 100644
123 --- a/drivers/misc/thinkpad_acpi.c
124 +++ b/drivers/misc/thinkpad_acpi.c
125 @@ -3114,6 +3114,66 @@ static struct backlight_ops ibm_backlight_data = {
127 static struct mutex brightness_mutex;
129 +static int __init tpacpi_query_bcll_levels(acpi_handle handle)
131 + struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
132 + union acpi_object *obj;
133 + int rc;
135 + if (ACPI_SUCCESS(acpi_evaluate_object(handle, NULL, NULL, &buffer))) {
136 + obj = (union acpi_object *)buffer.pointer;
137 + if (!obj || (obj->type != ACPI_TYPE_PACKAGE)) {
138 + printk(IBM_ERR "Unknown BCLL data, "
139 + "please report this to %s\n", IBM_MAIL);
140 + rc = 0;
141 + } else {
142 + rc = obj->package.count;
144 + } else {
145 + return 0;
148 + kfree(buffer.pointer);
149 + return rc;
152 +static acpi_status __init brightness_find_bcll(acpi_handle handle, u32 lvl,
153 + void *context, void **rv)
155 + char name[ACPI_PATH_SEGMENT_LENGTH];
156 + struct acpi_buffer buffer = { sizeof(name), &name };
158 + if (ACPI_SUCCESS(acpi_get_name(handle, ACPI_SINGLE_NAME, &buffer)) &&
159 + !strncmp("BCLL", name, sizeof(name) - 1)) {
160 + if (tpacpi_query_bcll_levels(handle) == 16) {
161 + *rv = handle;
162 + return AE_CTRL_TERMINATE;
163 + } else {
164 + return AE_OK;
166 + } else {
167 + return AE_OK;
171 +static int __init brightness_check_levels(void)
173 + int status;
174 + void *found_node = NULL;
176 + if (!vid_handle) {
177 + IBM_ACPIHANDLE_INIT(vid);
179 + if (!vid_handle)
180 + return 0;
182 + /* Search for a BCLL package with 16 levels */
183 + status = acpi_walk_namespace(ACPI_TYPE_PACKAGE, vid_handle, 3,
184 + brightness_find_bcll, NULL, &found_node);
186 + return (ACPI_SUCCESS(status) && found_node != NULL);
189 static int __init brightness_init(struct ibm_init_struct *iibm)
191 int b;
192 @@ -3135,10 +3195,17 @@ static int __init brightness_init(struct ibm_init_struct *iibm)
193 if (brightness_mode > 3)
194 return -EINVAL;
196 + tp_features.bright_16levels =
197 + thinkpad_id.vendor == PCI_VENDOR_ID_LENOVO &&
198 + brightness_check_levels();
200 b = brightness_get(NULL);
201 if (b < 0)
202 return 1;
204 + if (tp_features.bright_16levels)
205 + printk(IBM_INFO "detected a 16-level brightness capable ThinkPad\n");
207 ibm_backlight_device = backlight_device_register(
208 TPACPI_BACKLIGHT_DEV_NAME, NULL, NULL,
209 &ibm_backlight_data);
210 @@ -3148,7 +3215,8 @@ static int __init brightness_init(struct ibm_init_struct *iibm)
212 vdbg_printk(TPACPI_DBG_INIT, "brightness is supported\n");
214 - ibm_backlight_device->props.max_brightness = 7;
215 + ibm_backlight_device->props.max_brightness =
216 + (tp_features.bright_16levels)? 15 : 7;
217 ibm_backlight_device->props.brightness = b;
218 backlight_update_status(ibm_backlight_device);
220 @@ -3184,13 +3252,14 @@ static int brightness_get(struct backlight_device *bd)
221 if (brightness_mode & 1) {
222 if (!acpi_ec_read(brightness_offset, &lec))
223 return -EIO;
224 - lec &= 7;
225 + lec &= (tp_features.bright_16levels)? 0x0f : 0x07;
226 level = lec;
228 if (brightness_mode & 2) {
229 lcmos = (nvram_read_byte(TP_NVRAM_ADDR_BRIGHTNESS)
230 & TP_NVRAM_MASK_LEVEL_BRIGHTNESS)
231 >> TP_NVRAM_POS_LEVEL_BRIGHTNESS;
232 + lcmos &= (tp_features.bright_16levels)? 0x0f : 0x07;
233 level = lcmos;
236 @@ -3211,7 +3280,7 @@ static int brightness_set(int value)
237 int cmos_cmd, inc, i, res;
238 int current_value;
240 - if (value > 7)
241 + if (value > ((tp_features.bright_16levels)? 15 : 7))
242 return -EINVAL;
244 res = mutex_lock_interruptible(&brightness_mutex);
245 @@ -3227,7 +3296,7 @@ static int brightness_set(int value)
246 cmos_cmd = value > current_value ?
247 TP_CMOS_BRIGHTNESS_UP :
248 TP_CMOS_BRIGHTNESS_DOWN;
249 - inc = value > current_value ? 1 : -1;
250 + inc = (value > current_value)? 1 : -1;
252 res = 0;
253 for (i = current_value; i != value; i += inc) {
254 @@ -3256,10 +3325,11 @@ static int brightness_read(char *p)
255 if ((level = brightness_get(NULL)) < 0) {
256 len += sprintf(p + len, "level:\t\tunreadable\n");
257 } else {
258 - len += sprintf(p + len, "level:\t\t%d\n", level & 0x7);
259 + len += sprintf(p + len, "level:\t\t%d\n", level);
260 len += sprintf(p + len, "commands:\tup, down\n");
261 len += sprintf(p + len, "commands:\tlevel <level>"
262 - " (<level> is 0-7)\n");
263 + " (<level> is 0-%d)\n",
264 + (tp_features.bright_16levels) ? 15 : 7);
267 return len;
268 @@ -3270,18 +3340,19 @@ static int brightness_write(char *buf)
269 int level;
270 int new_level;
271 char *cmd;
272 + int max_level = (tp_features.bright_16levels) ? 15 : 7;
274 while ((cmd = next_cmd(&buf))) {
275 if ((level = brightness_get(NULL)) < 0)
276 return level;
277 - level &= 7;
279 if (strlencmp(cmd, "up") == 0) {
280 - new_level = level == 7 ? 7 : level + 1;
281 + new_level = level == (max_level)?
282 + max_level : level + 1;
283 } else if (strlencmp(cmd, "down") == 0) {
284 - new_level = level == 0 ? 0 : level - 1;
285 + new_level = level == 0? 0 : level - 1;
286 } else if (sscanf(cmd, "level %d", &new_level) == 1 &&
287 - new_level >= 0 && new_level <= 7) {
288 + new_level >= 0 && new_level <= max_level) {
289 /* new_level set */
290 } else
291 return -EINVAL;
292 diff --git a/drivers/misc/thinkpad_acpi.h b/drivers/misc/thinkpad_acpi.h
293 index 3abcc81..8ca19c3 100644
294 --- a/drivers/misc/thinkpad_acpi.h
295 +++ b/drivers/misc/thinkpad_acpi.h
296 @@ -84,7 +84,7 @@
298 /* ThinkPad CMOS NVRAM constants */
299 #define TP_NVRAM_ADDR_BRIGHTNESS 0x5e
300 -#define TP_NVRAM_MASK_LEVEL_BRIGHTNESS 0x07
301 +#define TP_NVRAM_MASK_LEVEL_BRIGHTNESS 0x0f
302 #define TP_NVRAM_POS_LEVEL_BRIGHTNESS 0
304 #define onoff(status,bit) ((status) & (1 << (bit)) ? "on" : "off")
305 @@ -246,6 +246,7 @@ static struct {
306 u32 hotkey_wlsw:1;
307 u32 light:1;
308 u32 light_status:1;
309 + u32 bright_16levels:1;
310 u32 wan:1;
311 u32 fan_ctrl_status_undef:1;
312 u32 input_device_registered:1;
314 1.5.3.4