mirror of
https://github.com/torvalds/linux.git
synced 2024-11-16 17:12:06 +00:00
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>
This commit is contained in:
parent
2d5e94d7ca
commit
e11aecf137
@ -4295,8 +4295,16 @@ static struct ibm_struct ecdump_driver_data = {
|
||||
|
||||
#define TPACPI_BACKLIGHT_DEV_NAME "thinkpad_screen"
|
||||
|
||||
enum {
|
||||
TP_EC_BACKLIGHT = 0x31,
|
||||
|
||||
/* TP_EC_BACKLIGHT bitmasks */
|
||||
TP_EC_BACKLIGHT_LVLMSK = 0x1F,
|
||||
TP_EC_BACKLIGHT_CMDMSK = 0xE0,
|
||||
TP_EC_BACKLIGHT_MAPSW = 0x20,
|
||||
};
|
||||
|
||||
static struct backlight_device *ibm_backlight_device;
|
||||
static int brightness_offset = 0x31;
|
||||
static int brightness_mode;
|
||||
static unsigned int brightness_enable = 2; /* 2 = auto, 0 = no, 1 = yes */
|
||||
|
||||
@ -4305,16 +4313,24 @@ static struct mutex brightness_mutex;
|
||||
/*
|
||||
* ThinkPads can read brightness from two places: EC 0x31, or
|
||||
* CMOS NVRAM byte 0x5E, bits 0-3.
|
||||
*
|
||||
* EC 0x31 has the following layout
|
||||
* Bit 7: unknown function
|
||||
* Bit 6: unknown function
|
||||
* Bit 5: Z: honour scale changes, NZ: ignore scale changes
|
||||
* Bit 4: must be set to zero to avoid problems
|
||||
* Bit 3-0: backlight brightness level
|
||||
*
|
||||
* brightness_get_raw returns status data in the EC 0x31 layout
|
||||
*/
|
||||
static int brightness_get(struct backlight_device *bd)
|
||||
static int brightness_get_raw(int *status)
|
||||
{
|
||||
u8 lec = 0, lcmos = 0, level = 0;
|
||||
|
||||
if (brightness_mode & 1) {
|
||||
if (!acpi_ec_read(brightness_offset, &lec))
|
||||
if (!acpi_ec_read(TP_EC_BACKLIGHT, &lec))
|
||||
return -EIO;
|
||||
lec &= (tp_features.bright_16levels)? 0x0f : 0x07;
|
||||
level = lec;
|
||||
level = lec & TP_EC_BACKLIGHT_LVLMSK;
|
||||
};
|
||||
if (brightness_mode & 2) {
|
||||
lcmos = (nvram_read_byte(TP_NVRAM_ADDR_BRIGHTNESS)
|
||||
@ -4325,6 +4341,8 @@ static int brightness_get(struct backlight_device *bd)
|
||||
}
|
||||
|
||||
if (brightness_mode == 3) {
|
||||
*status = lec; /* Prefer EC, CMOS is just a backing store */
|
||||
lec &= TP_EC_BACKLIGHT_LVLMSK;
|
||||
if (lec == lcmos)
|
||||
tp_warned.bright_cmos_ec_unsync = 0;
|
||||
else {
|
||||
@ -4338,9 +4356,11 @@ static int brightness_get(struct backlight_device *bd)
|
||||
}
|
||||
return -EIO;
|
||||
}
|
||||
} else {
|
||||
*status = level;
|
||||
}
|
||||
|
||||
return level;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* May return EINTR which can always be mapped to ERESTARTSYS */
|
||||
@ -4348,19 +4368,22 @@ static int brightness_set(int value)
|
||||
{
|
||||
int cmos_cmd, inc, i, res;
|
||||
int current_value;
|
||||
int command_bits;
|
||||
|
||||
if (value > ((tp_features.bright_16levels)? 15 : 7))
|
||||
if (value > ((tp_features.bright_16levels)? 15 : 7) ||
|
||||
value < 0)
|
||||
return -EINVAL;
|
||||
|
||||
res = mutex_lock_interruptible(&brightness_mutex);
|
||||
if (res < 0)
|
||||
return res;
|
||||
|
||||
current_value = brightness_get(NULL);
|
||||
if (current_value < 0) {
|
||||
res = current_value;
|
||||
res = brightness_get_raw(¤t_value);
|
||||
if (res < 0)
|
||||
goto errout;
|
||||
}
|
||||
|
||||
command_bits = current_value & TP_EC_BACKLIGHT_CMDMSK;
|
||||
current_value &= TP_EC_BACKLIGHT_LVLMSK;
|
||||
|
||||
cmos_cmd = value > current_value ?
|
||||
TP_CMOS_BRIGHTNESS_UP :
|
||||
@ -4375,7 +4398,8 @@ static int brightness_set(int value)
|
||||
goto errout;
|
||||
}
|
||||
if ((brightness_mode & 1) &&
|
||||
!acpi_ec_write(brightness_offset, i + inc)) {
|
||||
!acpi_ec_write(TP_EC_BACKLIGHT,
|
||||
(i + inc) | command_bits)) {
|
||||
res = -EIO;
|
||||
goto errout;;
|
||||
}
|
||||
@ -4398,6 +4422,17 @@ static int brightness_update_status(struct backlight_device *bd)
|
||||
bd->props.brightness : 0);
|
||||
}
|
||||
|
||||
static int brightness_get(struct backlight_device *bd)
|
||||
{
|
||||
int status, res;
|
||||
|
||||
res = brightness_get_raw(&status);
|
||||
if (res < 0)
|
||||
return 0; /* FIXME: teach backlight about error handling */
|
||||
|
||||
return status & TP_EC_BACKLIGHT_LVLMSK;
|
||||
}
|
||||
|
||||
static struct backlight_ops ibm_backlight_data = {
|
||||
.get_brightness = brightness_get,
|
||||
.update_status = brightness_update_status,
|
||||
@ -4462,8 +4497,7 @@ static int __init brightness_init(struct ibm_init_struct *iibm)
|
||||
if (brightness_mode > 3)
|
||||
return -EINVAL;
|
||||
|
||||
b = brightness_get(NULL);
|
||||
if (b < 0)
|
||||
if (brightness_get_raw(&b) < 0)
|
||||
return 1;
|
||||
|
||||
if (tp_features.bright_16levels)
|
||||
@ -4481,7 +4515,7 @@ static int __init brightness_init(struct ibm_init_struct *iibm)
|
||||
|
||||
ibm_backlight_device->props.max_brightness =
|
||||
(tp_features.bright_16levels)? 15 : 7;
|
||||
ibm_backlight_device->props.brightness = b;
|
||||
ibm_backlight_device->props.brightness = b & TP_EC_BACKLIGHT_LVLMSK;
|
||||
backlight_update_status(ibm_backlight_device);
|
||||
|
||||
return 0;
|
||||
|
Loading…
Reference in New Issue
Block a user