diff options
Diffstat (limited to 'drivers/misc')
-rw-r--r-- | drivers/misc/thinkpad_acpi.c | 64 |
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 | ||
4298 | enum { | ||
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 | |||
4298 | static struct backlight_device *ibm_backlight_device; | 4307 | static struct backlight_device *ibm_backlight_device; |
4299 | static int brightness_offset = 0x31; | ||
4300 | static int brightness_mode; | 4308 | static int brightness_mode; |
4301 | static unsigned int brightness_enable = 2; /* 2 = auto, 0 = no, 1 = yes */ | 4309 | static 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 | */ |
4309 | static int brightness_get(struct backlight_device *bd) | 4326 | static 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(¤t_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 | ||
4425 | static 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 | |||
4401 | static struct backlight_ops ibm_backlight_data = { | 4436 | static 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; |