diff options
-rw-r--r-- | drivers/platform/x86/dell-laptop.c | 59 |
1 files changed, 53 insertions, 6 deletions
diff --git a/drivers/platform/x86/dell-laptop.c b/drivers/platform/x86/dell-laptop.c index 296cb9632a71..ec202094bd50 100644 --- a/drivers/platform/x86/dell-laptop.c +++ b/drivers/platform/x86/dell-laptop.c @@ -45,6 +45,7 @@ #define KBD_LED_AUTO_100_TOKEN 0x02F6 #define GLOBAL_MIC_MUTE_ENABLE 0x0364 #define GLOBAL_MIC_MUTE_DISABLE 0x0365 +#define KBD_LED_AC_TOKEN 0x0451 struct quirk_entry { u8 touchpad_led; @@ -1027,7 +1028,7 @@ static void touchpad_led_exit(void) * bit 2 Pointing stick * bit 3 Any mouse * bits 4-7 Reserved for future use - * cbRES2, byte3 Current Timeout + * cbRES2, byte3 Current Timeout on battery * bits 7:6 Timeout units indicator: * 00b Seconds * 01b Minutes @@ -1039,6 +1040,15 @@ static void touchpad_led_exit(void) * cbRES3, byte0 Current setting of ALS value that turns the light on or off. * cbRES3, byte1 Current ALS reading * cbRES3, byte2 Current keyboard light level. + * cbRES3, byte3 Current timeout on AC Power + * bits 7:6 Timeout units indicator: + * 00b Seconds + * 01b Minutes + * 10b Hours + * 11b Days + * Bits 5:0 Timeout value (0-63) in sec/min/hr/day + * NOTE: A value of 0 means always on (no timeout) if any bits of RES3 byte2 + * are set upon return from the upon return from the [Get Feature information] call. * * cbArg1 0x2 = Set New State * cbRES1 Standard return codes (0, -1, -2) @@ -1061,7 +1071,7 @@ static void touchpad_led_exit(void) * bit 2 Pointing stick * bit 3 Any mouse * bits 4-7 Reserved for future use - * cbArg2, byte3 Desired Timeout + * cbArg2, byte3 Desired Timeout on battery * bits 7:6 Timeout units indicator: * 00b Seconds * 01b Minutes @@ -1070,6 +1080,13 @@ static void touchpad_led_exit(void) * bits 5:0 Timeout value (0-63) in sec/min/hr/day * cbArg3, byte0 Desired setting of ALS value that turns the light on or off. * cbArg3, byte2 Desired keyboard light level. + * cbArg3, byte3 Desired Timeout on AC power + * bits 7:6 Timeout units indicator: + * 00b Seconds + * 01b Minutes + * 10b Hours + * 11b Days + * bits 5:0 Timeout value (0-63) in sec/min/hr/day */ @@ -1115,6 +1132,8 @@ struct kbd_state { u8 triggers; u8 timeout_value; u8 timeout_unit; + u8 timeout_value_ac; + u8 timeout_unit_ac; u8 als_setting; u8 als_value; u8 level; @@ -1134,6 +1153,7 @@ static u16 kbd_token_bits; static struct kbd_info kbd_info; static bool kbd_als_supported; static bool kbd_triggers_supported; +static bool kbd_timeout_ac_supported; static u8 kbd_mode_levels[16]; static int kbd_mode_levels_count; @@ -1273,6 +1293,8 @@ static int kbd_get_state(struct kbd_state *state) state->als_setting = buffer->output[2] & 0xFF; state->als_value = (buffer->output[2] >> 8) & 0xFF; state->level = (buffer->output[2] >> 16) & 0xFF; + state->timeout_value_ac = (buffer->output[2] >> 24) & 0x3F; + state->timeout_unit_ac = (buffer->output[2] >> 30) & 0x3; out: dell_smbios_release_buffer(); @@ -1292,6 +1314,8 @@ static int kbd_set_state(struct kbd_state *state) buffer->input[1] |= (state->timeout_unit & 0x3) << 30; buffer->input[2] = state->als_setting & 0xFF; buffer->input[2] |= (state->level & 0xFF) << 16; + buffer->input[2] |= (state->timeout_value_ac & 0x3F) << 24; + buffer->input[2] |= (state->timeout_unit_ac & 0x3) << 30; dell_smbios_send_request(4, 11); ret = buffer->output[0]; dell_smbios_release_buffer(); @@ -1398,6 +1422,13 @@ static inline int kbd_init_info(void) if (ret) return ret; + /* NOTE: Old models without KBD_LED_AC_TOKEN token supports only one + * timeout value which is shared for both battery and AC power + * settings. So do not try to set AC values on old models. + */ + if (dell_smbios_find_token(KBD_LED_AC_TOKEN)) + kbd_timeout_ac_supported = true; + kbd_get_state(&state); /* NOTE: timeout value is stored in 6 bits so max value is 63 */ @@ -1579,8 +1610,14 @@ static ssize_t kbd_led_timeout_store(struct device *dev, goto out; new_state = state; - new_state.timeout_value = value; - new_state.timeout_unit = unit; + + if (kbd_timeout_ac_supported && power_supply_is_system_supplied() > 0) { + new_state.timeout_value_ac = value; + new_state.timeout_unit_ac = unit; + } else { + new_state.timeout_value = value; + new_state.timeout_unit = unit; + } ret = kbd_set_state_safe(&new_state, &state); if (ret) @@ -1596,16 +1633,26 @@ static ssize_t kbd_led_timeout_show(struct device *dev, struct device_attribute *attr, char *buf) { struct kbd_state state; + int value; int ret; int len; + u8 unit; ret = kbd_get_state(&state); if (ret) return ret; - len = sprintf(buf, "%d", state.timeout_value); + if (kbd_timeout_ac_supported && power_supply_is_system_supplied() > 0) { + value = state.timeout_value_ac; + unit = state.timeout_unit_ac; + } else { + value = state.timeout_value; + unit = state.timeout_unit; + } + + len = sprintf(buf, "%d", value); - switch (state.timeout_unit) { + switch (unit) { case KBD_TIMEOUT_SECONDS: return len + sprintf(buf+len, "s\n"); case KBD_TIMEOUT_MINUTES: |