Linux kernel mirror (for testing)
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel
os
linux
1// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * HP WMI hotkeys
4 *
5 * Copyright (C) 2008 Red Hat <mjg@redhat.com>
6 * Copyright (C) 2010, 2011 Anssi Hannula <anssi.hannula@iki.fi>
7 *
8 * Portions based on wistron_btns.c:
9 * Copyright (C) 2005 Miloslav Trmac <mitr@volny.cz>
10 * Copyright (C) 2005 Bernhard Rosenkraenzer <bero@arklinux.org>
11 * Copyright (C) 2005 Dmitry Torokhov <dtor@mail.ru>
12 */
13
14#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
15
16#include <linux/kernel.h>
17#include <linux/module.h>
18#include <linux/init.h>
19#include <linux/slab.h>
20#include <linux/types.h>
21#include <linux/input.h>
22#include <linux/input/sparse-keymap.h>
23#include <linux/platform_device.h>
24#include <linux/platform_profile.h>
25#include <linux/hwmon.h>
26#include <linux/acpi.h>
27#include <linux/mutex.h>
28#include <linux/cleanup.h>
29#include <linux/power_supply.h>
30#include <linux/rfkill.h>
31#include <linux/string.h>
32#include <linux/dmi.h>
33
34MODULE_AUTHOR("Matthew Garrett <mjg59@srcf.ucam.org>");
35MODULE_DESCRIPTION("HP laptop WMI driver");
36MODULE_LICENSE("GPL");
37
38MODULE_ALIAS("wmi:95F24279-4D7B-4334-9387-ACCDC67EF61C");
39MODULE_ALIAS("wmi:5FB7F034-2C63-45E9-BE91-3D44E2C707E4");
40
41#define HPWMI_EVENT_GUID "95F24279-4D7B-4334-9387-ACCDC67EF61C"
42#define HPWMI_BIOS_GUID "5FB7F034-2C63-45E9-BE91-3D44E2C707E4"
43
44#define HP_OMEN_EC_THERMAL_PROFILE_FLAGS_OFFSET 0x62
45#define HP_OMEN_EC_THERMAL_PROFILE_TIMER_OFFSET 0x63
46#define HP_OMEN_EC_THERMAL_PROFILE_OFFSET 0x95
47
48#define HP_FAN_SPEED_AUTOMATIC 0x00
49#define HP_POWER_LIMIT_DEFAULT 0x00
50#define HP_POWER_LIMIT_NO_CHANGE 0xFF
51
52#define ACPI_AC_CLASS "ac_adapter"
53
54#define zero_if_sup(tmp) (zero_insize_support?0:sizeof(tmp)) // use when zero insize is required
55
56/* DMI board names of devices that should use the omen specific path for
57 * thermal profiles.
58 * This was obtained by taking a look in the windows omen command center
59 * app and parsing a json file that they use to figure out what capabilities
60 * the device should have.
61 * A device is considered an omen if the DisplayName in that list contains
62 * "OMEN", and it can use the thermal profile stuff if the "Feature" array
63 * contains "PerformanceControl".
64 */
65static const char * const omen_thermal_profile_boards[] = {
66 "84DA", "84DB", "84DC",
67 "8572", "8573", "8574", "8575",
68 "8600", "8601", "8602", "8603", "8604", "8605", "8606", "8607", "860A",
69 "8746", "8747", "8748", "8749", "874A", "8786", "8787", "8788", "878A",
70 "878B", "878C", "87B5",
71 "886B", "886C", "88C8", "88CB", "88D1", "88D2", "88F4", "88F5", "88F6",
72 "88F7", "88FD", "88FE", "88FF",
73 "8900", "8901", "8902", "8912", "8917", "8918", "8949", "894A", "89EB",
74 "8A15", "8A42",
75 "8BAD",
76};
77
78/* DMI Board names of Omen laptops that are specifically set to be thermal
79 * profile version 0 by the Omen Command Center app, regardless of what
80 * the get system design information WMI call returns
81 */
82static const char * const omen_thermal_profile_force_v0_boards[] = {
83 "8607",
84 "8746", "8747", "8748", "8749", "874A",
85};
86
87/* DMI board names of Omen laptops that have a thermal profile timer which will
88 * cause the embedded controller to set the thermal profile back to
89 * "balanced" when reaching zero.
90 */
91static const char * const omen_timed_thermal_profile_boards[] = {
92 "8A15", "8A42",
93 "8BAD",
94};
95
96/* DMI Board names of Victus 16-d1xxx laptops */
97static const char * const victus_thermal_profile_boards[] = {
98 "8A25",
99};
100
101/* DMI Board names of Victus 16-r and Victus 16-s laptops */
102static const char * const victus_s_thermal_profile_boards[] = {
103 "8BBE", "8BD4", "8BD5",
104 "8C78", "8C99", "8C9C",
105 "8D41",
106};
107
108enum hp_wmi_radio {
109 HPWMI_WIFI = 0x0,
110 HPWMI_BLUETOOTH = 0x1,
111 HPWMI_WWAN = 0x2,
112 HPWMI_GPS = 0x3,
113};
114
115enum hp_wmi_event_ids {
116 HPWMI_DOCK_EVENT = 0x01,
117 HPWMI_PARK_HDD = 0x02,
118 HPWMI_SMART_ADAPTER = 0x03,
119 HPWMI_BEZEL_BUTTON = 0x04,
120 HPWMI_WIRELESS = 0x05,
121 HPWMI_CPU_BATTERY_THROTTLE = 0x06,
122 HPWMI_LOCK_SWITCH = 0x07,
123 HPWMI_LID_SWITCH = 0x08,
124 HPWMI_SCREEN_ROTATION = 0x09,
125 HPWMI_COOLSENSE_SYSTEM_MOBILE = 0x0A,
126 HPWMI_COOLSENSE_SYSTEM_HOT = 0x0B,
127 HPWMI_PROXIMITY_SENSOR = 0x0C,
128 HPWMI_BACKLIT_KB_BRIGHTNESS = 0x0D,
129 HPWMI_PEAKSHIFT_PERIOD = 0x0F,
130 HPWMI_BATTERY_CHARGE_PERIOD = 0x10,
131 HPWMI_SANITIZATION_MODE = 0x17,
132 HPWMI_CAMERA_TOGGLE = 0x1A,
133 HPWMI_FN_P_HOTKEY = 0x1B,
134 HPWMI_OMEN_KEY = 0x1D,
135 HPWMI_SMART_EXPERIENCE_APP = 0x21,
136};
137
138/*
139 * struct bios_args buffer is dynamically allocated. New WMI command types
140 * were introduced that exceeds 128-byte data size. Changes to handle
141 * the data size allocation scheme were kept in hp_wmi_perform_qurey function.
142 */
143struct bios_args {
144 u32 signature;
145 u32 command;
146 u32 commandtype;
147 u32 datasize;
148 u8 data[];
149};
150
151enum hp_wmi_commandtype {
152 HPWMI_DISPLAY_QUERY = 0x01,
153 HPWMI_HDDTEMP_QUERY = 0x02,
154 HPWMI_ALS_QUERY = 0x03,
155 HPWMI_HARDWARE_QUERY = 0x04,
156 HPWMI_WIRELESS_QUERY = 0x05,
157 HPWMI_BATTERY_QUERY = 0x07,
158 HPWMI_BIOS_QUERY = 0x09,
159 HPWMI_FEATURE_QUERY = 0x0b,
160 HPWMI_HOTKEY_QUERY = 0x0c,
161 HPWMI_FEATURE2_QUERY = 0x0d,
162 HPWMI_WIRELESS2_QUERY = 0x1b,
163 HPWMI_POSTCODEERROR_QUERY = 0x2a,
164 HPWMI_SYSTEM_DEVICE_MODE = 0x40,
165 HPWMI_THERMAL_PROFILE_QUERY = 0x4c,
166};
167
168struct victus_power_limits {
169 u8 pl1;
170 u8 pl2;
171 u8 pl4;
172 u8 cpu_gpu_concurrent_limit;
173};
174
175struct victus_gpu_power_modes {
176 u8 ctgp_enable;
177 u8 ppab_enable;
178 u8 dstate;
179 u8 gpu_slowdown_temp;
180};
181
182enum hp_wmi_gm_commandtype {
183 HPWMI_FAN_SPEED_GET_QUERY = 0x11,
184 HPWMI_SET_PERFORMANCE_MODE = 0x1A,
185 HPWMI_FAN_SPEED_MAX_GET_QUERY = 0x26,
186 HPWMI_FAN_SPEED_MAX_SET_QUERY = 0x27,
187 HPWMI_GET_SYSTEM_DESIGN_DATA = 0x28,
188 HPWMI_FAN_COUNT_GET_QUERY = 0x10,
189 HPWMI_GET_GPU_THERMAL_MODES_QUERY = 0x21,
190 HPWMI_SET_GPU_THERMAL_MODES_QUERY = 0x22,
191 HPWMI_SET_POWER_LIMITS_QUERY = 0x29,
192 HPWMI_VICTUS_S_FAN_SPEED_GET_QUERY = 0x2D,
193 HPWMI_FAN_SPEED_SET_QUERY = 0x2E,
194};
195
196enum hp_wmi_command {
197 HPWMI_READ = 0x01,
198 HPWMI_WRITE = 0x02,
199 HPWMI_ODM = 0x03,
200 HPWMI_GM = 0x20008,
201};
202
203enum hp_wmi_hardware_mask {
204 HPWMI_DOCK_MASK = 0x01,
205 HPWMI_TABLET_MASK = 0x04,
206};
207
208struct bios_return {
209 u32 sigpass;
210 u32 return_code;
211};
212
213enum hp_return_value {
214 HPWMI_RET_WRONG_SIGNATURE = 0x02,
215 HPWMI_RET_UNKNOWN_COMMAND = 0x03,
216 HPWMI_RET_UNKNOWN_CMDTYPE = 0x04,
217 HPWMI_RET_INVALID_PARAMETERS = 0x05,
218};
219
220enum hp_wireless2_bits {
221 HPWMI_POWER_STATE = 0x01,
222 HPWMI_POWER_SOFT = 0x02,
223 HPWMI_POWER_BIOS = 0x04,
224 HPWMI_POWER_HARD = 0x08,
225 HPWMI_POWER_FW_OR_HW = HPWMI_POWER_BIOS | HPWMI_POWER_HARD,
226};
227
228enum hp_thermal_profile_omen_v0 {
229 HP_OMEN_V0_THERMAL_PROFILE_DEFAULT = 0x00,
230 HP_OMEN_V0_THERMAL_PROFILE_PERFORMANCE = 0x01,
231 HP_OMEN_V0_THERMAL_PROFILE_COOL = 0x02,
232};
233
234enum hp_thermal_profile_omen_v1 {
235 HP_OMEN_V1_THERMAL_PROFILE_DEFAULT = 0x30,
236 HP_OMEN_V1_THERMAL_PROFILE_PERFORMANCE = 0x31,
237 HP_OMEN_V1_THERMAL_PROFILE_COOL = 0x50,
238};
239
240enum hp_thermal_profile_omen_flags {
241 HP_OMEN_EC_FLAGS_TURBO = 0x04,
242 HP_OMEN_EC_FLAGS_NOTIMER = 0x02,
243 HP_OMEN_EC_FLAGS_JUSTSET = 0x01,
244};
245
246enum hp_thermal_profile_victus {
247 HP_VICTUS_THERMAL_PROFILE_DEFAULT = 0x00,
248 HP_VICTUS_THERMAL_PROFILE_PERFORMANCE = 0x01,
249 HP_VICTUS_THERMAL_PROFILE_QUIET = 0x03,
250};
251
252enum hp_thermal_profile_victus_s {
253 HP_VICTUS_S_THERMAL_PROFILE_DEFAULT = 0x00,
254 HP_VICTUS_S_THERMAL_PROFILE_PERFORMANCE = 0x01,
255};
256
257enum hp_thermal_profile {
258 HP_THERMAL_PROFILE_PERFORMANCE = 0x00,
259 HP_THERMAL_PROFILE_DEFAULT = 0x01,
260 HP_THERMAL_PROFILE_COOL = 0x02,
261 HP_THERMAL_PROFILE_QUIET = 0x03,
262};
263
264#define IS_HWBLOCKED(x) ((x & HPWMI_POWER_FW_OR_HW) != HPWMI_POWER_FW_OR_HW)
265#define IS_SWBLOCKED(x) !(x & HPWMI_POWER_SOFT)
266
267struct bios_rfkill2_device_state {
268 u8 radio_type;
269 u8 bus_type;
270 u16 vendor_id;
271 u16 product_id;
272 u16 subsys_vendor_id;
273 u16 subsys_product_id;
274 u8 rfkill_id;
275 u8 power;
276 u8 unknown[4];
277};
278
279/* 7 devices fit into the 128 byte buffer */
280#define HPWMI_MAX_RFKILL2_DEVICES 7
281
282struct bios_rfkill2_state {
283 u8 unknown[7];
284 u8 count;
285 u8 pad[8];
286 struct bios_rfkill2_device_state device[HPWMI_MAX_RFKILL2_DEVICES];
287};
288
289static const struct key_entry hp_wmi_keymap[] = {
290 { KE_KEY, 0x02, { KEY_BRIGHTNESSUP } },
291 { KE_KEY, 0x03, { KEY_BRIGHTNESSDOWN } },
292 { KE_KEY, 0x270, { KEY_MICMUTE } },
293 { KE_KEY, 0x20e6, { KEY_PROG1 } },
294 { KE_KEY, 0x20e8, { KEY_MEDIA } },
295 { KE_KEY, 0x2142, { KEY_MEDIA } },
296 { KE_KEY, 0x213b, { KEY_INFO } },
297 { KE_KEY, 0x2169, { KEY_ROTATE_DISPLAY } },
298 { KE_KEY, 0x216a, { KEY_SETUP } },
299 { KE_IGNORE, 0x21a4, }, /* Win Lock On */
300 { KE_IGNORE, 0x121a4, }, /* Win Lock Off */
301 { KE_KEY, 0x21a5, { KEY_PROG2 } }, /* HP Omen Key */
302 { KE_KEY, 0x21a7, { KEY_FN_ESC } },
303 { KE_KEY, 0x21a8, { KEY_PROG2 } }, /* HP Envy x360 programmable key */
304 { KE_KEY, 0x21a9, { KEY_TOUCHPAD_OFF } },
305 { KE_KEY, 0x121a9, { KEY_TOUCHPAD_ON } },
306 { KE_KEY, 0x231b, { KEY_HELP } },
307 { KE_END, 0 }
308};
309
310/*
311 * Mutex for the active_platform_profile variable,
312 * see omen_powersource_event.
313 */
314static DEFINE_MUTEX(active_platform_profile_lock);
315
316static struct input_dev *hp_wmi_input_dev;
317static struct input_dev *camera_shutter_input_dev;
318static struct platform_device *hp_wmi_platform_dev;
319static struct device *platform_profile_device;
320static struct notifier_block platform_power_source_nb;
321static enum platform_profile_option active_platform_profile;
322static bool platform_profile_support;
323static bool zero_insize_support;
324
325static struct rfkill *wifi_rfkill;
326static struct rfkill *bluetooth_rfkill;
327static struct rfkill *wwan_rfkill;
328
329struct rfkill2_device {
330 u8 id;
331 int num;
332 struct rfkill *rfkill;
333};
334
335static int rfkill2_count;
336static struct rfkill2_device rfkill2[HPWMI_MAX_RFKILL2_DEVICES];
337
338/*
339 * Chassis Types values were obtained from SMBIOS reference
340 * specification version 3.00. A complete list of system enclosures
341 * and chassis types is available on Table 17.
342 */
343static const char * const tablet_chassis_types[] = {
344 "30", /* Tablet*/
345 "31", /* Convertible */
346 "32" /* Detachable */
347};
348
349#define DEVICE_MODE_TABLET 0x06
350
351/* map output size to the corresponding WMI method id */
352static inline int encode_outsize_for_pvsz(int outsize)
353{
354 if (outsize > 4096)
355 return -EINVAL;
356 if (outsize > 1024)
357 return 5;
358 if (outsize > 128)
359 return 4;
360 if (outsize > 4)
361 return 3;
362 if (outsize > 0)
363 return 2;
364 return 1;
365}
366
367/*
368 * hp_wmi_perform_query
369 *
370 * query: The commandtype (enum hp_wmi_commandtype)
371 * write: The command (enum hp_wmi_command)
372 * buffer: Buffer used as input and/or output
373 * insize: Size of input buffer
374 * outsize: Size of output buffer
375 *
376 * returns zero on success
377 * an HP WMI query specific error code (which is positive)
378 * -EINVAL if the query was not successful at all
379 * -EINVAL if the output buffer size exceeds buffersize
380 *
381 * Note: The buffersize must at least be the maximum of the input and output
382 * size. E.g. Battery info query is defined to have 1 byte input
383 * and 128 byte output. The caller would do:
384 * buffer = kzalloc(128, GFP_KERNEL);
385 * ret = hp_wmi_perform_query(HPWMI_BATTERY_QUERY, HPWMI_READ, buffer, 1, 128)
386 */
387static int hp_wmi_perform_query(int query, enum hp_wmi_command command,
388 void *buffer, int insize, int outsize)
389{
390 struct acpi_buffer input, output = { ACPI_ALLOCATE_BUFFER, NULL };
391 struct bios_return *bios_return;
392 union acpi_object *obj = NULL;
393 struct bios_args *args = NULL;
394 int mid, actual_insize, actual_outsize;
395 size_t bios_args_size;
396 int ret;
397
398 mid = encode_outsize_for_pvsz(outsize);
399 if (WARN_ON(mid < 0))
400 return mid;
401
402 actual_insize = max(insize, 128);
403 bios_args_size = struct_size(args, data, actual_insize);
404 args = kmalloc(bios_args_size, GFP_KERNEL);
405 if (!args)
406 return -ENOMEM;
407
408 input.length = bios_args_size;
409 input.pointer = args;
410
411 args->signature = 0x55434553;
412 args->command = command;
413 args->commandtype = query;
414 args->datasize = insize;
415 memcpy(args->data, buffer, flex_array_size(args, data, insize));
416
417 ret = wmi_evaluate_method(HPWMI_BIOS_GUID, 0, mid, &input, &output);
418 if (ret)
419 goto out_free;
420
421 obj = output.pointer;
422 if (!obj) {
423 ret = -EINVAL;
424 goto out_free;
425 }
426
427 if (obj->type != ACPI_TYPE_BUFFER) {
428 pr_warn("query 0x%x returned an invalid object 0x%x\n", query, ret);
429 ret = -EINVAL;
430 goto out_free;
431 }
432
433 bios_return = (struct bios_return *)obj->buffer.pointer;
434 ret = bios_return->return_code;
435
436 if (ret) {
437 if (ret != HPWMI_RET_UNKNOWN_COMMAND &&
438 ret != HPWMI_RET_UNKNOWN_CMDTYPE)
439 pr_warn("query 0x%x returned error 0x%x\n", query, ret);
440 goto out_free;
441 }
442
443 /* Ignore output data of zero size */
444 if (!outsize)
445 goto out_free;
446
447 actual_outsize = min(outsize, (int)(obj->buffer.length - sizeof(*bios_return)));
448 memcpy(buffer, obj->buffer.pointer + sizeof(*bios_return), actual_outsize);
449 memset(buffer + actual_outsize, 0, outsize - actual_outsize);
450
451out_free:
452 kfree(obj);
453 kfree(args);
454 return ret;
455}
456
457/*
458 * Calling this hp_wmi_get_fan_count_userdefine_trigger function also enables
459 * and/or maintains the laptop in user defined thermal and fan states, instead
460 * of using a fallback state. After a 120 seconds timeout however, the laptop
461 * goes back to its fallback state.
462 */
463static int hp_wmi_get_fan_count_userdefine_trigger(void)
464{
465 u8 fan_data[4] = {};
466 int ret;
467
468 ret = hp_wmi_perform_query(HPWMI_FAN_COUNT_GET_QUERY, HPWMI_GM,
469 &fan_data, sizeof(u8),
470 sizeof(fan_data));
471 if (ret != 0)
472 return -EINVAL;
473
474 return fan_data[0]; /* Others bytes aren't providing fan count */
475}
476
477static int hp_wmi_get_fan_speed(int fan)
478{
479 u8 fsh, fsl;
480 char fan_data[4] = { fan, 0, 0, 0 };
481
482 int ret = hp_wmi_perform_query(HPWMI_FAN_SPEED_GET_QUERY, HPWMI_GM,
483 &fan_data, sizeof(char),
484 sizeof(fan_data));
485
486 if (ret != 0)
487 return -EINVAL;
488
489 fsh = fan_data[2];
490 fsl = fan_data[3];
491
492 return (fsh << 8) | fsl;
493}
494
495static int hp_wmi_get_fan_speed_victus_s(int fan)
496{
497 u8 fan_data[128] = {};
498 int ret;
499
500 if (fan < 0 || fan >= sizeof(fan_data))
501 return -EINVAL;
502
503 ret = hp_wmi_perform_query(HPWMI_VICTUS_S_FAN_SPEED_GET_QUERY,
504 HPWMI_GM, &fan_data, sizeof(u8),
505 sizeof(fan_data));
506 if (ret != 0)
507 return -EINVAL;
508
509 return fan_data[fan] * 100;
510}
511
512static int hp_wmi_read_int(int query)
513{
514 int val = 0, ret;
515
516 ret = hp_wmi_perform_query(query, HPWMI_READ, &val,
517 zero_if_sup(val), sizeof(val));
518
519 if (ret)
520 return ret < 0 ? ret : -EINVAL;
521
522 return val;
523}
524
525static int hp_wmi_get_dock_state(void)
526{
527 int state = hp_wmi_read_int(HPWMI_HARDWARE_QUERY);
528
529 if (state < 0)
530 return state;
531
532 return !!(state & HPWMI_DOCK_MASK);
533}
534
535static int hp_wmi_get_tablet_mode(void)
536{
537 char system_device_mode[4] = { 0 };
538 const char *chassis_type;
539 bool tablet_found;
540 int ret;
541
542 chassis_type = dmi_get_system_info(DMI_CHASSIS_TYPE);
543 if (!chassis_type)
544 return -ENODEV;
545
546 tablet_found = match_string(tablet_chassis_types,
547 ARRAY_SIZE(tablet_chassis_types),
548 chassis_type) >= 0;
549 if (!tablet_found)
550 return -ENODEV;
551
552 ret = hp_wmi_perform_query(HPWMI_SYSTEM_DEVICE_MODE, HPWMI_READ,
553 system_device_mode, zero_if_sup(system_device_mode),
554 sizeof(system_device_mode));
555 if (ret < 0)
556 return ret;
557
558 return system_device_mode[0] == DEVICE_MODE_TABLET;
559}
560
561static int omen_thermal_profile_set(int mode)
562{
563 /* The Omen Control Center actively sets the first byte of the buffer to
564 * 255, so let's mimic this behaviour to be as close as possible to
565 * the original software.
566 */
567 char buffer[2] = {-1, mode};
568 int ret;
569
570 ret = hp_wmi_perform_query(HPWMI_SET_PERFORMANCE_MODE, HPWMI_GM,
571 &buffer, sizeof(buffer), 0);
572
573 if (ret)
574 return ret < 0 ? ret : -EINVAL;
575
576 return mode;
577}
578
579static bool is_omen_thermal_profile(void)
580{
581 const char *board_name = dmi_get_system_info(DMI_BOARD_NAME);
582
583 if (!board_name)
584 return false;
585
586 return match_string(omen_thermal_profile_boards,
587 ARRAY_SIZE(omen_thermal_profile_boards),
588 board_name) >= 0;
589}
590
591static int omen_get_thermal_policy_version(void)
592{
593 unsigned char buffer[8] = { 0 };
594 int ret;
595
596 const char *board_name = dmi_get_system_info(DMI_BOARD_NAME);
597
598 if (board_name) {
599 int matches = match_string(omen_thermal_profile_force_v0_boards,
600 ARRAY_SIZE(omen_thermal_profile_force_v0_boards),
601 board_name);
602 if (matches >= 0)
603 return 0;
604 }
605
606 ret = hp_wmi_perform_query(HPWMI_GET_SYSTEM_DESIGN_DATA, HPWMI_GM,
607 &buffer, sizeof(buffer), sizeof(buffer));
608
609 if (ret)
610 return ret < 0 ? ret : -EINVAL;
611
612 return buffer[3];
613}
614
615static int omen_thermal_profile_get(void)
616{
617 u8 data;
618
619 int ret = ec_read(HP_OMEN_EC_THERMAL_PROFILE_OFFSET, &data);
620
621 if (ret)
622 return ret;
623
624 return data;
625}
626
627static int hp_wmi_fan_speed_max_set(int enabled)
628{
629 int ret;
630
631 ret = hp_wmi_perform_query(HPWMI_FAN_SPEED_MAX_SET_QUERY, HPWMI_GM,
632 &enabled, sizeof(enabled), 0);
633
634 if (ret)
635 return ret < 0 ? ret : -EINVAL;
636
637 return enabled;
638}
639
640static int hp_wmi_fan_speed_reset(void)
641{
642 u8 fan_speed[2] = { HP_FAN_SPEED_AUTOMATIC, HP_FAN_SPEED_AUTOMATIC };
643 int ret;
644
645 ret = hp_wmi_perform_query(HPWMI_FAN_SPEED_SET_QUERY, HPWMI_GM,
646 &fan_speed, sizeof(fan_speed), 0);
647
648 return ret;
649}
650
651static int hp_wmi_fan_speed_max_reset(void)
652{
653 int ret;
654
655 ret = hp_wmi_fan_speed_max_set(0);
656 if (ret)
657 return ret;
658
659 /* Disabling max fan speed on Victus s1xxx laptops needs a 2nd step: */
660 ret = hp_wmi_fan_speed_reset();
661 return ret;
662}
663
664static int hp_wmi_fan_speed_max_get(void)
665{
666 int val = 0, ret;
667
668 ret = hp_wmi_perform_query(HPWMI_FAN_SPEED_MAX_GET_QUERY, HPWMI_GM,
669 &val, zero_if_sup(val), sizeof(val));
670
671 if (ret)
672 return ret < 0 ? ret : -EINVAL;
673
674 return val;
675}
676
677static int __init hp_wmi_bios_2008_later(void)
678{
679 int state = 0;
680 int ret = hp_wmi_perform_query(HPWMI_FEATURE_QUERY, HPWMI_READ, &state,
681 zero_if_sup(state), sizeof(state));
682 if (!ret)
683 return 1;
684
685 return (ret == HPWMI_RET_UNKNOWN_CMDTYPE) ? 0 : -ENXIO;
686}
687
688static int __init hp_wmi_bios_2009_later(void)
689{
690 u8 state[128];
691 int ret = hp_wmi_perform_query(HPWMI_FEATURE2_QUERY, HPWMI_READ, &state,
692 zero_if_sup(state), sizeof(state));
693 if (!ret)
694 return 1;
695
696 return (ret == HPWMI_RET_UNKNOWN_CMDTYPE) ? 0 : -ENXIO;
697}
698
699static int __init hp_wmi_enable_hotkeys(void)
700{
701 int value = 0x6e;
702 int ret = hp_wmi_perform_query(HPWMI_BIOS_QUERY, HPWMI_WRITE, &value,
703 sizeof(value), 0);
704
705 return ret <= 0 ? ret : -EINVAL;
706}
707
708static int hp_wmi_set_block(void *data, bool blocked)
709{
710 enum hp_wmi_radio r = (long)data;
711 int query = BIT(r + 8) | ((!blocked) << r);
712 int ret;
713
714 ret = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, HPWMI_WRITE,
715 &query, sizeof(query), 0);
716
717 return ret <= 0 ? ret : -EINVAL;
718}
719
720static const struct rfkill_ops hp_wmi_rfkill_ops = {
721 .set_block = hp_wmi_set_block,
722};
723
724static bool hp_wmi_get_sw_state(enum hp_wmi_radio r)
725{
726 int mask = 0x200 << (r * 8);
727
728 int wireless = hp_wmi_read_int(HPWMI_WIRELESS_QUERY);
729
730 /* TBD: Pass error */
731 WARN_ONCE(wireless < 0, "error executing HPWMI_WIRELESS_QUERY");
732
733 return !(wireless & mask);
734}
735
736static bool hp_wmi_get_hw_state(enum hp_wmi_radio r)
737{
738 int mask = 0x800 << (r * 8);
739
740 int wireless = hp_wmi_read_int(HPWMI_WIRELESS_QUERY);
741
742 /* TBD: Pass error */
743 WARN_ONCE(wireless < 0, "error executing HPWMI_WIRELESS_QUERY");
744
745 return !(wireless & mask);
746}
747
748static int hp_wmi_rfkill2_set_block(void *data, bool blocked)
749{
750 int rfkill_id = (int)(long)data;
751 char buffer[4] = { 0x01, 0x00, rfkill_id, !blocked };
752 int ret;
753
754 ret = hp_wmi_perform_query(HPWMI_WIRELESS2_QUERY, HPWMI_WRITE,
755 buffer, sizeof(buffer), 0);
756
757 return ret <= 0 ? ret : -EINVAL;
758}
759
760static const struct rfkill_ops hp_wmi_rfkill2_ops = {
761 .set_block = hp_wmi_rfkill2_set_block,
762};
763
764static int hp_wmi_rfkill2_refresh(void)
765{
766 struct bios_rfkill2_state state;
767 int err, i;
768
769 err = hp_wmi_perform_query(HPWMI_WIRELESS2_QUERY, HPWMI_READ, &state,
770 zero_if_sup(state), sizeof(state));
771 if (err)
772 return err;
773
774 for (i = 0; i < rfkill2_count; i++) {
775 int num = rfkill2[i].num;
776 struct bios_rfkill2_device_state *devstate;
777
778 devstate = &state.device[num];
779
780 if (num >= state.count ||
781 devstate->rfkill_id != rfkill2[i].id) {
782 pr_warn("power configuration of the wireless devices unexpectedly changed\n");
783 continue;
784 }
785
786 rfkill_set_states(rfkill2[i].rfkill,
787 IS_SWBLOCKED(devstate->power),
788 IS_HWBLOCKED(devstate->power));
789 }
790
791 return 0;
792}
793
794static ssize_t display_show(struct device *dev, struct device_attribute *attr,
795 char *buf)
796{
797 int value = hp_wmi_read_int(HPWMI_DISPLAY_QUERY);
798
799 if (value < 0)
800 return value;
801 return sysfs_emit(buf, "%d\n", value);
802}
803
804static ssize_t hddtemp_show(struct device *dev, struct device_attribute *attr,
805 char *buf)
806{
807 int value = hp_wmi_read_int(HPWMI_HDDTEMP_QUERY);
808
809 if (value < 0)
810 return value;
811 return sysfs_emit(buf, "%d\n", value);
812}
813
814static ssize_t als_show(struct device *dev, struct device_attribute *attr,
815 char *buf)
816{
817 int value = hp_wmi_read_int(HPWMI_ALS_QUERY);
818
819 if (value < 0)
820 return value;
821 return sysfs_emit(buf, "%d\n", value);
822}
823
824static ssize_t dock_show(struct device *dev, struct device_attribute *attr,
825 char *buf)
826{
827 int value = hp_wmi_get_dock_state();
828
829 if (value < 0)
830 return value;
831 return sysfs_emit(buf, "%d\n", value);
832}
833
834static ssize_t tablet_show(struct device *dev, struct device_attribute *attr,
835 char *buf)
836{
837 int value = hp_wmi_get_tablet_mode();
838
839 if (value < 0)
840 return value;
841 return sysfs_emit(buf, "%d\n", value);
842}
843
844static ssize_t postcode_show(struct device *dev, struct device_attribute *attr,
845 char *buf)
846{
847 /* Get the POST error code of previous boot failure. */
848 int value = hp_wmi_read_int(HPWMI_POSTCODEERROR_QUERY);
849
850 if (value < 0)
851 return value;
852 return sysfs_emit(buf, "0x%x\n", value);
853}
854
855static ssize_t als_store(struct device *dev, struct device_attribute *attr,
856 const char *buf, size_t count)
857{
858 u32 tmp;
859 int ret;
860
861 ret = kstrtou32(buf, 10, &tmp);
862 if (ret)
863 return ret;
864
865 ret = hp_wmi_perform_query(HPWMI_ALS_QUERY, HPWMI_WRITE, &tmp,
866 sizeof(tmp), 0);
867 if (ret)
868 return ret < 0 ? ret : -EINVAL;
869
870 return count;
871}
872
873static ssize_t postcode_store(struct device *dev, struct device_attribute *attr,
874 const char *buf, size_t count)
875{
876 u32 tmp = 1;
877 bool clear;
878 int ret;
879
880 ret = kstrtobool(buf, &clear);
881 if (ret)
882 return ret;
883
884 if (clear == false)
885 return -EINVAL;
886
887 /* Clear the POST error code. It is kept until cleared. */
888 ret = hp_wmi_perform_query(HPWMI_POSTCODEERROR_QUERY, HPWMI_WRITE, &tmp,
889 sizeof(tmp), 0);
890 if (ret)
891 return ret < 0 ? ret : -EINVAL;
892
893 return count;
894}
895
896static int camera_shutter_input_setup(void)
897{
898 int err;
899
900 camera_shutter_input_dev = input_allocate_device();
901 if (!camera_shutter_input_dev)
902 return -ENOMEM;
903
904 camera_shutter_input_dev->name = "HP WMI camera shutter";
905 camera_shutter_input_dev->phys = "wmi/input1";
906 camera_shutter_input_dev->id.bustype = BUS_HOST;
907
908 __set_bit(EV_SW, camera_shutter_input_dev->evbit);
909 __set_bit(SW_CAMERA_LENS_COVER, camera_shutter_input_dev->swbit);
910
911 err = input_register_device(camera_shutter_input_dev);
912 if (err)
913 goto err_free_dev;
914
915 return 0;
916
917 err_free_dev:
918 input_free_device(camera_shutter_input_dev);
919 camera_shutter_input_dev = NULL;
920 return err;
921}
922
923static DEVICE_ATTR_RO(display);
924static DEVICE_ATTR_RO(hddtemp);
925static DEVICE_ATTR_RW(als);
926static DEVICE_ATTR_RO(dock);
927static DEVICE_ATTR_RO(tablet);
928static DEVICE_ATTR_RW(postcode);
929
930static struct attribute *hp_wmi_attrs[] = {
931 &dev_attr_display.attr,
932 &dev_attr_hddtemp.attr,
933 &dev_attr_als.attr,
934 &dev_attr_dock.attr,
935 &dev_attr_tablet.attr,
936 &dev_attr_postcode.attr,
937 NULL,
938};
939ATTRIBUTE_GROUPS(hp_wmi);
940
941static void hp_wmi_notify(union acpi_object *obj, void *context)
942{
943 u32 event_id, event_data;
944 u32 *location;
945 int key_code;
946
947 if (!obj)
948 return;
949 if (obj->type != ACPI_TYPE_BUFFER) {
950 pr_info("Unknown response received %d\n", obj->type);
951 return;
952 }
953
954 /*
955 * Depending on ACPI version the concatenation of id and event data
956 * inside _WED function will result in a 8 or 16 byte buffer.
957 */
958 location = (u32 *)obj->buffer.pointer;
959 if (obj->buffer.length == 8) {
960 event_id = *location;
961 event_data = *(location + 1);
962 } else if (obj->buffer.length == 16) {
963 event_id = *location;
964 event_data = *(location + 2);
965 } else {
966 pr_info("Unknown buffer length %d\n", obj->buffer.length);
967 return;
968 }
969
970 switch (event_id) {
971 case HPWMI_DOCK_EVENT:
972 if (test_bit(SW_DOCK, hp_wmi_input_dev->swbit))
973 input_report_switch(hp_wmi_input_dev, SW_DOCK,
974 hp_wmi_get_dock_state());
975 if (test_bit(SW_TABLET_MODE, hp_wmi_input_dev->swbit))
976 input_report_switch(hp_wmi_input_dev, SW_TABLET_MODE,
977 hp_wmi_get_tablet_mode());
978 input_sync(hp_wmi_input_dev);
979 break;
980 case HPWMI_PARK_HDD:
981 break;
982 case HPWMI_SMART_ADAPTER:
983 break;
984 case HPWMI_BEZEL_BUTTON:
985 key_code = hp_wmi_read_int(HPWMI_HOTKEY_QUERY);
986 if (key_code < 0)
987 break;
988
989 if (!sparse_keymap_report_event(hp_wmi_input_dev,
990 key_code, 1, true))
991 pr_info("Unknown key code - 0x%x\n", key_code);
992 break;
993 case HPWMI_FN_P_HOTKEY:
994 platform_profile_cycle();
995 break;
996 case HPWMI_OMEN_KEY:
997 if (event_data) /* Only should be true for HP Omen */
998 key_code = event_data;
999 else
1000 key_code = hp_wmi_read_int(HPWMI_HOTKEY_QUERY);
1001
1002 if (!sparse_keymap_report_event(hp_wmi_input_dev,
1003 key_code, 1, true))
1004 pr_info("Unknown key code - 0x%x\n", key_code);
1005 break;
1006 case HPWMI_WIRELESS:
1007 if (rfkill2_count) {
1008 hp_wmi_rfkill2_refresh();
1009 break;
1010 }
1011
1012 if (wifi_rfkill)
1013 rfkill_set_states(wifi_rfkill,
1014 hp_wmi_get_sw_state(HPWMI_WIFI),
1015 hp_wmi_get_hw_state(HPWMI_WIFI));
1016 if (bluetooth_rfkill)
1017 rfkill_set_states(bluetooth_rfkill,
1018 hp_wmi_get_sw_state(HPWMI_BLUETOOTH),
1019 hp_wmi_get_hw_state(HPWMI_BLUETOOTH));
1020 if (wwan_rfkill)
1021 rfkill_set_states(wwan_rfkill,
1022 hp_wmi_get_sw_state(HPWMI_WWAN),
1023 hp_wmi_get_hw_state(HPWMI_WWAN));
1024 break;
1025 case HPWMI_CPU_BATTERY_THROTTLE:
1026 pr_info("Unimplemented CPU throttle because of 3 Cell battery event detected\n");
1027 break;
1028 case HPWMI_LOCK_SWITCH:
1029 break;
1030 case HPWMI_LID_SWITCH:
1031 break;
1032 case HPWMI_SCREEN_ROTATION:
1033 break;
1034 case HPWMI_COOLSENSE_SYSTEM_MOBILE:
1035 break;
1036 case HPWMI_COOLSENSE_SYSTEM_HOT:
1037 break;
1038 case HPWMI_PROXIMITY_SENSOR:
1039 break;
1040 case HPWMI_BACKLIT_KB_BRIGHTNESS:
1041 break;
1042 case HPWMI_PEAKSHIFT_PERIOD:
1043 break;
1044 case HPWMI_BATTERY_CHARGE_PERIOD:
1045 break;
1046 case HPWMI_SANITIZATION_MODE:
1047 break;
1048 case HPWMI_CAMERA_TOGGLE:
1049 if (!camera_shutter_input_dev)
1050 if (camera_shutter_input_setup()) {
1051 pr_err("Failed to setup camera shutter input device\n");
1052 break;
1053 }
1054 if (event_data == 0xff)
1055 input_report_switch(camera_shutter_input_dev, SW_CAMERA_LENS_COVER, 1);
1056 else if (event_data == 0xfe)
1057 input_report_switch(camera_shutter_input_dev, SW_CAMERA_LENS_COVER, 0);
1058 else
1059 pr_warn("Unknown camera shutter state - 0x%x\n", event_data);
1060 input_sync(camera_shutter_input_dev);
1061 break;
1062 case HPWMI_SMART_EXPERIENCE_APP:
1063 break;
1064 default:
1065 pr_info("Unknown event_id - %d - 0x%x\n", event_id, event_data);
1066 break;
1067 }
1068}
1069
1070static int __init hp_wmi_input_setup(void)
1071{
1072 acpi_status status;
1073 int err, val;
1074
1075 hp_wmi_input_dev = input_allocate_device();
1076 if (!hp_wmi_input_dev)
1077 return -ENOMEM;
1078
1079 hp_wmi_input_dev->name = "HP WMI hotkeys";
1080 hp_wmi_input_dev->phys = "wmi/input0";
1081 hp_wmi_input_dev->id.bustype = BUS_HOST;
1082
1083 __set_bit(EV_SW, hp_wmi_input_dev->evbit);
1084
1085 /* Dock */
1086 val = hp_wmi_get_dock_state();
1087 if (!(val < 0)) {
1088 __set_bit(SW_DOCK, hp_wmi_input_dev->swbit);
1089 input_report_switch(hp_wmi_input_dev, SW_DOCK, val);
1090 }
1091
1092 /* Tablet mode */
1093 val = hp_wmi_get_tablet_mode();
1094 if (!(val < 0)) {
1095 __set_bit(SW_TABLET_MODE, hp_wmi_input_dev->swbit);
1096 input_report_switch(hp_wmi_input_dev, SW_TABLET_MODE, val);
1097 }
1098
1099 err = sparse_keymap_setup(hp_wmi_input_dev, hp_wmi_keymap, NULL);
1100 if (err)
1101 goto err_free_dev;
1102
1103 /* Set initial hardware state */
1104 input_sync(hp_wmi_input_dev);
1105
1106 if (!hp_wmi_bios_2009_later() && hp_wmi_bios_2008_later())
1107 hp_wmi_enable_hotkeys();
1108
1109 status = wmi_install_notify_handler(HPWMI_EVENT_GUID, hp_wmi_notify, NULL);
1110 if (ACPI_FAILURE(status)) {
1111 err = -EIO;
1112 goto err_free_dev;
1113 }
1114
1115 err = input_register_device(hp_wmi_input_dev);
1116 if (err)
1117 goto err_uninstall_notifier;
1118
1119 return 0;
1120
1121 err_uninstall_notifier:
1122 wmi_remove_notify_handler(HPWMI_EVENT_GUID);
1123 err_free_dev:
1124 input_free_device(hp_wmi_input_dev);
1125 return err;
1126}
1127
1128static void hp_wmi_input_destroy(void)
1129{
1130 wmi_remove_notify_handler(HPWMI_EVENT_GUID);
1131 input_unregister_device(hp_wmi_input_dev);
1132}
1133
1134static int __init hp_wmi_rfkill_setup(struct platform_device *device)
1135{
1136 int err, wireless;
1137
1138 wireless = hp_wmi_read_int(HPWMI_WIRELESS_QUERY);
1139 if (wireless < 0)
1140 return wireless;
1141
1142 err = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, HPWMI_WRITE, &wireless,
1143 sizeof(wireless), 0);
1144 if (err)
1145 return err;
1146
1147 if (wireless & 0x1) {
1148 wifi_rfkill = rfkill_alloc("hp-wifi", &device->dev,
1149 RFKILL_TYPE_WLAN,
1150 &hp_wmi_rfkill_ops,
1151 (void *) HPWMI_WIFI);
1152 if (!wifi_rfkill)
1153 return -ENOMEM;
1154 rfkill_init_sw_state(wifi_rfkill,
1155 hp_wmi_get_sw_state(HPWMI_WIFI));
1156 rfkill_set_hw_state(wifi_rfkill,
1157 hp_wmi_get_hw_state(HPWMI_WIFI));
1158 err = rfkill_register(wifi_rfkill);
1159 if (err)
1160 goto register_wifi_error;
1161 }
1162
1163 if (wireless & 0x2) {
1164 bluetooth_rfkill = rfkill_alloc("hp-bluetooth", &device->dev,
1165 RFKILL_TYPE_BLUETOOTH,
1166 &hp_wmi_rfkill_ops,
1167 (void *) HPWMI_BLUETOOTH);
1168 if (!bluetooth_rfkill) {
1169 err = -ENOMEM;
1170 goto register_bluetooth_error;
1171 }
1172 rfkill_init_sw_state(bluetooth_rfkill,
1173 hp_wmi_get_sw_state(HPWMI_BLUETOOTH));
1174 rfkill_set_hw_state(bluetooth_rfkill,
1175 hp_wmi_get_hw_state(HPWMI_BLUETOOTH));
1176 err = rfkill_register(bluetooth_rfkill);
1177 if (err)
1178 goto register_bluetooth_error;
1179 }
1180
1181 if (wireless & 0x4) {
1182 wwan_rfkill = rfkill_alloc("hp-wwan", &device->dev,
1183 RFKILL_TYPE_WWAN,
1184 &hp_wmi_rfkill_ops,
1185 (void *) HPWMI_WWAN);
1186 if (!wwan_rfkill) {
1187 err = -ENOMEM;
1188 goto register_wwan_error;
1189 }
1190 rfkill_init_sw_state(wwan_rfkill,
1191 hp_wmi_get_sw_state(HPWMI_WWAN));
1192 rfkill_set_hw_state(wwan_rfkill,
1193 hp_wmi_get_hw_state(HPWMI_WWAN));
1194 err = rfkill_register(wwan_rfkill);
1195 if (err)
1196 goto register_wwan_error;
1197 }
1198
1199 return 0;
1200
1201register_wwan_error:
1202 rfkill_destroy(wwan_rfkill);
1203 wwan_rfkill = NULL;
1204 if (bluetooth_rfkill)
1205 rfkill_unregister(bluetooth_rfkill);
1206register_bluetooth_error:
1207 rfkill_destroy(bluetooth_rfkill);
1208 bluetooth_rfkill = NULL;
1209 if (wifi_rfkill)
1210 rfkill_unregister(wifi_rfkill);
1211register_wifi_error:
1212 rfkill_destroy(wifi_rfkill);
1213 wifi_rfkill = NULL;
1214 return err;
1215}
1216
1217static int __init hp_wmi_rfkill2_setup(struct platform_device *device)
1218{
1219 struct bios_rfkill2_state state;
1220 int err, i;
1221
1222 err = hp_wmi_perform_query(HPWMI_WIRELESS2_QUERY, HPWMI_READ, &state,
1223 zero_if_sup(state), sizeof(state));
1224 if (err)
1225 return err < 0 ? err : -EINVAL;
1226
1227 if (state.count > HPWMI_MAX_RFKILL2_DEVICES) {
1228 pr_warn("unable to parse 0x1b query output\n");
1229 return -EINVAL;
1230 }
1231
1232 for (i = 0; i < state.count; i++) {
1233 struct rfkill *rfkill;
1234 enum rfkill_type type;
1235 char *name;
1236
1237 switch (state.device[i].radio_type) {
1238 case HPWMI_WIFI:
1239 type = RFKILL_TYPE_WLAN;
1240 name = "hp-wifi";
1241 break;
1242 case HPWMI_BLUETOOTH:
1243 type = RFKILL_TYPE_BLUETOOTH;
1244 name = "hp-bluetooth";
1245 break;
1246 case HPWMI_WWAN:
1247 type = RFKILL_TYPE_WWAN;
1248 name = "hp-wwan";
1249 break;
1250 case HPWMI_GPS:
1251 type = RFKILL_TYPE_GPS;
1252 name = "hp-gps";
1253 break;
1254 default:
1255 pr_warn("unknown device type 0x%x\n",
1256 state.device[i].radio_type);
1257 continue;
1258 }
1259
1260 if (!state.device[i].vendor_id) {
1261 pr_warn("zero device %d while %d reported\n",
1262 i, state.count);
1263 continue;
1264 }
1265
1266 rfkill = rfkill_alloc(name, &device->dev, type,
1267 &hp_wmi_rfkill2_ops, (void *)(long)i);
1268 if (!rfkill) {
1269 err = -ENOMEM;
1270 goto fail;
1271 }
1272
1273 rfkill2[rfkill2_count].id = state.device[i].rfkill_id;
1274 rfkill2[rfkill2_count].num = i;
1275 rfkill2[rfkill2_count].rfkill = rfkill;
1276
1277 rfkill_init_sw_state(rfkill,
1278 IS_SWBLOCKED(state.device[i].power));
1279 rfkill_set_hw_state(rfkill,
1280 IS_HWBLOCKED(state.device[i].power));
1281
1282 if (!(state.device[i].power & HPWMI_POWER_BIOS))
1283 pr_info("device %s blocked by BIOS\n", name);
1284
1285 err = rfkill_register(rfkill);
1286 if (err) {
1287 rfkill_destroy(rfkill);
1288 goto fail;
1289 }
1290
1291 rfkill2_count++;
1292 }
1293
1294 return 0;
1295fail:
1296 for (; rfkill2_count > 0; rfkill2_count--) {
1297 rfkill_unregister(rfkill2[rfkill2_count - 1].rfkill);
1298 rfkill_destroy(rfkill2[rfkill2_count - 1].rfkill);
1299 }
1300 return err;
1301}
1302
1303static int platform_profile_omen_get_ec(enum platform_profile_option *profile)
1304{
1305 int tp;
1306
1307 tp = omen_thermal_profile_get();
1308 if (tp < 0)
1309 return tp;
1310
1311 switch (tp) {
1312 case HP_OMEN_V0_THERMAL_PROFILE_PERFORMANCE:
1313 case HP_OMEN_V1_THERMAL_PROFILE_PERFORMANCE:
1314 *profile = PLATFORM_PROFILE_PERFORMANCE;
1315 break;
1316 case HP_OMEN_V0_THERMAL_PROFILE_DEFAULT:
1317 case HP_OMEN_V1_THERMAL_PROFILE_DEFAULT:
1318 *profile = PLATFORM_PROFILE_BALANCED;
1319 break;
1320 case HP_OMEN_V0_THERMAL_PROFILE_COOL:
1321 case HP_OMEN_V1_THERMAL_PROFILE_COOL:
1322 *profile = PLATFORM_PROFILE_COOL;
1323 break;
1324 default:
1325 return -EINVAL;
1326 }
1327
1328 return 0;
1329}
1330
1331static int platform_profile_omen_get(struct device *dev,
1332 enum platform_profile_option *profile)
1333{
1334 /*
1335 * We directly return the stored platform profile, as the embedded
1336 * controller will not accept switching to the performance option when
1337 * the conditions are not met (e.g. the laptop is not plugged in).
1338 *
1339 * If we directly return what the EC reports, the platform profile will
1340 * immediately "switch back" to normal mode, which is against the
1341 * expected behaviour from a userspace point of view, as described in
1342 * the Platform Profile Section page of the kernel documentation.
1343 *
1344 * See also omen_powersource_event.
1345 */
1346 guard(mutex)(&active_platform_profile_lock);
1347 *profile = active_platform_profile;
1348
1349 return 0;
1350}
1351
1352static bool has_omen_thermal_profile_ec_timer(void)
1353{
1354 const char *board_name = dmi_get_system_info(DMI_BOARD_NAME);
1355
1356 if (!board_name)
1357 return false;
1358
1359 return match_string(omen_timed_thermal_profile_boards,
1360 ARRAY_SIZE(omen_timed_thermal_profile_boards),
1361 board_name) >= 0;
1362}
1363
1364inline int omen_thermal_profile_ec_flags_set(enum hp_thermal_profile_omen_flags flags)
1365{
1366 return ec_write(HP_OMEN_EC_THERMAL_PROFILE_FLAGS_OFFSET, flags);
1367}
1368
1369inline int omen_thermal_profile_ec_timer_set(u8 value)
1370{
1371 return ec_write(HP_OMEN_EC_THERMAL_PROFILE_TIMER_OFFSET, value);
1372}
1373
1374static int platform_profile_omen_set_ec(enum platform_profile_option profile)
1375{
1376 int err, tp, tp_version;
1377 enum hp_thermal_profile_omen_flags flags = 0;
1378
1379 tp_version = omen_get_thermal_policy_version();
1380
1381 if (tp_version < 0 || tp_version > 1)
1382 return -EOPNOTSUPP;
1383
1384 switch (profile) {
1385 case PLATFORM_PROFILE_PERFORMANCE:
1386 if (tp_version == 0)
1387 tp = HP_OMEN_V0_THERMAL_PROFILE_PERFORMANCE;
1388 else
1389 tp = HP_OMEN_V1_THERMAL_PROFILE_PERFORMANCE;
1390 break;
1391 case PLATFORM_PROFILE_BALANCED:
1392 if (tp_version == 0)
1393 tp = HP_OMEN_V0_THERMAL_PROFILE_DEFAULT;
1394 else
1395 tp = HP_OMEN_V1_THERMAL_PROFILE_DEFAULT;
1396 break;
1397 case PLATFORM_PROFILE_COOL:
1398 if (tp_version == 0)
1399 tp = HP_OMEN_V0_THERMAL_PROFILE_COOL;
1400 else
1401 tp = HP_OMEN_V1_THERMAL_PROFILE_COOL;
1402 break;
1403 default:
1404 return -EOPNOTSUPP;
1405 }
1406
1407 err = omen_thermal_profile_set(tp);
1408 if (err < 0)
1409 return err;
1410
1411 if (has_omen_thermal_profile_ec_timer()) {
1412 err = omen_thermal_profile_ec_timer_set(0);
1413 if (err < 0)
1414 return err;
1415
1416 if (profile == PLATFORM_PROFILE_PERFORMANCE)
1417 flags = HP_OMEN_EC_FLAGS_NOTIMER |
1418 HP_OMEN_EC_FLAGS_TURBO;
1419
1420 err = omen_thermal_profile_ec_flags_set(flags);
1421 if (err < 0)
1422 return err;
1423 }
1424
1425 return 0;
1426}
1427
1428static int platform_profile_omen_set(struct device *dev,
1429 enum platform_profile_option profile)
1430{
1431 int err;
1432
1433 guard(mutex)(&active_platform_profile_lock);
1434
1435 err = platform_profile_omen_set_ec(profile);
1436 if (err < 0)
1437 return err;
1438
1439 active_platform_profile = profile;
1440
1441 return 0;
1442}
1443
1444static int thermal_profile_get(void)
1445{
1446 return hp_wmi_read_int(HPWMI_THERMAL_PROFILE_QUERY);
1447}
1448
1449static int thermal_profile_set(int thermal_profile)
1450{
1451 return hp_wmi_perform_query(HPWMI_THERMAL_PROFILE_QUERY, HPWMI_WRITE, &thermal_profile,
1452 sizeof(thermal_profile), 0);
1453}
1454
1455static int hp_wmi_platform_profile_get(struct device *dev,
1456 enum platform_profile_option *profile)
1457{
1458 int tp;
1459
1460 tp = thermal_profile_get();
1461 if (tp < 0)
1462 return tp;
1463
1464 switch (tp) {
1465 case HP_THERMAL_PROFILE_PERFORMANCE:
1466 *profile = PLATFORM_PROFILE_PERFORMANCE;
1467 break;
1468 case HP_THERMAL_PROFILE_DEFAULT:
1469 *profile = PLATFORM_PROFILE_BALANCED;
1470 break;
1471 case HP_THERMAL_PROFILE_COOL:
1472 *profile = PLATFORM_PROFILE_COOL;
1473 break;
1474 case HP_THERMAL_PROFILE_QUIET:
1475 *profile = PLATFORM_PROFILE_QUIET;
1476 break;
1477 default:
1478 return -EINVAL;
1479 }
1480
1481 return 0;
1482}
1483
1484static int hp_wmi_platform_profile_set(struct device *dev,
1485 enum platform_profile_option profile)
1486{
1487 int err, tp;
1488
1489 switch (profile) {
1490 case PLATFORM_PROFILE_PERFORMANCE:
1491 tp = HP_THERMAL_PROFILE_PERFORMANCE;
1492 break;
1493 case PLATFORM_PROFILE_BALANCED:
1494 tp = HP_THERMAL_PROFILE_DEFAULT;
1495 break;
1496 case PLATFORM_PROFILE_COOL:
1497 tp = HP_THERMAL_PROFILE_COOL;
1498 break;
1499 case PLATFORM_PROFILE_QUIET:
1500 tp = HP_THERMAL_PROFILE_QUIET;
1501 break;
1502 default:
1503 return -EOPNOTSUPP;
1504 }
1505
1506 err = thermal_profile_set(tp);
1507 if (err)
1508 return err;
1509
1510 return 0;
1511}
1512
1513static bool is_victus_thermal_profile(void)
1514{
1515 const char *board_name = dmi_get_system_info(DMI_BOARD_NAME);
1516
1517 if (!board_name)
1518 return false;
1519
1520 return match_string(victus_thermal_profile_boards,
1521 ARRAY_SIZE(victus_thermal_profile_boards),
1522 board_name) >= 0;
1523}
1524
1525static int platform_profile_victus_get_ec(enum platform_profile_option *profile)
1526{
1527 int tp;
1528
1529 tp = omen_thermal_profile_get();
1530 if (tp < 0)
1531 return tp;
1532
1533 switch (tp) {
1534 case HP_VICTUS_THERMAL_PROFILE_PERFORMANCE:
1535 *profile = PLATFORM_PROFILE_PERFORMANCE;
1536 break;
1537 case HP_VICTUS_THERMAL_PROFILE_DEFAULT:
1538 *profile = PLATFORM_PROFILE_BALANCED;
1539 break;
1540 case HP_VICTUS_THERMAL_PROFILE_QUIET:
1541 *profile = PLATFORM_PROFILE_QUIET;
1542 break;
1543 default:
1544 return -EOPNOTSUPP;
1545 }
1546
1547 return 0;
1548}
1549
1550static int platform_profile_victus_get(struct device *dev,
1551 enum platform_profile_option *profile)
1552{
1553 /* Same behaviour as platform_profile_omen_get */
1554 return platform_profile_omen_get(dev, profile);
1555}
1556
1557static int platform_profile_victus_set_ec(enum platform_profile_option profile)
1558{
1559 int err, tp;
1560
1561 switch (profile) {
1562 case PLATFORM_PROFILE_PERFORMANCE:
1563 tp = HP_VICTUS_THERMAL_PROFILE_PERFORMANCE;
1564 break;
1565 case PLATFORM_PROFILE_BALANCED:
1566 tp = HP_VICTUS_THERMAL_PROFILE_DEFAULT;
1567 break;
1568 case PLATFORM_PROFILE_QUIET:
1569 tp = HP_VICTUS_THERMAL_PROFILE_QUIET;
1570 break;
1571 default:
1572 return -EOPNOTSUPP;
1573 }
1574
1575 err = omen_thermal_profile_set(tp);
1576 if (err < 0)
1577 return err;
1578
1579 return 0;
1580}
1581
1582static bool is_victus_s_thermal_profile(void)
1583{
1584 const char *board_name;
1585
1586 board_name = dmi_get_system_info(DMI_BOARD_NAME);
1587 if (!board_name)
1588 return false;
1589
1590 return match_string(victus_s_thermal_profile_boards,
1591 ARRAY_SIZE(victus_s_thermal_profile_boards),
1592 board_name) >= 0;
1593}
1594
1595static int victus_s_gpu_thermal_profile_get(bool *ctgp_enable,
1596 bool *ppab_enable,
1597 u8 *dstate,
1598 u8 *gpu_slowdown_temp)
1599{
1600 struct victus_gpu_power_modes gpu_power_modes;
1601 int ret;
1602
1603 ret = hp_wmi_perform_query(HPWMI_GET_GPU_THERMAL_MODES_QUERY, HPWMI_GM,
1604 &gpu_power_modes, sizeof(gpu_power_modes),
1605 sizeof(gpu_power_modes));
1606 if (ret == 0) {
1607 *ctgp_enable = gpu_power_modes.ctgp_enable ? true : false;
1608 *ppab_enable = gpu_power_modes.ppab_enable ? true : false;
1609 *dstate = gpu_power_modes.dstate;
1610 *gpu_slowdown_temp = gpu_power_modes.gpu_slowdown_temp;
1611 }
1612
1613 return ret;
1614}
1615
1616static int victus_s_gpu_thermal_profile_set(bool ctgp_enable,
1617 bool ppab_enable,
1618 u8 dstate)
1619{
1620 struct victus_gpu_power_modes gpu_power_modes;
1621 int ret;
1622
1623 bool current_ctgp_state, current_ppab_state;
1624 u8 current_dstate, current_gpu_slowdown_temp;
1625
1626 /* Retrieving GPU slowdown temperature, in order to keep it unchanged */
1627 ret = victus_s_gpu_thermal_profile_get(¤t_ctgp_state,
1628 ¤t_ppab_state,
1629 ¤t_dstate,
1630 ¤t_gpu_slowdown_temp);
1631 if (ret < 0) {
1632 pr_warn("GPU modes not updated, unable to get slowdown temp\n");
1633 return ret;
1634 }
1635
1636 gpu_power_modes.ctgp_enable = ctgp_enable ? 0x01 : 0x00;
1637 gpu_power_modes.ppab_enable = ppab_enable ? 0x01 : 0x00;
1638 gpu_power_modes.dstate = dstate;
1639 gpu_power_modes.gpu_slowdown_temp = current_gpu_slowdown_temp;
1640
1641
1642 ret = hp_wmi_perform_query(HPWMI_SET_GPU_THERMAL_MODES_QUERY, HPWMI_GM,
1643 &gpu_power_modes, sizeof(gpu_power_modes), 0);
1644
1645 return ret;
1646}
1647
1648/* Note: HP_POWER_LIMIT_DEFAULT can be used to restore default PL1 and PL2 */
1649static int victus_s_set_cpu_pl1_pl2(u8 pl1, u8 pl2)
1650{
1651 struct victus_power_limits power_limits;
1652 int ret;
1653
1654 /* We need to know both PL1 and PL2 values in order to check them */
1655 if (pl1 == HP_POWER_LIMIT_NO_CHANGE || pl2 == HP_POWER_LIMIT_NO_CHANGE)
1656 return -EINVAL;
1657
1658 /* PL2 is not supposed to be lower than PL1 */
1659 if (pl2 < pl1)
1660 return -EINVAL;
1661
1662 power_limits.pl1 = pl1;
1663 power_limits.pl2 = pl2;
1664 power_limits.pl4 = HP_POWER_LIMIT_NO_CHANGE;
1665 power_limits.cpu_gpu_concurrent_limit = HP_POWER_LIMIT_NO_CHANGE;
1666
1667 ret = hp_wmi_perform_query(HPWMI_SET_POWER_LIMITS_QUERY, HPWMI_GM,
1668 &power_limits, sizeof(power_limits), 0);
1669
1670 return ret;
1671}
1672
1673static int platform_profile_victus_s_set_ec(enum platform_profile_option profile)
1674{
1675 bool gpu_ctgp_enable, gpu_ppab_enable;
1676 u8 gpu_dstate; /* Test shows 1 = 100%, 2 = 50%, 3 = 25%, 4 = 12.5% */
1677 int err, tp;
1678
1679 switch (profile) {
1680 case PLATFORM_PROFILE_PERFORMANCE:
1681 tp = HP_VICTUS_S_THERMAL_PROFILE_PERFORMANCE;
1682 gpu_ctgp_enable = true;
1683 gpu_ppab_enable = true;
1684 gpu_dstate = 1;
1685 break;
1686 case PLATFORM_PROFILE_BALANCED:
1687 tp = HP_VICTUS_S_THERMAL_PROFILE_DEFAULT;
1688 gpu_ctgp_enable = false;
1689 gpu_ppab_enable = true;
1690 gpu_dstate = 1;
1691 break;
1692 case PLATFORM_PROFILE_LOW_POWER:
1693 tp = HP_VICTUS_S_THERMAL_PROFILE_DEFAULT;
1694 gpu_ctgp_enable = false;
1695 gpu_ppab_enable = false;
1696 gpu_dstate = 1;
1697 break;
1698 default:
1699 return -EOPNOTSUPP;
1700 }
1701
1702 hp_wmi_get_fan_count_userdefine_trigger();
1703
1704 err = omen_thermal_profile_set(tp);
1705 if (err < 0) {
1706 pr_err("Failed to set platform profile %d: %d\n", profile, err);
1707 return err;
1708 }
1709
1710 err = victus_s_gpu_thermal_profile_set(gpu_ctgp_enable,
1711 gpu_ppab_enable,
1712 gpu_dstate);
1713 if (err < 0) {
1714 pr_err("Failed to set GPU profile %d: %d\n", profile, err);
1715 return err;
1716 }
1717
1718 return 0;
1719}
1720
1721static int platform_profile_victus_s_set(struct device *dev,
1722 enum platform_profile_option profile)
1723{
1724 int err;
1725
1726 guard(mutex)(&active_platform_profile_lock);
1727
1728 err = platform_profile_victus_s_set_ec(profile);
1729 if (err < 0)
1730 return err;
1731
1732 active_platform_profile = profile;
1733
1734 return 0;
1735}
1736
1737static int platform_profile_victus_set(struct device *dev,
1738 enum platform_profile_option profile)
1739{
1740 int err;
1741
1742 guard(mutex)(&active_platform_profile_lock);
1743
1744 err = platform_profile_victus_set_ec(profile);
1745 if (err < 0)
1746 return err;
1747
1748 active_platform_profile = profile;
1749
1750 return 0;
1751}
1752
1753static int hp_wmi_platform_profile_probe(void *drvdata, unsigned long *choices)
1754{
1755 if (is_omen_thermal_profile()) {
1756 set_bit(PLATFORM_PROFILE_COOL, choices);
1757 } else if (is_victus_thermal_profile()) {
1758 set_bit(PLATFORM_PROFILE_QUIET, choices);
1759 } else if (is_victus_s_thermal_profile()) {
1760 /* Adding an equivalent to HP Omen software ECO mode: */
1761 set_bit(PLATFORM_PROFILE_LOW_POWER, choices);
1762 } else {
1763 set_bit(PLATFORM_PROFILE_QUIET, choices);
1764 set_bit(PLATFORM_PROFILE_COOL, choices);
1765 }
1766
1767 set_bit(PLATFORM_PROFILE_BALANCED, choices);
1768 set_bit(PLATFORM_PROFILE_PERFORMANCE, choices);
1769
1770 return 0;
1771}
1772
1773static int omen_powersource_event(struct notifier_block *nb,
1774 unsigned long value,
1775 void *data)
1776{
1777 struct acpi_bus_event *event_entry = data;
1778 enum platform_profile_option actual_profile;
1779 int err;
1780
1781 if (strcmp(event_entry->device_class, ACPI_AC_CLASS) != 0)
1782 return NOTIFY_DONE;
1783
1784 pr_debug("Received power source device event\n");
1785
1786 guard(mutex)(&active_platform_profile_lock);
1787
1788 /*
1789 * This handler can only be called on Omen and Victus models, so
1790 * there's no need to call is_victus_thermal_profile() here.
1791 */
1792 if (is_omen_thermal_profile())
1793 err = platform_profile_omen_get_ec(&actual_profile);
1794 else
1795 err = platform_profile_victus_get_ec(&actual_profile);
1796
1797 if (err < 0) {
1798 /*
1799 * Although we failed to get the current platform profile, we
1800 * still want the other event consumers to process it.
1801 */
1802 pr_warn("Failed to read current platform profile (%d)\n", err);
1803 return NOTIFY_DONE;
1804 }
1805
1806 /*
1807 * If we're back on AC and that the user-chosen power profile is
1808 * different from what the EC reports, we restore the user-chosen
1809 * one.
1810 */
1811 if (power_supply_is_system_supplied() <= 0 ||
1812 active_platform_profile == actual_profile) {
1813 pr_debug("Platform profile update skipped, conditions unmet\n");
1814 return NOTIFY_DONE;
1815 }
1816
1817 if (is_omen_thermal_profile())
1818 err = platform_profile_omen_set_ec(active_platform_profile);
1819 else
1820 err = platform_profile_victus_set_ec(active_platform_profile);
1821
1822 if (err < 0) {
1823 pr_warn("Failed to restore platform profile (%d)\n", err);
1824 return NOTIFY_DONE;
1825 }
1826
1827 return NOTIFY_OK;
1828}
1829
1830static int victus_s_powersource_event(struct notifier_block *nb,
1831 unsigned long value,
1832 void *data)
1833{
1834 struct acpi_bus_event *event_entry = data;
1835 int err;
1836
1837 if (strcmp(event_entry->device_class, ACPI_AC_CLASS) != 0)
1838 return NOTIFY_DONE;
1839
1840 pr_debug("Received power source device event\n");
1841
1842 /*
1843 * Switching to battery power source while Performance mode is active
1844 * needs manual triggering of CPU power limits. Same goes when switching
1845 * to AC power source while Performance mode is active. Other modes
1846 * however are automatically behaving without any manual action.
1847 * Seen on HP 16-s1034nf (board 8C9C) with F.11 and F.13 BIOS versions.
1848 */
1849
1850 if (active_platform_profile == PLATFORM_PROFILE_PERFORMANCE) {
1851 pr_debug("Triggering CPU PL1/PL2 actualization\n");
1852 err = victus_s_set_cpu_pl1_pl2(HP_POWER_LIMIT_DEFAULT,
1853 HP_POWER_LIMIT_DEFAULT);
1854 if (err)
1855 pr_warn("Failed to actualize power limits: %d\n", err);
1856
1857 return NOTIFY_DONE;
1858 }
1859
1860 return NOTIFY_OK;
1861}
1862
1863static int omen_register_powersource_event_handler(void)
1864{
1865 int err;
1866
1867 platform_power_source_nb.notifier_call = omen_powersource_event;
1868 err = register_acpi_notifier(&platform_power_source_nb);
1869
1870 if (err < 0) {
1871 pr_warn("Failed to install ACPI power source notify handler\n");
1872 return err;
1873 }
1874
1875 return 0;
1876}
1877
1878static int victus_s_register_powersource_event_handler(void)
1879{
1880 int err;
1881
1882 platform_power_source_nb.notifier_call = victus_s_powersource_event;
1883 err = register_acpi_notifier(&platform_power_source_nb);
1884 if (err < 0) {
1885 pr_warn("Failed to install ACPI power source notify handler\n");
1886 return err;
1887 }
1888
1889 return 0;
1890}
1891
1892static inline void omen_unregister_powersource_event_handler(void)
1893{
1894 unregister_acpi_notifier(&platform_power_source_nb);
1895}
1896
1897static inline void victus_s_unregister_powersource_event_handler(void)
1898{
1899 unregister_acpi_notifier(&platform_power_source_nb);
1900}
1901
1902static const struct platform_profile_ops platform_profile_omen_ops = {
1903 .probe = hp_wmi_platform_profile_probe,
1904 .profile_get = platform_profile_omen_get,
1905 .profile_set = platform_profile_omen_set,
1906};
1907
1908static const struct platform_profile_ops platform_profile_victus_ops = {
1909 .probe = hp_wmi_platform_profile_probe,
1910 .profile_get = platform_profile_victus_get,
1911 .profile_set = platform_profile_victus_set,
1912};
1913
1914static const struct platform_profile_ops platform_profile_victus_s_ops = {
1915 .probe = hp_wmi_platform_profile_probe,
1916 .profile_get = platform_profile_omen_get,
1917 .profile_set = platform_profile_victus_s_set,
1918};
1919
1920static const struct platform_profile_ops hp_wmi_platform_profile_ops = {
1921 .probe = hp_wmi_platform_profile_probe,
1922 .profile_get = hp_wmi_platform_profile_get,
1923 .profile_set = hp_wmi_platform_profile_set,
1924};
1925
1926static int thermal_profile_setup(struct platform_device *device)
1927{
1928 const struct platform_profile_ops *ops;
1929 int err, tp;
1930
1931 if (is_omen_thermal_profile()) {
1932 err = platform_profile_omen_get_ec(&active_platform_profile);
1933 if (err < 0)
1934 return err;
1935
1936 /*
1937 * call thermal profile write command to ensure that the
1938 * firmware correctly sets the OEM variables
1939 */
1940 err = platform_profile_omen_set_ec(active_platform_profile);
1941 if (err < 0)
1942 return err;
1943
1944 ops = &platform_profile_omen_ops;
1945 } else if (is_victus_thermal_profile()) {
1946 err = platform_profile_victus_get_ec(&active_platform_profile);
1947 if (err < 0)
1948 return err;
1949
1950 /*
1951 * call thermal profile write command to ensure that the
1952 * firmware correctly sets the OEM variables
1953 */
1954 err = platform_profile_victus_set_ec(active_platform_profile);
1955 if (err < 0)
1956 return err;
1957
1958 ops = &platform_profile_victus_ops;
1959 } else if (is_victus_s_thermal_profile()) {
1960 /*
1961 * Being unable to retrieve laptop's current thermal profile,
1962 * during this setup, we set it to Balanced by default.
1963 */
1964 active_platform_profile = PLATFORM_PROFILE_BALANCED;
1965
1966 err = platform_profile_victus_s_set_ec(active_platform_profile);
1967 if (err < 0)
1968 return err;
1969
1970 ops = &platform_profile_victus_s_ops;
1971 } else {
1972 tp = thermal_profile_get();
1973
1974 if (tp < 0)
1975 return tp;
1976
1977 /*
1978 * call thermal profile write command to ensure that the
1979 * firmware correctly sets the OEM variables for the DPTF
1980 */
1981 err = thermal_profile_set(tp);
1982 if (err)
1983 return err;
1984
1985 ops = &hp_wmi_platform_profile_ops;
1986 }
1987
1988 platform_profile_device = devm_platform_profile_register(&device->dev, "hp-wmi",
1989 NULL, ops);
1990 if (IS_ERR(platform_profile_device))
1991 return PTR_ERR(platform_profile_device);
1992
1993 pr_info("Registered as platform profile handler\n");
1994 platform_profile_support = true;
1995
1996 return 0;
1997}
1998
1999static int hp_wmi_hwmon_init(void);
2000
2001static int __init hp_wmi_bios_setup(struct platform_device *device)
2002{
2003 int err;
2004 /* clear detected rfkill devices */
2005 wifi_rfkill = NULL;
2006 bluetooth_rfkill = NULL;
2007 wwan_rfkill = NULL;
2008 rfkill2_count = 0;
2009
2010 /*
2011 * In pre-2009 BIOS, command 1Bh return 0x4 to indicate that
2012 * BIOS no longer controls the power for the wireless
2013 * devices. All features supported by this command will no
2014 * longer be supported.
2015 */
2016 if (!hp_wmi_bios_2009_later()) {
2017 if (hp_wmi_rfkill_setup(device))
2018 hp_wmi_rfkill2_setup(device);
2019 }
2020
2021 err = hp_wmi_hwmon_init();
2022
2023 if (err < 0)
2024 return err;
2025
2026 thermal_profile_setup(device);
2027
2028 return 0;
2029}
2030
2031static void __exit hp_wmi_bios_remove(struct platform_device *device)
2032{
2033 int i;
2034
2035 for (i = 0; i < rfkill2_count; i++) {
2036 rfkill_unregister(rfkill2[i].rfkill);
2037 rfkill_destroy(rfkill2[i].rfkill);
2038 }
2039
2040 if (wifi_rfkill) {
2041 rfkill_unregister(wifi_rfkill);
2042 rfkill_destroy(wifi_rfkill);
2043 }
2044 if (bluetooth_rfkill) {
2045 rfkill_unregister(bluetooth_rfkill);
2046 rfkill_destroy(bluetooth_rfkill);
2047 }
2048 if (wwan_rfkill) {
2049 rfkill_unregister(wwan_rfkill);
2050 rfkill_destroy(wwan_rfkill);
2051 }
2052}
2053
2054static int hp_wmi_resume_handler(struct device *device)
2055{
2056 /*
2057 * Hardware state may have changed while suspended, so trigger
2058 * input events for the current state. As this is a switch,
2059 * the input layer will only actually pass it on if the state
2060 * changed.
2061 */
2062 if (hp_wmi_input_dev) {
2063 if (test_bit(SW_DOCK, hp_wmi_input_dev->swbit))
2064 input_report_switch(hp_wmi_input_dev, SW_DOCK,
2065 hp_wmi_get_dock_state());
2066 if (test_bit(SW_TABLET_MODE, hp_wmi_input_dev->swbit))
2067 input_report_switch(hp_wmi_input_dev, SW_TABLET_MODE,
2068 hp_wmi_get_tablet_mode());
2069 input_sync(hp_wmi_input_dev);
2070 }
2071
2072 if (rfkill2_count)
2073 hp_wmi_rfkill2_refresh();
2074
2075 if (wifi_rfkill)
2076 rfkill_set_states(wifi_rfkill,
2077 hp_wmi_get_sw_state(HPWMI_WIFI),
2078 hp_wmi_get_hw_state(HPWMI_WIFI));
2079 if (bluetooth_rfkill)
2080 rfkill_set_states(bluetooth_rfkill,
2081 hp_wmi_get_sw_state(HPWMI_BLUETOOTH),
2082 hp_wmi_get_hw_state(HPWMI_BLUETOOTH));
2083 if (wwan_rfkill)
2084 rfkill_set_states(wwan_rfkill,
2085 hp_wmi_get_sw_state(HPWMI_WWAN),
2086 hp_wmi_get_hw_state(HPWMI_WWAN));
2087
2088 return 0;
2089}
2090
2091static const struct dev_pm_ops hp_wmi_pm_ops = {
2092 .resume = hp_wmi_resume_handler,
2093 .restore = hp_wmi_resume_handler,
2094};
2095
2096/*
2097 * hp_wmi_bios_remove() lives in .exit.text. For drivers registered via
2098 * module_platform_driver_probe() this is ok because they cannot get unbound at
2099 * runtime. So mark the driver struct with __refdata to prevent modpost
2100 * triggering a section mismatch warning.
2101 */
2102static struct platform_driver hp_wmi_driver __refdata = {
2103 .driver = {
2104 .name = "hp-wmi",
2105 .pm = &hp_wmi_pm_ops,
2106 .dev_groups = hp_wmi_groups,
2107 },
2108 .remove = __exit_p(hp_wmi_bios_remove),
2109};
2110
2111static umode_t hp_wmi_hwmon_is_visible(const void *data,
2112 enum hwmon_sensor_types type,
2113 u32 attr, int channel)
2114{
2115 switch (type) {
2116 case hwmon_pwm:
2117 return 0644;
2118 case hwmon_fan:
2119 if (is_victus_s_thermal_profile()) {
2120 if (hp_wmi_get_fan_speed_victus_s(channel) >= 0)
2121 return 0444;
2122 } else {
2123 if (hp_wmi_get_fan_speed(channel) >= 0)
2124 return 0444;
2125 }
2126 break;
2127 default:
2128 return 0;
2129 }
2130
2131 return 0;
2132}
2133
2134static int hp_wmi_hwmon_read(struct device *dev, enum hwmon_sensor_types type,
2135 u32 attr, int channel, long *val)
2136{
2137 int ret;
2138
2139 switch (type) {
2140 case hwmon_fan:
2141 if (is_victus_s_thermal_profile())
2142 ret = hp_wmi_get_fan_speed_victus_s(channel);
2143 else
2144 ret = hp_wmi_get_fan_speed(channel);
2145 if (ret < 0)
2146 return ret;
2147 *val = ret;
2148 return 0;
2149 case hwmon_pwm:
2150 switch (hp_wmi_fan_speed_max_get()) {
2151 case 0:
2152 /* 0 is automatic fan, which is 2 for hwmon */
2153 *val = 2;
2154 return 0;
2155 case 1:
2156 /* 1 is max fan, which is 0
2157 * (no fan speed control) for hwmon
2158 */
2159 *val = 0;
2160 return 0;
2161 default:
2162 /* shouldn't happen */
2163 return -ENODATA;
2164 }
2165 default:
2166 return -EINVAL;
2167 }
2168}
2169
2170static int hp_wmi_hwmon_write(struct device *dev, enum hwmon_sensor_types type,
2171 u32 attr, int channel, long val)
2172{
2173 switch (type) {
2174 case hwmon_pwm:
2175 switch (val) {
2176 case 0:
2177 if (is_victus_s_thermal_profile())
2178 hp_wmi_get_fan_count_userdefine_trigger();
2179 /* 0 is no fan speed control (max), which is 1 for us */
2180 return hp_wmi_fan_speed_max_set(1);
2181 case 2:
2182 /* 2 is automatic speed control, which is 0 for us */
2183 if (is_victus_s_thermal_profile()) {
2184 hp_wmi_get_fan_count_userdefine_trigger();
2185 return hp_wmi_fan_speed_max_reset();
2186 } else
2187 return hp_wmi_fan_speed_max_set(0);
2188 default:
2189 /* we don't support manual fan speed control */
2190 return -EINVAL;
2191 }
2192 default:
2193 return -EOPNOTSUPP;
2194 }
2195}
2196
2197static const struct hwmon_channel_info * const info[] = {
2198 HWMON_CHANNEL_INFO(fan, HWMON_F_INPUT, HWMON_F_INPUT),
2199 HWMON_CHANNEL_INFO(pwm, HWMON_PWM_ENABLE),
2200 NULL
2201};
2202
2203static const struct hwmon_ops ops = {
2204 .is_visible = hp_wmi_hwmon_is_visible,
2205 .read = hp_wmi_hwmon_read,
2206 .write = hp_wmi_hwmon_write,
2207};
2208
2209static const struct hwmon_chip_info chip_info = {
2210 .ops = &ops,
2211 .info = info,
2212};
2213
2214static int hp_wmi_hwmon_init(void)
2215{
2216 struct device *dev = &hp_wmi_platform_dev->dev;
2217 struct device *hwmon;
2218
2219 hwmon = devm_hwmon_device_register_with_info(dev, "hp", &hp_wmi_driver,
2220 &chip_info, NULL);
2221
2222 if (IS_ERR(hwmon)) {
2223 dev_err(dev, "Could not register hp hwmon device\n");
2224 return PTR_ERR(hwmon);
2225 }
2226
2227 return 0;
2228}
2229
2230static int __init hp_wmi_init(void)
2231{
2232 int event_capable = wmi_has_guid(HPWMI_EVENT_GUID);
2233 int bios_capable = wmi_has_guid(HPWMI_BIOS_GUID);
2234 int err, tmp = 0;
2235
2236 if (!bios_capable && !event_capable)
2237 return -ENODEV;
2238
2239 if (hp_wmi_perform_query(HPWMI_HARDWARE_QUERY, HPWMI_READ, &tmp,
2240 sizeof(tmp), sizeof(tmp)) == HPWMI_RET_INVALID_PARAMETERS)
2241 zero_insize_support = true;
2242
2243 if (event_capable) {
2244 err = hp_wmi_input_setup();
2245 if (err)
2246 return err;
2247 }
2248
2249 if (bios_capable) {
2250 hp_wmi_platform_dev =
2251 platform_device_register_simple("hp-wmi", PLATFORM_DEVID_NONE, NULL, 0);
2252 if (IS_ERR(hp_wmi_platform_dev)) {
2253 err = PTR_ERR(hp_wmi_platform_dev);
2254 goto err_destroy_input;
2255 }
2256
2257 err = platform_driver_probe(&hp_wmi_driver, hp_wmi_bios_setup);
2258 if (err)
2259 goto err_unregister_device;
2260 }
2261
2262 if (is_omen_thermal_profile() || is_victus_thermal_profile()) {
2263 err = omen_register_powersource_event_handler();
2264 if (err)
2265 goto err_unregister_device;
2266 } else if (is_victus_s_thermal_profile()) {
2267 err = victus_s_register_powersource_event_handler();
2268 if (err)
2269 goto err_unregister_device;
2270 }
2271
2272 return 0;
2273
2274err_unregister_device:
2275 platform_device_unregister(hp_wmi_platform_dev);
2276err_destroy_input:
2277 if (event_capable)
2278 hp_wmi_input_destroy();
2279
2280 return err;
2281}
2282module_init(hp_wmi_init);
2283
2284static void __exit hp_wmi_exit(void)
2285{
2286 if (is_omen_thermal_profile() || is_victus_thermal_profile())
2287 omen_unregister_powersource_event_handler();
2288
2289 if (is_victus_s_thermal_profile())
2290 victus_s_unregister_powersource_event_handler();
2291
2292 if (wmi_has_guid(HPWMI_EVENT_GUID))
2293 hp_wmi_input_destroy();
2294
2295 if (camera_shutter_input_dev)
2296 input_unregister_device(camera_shutter_input_dev);
2297
2298 if (hp_wmi_platform_dev) {
2299 platform_device_unregister(hp_wmi_platform_dev);
2300 platform_driver_unregister(&hp_wmi_driver);
2301 }
2302}
2303module_exit(hp_wmi_exit);