Compare commits

...

3 commits

2 changed files with 227 additions and 7 deletions

View file

@ -27,6 +27,7 @@
#include <linux/rfkill.h>
#include <linux/string.h>
#include <linux/dmi.h>
#include <linux/leds.h>
MODULE_AUTHOR("Matthew Garrett <mjg59@srcf.ucam.org>");
MODULE_DESCRIPTION("HP laptop WMI hotkeys driver");
@ -55,7 +56,7 @@ static const char * const omen_thermal_profile_boards[] = {
"874A", "8603", "8604", "8748", "886B", "886C", "878A", "878B", "878C",
"88C8", "88CB", "8786", "8787", "8788", "88D1", "88D2", "88F4", "88FD",
"88F5", "88F6", "88F7", "88FE", "88FF", "8900", "8901", "8902", "8912",
"8917", "8918", "8949", "894A", "89EB"
"8917", "8918", "8949", "894A", "89EB", "8A42"
};
/* DMI Board names of Omen laptops that are specifically set to be thermal
@ -143,6 +144,7 @@ enum hp_wmi_command {
HPWMI_WRITE = 0x02,
HPWMI_ODM = 0x03,
HPWMI_GM = 0x20008,
HPWMI_KB = 0x20009,
};
enum hp_wmi_hardware_mask {
@ -274,6 +276,9 @@ static const char * const tablet_chassis_types[] = {
#define DEVICE_MODE_TABLET 0x06
#define OMEN_ZONE_COLOR_OFFSET 0x19
#define OMEN_ZONE_COLOR_LEN 0x0c
/* map output size to the corresponding WMI method id */
static inline int encode_outsize_for_pvsz(int outsize)
{
@ -290,6 +295,12 @@ static inline int encode_outsize_for_pvsz(int outsize)
return 1;
}
static void omen_thermal_profile_refresh(struct work_struct *work);
DECLARE_DELAYED_WORK(omen_profile_refresh, omen_thermal_profile_refresh);
static int omen_saved_thermal_profile_value = -1;
/*
* hp_wmi_perform_query
*
@ -509,10 +520,61 @@ static int omen_thermal_profile_get(void)
return data;
}
static void omen_thermal_profile_refresh(struct work_struct *work) {
int tp, err;
tp = omen_thermal_profile_get();
if (tp < 0) {
pr_warn("omen-refresh: Failed to get thermal profile, refreshing disabled [code: 0x%x]\n", tp);
return;
}
err = omen_thermal_profile_set(tp);
if (err < 0) {
pr_warn("omen-refresh: Failed to set thermal profile to 0x%x, refreshing disabled [code: 0x%x]\n", tp, err);
return;
}
// Run every 100 seconds
schedule_delayed_work(&omen_profile_refresh, 100 * HZ);
}
static void omen_setup_profile_refresh(void) {
schedule_delayed_work(&omen_profile_refresh, 0);
}
static int omen_save_thermal_profile(void) {
int tp;
tp = omen_thermal_profile_get();
if (tp < 0) {
return tp;
}
omen_saved_thermal_profile_value = tp;
return tp;
}
static int omen_restore_thermal_profile(void) {
int err, tp;
if (omen_saved_thermal_profile_value < 0) {
pr_info("omen-pm: no saved thermal profile, restore skipped");
return 0;
}
tp = omen_saved_thermal_profile_value;
omen_saved_thermal_profile_value = -1;
err = omen_thermal_profile_set(tp);
if (err < 0) {
return err;
}
return tp;
}
static int hp_wmi_fan_speed_max_set(int enabled)
{
int ret;
ret = hp_wmi_perform_query(HPWMI_FAN_SPEED_MAX_SET_QUERY, HPWMI_GM,
&enabled, sizeof(enabled), 0);
@ -781,12 +843,61 @@ static int camera_shutter_input_setup(void)
return err;
}
static ssize_t zone_colors_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
u8 val[128];
int ret = hp_wmi_perform_query(HPWMI_HDDTEMP_QUERY, HPWMI_KB, &val,
zero_if_sup(val), sizeof(val));
if (ret)
return ret;
memcpy(buf, &val[OMEN_ZONE_COLOR_OFFSET], OMEN_ZONE_COLOR_LEN);
pr_info("READ COLOR");
return OMEN_ZONE_COLOR_LEN;
}
static ssize_t zone_colors_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
u8 val[128];
int ret;
ret = hp_wmi_perform_query(HPWMI_HDDTEMP_QUERY, HPWMI_KB, &val,
zero_if_sup(val), sizeof(val));
if (ret)
return ret;
if (count != OMEN_ZONE_COLOR_LEN)
return -1;
memcpy(&val[OMEN_ZONE_COLOR_OFFSET], buf, count);
ret = hp_wmi_perform_query(HPWMI_ALS_QUERY, HPWMI_KB, &val, sizeof(val),
0);
if (ret)
return ret;
return OMEN_ZONE_COLOR_LEN;
}
static DEVICE_ATTR_RO(display);
static DEVICE_ATTR_RO(hddtemp);
static DEVICE_ATTR_RW(als);
static DEVICE_ATTR_RO(dock);
static DEVICE_ATTR_RO(tablet);
static DEVICE_ATTR_RW(postcode);
static DEVICE_ATTR_RW(zone_colors);
static struct attribute *hp_wmi_attrs[] = {
&dev_attr_display.attr,
@ -799,6 +910,12 @@ static struct attribute *hp_wmi_attrs[] = {
};
ATTRIBUTE_GROUPS(hp_wmi);
static struct attribute *omen_kbd_led_attrs[] = {
&dev_attr_zone_colors.attr,
NULL,
};
ATTRIBUTE_GROUPS(omen_kbd_led);
static void hp_wmi_notify(u32 value, void *context)
{
struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL };
@ -910,6 +1027,10 @@ static void hp_wmi_notify(u32 value, void *context)
case HPWMI_PROXIMITY_SENSOR:
break;
case HPWMI_BACKLIT_KB_BRIGHTNESS:
input_report_key(hp_wmi_input_dev, KEY_KBDILLUMTOGGLE, true);
input_sync(hp_wmi_input_dev);
input_report_key(hp_wmi_input_dev, KEY_KBDILLUMTOGGLE, false);
input_sync(hp_wmi_input_dev);
break;
case HPWMI_PEAKSHIFT_PERIOD:
break;
@ -1392,10 +1513,19 @@ static int thermal_profile_setup(void)
if (err < 0)
return err;
// Set default profile to 0x30 - Balanced
err = omen_thermal_profile_set(0x30);
if (err < 0)
return err;
platform_profile_handler.profile_get = platform_profile_omen_get;
platform_profile_handler.profile_set = platform_profile_omen_set;
set_bit(PLATFORM_PROFILE_COOL, platform_profile_handler.choices);
// Disable cool profile
/* set_bit(PLATFORM_PROFILE_COOL, platform_profile_handler.choices); */
omen_setup_profile_refresh();
} else if (is_victus_thermal_profile()) {
tp = omen_thermal_profile_get();
if (tp < 0)
@ -1448,6 +1578,60 @@ static int thermal_profile_setup(void)
static int hp_wmi_hwmon_init(void);
static enum led_brightness get_omen_backlight_brightness(struct led_classdev *cdev)
{
u8 val;
int ret = hp_wmi_perform_query(HPWMI_HARDWARE_QUERY, HPWMI_KB, &val, zero_if_sup(val), sizeof(val));
if (ret)
return ret;
return (val & 0x80) ? LED_ON : LED_OFF;
}
static void set_omen_backlight_brightness(struct led_classdev *cdev, enum led_brightness value)
{
char buffer[4] = { (value == LED_OFF) ? 0x64 : 0xe4, 0, 0, 0 };
hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, HPWMI_KB, &buffer,
sizeof(buffer), 0);
}
static struct led_classdev omen_kbd_led = {
.name = "hp_omen::kbd_backlight",
.brightness_set = set_omen_backlight_brightness,
.brightness_get = get_omen_backlight_brightness,
.max_brightness = 1,
.groups = omen_kbd_led_groups,
};
static bool is_omen_lighting_supported(void)
{
u8 val;
int ret = hp_wmi_perform_query(HPWMI_DISPLAY_QUERY, HPWMI_KB, &val, zero_if_sup(val), sizeof(val));
if (ret)
return false;
return (val & 1) == 1;
}
static int omen_backlight_init(struct device *dev)
{
int ret;
input_set_capability(hp_wmi_input_dev, KE_KEY, KEY_KBDILLUMTOGGLE);
ret = devm_led_classdev_register(dev, &omen_kbd_led);
if (ret < 0)
return -1;
return 0;
}
static int __init hp_wmi_bios_setup(struct platform_device *device)
{
int err;
@ -1475,6 +1659,9 @@ static int __init hp_wmi_bios_setup(struct platform_device *device)
thermal_profile_setup();
if (is_omen_lighting_supported())
omen_backlight_init(&device->dev);
return 0;
}
@ -1508,6 +1695,17 @@ static int __exit hp_wmi_bios_remove(struct platform_device *device)
static int hp_wmi_resume_handler(struct device *device)
{
int tp;
tp = omen_restore_thermal_profile();
if (tp < 0) {
pr_info("omen-tp: Failed to restore thermal profile value: code 0x%x\n", tp);
pr_info("omen-tp: Using default profile value: 0x30");
tp = 0x30;
}
pr_info("omen-tp: Restored thermal profile: 0x%x", tp);
/*
* Hardware state may have changed while suspended, so trigger
* input events for the current state. As this is a switch,
@ -1543,9 +1741,21 @@ static int hp_wmi_resume_handler(struct device *device)
return 0;
}
static int hp_wmi_suspend_handler(struct device *device) {
int tp;
tp = omen_save_thermal_profile();
if (tp < 0) pr_info("omen-tp: Failed to save thermal profile value: code 0x%x", tp);
pr_info("omen-tp: Saved thermal profile: 0x%x", tp);
return 0;
}
static const struct dev_pm_ops hp_wmi_pm_ops = {
.resume = hp_wmi_resume_handler,
.restore = hp_wmi_resume_handler,
.suspend = hp_wmi_suspend_handler,
.freeze = hp_wmi_suspend_handler
};
static struct platform_driver hp_wmi_driver = {
@ -1621,6 +1831,16 @@ static int hp_wmi_hwmon_write(struct device *dev, enum hwmon_sensor_types type,
case 2:
/* 2 is automatic speed control, which is 0 for us */
return hp_wmi_fan_speed_max_set(0);
case 3:
int ret;
int value = 0x2828;
ret = hp_wmi_perform_query(0x2E, HPWMI_GM,
&value, sizeof(value), 0);
if (ret)
return ret < 0 ? ret : -EINVAL;
return value;
default:
/* we don't support manual fan speed control */
return -EINVAL;

View file

@ -4713,17 +4713,17 @@ static void alc245_fixup_hp_amp(struct hda_codec *codec,
{{0x4c0, 0xb}, {0x400, 0x0}, {0x400, 0xbf}}
};
if (action != HDA_FIXUP_ACT_PRE_PROBE) return;
if (action != HDA_FIXUP_ACT_INIT) return;
for (i = 0; i < 9; i++) {
snd_hda_codec_write(codec, 0x20, 0, 0x500, 0x26);
msleep(20);
msleep(50);
for (j = 0; j < 3; j++) {
snd_hda_codec_write(codec, 0x20, 0, frames[i][j][0], frames[i][j][1]);
msleep(20);
msleep(50);
}
snd_hda_codec_write(codec, 0x20, 0, 0x4b0, 0x23);
msleep(20);
msleep(50);
}
}