aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHenrique de Moraes Holschuh <hmh@hmh.eng.br>2008-04-26 00:02:21 -0400
committerLen Brown <len.brown@intel.com>2008-04-29 09:47:01 -0400
commite11aecf1379e7c4a0293182096e38e5a336696b2 (patch)
tree9dfc915ef98293b7a7b3e42b7a5de9797b0ceb29
parent2d5e94d7ca315f859a0eee1366838e8ad34dd7b2 (diff)
ACPI: thinkpad-acpi: fix brightness dimming control bug
ibm-acpi and thinkpad-acpi did not know about bit 5 of the EC backlight level control register (EC 0x31), so it was always forced to zero on any writes. This would disable the BIOS option to *not* use a dimmer backlight level scale while on battery, and who knows what else (there are two other control bits of unknown function). Bit 5 controls the "reduce backlight levels when on battery" optional functionality (active low). Bits 6 and 7 are better left alone as well, instead of being forced to zero. Signed-off-by: Henrique de Moraes Holschuh <hmh@hmh.eng.br> Signed-off-by: Len Brown <len.brown@intel.com>
-rw-r--r--drivers/misc/thinkpad_acpi.c64
1 files changed, 49 insertions, 15 deletions
diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c
index 7dc6b73e8f5b..5e25abc54008 100644
--- a/drivers/misc/thinkpad_acpi.c
+++ b/drivers/misc/thinkpad_acpi.c
@@ -4295,8 +4295,16 @@ static struct ibm_struct ecdump_driver_data = {
4295 4295
4296#define TPACPI_BACKLIGHT_DEV_NAME "thinkpad_screen" 4296#define TPACPI_BACKLIGHT_DEV_NAME "thinkpad_screen"
4297 4297
4298enum {
4299 TP_EC_BACKLIGHT = 0x31,
4300
4301 /* TP_EC_BACKLIGHT bitmasks */
4302 TP_EC_BACKLIGHT_LVLMSK = 0x1F,
4303 TP_EC_BACKLIGHT_CMDMSK = 0xE0,
4304 TP_EC_BACKLIGHT_MAPSW = 0x20,
4305};
4306
4298static struct backlight_device *ibm_backlight_device; 4307static struct backlight_device *ibm_backlight_device;
4299static int brightness_offset = 0x31;
4300static int brightness_mode; 4308static int brightness_mode;
4301static unsigned int brightness_enable = 2; /* 2 = auto, 0 = no, 1 = yes */ 4309static unsigned int brightness_enable = 2; /* 2 = auto, 0 = no, 1 = yes */
4302 4310
@@ -4305,16 +4313,24 @@ static struct mutex brightness_mutex;
4305/* 4313/*
4306 * ThinkPads can read brightness from two places: EC 0x31, or 4314 * ThinkPads can read brightness from two places: EC 0x31, or
4307 * CMOS NVRAM byte 0x5E, bits 0-3. 4315 * CMOS NVRAM byte 0x5E, bits 0-3.
4316 *
4317 * EC 0x31 has the following layout
4318 * Bit 7: unknown function
4319 * Bit 6: unknown function
4320 * Bit 5: Z: honour scale changes, NZ: ignore scale changes
4321 * Bit 4: must be set to zero to avoid problems
4322 * Bit 3-0: backlight brightness level
4323 *
4324 * brightness_get_raw returns status data in the EC 0x31 layout
4308 */ 4325 */
4309static int brightness_get(struct backlight_device *bd) 4326static int brightness_get_raw(int *status)
4310{ 4327{
4311 u8 lec = 0, lcmos = 0, level = 0; 4328 u8 lec = 0, lcmos = 0, level = 0;
4312 4329
4313 if (brightness_mode & 1) { 4330 if (brightness_mode & 1) {
4314 if (!acpi_ec_read(brightness_offset, &lec)) 4331 if (!acpi_ec_read(TP_EC_BACKLIGHT, &lec))
4315 return -EIO; 4332 return -EIO;
4316 lec &= (tp_features.bright_16levels)? 0x0f : 0x07; 4333 level = lec & TP_EC_BACKLIGHT_LVLMSK;
4317 level = lec;
4318 }; 4334 };
4319 if (brightness_mode & 2) { 4335 if (brightness_mode & 2) {
4320 lcmos = (nvram_read_byte(TP_NVRAM_ADDR_BRIGHTNESS) 4336 lcmos = (nvram_read_byte(TP_NVRAM_ADDR_BRIGHTNESS)
@@ -4325,6 +4341,8 @@ static int brightness_get(struct backlight_device *bd)
4325 } 4341 }
4326 4342
4327 if (brightness_mode == 3) { 4343 if (brightness_mode == 3) {
4344 *status = lec; /* Prefer EC, CMOS is just a backing store */
4345 lec &= TP_EC_BACKLIGHT_LVLMSK;
4328 if (lec == lcmos) 4346 if (lec == lcmos)
4329 tp_warned.bright_cmos_ec_unsync = 0; 4347 tp_warned.bright_cmos_ec_unsync = 0;
4330 else { 4348 else {
@@ -4338,9 +4356,11 @@ static int brightness_get(struct backlight_device *bd)
4338 } 4356 }
4339 return -EIO; 4357 return -EIO;
4340 } 4358 }
4359 } else {
4360 *status = level;
4341 } 4361 }
4342 4362
4343 return level; 4363 return 0;
4344} 4364}
4345 4365
4346/* May return EINTR which can always be mapped to ERESTARTSYS */ 4366/* May return EINTR which can always be mapped to ERESTARTSYS */
@@ -4348,19 +4368,22 @@ static int brightness_set(int value)
4348{ 4368{
4349 int cmos_cmd, inc, i, res; 4369 int cmos_cmd, inc, i, res;
4350 int current_value; 4370 int current_value;
4371 int command_bits;
4351 4372
4352 if (value > ((tp_features.bright_16levels)? 15 : 7)) 4373 if (value > ((tp_features.bright_16levels)? 15 : 7) ||
4374 value < 0)
4353 return -EINVAL; 4375 return -EINVAL;
4354 4376
4355 res = mutex_lock_interruptible(&brightness_mutex); 4377 res = mutex_lock_interruptible(&brightness_mutex);
4356 if (res < 0) 4378 if (res < 0)
4357 return res; 4379 return res;
4358 4380
4359 current_value = brightness_get(NULL); 4381 res = brightness_get_raw(&current_value);
4360 if (current_value < 0) { 4382 if (res < 0)
4361 res = current_value;
4362 goto errout; 4383 goto errout;
4363 } 4384
4385 command_bits = current_value & TP_EC_BACKLIGHT_CMDMSK;
4386 current_value &= TP_EC_BACKLIGHT_LVLMSK;
4364 4387
4365 cmos_cmd = value > current_value ? 4388 cmos_cmd = value > current_value ?
4366 TP_CMOS_BRIGHTNESS_UP : 4389 TP_CMOS_BRIGHTNESS_UP :
@@ -4375,7 +4398,8 @@ static int brightness_set(int value)
4375 goto errout; 4398 goto errout;
4376 } 4399 }
4377 if ((brightness_mode & 1) && 4400 if ((brightness_mode & 1) &&
4378 !acpi_ec_write(brightness_offset, i + inc)) { 4401 !acpi_ec_write(TP_EC_BACKLIGHT,
4402 (i + inc) | command_bits)) {
4379 res = -EIO; 4403 res = -EIO;
4380 goto errout;; 4404 goto errout;;
4381 } 4405 }
@@ -4398,6 +4422,17 @@ static int brightness_update_status(struct backlight_device *bd)
4398 bd->props.brightness : 0); 4422 bd->props.brightness : 0);
4399} 4423}
4400 4424
4425static int brightness_get(struct backlight_device *bd)
4426{
4427 int status, res;
4428
4429 res = brightness_get_raw(&status);
4430 if (res < 0)
4431 return 0; /* FIXME: teach backlight about error handling */
4432
4433 return status & TP_EC_BACKLIGHT_LVLMSK;
4434}
4435
4401static struct backlight_ops ibm_backlight_data = { 4436static struct backlight_ops ibm_backlight_data = {
4402 .get_brightness = brightness_get, 4437 .get_brightness = brightness_get,
4403 .update_status = brightness_update_status, 4438 .update_status = brightness_update_status,
@@ -4462,8 +4497,7 @@ static int __init brightness_init(struct ibm_init_struct *iibm)
4462 if (brightness_mode > 3) 4497 if (brightness_mode > 3)
4463 return -EINVAL; 4498 return -EINVAL;
4464 4499
4465 b = brightness_get(NULL); 4500 if (brightness_get_raw(&b) < 0)
4466 if (b < 0)
4467 return 1; 4501 return 1;
4468 4502
4469 if (tp_features.bright_16levels) 4503 if (tp_features.bright_16levels)
@@ -4481,7 +4515,7 @@ static int __init brightness_init(struct ibm_init_struct *iibm)
4481 4515
4482 ibm_backlight_device->props.max_brightness = 4516 ibm_backlight_device->props.max_brightness =
4483 (tp_features.bright_16levels)? 15 : 7; 4517 (tp_features.bright_16levels)? 15 : 7;
4484 ibm_backlight_device->props.brightness = b; 4518 ibm_backlight_device->props.brightness = b & TP_EC_BACKLIGHT_LVLMSK;
4485 backlight_update_status(ibm_backlight_device); 4519 backlight_update_status(ibm_backlight_device);
4486 4520
4487 return 0; 4521 return 0;