Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e11aecf1 authored by Henrique de Moraes Holschuh's avatar Henrique de Moraes Holschuh Committed by Len Brown
Browse files

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: default avatarHenrique de Moraes Holschuh <hmh@hmh.eng.br>
Signed-off-by: default avatarLen Brown <len.brown@intel.com>
parent 2d5e94d7
Loading
Loading
Loading
Loading
+49 −15
Original line number Diff line number Diff line
@@ -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(&current_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;