24
24
#include <linux/platform_profile.h>
25
25
#include <linux/hwmon.h>
26
26
#include <linux/acpi.h>
27
+ #include <linux/mutex.h>
28
+ #include <linux/cleanup.h>
29
+ #include <linux/power_supply.h>
27
30
#include <linux/rfkill.h>
28
31
#include <linux/string.h>
29
32
#include <linux/dmi.h>
@@ -42,6 +45,8 @@ MODULE_ALIAS("wmi:5FB7F034-2C63-45E9-BE91-3D44E2C707E4");
42
45
#define HP_OMEN_EC_THERMAL_PROFILE_TIMER_OFFSET 0x63
43
46
#define HP_OMEN_EC_THERMAL_PROFILE_OFFSET 0x95
44
47
48
+ #define ACPI_AC_CLASS "ac_adapter"
49
+
45
50
#define zero_if_sup (tmp ) (zero_insize_support?0:sizeof(tmp)) // use when zero insize is required
46
51
47
52
/* DMI board names of devices that should use the omen specific path for
@@ -259,10 +264,18 @@ static const struct key_entry hp_wmi_keymap[] = {
259
264
{ KE_END , 0 }
260
265
};
261
266
267
+ /*
268
+ * Mutex for the active_platform_profile variable,
269
+ * see omen_powersource_event.
270
+ */
271
+ static DEFINE_MUTEX (active_platform_profile_lock );
272
+
262
273
static struct input_dev * hp_wmi_input_dev ;
263
274
static struct input_dev * camera_shutter_input_dev ;
264
275
static struct platform_device * hp_wmi_platform_dev ;
265
276
static struct platform_profile_handler platform_profile_handler ;
277
+ static struct notifier_block platform_power_source_nb ;
278
+ static enum platform_profile_option active_platform_profile ;
266
279
static bool platform_profile_support ;
267
280
static bool zero_insize_support ;
268
281
@@ -1194,8 +1207,7 @@ static int __init hp_wmi_rfkill2_setup(struct platform_device *device)
1194
1207
return err ;
1195
1208
}
1196
1209
1197
- static int platform_profile_omen_get (struct platform_profile_handler * pprof ,
1198
- enum platform_profile_option * profile )
1210
+ static int platform_profile_omen_get_ec (enum platform_profile_option * profile )
1199
1211
{
1200
1212
int tp ;
1201
1213
@@ -1223,6 +1235,29 @@ static int platform_profile_omen_get(struct platform_profile_handler *pprof,
1223
1235
return 0 ;
1224
1236
}
1225
1237
1238
+ static int platform_profile_omen_get (struct platform_profile_handler * pprof ,
1239
+ enum platform_profile_option * profile )
1240
+ {
1241
+ enum platform_profile_option selected_platform_profile ;
1242
+
1243
+ /*
1244
+ * We directly return the stored platform profile, as the embedded
1245
+ * controller will not accept switching to the performance option when
1246
+ * the conditions are not met (e.g. the laptop is not plugged in).
1247
+ *
1248
+ * If we directly return what the EC reports, the platform profile will
1249
+ * immediately "switch back" to normal mode, which is against the
1250
+ * expected behaviour from a userspace point of view, as described in
1251
+ * the Platform Profile Section page of the kernel documentation.
1252
+ *
1253
+ * See also omen_powersource_event.
1254
+ */
1255
+ guard (mutex )(& active_platform_profile_lock );
1256
+ selected_platform_profile = active_platform_profile ;
1257
+
1258
+ return selected_platform_profile ;
1259
+ }
1260
+
1226
1261
static bool has_omen_thermal_profile_ec_timer (void )
1227
1262
{
1228
1263
const char * board_name = dmi_get_system_info (DMI_BOARD_NAME );
@@ -1245,8 +1280,7 @@ inline int omen_thermal_profile_ec_timer_set(u8 value)
1245
1280
return ec_write (HP_OMEN_EC_THERMAL_PROFILE_TIMER_OFFSET , value );
1246
1281
}
1247
1282
1248
- static int platform_profile_omen_set (struct platform_profile_handler * pprof ,
1249
- enum platform_profile_option profile )
1283
+ static int platform_profile_omen_set_ec (enum platform_profile_option profile )
1250
1284
{
1251
1285
int err , tp , tp_version ;
1252
1286
enum hp_thermal_profile_omen_flags flags = 0 ;
@@ -1300,6 +1334,22 @@ static int platform_profile_omen_set(struct platform_profile_handler *pprof,
1300
1334
return 0 ;
1301
1335
}
1302
1336
1337
+ static int platform_profile_omen_set (struct platform_profile_handler * pprof ,
1338
+ enum platform_profile_option profile )
1339
+ {
1340
+ int err ;
1341
+
1342
+ guard (mutex )(& active_platform_profile_lock );
1343
+
1344
+ err = platform_profile_omen_set_ec (profile );
1345
+ if (err < 0 )
1346
+ return err ;
1347
+
1348
+ active_platform_profile = profile ;
1349
+
1350
+ return 0 ;
1351
+ }
1352
+
1303
1353
static int thermal_profile_get (void )
1304
1354
{
1305
1355
return hp_wmi_read_int (HPWMI_THERMAL_PROFILE_QUERY );
@@ -1381,8 +1431,7 @@ static bool is_victus_thermal_profile(void)
1381
1431
board_name ) >= 0 ;
1382
1432
}
1383
1433
1384
- static int platform_profile_victus_get (struct platform_profile_handler * pprof ,
1385
- enum platform_profile_option * profile )
1434
+ static int platform_profile_victus_get_ec (enum platform_profile_option * profile )
1386
1435
{
1387
1436
int tp ;
1388
1437
@@ -1407,8 +1456,14 @@ static int platform_profile_victus_get(struct platform_profile_handler *pprof,
1407
1456
return 0 ;
1408
1457
}
1409
1458
1410
- static int platform_profile_victus_set (struct platform_profile_handler * pprof ,
1411
- enum platform_profile_option profile )
1459
+ static int platform_profile_victus_get (struct platform_profile_handler * pprof ,
1460
+ enum platform_profile_option * profile )
1461
+ {
1462
+ /* Same behaviour as platform_profile_omen_get */
1463
+ return platform_profile_omen_get (pprof , profile );
1464
+ }
1465
+
1466
+ static int platform_profile_victus_set_ec (enum platform_profile_option profile )
1412
1467
{
1413
1468
int err , tp ;
1414
1469
@@ -1433,21 +1488,113 @@ static int platform_profile_victus_set(struct platform_profile_handler *pprof,
1433
1488
return 0 ;
1434
1489
}
1435
1490
1491
+ static int platform_profile_victus_set (struct platform_profile_handler * pprof ,
1492
+ enum platform_profile_option profile )
1493
+ {
1494
+ int err ;
1495
+
1496
+ guard (mutex )(& active_platform_profile_lock );
1497
+
1498
+ err = platform_profile_victus_set_ec (profile );
1499
+ if (err < 0 )
1500
+ return err ;
1501
+
1502
+ active_platform_profile = profile ;
1503
+
1504
+ return 0 ;
1505
+ }
1506
+
1507
+ static int omen_powersource_event (struct notifier_block * nb ,
1508
+ unsigned long value ,
1509
+ void * data )
1510
+ {
1511
+ struct acpi_bus_event * event_entry = data ;
1512
+ enum platform_profile_option actual_profile ;
1513
+ int err ;
1514
+
1515
+ if (strcmp (event_entry -> device_class , ACPI_AC_CLASS ) != 0 )
1516
+ return NOTIFY_DONE ;
1517
+
1518
+ pr_debug ("Received power source device event\n" );
1519
+
1520
+ guard (mutex )(& active_platform_profile_lock );
1521
+
1522
+ /*
1523
+ * This handler can only be called on Omen and Victus models, so
1524
+ * there's no need to call is_victus_thermal_profile() here.
1525
+ */
1526
+ if (is_omen_thermal_profile ())
1527
+ err = platform_profile_omen_get_ec (& actual_profile );
1528
+ else
1529
+ err = platform_profile_victus_get_ec (& actual_profile );
1530
+
1531
+ if (err < 0 ) {
1532
+ /*
1533
+ * Although we failed to get the current platform profile, we
1534
+ * still want the other event consumers to process it.
1535
+ */
1536
+ pr_warn ("Failed to read current platform profile (%d)\n" , err );
1537
+ return NOTIFY_DONE ;
1538
+ }
1539
+
1540
+ /*
1541
+ * If we're back on AC and that the user-chosen power profile is
1542
+ * different from what the EC reports, we restore the user-chosen
1543
+ * one.
1544
+ */
1545
+ if (power_supply_is_system_supplied () <= 0 ||
1546
+ active_platform_profile == actual_profile ) {
1547
+ pr_debug ("Platform profile update skipped, conditions unmet\n" );
1548
+ return NOTIFY_DONE ;
1549
+ }
1550
+
1551
+ if (is_omen_thermal_profile ())
1552
+ err = platform_profile_omen_set_ec (active_platform_profile );
1553
+ else
1554
+ err = platform_profile_victus_set_ec (active_platform_profile );
1555
+
1556
+ if (err < 0 ) {
1557
+ pr_warn ("Failed to restore platform profile (%d)\n" , err );
1558
+ return NOTIFY_DONE ;
1559
+ }
1560
+
1561
+ return NOTIFY_OK ;
1562
+ }
1563
+
1564
+ static int omen_register_powersource_event_handler (void )
1565
+ {
1566
+ int err ;
1567
+
1568
+ platform_power_source_nb .notifier_call = omen_powersource_event ;
1569
+ err = register_acpi_notifier (& platform_power_source_nb );
1570
+
1571
+ if (err < 0 ) {
1572
+ pr_warn ("Failed to install ACPI power source notify handler\n" );
1573
+ return err ;
1574
+ }
1575
+
1576
+ return 0 ;
1577
+ }
1578
+
1579
+ static inline void omen_unregister_powersource_event_handler (void )
1580
+ {
1581
+ unregister_acpi_notifier (& platform_power_source_nb );
1582
+ }
1583
+
1436
1584
static int thermal_profile_setup (void )
1437
1585
{
1438
1586
int err , tp ;
1439
1587
1440
1588
if (is_omen_thermal_profile ()) {
1441
- tp = omen_thermal_profile_get ( );
1442
- if (tp < 0 )
1443
- return tp ;
1589
+ err = platform_profile_omen_get_ec ( & active_platform_profile );
1590
+ if (err < 0 )
1591
+ return err ;
1444
1592
1445
1593
/*
1446
1594
* call thermal profile write command to ensure that the
1447
1595
* firmware correctly sets the OEM variables
1448
1596
*/
1449
-
1450
- err = omen_thermal_profile_set (tp );
1597
+ err = platform_profile_omen_set_ec (active_platform_profile );
1451
1598
if (err < 0 )
1452
1599
return err ;
1453
1600
@@ -1456,15 +1603,15 @@ static int thermal_profile_setup(void)
1456
1603
1457
1604
set_bit (PLATFORM_PROFILE_COOL , platform_profile_handler .choices );
1458
1605
} else if (is_victus_thermal_profile ()) {
1459
- tp = omen_thermal_profile_get ( );
1460
- if (tp < 0 )
1461
- return tp ;
1606
+ err = platform_profile_victus_get_ec ( & active_platform_profile );
1607
+ if (err < 0 )
1608
+ return err ;
1462
1609
1463
1610
/*
1464
1611
* call thermal profile write command to ensure that the
1465
1612
* firmware correctly sets the OEM variables
1466
1613
*/
1467
- err = omen_thermal_profile_set ( tp );
1614
+ err = platform_profile_victus_set_ec ( active_platform_profile );
1468
1615
if (err < 0 )
1469
1616
return err ;
1470
1617
@@ -1758,6 +1905,12 @@ static int __init hp_wmi_init(void)
1758
1905
goto err_unregister_device ;
1759
1906
}
1760
1907
1908
+ if (is_omen_thermal_profile () || is_victus_thermal_profile ()) {
1909
+ err = omen_register_powersource_event_handler ();
1910
+ if (err )
1911
+ goto err_unregister_device ;
1912
+ }
1913
+
1761
1914
return 0 ;
1762
1915
1763
1916
err_unregister_device :
@@ -1772,6 +1925,9 @@ module_init(hp_wmi_init);
1772
1925
1773
1926
static void __exit hp_wmi_exit (void )
1774
1927
{
1928
+ if (is_omen_thermal_profile () || is_victus_thermal_profile ())
1929
+ omen_unregister_powersource_event_handler ();
1930
+
1775
1931
if (wmi_has_guid (HPWMI_EVENT_GUID ))
1776
1932
hp_wmi_input_destroy ();
1777
1933
0 commit comments