summaryrefslogtreecommitdiff
path: root/drivers/platform
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/platform')
-rw-r--r--drivers/platform/chrome/cros_typec_altmode.c1
-rw-r--r--drivers/platform/surface/surface_aggregator_registry.c2
-rw-r--r--drivers/platform/surface/surfacepro3_button.c10
-rw-r--r--drivers/platform/wmi/core.c3
-rw-r--r--drivers/platform/x86/Kconfig1
-rw-r--r--drivers/platform/x86/acer-wireless.c8
-rw-r--r--drivers/platform/x86/adv_swbutton.c6
-rw-r--r--drivers/platform/x86/asus-armoury.c16
-rw-r--r--drivers/platform/x86/asus-armoury.h113
-rw-r--r--drivers/platform/x86/asus-laptop.c6
-rw-r--r--drivers/platform/x86/asus-nb-wmi.c9
-rw-r--r--drivers/platform/x86/dell/dell-rbtn.c6
-rw-r--r--drivers/platform/x86/eeepc-laptop.c6
-rw-r--r--drivers/platform/x86/fujitsu-laptop.c12
-rw-r--r--drivers/platform/x86/fujitsu-tablet.c6
-rw-r--r--drivers/platform/x86/hp/hp-wmi.c10
-rw-r--r--drivers/platform/x86/hp/hp_accel.c3
-rw-r--r--drivers/platform/x86/intel/hid.c6
-rw-r--r--drivers/platform/x86/intel/int1092/intel_sar.c7
-rw-r--r--drivers/platform/x86/intel/plr_tpmi.c45
-rw-r--r--drivers/platform/x86/intel/rst.c6
-rw-r--r--drivers/platform/x86/intel/smartconnect.c6
-rw-r--r--drivers/platform/x86/intel/vbtn.c6
-rw-r--r--drivers/platform/x86/intel/vsec.c54
-rw-r--r--drivers/platform/x86/intel/vsec_tpmi.c29
-rw-r--r--drivers/platform/x86/lenovo/Kconfig1
-rw-r--r--drivers/platform/x86/lenovo/wmi-capdata.c8
-rw-r--r--drivers/platform/x86/lenovo/wmi-capdata.h20
-rw-r--r--drivers/platform/x86/lenovo/wmi-events.c2
-rw-r--r--drivers/platform/x86/lenovo/wmi-gamezone.c7
-rw-r--r--drivers/platform/x86/lenovo/wmi-gamezone.h20
-rw-r--r--drivers/platform/x86/lenovo/wmi-helpers.c105
-rw-r--r--drivers/platform/x86/lenovo/wmi-helpers.h21
-rw-r--r--drivers/platform/x86/lenovo/wmi-other.c296
-rw-r--r--drivers/platform/x86/lenovo/wmi-other.h16
-rw-r--r--drivers/platform/x86/lg-laptop.c9
-rw-r--r--drivers/platform/x86/panasonic-laptop.c6
-rw-r--r--drivers/platform/x86/samsung-galaxybook.c69
-rw-r--r--drivers/platform/x86/sony-laptop.c12
-rw-r--r--drivers/platform/x86/system76_acpi.c6
-rw-r--r--drivers/platform/x86/toshiba_acpi.c6
-rw-r--r--drivers/platform/x86/toshiba_bluetooth.c6
-rw-r--r--drivers/platform/x86/toshiba_haps.c6
-rw-r--r--drivers/platform/x86/uniwill/uniwill-acpi.c47
-rw-r--r--drivers/platform/x86/wireless-hotkey.c9
45 files changed, 753 insertions, 296 deletions
diff --git a/drivers/platform/chrome/cros_typec_altmode.c b/drivers/platform/chrome/cros_typec_altmode.c
index 557340b53af0..66c546bf89b5 100644
--- a/drivers/platform/chrome/cros_typec_altmode.c
+++ b/drivers/platform/chrome/cros_typec_altmode.c
@@ -359,6 +359,7 @@ cros_typec_register_thunderbolt(struct cros_typec_port *port,
}
INIT_WORK(&adata->work, cros_typec_altmode_work);
+ mutex_init(&adata->lock);
adata->alt = alt;
adata->port = port;
adata->ap_mode_entry = true;
diff --git a/drivers/platform/surface/surface_aggregator_registry.c b/drivers/platform/surface/surface_aggregator_registry.c
index 0599d5adf02e..f0881edfb616 100644
--- a/drivers/platform/surface/surface_aggregator_registry.c
+++ b/drivers/platform/surface/surface_aggregator_registry.c
@@ -295,8 +295,6 @@ static const struct software_node *ssam_node_group_sl6[] = {
/* Devices for Surface Laptop 7. */
static const struct software_node *ssam_node_group_sl7[] = {
&ssam_node_root,
- &ssam_node_bat_ac,
- &ssam_node_bat_main,
&ssam_node_tmp_perf_profile_with_fan,
&ssam_node_fan_speed,
&ssam_node_hid_sam_keyboard,
diff --git a/drivers/platform/surface/surfacepro3_button.c b/drivers/platform/surface/surfacepro3_button.c
index 0293bc517b54..388a3e1a488c 100644
--- a/drivers/platform/surface/surfacepro3_button.c
+++ b/drivers/platform/surface/surfacepro3_button.c
@@ -185,12 +185,15 @@ static bool surface_button_check_MSHW0040(struct device *dev, acpi_handle handle
static int surface_button_probe(struct platform_device *pdev)
{
- struct acpi_device *device = ACPI_COMPANION(&pdev->dev);
struct surface_button *button;
+ struct acpi_device *device;
struct input_dev *input;
- const char *hid = acpi_device_hid(device);
int error;
+ device = ACPI_COMPANION(&pdev->dev);
+ if (!device)
+ return -ENODEV;
+
if (strncmp(acpi_device_bid(device), SURFACE_BUTTON_OBJ_NAME,
strlen(SURFACE_BUTTON_OBJ_NAME)))
return -ENODEV;
@@ -210,7 +213,8 @@ static int surface_button_probe(struct platform_device *pdev)
}
strscpy(acpi_device_name(device), SURFACE_BUTTON_DEVICE_NAME);
- snprintf(button->phys, sizeof(button->phys), "%s/buttons", hid);
+ snprintf(button->phys, sizeof(button->phys), "%s/buttons",
+ acpi_device_hid(device));
input->name = acpi_device_name(device);
input->phys = button->phys;
diff --git a/drivers/platform/wmi/core.c b/drivers/platform/wmi/core.c
index 7aa40dab6145..5a2ffcbab6af 100644
--- a/drivers/platform/wmi/core.c
+++ b/drivers/platform/wmi/core.c
@@ -411,6 +411,9 @@ int wmidev_invoke_method(struct wmi_device *wdev, u8 instance, u32 method_id,
obj = aout.pointer;
if (!obj) {
+ if (min_size != 0)
+ return -ENOMSG;
+
out->length = 0;
out->data = ZERO_SIZE_PTR;
diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
index 2ffa4ecf65b0..7a4956088300 100644
--- a/drivers/platform/x86/Kconfig
+++ b/drivers/platform/x86/Kconfig
@@ -118,6 +118,7 @@ config BITLAND_MIFS_WMI
depends on ACPI_WMI
depends on HWMON
depends on INPUT
+ depends on LEDS_CLASS
depends on POWER_SUPPLY
select ACPI_PLATFORM_PROFILE
select INPUT_SPARSEKMAP
diff --git a/drivers/platform/x86/acer-wireless.c b/drivers/platform/x86/acer-wireless.c
index f464b13a58af..fae8e5ad0f97 100644
--- a/drivers/platform/x86/acer-wireless.c
+++ b/drivers/platform/x86/acer-wireless.c
@@ -37,9 +37,14 @@ static void acer_wireless_notify(acpi_handle handle, u32 event, void *data)
static int acer_wireless_probe(struct platform_device *pdev)
{
+ struct acpi_device *adev;
struct input_dev *idev;
int ret;
+ adev = ACPI_COMPANION(&pdev->dev);
+ if (!adev)
+ return -ENODEV;
+
idev = devm_input_allocate_device(&pdev->dev);
if (!idev)
return -ENOMEM;
@@ -57,8 +62,7 @@ static int acer_wireless_probe(struct platform_device *pdev)
if (ret)
return ret;
- return acpi_dev_install_notify_handler(ACPI_COMPANION(&pdev->dev),
- ACPI_DEVICE_NOTIFY,
+ return acpi_dev_install_notify_handler(adev, ACPI_DEVICE_NOTIFY,
acer_wireless_notify,
&pdev->dev);
}
diff --git a/drivers/platform/x86/adv_swbutton.c b/drivers/platform/x86/adv_swbutton.c
index 6fa60f3fc53c..8f7a26e6de81 100644
--- a/drivers/platform/x86/adv_swbutton.c
+++ b/drivers/platform/x86/adv_swbutton.c
@@ -48,10 +48,14 @@ static int adv_swbutton_probe(struct platform_device *device)
{
struct adv_swbutton *button;
struct input_dev *input;
- acpi_handle handle = ACPI_HANDLE(&device->dev);
+ acpi_handle handle;
acpi_status status;
int error;
+ handle = ACPI_HANDLE(&device->dev);
+ if (!handle)
+ return -ENODEV;
+
button = devm_kzalloc(&device->dev, sizeof(*button), GFP_KERNEL);
if (!button)
return -ENOMEM;
diff --git a/drivers/platform/x86/asus-armoury.c b/drivers/platform/x86/asus-armoury.c
index 5b0987ccc270..495dc1e31d40 100644
--- a/drivers/platform/x86/asus-armoury.c
+++ b/drivers/platform/x86/asus-armoury.c
@@ -370,7 +370,7 @@ static ssize_t mini_led_mode_current_value_show(struct kobject *kobj,
if (err)
return err;
- mode = FIELD_GET(ASUS_MINI_LED_MODE_MASK, 0);
+ mode = FIELD_GET(ASUS_MINI_LED_MODE_MASK, mode);
for (i = 0; i < mini_led_mode_map_size; i++)
if (mode == mini_led_mode_map[i])
@@ -386,6 +386,7 @@ static ssize_t mini_led_mode_current_value_store(struct kobject *kobj,
{
u32 *mini_led_mode_map;
size_t mini_led_mode_map_size;
+ char mapped_value[12];
u32 mode;
int err;
@@ -414,9 +415,16 @@ static ssize_t mini_led_mode_current_value_store(struct kobject *kobj,
return -ENODEV;
}
- return armoury_attr_uint_store(kobj, attr, buf, count,
- 0, mini_led_mode_map[mode],
- NULL, asus_armoury.mini_led_dev_id);
+ /*
+ * armoury_attr_uint_store() parses and sends the value from the
+ * passed buffer; hand it the mapped firmware value so the device
+ * receives the translated mode instead of the raw index.
+ */
+ snprintf(mapped_value, sizeof(mapped_value), "%u", mini_led_mode_map[mode]);
+
+ return armoury_attr_uint_store(kobj, attr, mapped_value, count, 0,
+ mini_led_mode_map[mode], NULL,
+ asus_armoury.mini_led_dev_id);
}
static ssize_t mini_led_mode_possible_values_show(struct kobject *kobj,
diff --git a/drivers/platform/x86/asus-armoury.h b/drivers/platform/x86/asus-armoury.h
index c30d2b451e01..692978b61959 100644
--- a/drivers/platform/x86/asus-armoury.h
+++ b/drivers/platform/x86/asus-armoury.h
@@ -348,6 +348,29 @@ struct power_data {
static const struct dmi_system_id power_limits[] = {
{
.matches = {
+ DMI_MATCH(DMI_BOARD_NAME, "FA401EA"),
+ },
+ .driver_data = &(struct power_data) {
+ .ac_data = &(struct power_limits) {
+ .ppt_pl1_spl_min = 15,
+ .ppt_pl1_spl_max = 95,
+ .ppt_pl2_sppt_min = 35,
+ .ppt_pl2_sppt_max = 100,
+ .ppt_pl3_fppt_min = 35,
+ .ppt_pl3_fppt_max = 115,
+ },
+ .dc_data = &(struct power_limits) {
+ .ppt_pl1_spl_min = 15,
+ .ppt_pl1_spl_max = 71,
+ .ppt_pl2_sppt_min = 35,
+ .ppt_pl2_sppt_max = 71,
+ .ppt_pl3_fppt_min = 35,
+ .ppt_pl3_fppt_max = 71,
+ },
+ },
+ },
+ {
+ .matches = {
DMI_MATCH(DMI_BOARD_NAME, "FA401UM"),
},
.driver_data = &(struct power_data) {
@@ -888,6 +911,33 @@ static const struct dmi_system_id power_limits[] = {
},
{
.matches = {
+ DMI_MATCH(DMI_BOARD_NAME, "FX607VU"),
+ },
+ .driver_data = &(struct power_data) {
+ .ac_data = &(struct power_limits) {
+ .ppt_pl1_spl_min = 28,
+ .ppt_pl1_spl_def = 115,
+ .ppt_pl1_spl_max = 135,
+ .ppt_pl2_sppt_min = 28,
+ .ppt_pl2_sppt_max = 135,
+ .nv_dynamic_boost_min = 5,
+ .nv_dynamic_boost_max = 25,
+ .nv_temp_target_min = 75,
+ .nv_temp_target_max = 87,
+ },
+ .dc_data = &(struct power_limits) {
+ .ppt_pl1_spl_min = 25,
+ .ppt_pl1_spl_max = 45,
+ .ppt_pl2_sppt_min = 35,
+ .ppt_pl2_sppt_max = 60,
+ .nv_temp_target_min = 75,
+ .nv_temp_target_max = 87,
+ },
+ .requires_fan_curve = true,
+ },
+ },
+ {
+ .matches = {
DMI_MATCH(DMI_BOARD_NAME, "GA401Q"),
},
.driver_data = &(struct power_data) {
@@ -1255,6 +1305,35 @@ static const struct dmi_system_id power_limits[] = {
},
{
.matches = {
+ DMI_MATCH(DMI_BOARD_NAME, "GU605CP"),
+ },
+ .driver_data = &(struct power_data) {
+ .ac_data = &(struct power_limits) {
+ .ppt_pl1_spl_min = 45,
+ .ppt_pl1_spl_max = 75,
+ .ppt_pl2_sppt_min = 56,
+ .ppt_pl2_sppt_max = 95,
+ .nv_dynamic_boost_min = 5,
+ .nv_dynamic_boost_max = 15,
+ .nv_temp_target_min = 75,
+ .nv_temp_target_max = 87,
+ .nv_tgp_min = 55,
+ .nv_tgp_def = 75,
+ .nv_tgp_max = 95,
+ },
+ .dc_data = &(struct power_limits) {
+ .ppt_pl1_spl_min = 25,
+ .ppt_pl1_spl_max = 75,
+ .ppt_pl2_sppt_min = 32,
+ .ppt_pl2_sppt_max = 95,
+ .nv_temp_target_min = 75,
+ .nv_temp_target_max = 87,
+ },
+ .requires_fan_curve = true,
+ },
+ },
+ {
+ .matches = {
DMI_MATCH(DMI_BOARD_NAME, "GU605CR"),
},
.driver_data = &(struct power_data) {
@@ -1761,6 +1840,40 @@ static const struct dmi_system_id power_limits[] = {
},
{
.matches = {
+ DMI_MATCH(DMI_BOARD_NAME, "G614FR"),
+ },
+ .driver_data = &(struct power_data) {
+ .ac_data = &(struct power_limits) {
+ .ppt_pl1_spl_min = 30,
+ .ppt_pl1_spl_max = 120,
+ .ppt_pl2_sppt_min = 65,
+ .ppt_pl2_sppt_def = 140,
+ .ppt_pl2_sppt_max = 162,
+ .ppt_pl3_fppt_min = 65,
+ .ppt_pl3_fppt_def = 140,
+ .ppt_pl3_fppt_max = 162,
+ .nv_temp_target_min = 75,
+ .nv_temp_target_max = 87,
+ .nv_dynamic_boost_min = 5,
+ .nv_dynamic_boost_max = 25,
+ .nv_tgp_min = 65,
+ .nv_tgp_max = 115,
+ },
+ .dc_data = &(struct power_limits) {
+ .ppt_pl1_spl_min = 25,
+ .ppt_pl1_spl_max = 65,
+ .ppt_pl2_sppt_min = 25,
+ .ppt_pl2_sppt_max = 65,
+ .ppt_pl3_fppt_min = 35,
+ .ppt_pl3_fppt_max = 75,
+ .nv_temp_target_min = 75,
+ .nv_temp_target_max = 87,
+ },
+ .requires_fan_curve = true,
+ },
+ },
+ {
+ .matches = {
DMI_MATCH(DMI_BOARD_NAME, "G614J"),
},
.driver_data = &(struct power_data) {
diff --git a/drivers/platform/x86/asus-laptop.c b/drivers/platform/x86/asus-laptop.c
index dbbb6292cd11..140ac8a10537 100644
--- a/drivers/platform/x86/asus-laptop.c
+++ b/drivers/platform/x86/asus-laptop.c
@@ -1826,10 +1826,14 @@ static bool asus_device_present;
static int asus_acpi_probe(struct platform_device *pdev)
{
- struct acpi_device *device = ACPI_COMPANION(&pdev->dev);
+ struct acpi_device *device;
struct asus_laptop *asus;
int result;
+ device = ACPI_COMPANION(&pdev->dev);
+ if (!device)
+ return -ENODEV;
+
pr_notice("Asus Laptop Support version %s\n",
ASUS_LAPTOP_VERSION);
asus = kzalloc_obj(struct asus_laptop);
diff --git a/drivers/platform/x86/asus-nb-wmi.c b/drivers/platform/x86/asus-nb-wmi.c
index b4677c5bba5b..8005c088e9ee 100644
--- a/drivers/platform/x86/asus-nb-wmi.c
+++ b/drivers/platform/x86/asus-nb-wmi.c
@@ -546,6 +546,15 @@ static const struct dmi_system_id asus_quirks[] = {
},
{
.callback = dmi_matched,
+ .ident = "ASUS Zenbook Duo UX8407AA",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "ASUS"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Zenbook Duo UX8407AA"),
+ },
+ .driver_data = &quirk_asus_zenbook_duo_kbd,
+ },
+ {
+ .callback = dmi_matched,
.ident = "ASUS ROG Z13",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "ASUS"),
diff --git a/drivers/platform/x86/dell/dell-rbtn.c b/drivers/platform/x86/dell/dell-rbtn.c
index 34af9f4ff741..180b8c6720e6 100644
--- a/drivers/platform/x86/dell/dell-rbtn.c
+++ b/drivers/platform/x86/dell/dell-rbtn.c
@@ -396,11 +396,15 @@ static void rbtn_cleanup(struct device *dev)
static int rbtn_probe(struct platform_device *pdev)
{
- struct acpi_device *device = ACPI_COMPANION(&pdev->dev);
struct rbtn_data *rbtn_data;
+ struct acpi_device *device;
enum rbtn_type type;
int ret = 0;
+ device = ACPI_COMPANION(&pdev->dev);
+ if (!device)
+ return -ENODEV;
+
type = rbtn_check(device);
if (type == RBTN_UNKNOWN) {
dev_info(&pdev->dev, "Unknown device type\n");
diff --git a/drivers/platform/x86/eeepc-laptop.c b/drivers/platform/x86/eeepc-laptop.c
index 02a71095920e..d18a80907611 100644
--- a/drivers/platform/x86/eeepc-laptop.c
+++ b/drivers/platform/x86/eeepc-laptop.c
@@ -1363,10 +1363,14 @@ static bool eeepc_device_present;
static int eeepc_acpi_probe(struct platform_device *pdev)
{
- struct acpi_device *device = ACPI_COMPANION(&pdev->dev);
+ struct acpi_device *device;
struct eeepc_laptop *eeepc;
int result;
+ device = ACPI_COMPANION(&pdev->dev);
+ if (!device)
+ return -ENODEV;
+
pr_notice(EEEPC_LAPTOP_NAME "\n");
eeepc = kzalloc_obj(struct eeepc_laptop);
if (!eeepc)
diff --git a/drivers/platform/x86/fujitsu-laptop.c b/drivers/platform/x86/fujitsu-laptop.c
index 2e265be2267e..54d0b9cec4d3 100644
--- a/drivers/platform/x86/fujitsu-laptop.c
+++ b/drivers/platform/x86/fujitsu-laptop.c
@@ -530,10 +530,14 @@ static void acpi_fujitsu_bl_notify(acpi_handle handle, u32 event, void *data)
static int acpi_fujitsu_bl_probe(struct platform_device *pdev)
{
- struct acpi_device *device = ACPI_COMPANION(&pdev->dev);
+ struct acpi_device *device;
struct fujitsu_bl *priv;
int ret;
+ device = ACPI_COMPANION(&pdev->dev);
+ if (!device)
+ return -ENODEV;
+
if (acpi_video_get_backlight_type() != acpi_backlight_vendor)
return -ENODEV;
@@ -993,10 +997,14 @@ static void acpi_fujitsu_laptop_notify(acpi_handle handle, u32 event, void *data
static int acpi_fujitsu_laptop_probe(struct platform_device *pdev)
{
- struct acpi_device *device = ACPI_COMPANION(&pdev->dev);
struct fujitsu_laptop *priv;
+ struct acpi_device *device;
int ret, i = 0;
+ device = ACPI_COMPANION(&pdev->dev);
+ if (!device)
+ return -ENODEV;
+
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
diff --git a/drivers/platform/x86/fujitsu-tablet.c b/drivers/platform/x86/fujitsu-tablet.c
index 8319df28e9b8..2f8c1b89cbca 100644
--- a/drivers/platform/x86/fujitsu-tablet.c
+++ b/drivers/platform/x86/fujitsu-tablet.c
@@ -445,10 +445,14 @@ static acpi_status fujitsu_walk_resources(struct acpi_resource *res, void *data)
static int acpi_fujitsu_probe(struct platform_device *pdev)
{
- struct acpi_device *adev = ACPI_COMPANION(&pdev->dev);
+ struct acpi_device *adev;
acpi_status status;
int error;
+ adev = ACPI_COMPANION(&pdev->dev);
+ if (!adev)
+ return -ENODEV;
+
status = acpi_walk_resources(adev->handle, METHOD_NAME__CRS,
fujitsu_walk_resources, NULL);
if (ACPI_FAILURE(status) || !fujitsu.irq || !fujitsu.io_base)
diff --git a/drivers/platform/x86/hp/hp-wmi.c b/drivers/platform/x86/hp/hp-wmi.c
index d1cc6e7d176c..f63bc00d9a9b 100644
--- a/drivers/platform/x86/hp/hp-wmi.c
+++ b/drivers/platform/x86/hp/hp-wmi.c
@@ -190,6 +190,10 @@ static const char * const victus_thermal_profile_boards[] = {
/* DMI Board names of Victus 16-r and Victus 16-s laptops */
static const struct dmi_system_id victus_s_thermal_profile_boards[] __initconst = {
{
+ .matches = { DMI_MATCH(DMI_BOARD_NAME, "8902") },
+ .driver_data = (void *)&omen_v1_legacy_thermal_params,
+ },
+ {
.matches = { DMI_MATCH(DMI_BOARD_NAME, "8A44") },
.driver_data = (void *)&omen_v1_legacy_thermal_params,
},
@@ -206,6 +210,10 @@ static const struct dmi_system_id victus_s_thermal_profile_boards[] __initconst
.driver_data = (void *)&victus_s_thermal_params,
},
{
+ .matches = { DMI_MATCH(DMI_BOARD_NAME, "8BC2") },
+ .driver_data = (void *)&omen_v1_thermal_params,
+ },
+ {
.matches = { DMI_MATCH(DMI_BOARD_NAME, "8BCA") },
.driver_data = (void *)&omen_v1_thermal_params,
},
@@ -243,7 +251,7 @@ static const struct dmi_system_id victus_s_thermal_profile_boards[] __initconst
},
{
.matches = { DMI_MATCH(DMI_BOARD_NAME, "8D41") },
- .driver_data = (void *)&victus_s_thermal_params,
+ .driver_data = (void *)&omen_v1_no_ec_thermal_params,
},
{
.matches = { DMI_MATCH(DMI_BOARD_NAME, "8D87") },
diff --git a/drivers/platform/x86/hp/hp_accel.c b/drivers/platform/x86/hp/hp_accel.c
index 10d5af18d639..39b73dc473f1 100644
--- a/drivers/platform/x86/hp/hp_accel.c
+++ b/drivers/platform/x86/hp/hp_accel.c
@@ -300,6 +300,9 @@ static int lis3lv02d_probe(struct platform_device *device)
int ret;
lis3_dev.bus_priv = ACPI_COMPANION(&device->dev);
+ if (!lis3_dev.bus_priv)
+ return -ENODEV;
+
lis3_dev.init = lis3lv02d_acpi_init;
lis3_dev.read = lis3lv02d_acpi_read;
lis3_dev.write = lis3lv02d_acpi_write;
diff --git a/drivers/platform/x86/intel/hid.c b/drivers/platform/x86/intel/hid.c
index 2ddd8af8c1ce..085093506dda 100644
--- a/drivers/platform/x86/intel/hid.c
+++ b/drivers/platform/x86/intel/hid.c
@@ -688,12 +688,16 @@ static bool button_array_present(struct platform_device *device)
static int intel_hid_probe(struct platform_device *device)
{
- acpi_handle handle = ACPI_HANDLE(&device->dev);
unsigned long long mode, dummy;
struct intel_hid_priv *priv;
+ acpi_handle handle;
acpi_status status;
int err;
+ handle = ACPI_HANDLE(&device->dev);
+ if (!handle)
+ return -ENODEV;
+
intel_hid_init_dsm(handle);
if (!intel_hid_evaluate_method(handle, INTEL_HID_DSM_HDMM_FN, &mode)) {
diff --git a/drivers/platform/x86/intel/int1092/intel_sar.c b/drivers/platform/x86/intel/int1092/intel_sar.c
index 88822023a149..849f7b415c1e 100644
--- a/drivers/platform/x86/intel/int1092/intel_sar.c
+++ b/drivers/platform/x86/intel/int1092/intel_sar.c
@@ -245,15 +245,20 @@ static void sar_get_data(int reg, struct wwan_sar_context *context)
static int sar_probe(struct platform_device *device)
{
struct wwan_sar_context *context;
+ acpi_handle handle;
int reg;
int result;
+ handle = ACPI_HANDLE(&device->dev);
+ if (!handle)
+ return -ENODEV;
+
context = kzalloc_obj(*context);
if (!context)
return -ENOMEM;
context->sar_device = device;
- context->handle = ACPI_HANDLE(&device->dev);
+ context->handle = handle;
dev_set_drvdata(&device->dev, context);
result = guid_parse(SAR_DSM_UUID, &context->guid);
diff --git a/drivers/platform/x86/intel/plr_tpmi.c b/drivers/platform/x86/intel/plr_tpmi.c
index 05727169f49c..8faecc311038 100644
--- a/drivers/platform/x86/intel/plr_tpmi.c
+++ b/drivers/platform/x86/intel/plr_tpmi.c
@@ -22,6 +22,7 @@
#include <linux/module.h>
#include <linux/mod_devicetable.h>
#include <linux/mutex.h>
+#include <linux/notifier.h>
#include <linux/seq_file.h>
#include <linux/sprintf.h>
#include <linux/types.h>
@@ -60,6 +61,8 @@ struct tpmi_plr {
struct tpmi_plr_die *die_info;
int num_dies;
struct auxiliary_device *auxdev;
+ struct notifier_block nb;
+ struct mutex lock; /* Protect access to dbgfs_dir */
};
static const char * const plr_coarse_reasons[] = {
@@ -255,6 +258,30 @@ static ssize_t plr_status_write(struct file *filp, const char __user *ubuf,
}
DEFINE_SHOW_STORE_ATTRIBUTE(plr_status);
+static int intel_plr_notify(struct notifier_block *self, unsigned long action, void *data)
+{
+ struct tpmi_plr *plr = container_of(self, struct tpmi_plr, nb);
+
+ if (action == TPMI_CORE_EXIT) {
+ guard(mutex)(&plr->lock);
+ plr->dbgfs_dir = NULL;
+ }
+
+ return NOTIFY_DONE;
+}
+
+static int intel_plr_register_notifier(struct notifier_block *nb)
+{
+ nb->notifier_call = intel_plr_notify;
+ nb->priority = 0;
+ return tpmi_register_notifier(nb);
+}
+
+static void intel_plr_unregister_notifier(struct notifier_block *nb)
+{
+ tpmi_unregister_notifier(nb);
+}
+
static int intel_plr_probe(struct auxiliary_device *auxdev, const struct auxiliary_device_id *id)
{
struct oobmsm_plat_info *plat_info;
@@ -282,10 +309,18 @@ static int intel_plr_probe(struct auxiliary_device *auxdev, const struct auxilia
if (!plr)
return -ENOMEM;
+ err = devm_mutex_init(&auxdev->dev, &plr->lock);
+ if (err)
+ return err;
+
+ intel_plr_register_notifier(&plr->nb);
+
plr->die_info = devm_kcalloc(&auxdev->dev, num_resources, sizeof(*plr->die_info),
GFP_KERNEL);
- if (!plr->die_info)
- return -ENOMEM;
+ if (!plr->die_info) {
+ err = -ENOMEM;
+ goto err_notify;
+ }
plr->num_dies = num_resources;
plr->dbgfs_dir = debugfs_create_dir("plr", dentry);
@@ -326,6 +361,9 @@ static int intel_plr_probe(struct auxiliary_device *auxdev, const struct auxilia
err:
debugfs_remove_recursive(plr->dbgfs_dir);
+err_notify:
+ intel_plr_unregister_notifier(&plr->nb);
+
return err;
}
@@ -333,6 +371,9 @@ static void intel_plr_remove(struct auxiliary_device *auxdev)
{
struct tpmi_plr *plr = auxiliary_get_drvdata(auxdev);
+ intel_plr_unregister_notifier(&plr->nb);
+
+ guard(mutex)(&plr->lock);
debugfs_remove_recursive(plr->dbgfs_dir);
}
diff --git a/drivers/platform/x86/intel/rst.c b/drivers/platform/x86/intel/rst.c
index 4bd10927aad9..bb19f0d89305 100644
--- a/drivers/platform/x86/intel/rst.c
+++ b/drivers/platform/x86/intel/rst.c
@@ -102,9 +102,13 @@ static struct device_attribute irst_timeout_attr = {
static int irst_probe(struct platform_device *pdev)
{
- struct acpi_device *acpi = ACPI_COMPANION(&pdev->dev);
+ struct acpi_device *acpi;
int error;
+ acpi = ACPI_COMPANION(&pdev->dev);
+ if (!acpi)
+ return -ENODEV;
+
error = device_create_file(&acpi->dev, &irst_timeout_attr);
if (unlikely(error))
return error;
diff --git a/drivers/platform/x86/intel/smartconnect.c b/drivers/platform/x86/intel/smartconnect.c
index 4d866b6366d6..71e91ac60e5d 100644
--- a/drivers/platform/x86/intel/smartconnect.c
+++ b/drivers/platform/x86/intel/smartconnect.c
@@ -12,10 +12,14 @@ MODULE_LICENSE("GPL");
static int smartconnect_acpi_probe(struct platform_device *pdev)
{
- acpi_handle handle = ACPI_HANDLE(&pdev->dev);
unsigned long long value;
+ acpi_handle handle;
acpi_status status;
+ handle = ACPI_HANDLE(&pdev->dev);
+ if (!handle)
+ return -ENODEV;
+
status = acpi_evaluate_integer(handle, "GAOS", NULL, &value);
if (ACPI_FAILURE(status))
return -EINVAL;
diff --git a/drivers/platform/x86/intel/vbtn.c b/drivers/platform/x86/intel/vbtn.c
index 9ca87e707582..874023c38fd1 100644
--- a/drivers/platform/x86/intel/vbtn.c
+++ b/drivers/platform/x86/intel/vbtn.c
@@ -275,12 +275,16 @@ static bool intel_vbtn_has_switches(acpi_handle handle, bool dual_accel)
static int intel_vbtn_probe(struct platform_device *device)
{
- acpi_handle handle = ACPI_HANDLE(&device->dev);
bool dual_accel, has_buttons, has_switches;
struct intel_vbtn_priv *priv;
+ acpi_handle handle;
acpi_status status;
int err;
+ handle = ACPI_HANDLE(&device->dev);
+ if (!handle)
+ return -ENODEV;
+
dual_accel = dual_accel_detect();
has_buttons = acpi_has_method(handle, "VBDL");
has_switches = intel_vbtn_has_switches(handle, dual_accel);
diff --git a/drivers/platform/x86/intel/vsec.c b/drivers/platform/x86/intel/vsec.c
index 7d5dbc1c1d05..18e4a892bf0f 100644
--- a/drivers/platform/x86/intel/vsec.c
+++ b/drivers/platform/x86/intel/vsec.c
@@ -649,29 +649,13 @@ static void intel_vsec_skip_missing_dependencies(struct pci_dev *pdev)
}
}
-static int intel_vsec_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+static int intel_vsec_pci_init(struct pci_dev *pdev)
{
- const struct intel_vsec_platform_info *info;
- struct vsec_priv *priv;
- int num_caps, ret;
+ struct vsec_priv *priv = pci_get_drvdata(pdev);
+ const struct intel_vsec_platform_info *info = priv->info;
int run_once = 0;
bool found_any = false;
-
- ret = pcim_enable_device(pdev);
- if (ret)
- return ret;
-
- pci_save_state(pdev);
- info = (const struct intel_vsec_platform_info *)id->driver_data;
- if (!info)
- return -EINVAL;
-
- priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
- if (!priv)
- return -ENOMEM;
-
- priv->info = info;
- pci_set_drvdata(pdev, priv);
+ int num_caps;
num_caps = hweight_long(info->caps);
while (num_caps--) {
@@ -692,6 +676,31 @@ static int intel_vsec_pci_probe(struct pci_dev *pdev, const struct pci_device_id
return 0;
}
+static int intel_vsec_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+{
+ const struct intel_vsec_platform_info *info;
+ struct vsec_priv *priv;
+ int ret;
+
+ ret = pcim_enable_device(pdev);
+ if (ret)
+ return ret;
+
+ pci_save_state(pdev);
+ info = (const struct intel_vsec_platform_info *)id->driver_data;
+ if (!info)
+ return -EINVAL;
+
+ priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->info = info;
+ pci_set_drvdata(pdev, priv);
+
+ return intel_vsec_pci_init(pdev);
+}
+
int intel_vsec_set_mapping(struct oobmsm_plat_info *plat_info,
struct intel_vsec_device *vsec_dev)
{
@@ -832,7 +841,6 @@ static pci_ers_result_t intel_vsec_pci_slot_reset(struct pci_dev *pdev)
{
struct intel_vsec_device *intel_vsec_dev;
pci_ers_result_t status = PCI_ERS_RESULT_DISCONNECT;
- const struct pci_device_id *pci_dev_id;
unsigned long index;
dev_info(&pdev->dev, "Resetting PCI slot\n");
@@ -853,10 +861,8 @@ static pci_ers_result_t intel_vsec_pci_slot_reset(struct pci_dev *pdev)
devm_release_action(&pdev->dev, intel_vsec_remove_aux,
&intel_vsec_dev->auxdev);
}
- pci_disable_device(pdev);
pci_restore_state(pdev);
- pci_dev_id = pci_match_id(intel_vsec_pci_ids, pdev);
- intel_vsec_pci_probe(pdev, pci_dev_id);
+ intel_vsec_pci_init(pdev);
out:
return status;
diff --git a/drivers/platform/x86/intel/vsec_tpmi.c b/drivers/platform/x86/intel/vsec_tpmi.c
index 7fc6ff8d1040..16fd7aa41f20 100644
--- a/drivers/platform/x86/intel/vsec_tpmi.c
+++ b/drivers/platform/x86/intel/vsec_tpmi.c
@@ -56,6 +56,7 @@
#include <linux/io.h>
#include <linux/iopoll.h>
#include <linux/module.h>
+#include <linux/notifier.h>
#include <linux/pci.h>
#include <linux/security.h>
#include <linux/sizes.h>
@@ -188,6 +189,20 @@ struct tpmi_feature_state {
/* Used during auxbus device creation */
static DEFINE_IDA(intel_vsec_tpmi_ida);
+static BLOCKING_NOTIFIER_HEAD(tpmi_notify_list);
+
+int tpmi_register_notifier(struct notifier_block *nb)
+{
+ return blocking_notifier_chain_register(&tpmi_notify_list, nb);
+}
+EXPORT_SYMBOL_NS_GPL(tpmi_register_notifier, "INTEL_TPMI");
+
+int tpmi_unregister_notifier(struct notifier_block *nb)
+{
+ return blocking_notifier_chain_unregister(&tpmi_notify_list, nb);
+}
+EXPORT_SYMBOL_NS_GPL(tpmi_unregister_notifier, "INTEL_TPMI");
+
struct oobmsm_plat_info *tpmi_get_platform_data(struct auxiliary_device *auxdev)
{
struct intel_vsec_device *vsec_dev = auxdev_to_ivdev(auxdev);
@@ -817,10 +832,6 @@ static int intel_vsec_tpmi_init(struct auxiliary_device *auxdev)
auxiliary_set_drvdata(auxdev, tpmi_info);
- ret = tpmi_create_devices(tpmi_info);
- if (ret)
- return ret;
-
/*
* Allow debugfs when security policy allows. Everything this debugfs
* interface provides, can also be done via /dev/mem access. If
@@ -830,6 +841,14 @@ static int intel_vsec_tpmi_init(struct auxiliary_device *auxdev)
if (!security_locked_down(LOCKDOWN_DEV_MEM) && capable(CAP_SYS_RAWIO))
tpmi_dbgfs_register(tpmi_info);
+ ret = tpmi_create_devices(tpmi_info);
+ if (ret) {
+ debugfs_remove_recursive(tpmi_info->dbgfs_dir);
+ return ret;
+ }
+
+ blocking_notifier_call_chain(&tpmi_notify_list, TPMI_CORE_INIT, auxdev);
+
return 0;
}
@@ -843,6 +862,8 @@ static void tpmi_remove(struct auxiliary_device *auxdev)
{
struct intel_tpmi_info *tpmi_info = auxiliary_get_drvdata(auxdev);
+ blocking_notifier_call_chain(&tpmi_notify_list, TPMI_CORE_EXIT, auxdev);
+
debugfs_remove_recursive(tpmi_info->dbgfs_dir);
}
diff --git a/drivers/platform/x86/lenovo/Kconfig b/drivers/platform/x86/lenovo/Kconfig
index f885127b007f..09b1b055d2e0 100644
--- a/drivers/platform/x86/lenovo/Kconfig
+++ b/drivers/platform/x86/lenovo/Kconfig
@@ -252,7 +252,6 @@ config LENOVO_WMI_GAMEZONE
select ACPI_PLATFORM_PROFILE
select LENOVO_WMI_EVENTS
select LENOVO_WMI_HELPERS
- select LENOVO_WMI_TUNING
help
Say Y here if you have a WMI aware Lenovo Legion device and would like to use the
platform-profile firmware interface to manage power usage.
diff --git a/drivers/platform/x86/lenovo/wmi-capdata.c b/drivers/platform/x86/lenovo/wmi-capdata.c
index b73d378f0e8b..714aa6fd6f1f 100644
--- a/drivers/platform/x86/lenovo/wmi-capdata.c
+++ b/drivers/platform/x86/lenovo/wmi-capdata.c
@@ -27,7 +27,6 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/acpi.h>
-#include <linux/bitfield.h>
#include <linux/bug.h>
#include <linux/cleanup.h>
#include <linux/component.h>
@@ -48,6 +47,7 @@
#include <linux/wmi.h>
#include "wmi-capdata.h"
+#include "wmi-helpers.h"
#define LENOVO_CAPABILITY_DATA_00_GUID "362A3AFE-3D96-4665-8530-96DAD5BB300E"
#define LENOVO_CAPABILITY_DATA_01_GUID "7A8F5407-CB67-4D6E-B547-39B3BE018154"
@@ -57,9 +57,9 @@
#define LWMI_FEATURE_ID_FAN_TEST 0x05
-#define LWMI_ATTR_ID_FAN_TEST \
- (FIELD_PREP(LWMI_ATTR_DEV_ID_MASK, LWMI_DEVICE_ID_FAN) | \
- FIELD_PREP(LWMI_ATTR_FEAT_ID_MASK, LWMI_FEATURE_ID_FAN_TEST))
+#define LWMI_ATTR_ID_FAN_TEST \
+ lwmi_attr_id(LWMI_DEVICE_ID_FAN, LWMI_FEATURE_ID_FAN_TEST, \
+ LWMI_GZ_THERMAL_MODE_NONE, LWMI_TYPE_ID_NONE)
enum lwmi_cd_type {
LENOVO_CAPABILITY_DATA_00,
diff --git a/drivers/platform/x86/lenovo/wmi-capdata.h b/drivers/platform/x86/lenovo/wmi-capdata.h
index 8c1df3efcc55..c3e760b8c3c3 100644
--- a/drivers/platform/x86/lenovo/wmi-capdata.h
+++ b/drivers/platform/x86/lenovo/wmi-capdata.h
@@ -6,6 +6,7 @@
#define _LENOVO_WMI_CAPDATA_H_
#include <linux/bits.h>
+#include <linux/bitfield.h>
#include <linux/types.h>
#define LWMI_SUPP_VALID BIT(0)
@@ -19,6 +20,8 @@
#define LWMI_DEVICE_ID_FAN 0x04
+#define LWMI_TYPE_ID_NONE 0x00
+
struct component_match;
struct device;
struct cd_list;
@@ -57,6 +60,23 @@ struct lwmi_cd_binder {
cd_list_cb_t cd_fan_list_cb;
};
+/**
+ * lwmi_attr_id() - Formats a capability data attribute ID
+ * @dev_id: The u8 corresponding to the device ID.
+ * @feat_id: The u8 corresponding to the feature ID on the device.
+ * @mode_id: The u8 corresponding to the wmi-gamezone mode for set/get.
+ * @type_id: The u8 corresponding to the sub-device.
+ *
+ * Return: encoded capability data attribute ID.
+ */
+static inline u32 lwmi_attr_id(u8 dev_id, u8 feat_id, u8 mode_id, u8 type_id)
+{
+ return (FIELD_PREP(LWMI_ATTR_DEV_ID_MASK, dev_id) |
+ FIELD_PREP(LWMI_ATTR_FEAT_ID_MASK, feat_id) |
+ FIELD_PREP(LWMI_ATTR_MODE_ID_MASK, mode_id) |
+ FIELD_PREP(LWMI_ATTR_TYPE_ID_MASK, type_id));
+}
+
void lwmi_cd_match_add_all(struct device *master, struct component_match **matchptr);
int lwmi_cd00_get_data(struct cd_list *list, u32 attribute_id, struct capdata00 *output);
int lwmi_cd01_get_data(struct cd_list *list, u32 attribute_id, struct capdata01 *output);
diff --git a/drivers/platform/x86/lenovo/wmi-events.c b/drivers/platform/x86/lenovo/wmi-events.c
index 4a6a2c82413a..fc25bba68a7c 100644
--- a/drivers/platform/x86/lenovo/wmi-events.c
+++ b/drivers/platform/x86/lenovo/wmi-events.c
@@ -17,7 +17,7 @@
#include <linux/wmi.h>
#include "wmi-events.h"
-#include "wmi-gamezone.h"
+#include "wmi-helpers.h"
#define THERMAL_MODE_EVENT_GUID "D320289E-8FEA-41E0-86F9-911D83151B5F"
diff --git a/drivers/platform/x86/lenovo/wmi-gamezone.c b/drivers/platform/x86/lenovo/wmi-gamezone.c
index c7fe7e3c9f17..109c0b564a9f 100644
--- a/drivers/platform/x86/lenovo/wmi-gamezone.c
+++ b/drivers/platform/x86/lenovo/wmi-gamezone.c
@@ -21,9 +21,7 @@
#include <linux/wmi.h>
#include "wmi-events.h"
-#include "wmi-gamezone.h"
#include "wmi-helpers.h"
-#include "wmi-other.h"
#define LENOVO_GAMEZONE_GUID "887B54E3-DDDC-4B2C-8B88-68A26A8835D0"
@@ -201,7 +199,7 @@ static int lwmi_gz_profile_set(struct device *dev,
enum platform_profile_option profile)
{
struct lwmi_gz_priv *priv = dev_get_drvdata(dev);
- struct wmi_method_args_32 args;
+ struct wmi_method_args_32 args = {};
enum thermal_mode mode;
int ret;
@@ -383,7 +381,7 @@ static int lwmi_gz_probe(struct wmi_device *wdev, const void *context)
return ret;
priv->mode_nb.notifier_call = lwmi_gz_mode_call;
- return devm_lwmi_om_register_notifier(&wdev->dev, &priv->mode_nb);
+ return devm_lwmi_tm_register_notifier(&wdev->dev, &priv->mode_nb);
}
static const struct wmi_device_id lwmi_gz_id_table[] = {
@@ -405,7 +403,6 @@ module_wmi_driver(lwmi_gz_driver);
MODULE_IMPORT_NS("LENOVO_WMI_EVENTS");
MODULE_IMPORT_NS("LENOVO_WMI_HELPERS");
-MODULE_IMPORT_NS("LENOVO_WMI_OTHER");
MODULE_DEVICE_TABLE(wmi, lwmi_gz_id_table);
MODULE_AUTHOR("Derek J. Clark <derekjohn.clark@gmail.com>");
MODULE_DESCRIPTION("Lenovo GameZone WMI Driver");
diff --git a/drivers/platform/x86/lenovo/wmi-gamezone.h b/drivers/platform/x86/lenovo/wmi-gamezone.h
deleted file mode 100644
index 6b163a5eeb95..000000000000
--- a/drivers/platform/x86/lenovo/wmi-gamezone.h
+++ /dev/null
@@ -1,20 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-
-/* Copyright (C) 2025 Derek J. Clark <derekjohn.clark@gmail.com> */
-
-#ifndef _LENOVO_WMI_GAMEZONE_H_
-#define _LENOVO_WMI_GAMEZONE_H_
-
-enum gamezone_events_type {
- LWMI_GZ_GET_THERMAL_MODE = 1,
-};
-
-enum thermal_mode {
- LWMI_GZ_THERMAL_MODE_QUIET = 0x01,
- LWMI_GZ_THERMAL_MODE_BALANCED = 0x02,
- LWMI_GZ_THERMAL_MODE_PERFORMANCE = 0x03,
- LWMI_GZ_THERMAL_MODE_EXTREME = 0xE0, /* Ver 6+ */
- LWMI_GZ_THERMAL_MODE_CUSTOM = 0xFF,
-};
-
-#endif /* !_LENOVO_WMI_GAMEZONE_H_ */
diff --git a/drivers/platform/x86/lenovo/wmi-helpers.c b/drivers/platform/x86/lenovo/wmi-helpers.c
index 7379defac500..7a198259e393 100644
--- a/drivers/platform/x86/lenovo/wmi-helpers.c
+++ b/drivers/platform/x86/lenovo/wmi-helpers.c
@@ -21,11 +21,15 @@
#include <linux/errno.h>
#include <linux/export.h>
#include <linux/module.h>
+#include <linux/notifier.h>
#include <linux/unaligned.h>
#include <linux/wmi.h>
#include "wmi-helpers.h"
+/* Thermal mode notifier chain. */
+static BLOCKING_NOTIFIER_HEAD(tm_chain_head);
+
/**
* lwmi_dev_evaluate_int() - Helper function for calling WMI methods that
* return an integer.
@@ -46,7 +50,6 @@ int lwmi_dev_evaluate_int(struct wmi_device *wdev, u8 instance, u32 method_id,
unsigned char *buf, size_t size, u32 *retval)
{
struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
- union acpi_object *ret_obj __free(kfree) = NULL;
struct acpi_buffer input = { size, buf };
acpi_status status;
@@ -55,8 +58,9 @@ int lwmi_dev_evaluate_int(struct wmi_device *wdev, u8 instance, u32 method_id,
if (ACPI_FAILURE(status))
return -EIO;
+ union acpi_object *ret_obj __free(kfree) = output.pointer;
+
if (retval) {
- ret_obj = output.pointer;
if (!ret_obj)
return -ENODATA;
@@ -84,6 +88,103 @@ int lwmi_dev_evaluate_int(struct wmi_device *wdev, u8 instance, u32 method_id,
};
EXPORT_SYMBOL_NS_GPL(lwmi_dev_evaluate_int, "LENOVO_WMI_HELPERS");
+/**
+ * lwmi_tm_register_notifier() - Add a notifier to the blocking notifier chain
+ * @nb: The notifier_block struct to register
+ *
+ * Call blocking_notifier_chain_register to register the notifier block to the
+ * thermal mode notifier chain.
+ *
+ * Return: 0 on success, %-EEXIST on error.
+ */
+int lwmi_tm_register_notifier(struct notifier_block *nb)
+{
+ return blocking_notifier_chain_register(&tm_chain_head, nb);
+}
+EXPORT_SYMBOL_NS_GPL(lwmi_tm_register_notifier, "LENOVO_WMI_HELPERS");
+
+/**
+ * lwmi_tm_unregister_notifier() - Remove a notifier from the blocking notifier
+ * chain.
+ * @nb: The notifier_block struct to register
+ *
+ * Call blocking_notifier_chain_unregister to unregister the notifier block from the
+ * thermal mode notifier chain.
+ *
+ * Return: 0 on success, %-ENOENT on error.
+ */
+int lwmi_tm_unregister_notifier(struct notifier_block *nb)
+{
+ return blocking_notifier_chain_unregister(&tm_chain_head, nb);
+}
+EXPORT_SYMBOL_NS_GPL(lwmi_tm_unregister_notifier, "LENOVO_WMI_HELPERS");
+
+/**
+ * devm_lwmi_tm_unregister_notifier() - Remove a notifier from the blocking
+ * notifier chain.
+ * @data: Void pointer to the notifier_block struct to register.
+ *
+ * Call lwmi_tm_unregister_notifier to unregister the notifier block from the
+ * thermal mode notifier chain.
+ *
+ * Return: 0 on success, %-ENOENT on error.
+ */
+static void devm_lwmi_tm_unregister_notifier(void *data)
+{
+ struct notifier_block *nb = data;
+
+ lwmi_tm_unregister_notifier(nb);
+}
+
+/**
+ * devm_lwmi_tm_register_notifier() - Add a notifier to the blocking notifier
+ * chain.
+ * @dev: The parent device of the notifier_block struct.
+ * @nb: The notifier_block struct to register
+ *
+ * Call lwmi_tm_register_notifier to register the notifier block to the
+ * thermal mode notifier chain. Then add devm_lwmi_tm_unregister_notifier
+ * as a device managed action to automatically unregister the notifier block
+ * upon parent device removal.
+ *
+ * Return: 0 on success, or an error code.
+ */
+int devm_lwmi_tm_register_notifier(struct device *dev,
+ struct notifier_block *nb)
+{
+ int ret;
+
+ ret = lwmi_tm_register_notifier(nb);
+ if (ret < 0)
+ return ret;
+
+ return devm_add_action_or_reset(dev, devm_lwmi_tm_unregister_notifier,
+ nb);
+}
+EXPORT_SYMBOL_NS_GPL(devm_lwmi_tm_register_notifier, "LENOVO_WMI_HELPERS");
+
+/**
+ * lwmi_tm_notifier_call() - Call functions for the notifier call chain.
+ * @mode: Pointer to a thermal mode enum to retrieve the data from.
+ *
+ * Call blocking_notifier_call_chain to retrieve the thermal mode from the
+ * lenovo-wmi-gamezone driver.
+ *
+ * Return: 0 on success, or an error code.
+ */
+int lwmi_tm_notifier_call(enum thermal_mode *mode)
+{
+ int ret;
+
+ ret = blocking_notifier_call_chain(&tm_chain_head,
+ LWMI_GZ_GET_THERMAL_MODE, &mode);
+ if ((ret & ~NOTIFY_STOP_MASK) != NOTIFY_OK)
+ return -EINVAL;
+
+ return 0;
+}
+EXPORT_SYMBOL_NS_GPL(lwmi_tm_notifier_call, "LENOVO_WMI_HELPERS");
+
MODULE_AUTHOR("Derek J. Clark <derekjohn.clark@gmail.com>");
MODULE_DESCRIPTION("Lenovo WMI Helpers Driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/platform/x86/lenovo/wmi-helpers.h b/drivers/platform/x86/lenovo/wmi-helpers.h
index 20fd21749803..ed7db3ebba6c 100644
--- a/drivers/platform/x86/lenovo/wmi-helpers.h
+++ b/drivers/platform/x86/lenovo/wmi-helpers.h
@@ -7,6 +7,8 @@
#include <linux/types.h>
+struct device;
+struct notifier_block;
struct wmi_device;
struct wmi_method_args_32 {
@@ -14,7 +16,26 @@ struct wmi_method_args_32 {
u32 arg1;
};
+enum lwmi_event_type {
+ LWMI_GZ_GET_THERMAL_MODE = 0x01,
+};
+
+enum thermal_mode {
+ LWMI_GZ_THERMAL_MODE_NONE = 0x00,
+ LWMI_GZ_THERMAL_MODE_QUIET = 0x01,
+ LWMI_GZ_THERMAL_MODE_BALANCED = 0x02,
+ LWMI_GZ_THERMAL_MODE_PERFORMANCE = 0x03,
+ LWMI_GZ_THERMAL_MODE_EXTREME = 0xE0, /* Ver 6+ */
+ LWMI_GZ_THERMAL_MODE_CUSTOM = 0xFF,
+};
+
int lwmi_dev_evaluate_int(struct wmi_device *wdev, u8 instance, u32 method_id,
unsigned char *buf, size_t size, u32 *retval);
+int lwmi_tm_register_notifier(struct notifier_block *nb);
+int lwmi_tm_unregister_notifier(struct notifier_block *nb);
+int devm_lwmi_tm_register_notifier(struct device *dev,
+ struct notifier_block *nb);
+int lwmi_tm_notifier_call(enum thermal_mode *mode);
+
#endif /* !_LENOVO_WMI_HELPERS_H_ */
diff --git a/drivers/platform/x86/lenovo/wmi-other.c b/drivers/platform/x86/lenovo/wmi-other.c
index 6040f45aa2b0..d318ba432fdc 100644
--- a/drivers/platform/x86/lenovo/wmi-other.c
+++ b/drivers/platform/x86/lenovo/wmi-other.c
@@ -40,16 +40,13 @@
#include <linux/kobject.h>
#include <linux/limits.h>
#include <linux/module.h>
-#include <linux/notifier.h>
#include <linux/platform_profile.h>
#include <linux/types.h>
#include <linux/wmi.h>
#include "wmi-capdata.h"
#include "wmi-events.h"
-#include "wmi-gamezone.h"
#include "wmi-helpers.h"
-#include "wmi-other.h"
#include "../firmware_attributes_class.h"
#define LENOVO_OTHER_MODE_GUID "DC2A8805-3A8C-41BA-A6F7-092E0089CD3B"
@@ -62,8 +59,6 @@
#define LWMI_FEATURE_ID_FAN_RPM 0x03
-#define LWMI_TYPE_ID_NONE 0x00
-
#define LWMI_FEATURE_VALUE_GET 17
#define LWMI_FEATURE_VALUE_SET 18
@@ -71,17 +66,15 @@
#define LWMI_FAN_NR 4
#define LWMI_FAN_ID(x) ((x) + LWMI_FAN_ID_BASE)
-#define LWMI_ATTR_ID_FAN_RPM(x) \
- (FIELD_PREP(LWMI_ATTR_DEV_ID_MASK, LWMI_DEVICE_ID_FAN) | \
- FIELD_PREP(LWMI_ATTR_FEAT_ID_MASK, LWMI_FEATURE_ID_FAN_RPM) | \
- FIELD_PREP(LWMI_ATTR_TYPE_ID_MASK, LWMI_FAN_ID(x)))
-
#define LWMI_FAN_DIV 100
+#define LWMI_ATTR_ID_FAN_RPM(x) \
+ lwmi_attr_id(LWMI_DEVICE_ID_FAN, LWMI_FEATURE_ID_FAN_RPM, \
+ LWMI_GZ_THERMAL_MODE_NONE, LWMI_FAN_ID(x))
+
#define LWMI_OM_FW_ATTR_BASE_PATH "lenovo-wmi-other"
#define LWMI_OM_HWMON_NAME "lenovo_wmi_other"
-static BLOCKING_NOTIFIER_HEAD(om_chain_head);
static DEFINE_IDA(lwmi_om_ida);
enum attribute_property {
@@ -109,7 +102,6 @@ struct lwmi_om_priv {
struct device *hwmon_dev;
struct device *fw_attr_dev;
struct kset *fw_attr_kset;
- struct notifier_block nb;
struct wmi_device *wdev;
int ida_id;
@@ -166,7 +158,7 @@ MODULE_PARM_DESC(relax_fan_constraint,
*/
static int lwmi_om_fan_get_set(struct lwmi_om_priv *priv, int channel, u32 *val, bool set)
{
- struct wmi_method_args_32 args;
+ struct wmi_method_args_32 args = {};
u32 method_id, retval;
int err;
@@ -349,6 +341,8 @@ static int lwmi_om_hwmon_write(struct device *dev, enum hwmon_sensor_types type,
*/
if (!relax_fan_constraint)
raw = val / LWMI_FAN_DIV * LWMI_FAN_DIV;
+ else
+ raw = val;
err = lwmi_om_fan_get_set(priv, channel, &raw, true);
if (err)
@@ -546,13 +540,26 @@ out:
/* ======== fw_attributes (component: lenovo-wmi-capdata 01) ======== */
struct tunable_attr_01 {
- struct capdata01 *capdata;
struct device *dev;
- u32 feature_id;
- u32 device_id;
- u32 type_id;
+ u8 feature_id;
+ u8 device_id;
+ u8 type_id;
+ u8 cd_mode_id; /* mode arg for searching capdata */
+ u8 cv_mode_id; /* mode arg for set/get current_value */
};
+/**
+ * tunable_attr_01_id() - Formats a tunable_attr_01 to a capdata attribute ID
+ * @attr: The tunable_attr_01 to format.
+ * @mode: The u8 corresponding to the wmi-gamezone mode for set/get.
+ *
+ * Return: encoded capability data attribute ID.
+ */
+static u32 tunable_attr_01_id(struct tunable_attr_01 *attr, u8 mode)
+{
+ return lwmi_attr_id(attr->device_id, attr->feature_id, mode, attr->type_id);
+}
+
static struct tunable_attr_01 ppt_pl1_spl = {
.device_id = LWMI_DEVICE_ID_CPU,
.feature_id = LWMI_FEATURE_ID_CPU_SPL,
@@ -576,102 +583,6 @@ struct capdata01_attr_group {
struct tunable_attr_01 *tunable_attr;
};
-/**
- * lwmi_om_register_notifier() - Add a notifier to the blocking notifier chain
- * @nb: The notifier_block struct to register
- *
- * Call blocking_notifier_chain_register to register the notifier block to the
- * lenovo-wmi-other driver notifier chain.
- *
- * Return: 0 on success, %-EEXIST on error.
- */
-int lwmi_om_register_notifier(struct notifier_block *nb)
-{
- return blocking_notifier_chain_register(&om_chain_head, nb);
-}
-EXPORT_SYMBOL_NS_GPL(lwmi_om_register_notifier, "LENOVO_WMI_OTHER");
-
-/**
- * lwmi_om_unregister_notifier() - Remove a notifier from the blocking notifier
- * chain.
- * @nb: The notifier_block struct to register
- *
- * Call blocking_notifier_chain_unregister to unregister the notifier block from the
- * lenovo-wmi-other driver notifier chain.
- *
- * Return: 0 on success, %-ENOENT on error.
- */
-int lwmi_om_unregister_notifier(struct notifier_block *nb)
-{
- return blocking_notifier_chain_unregister(&om_chain_head, nb);
-}
-EXPORT_SYMBOL_NS_GPL(lwmi_om_unregister_notifier, "LENOVO_WMI_OTHER");
-
-/**
- * devm_lwmi_om_unregister_notifier() - Remove a notifier from the blocking
- * notifier chain.
- * @data: Void pointer to the notifier_block struct to register.
- *
- * Call lwmi_om_unregister_notifier to unregister the notifier block from the
- * lenovo-wmi-other driver notifier chain.
- *
- * Return: 0 on success, %-ENOENT on error.
- */
-static void devm_lwmi_om_unregister_notifier(void *data)
-{
- struct notifier_block *nb = data;
-
- lwmi_om_unregister_notifier(nb);
-}
-
-/**
- * devm_lwmi_om_register_notifier() - Add a notifier to the blocking notifier
- * chain.
- * @dev: The parent device of the notifier_block struct.
- * @nb: The notifier_block struct to register
- *
- * Call lwmi_om_register_notifier to register the notifier block to the
- * lenovo-wmi-other driver notifier chain. Then add devm_lwmi_om_unregister_notifier
- * as a device managed action to automatically unregister the notifier block
- * upon parent device removal.
- *
- * Return: 0 on success, or an error code.
- */
-int devm_lwmi_om_register_notifier(struct device *dev,
- struct notifier_block *nb)
-{
- int ret;
-
- ret = lwmi_om_register_notifier(nb);
- if (ret < 0)
- return ret;
-
- return devm_add_action_or_reset(dev, devm_lwmi_om_unregister_notifier,
- nb);
-}
-EXPORT_SYMBOL_NS_GPL(devm_lwmi_om_register_notifier, "LENOVO_WMI_OTHER");
-
-/**
- * lwmi_om_notifier_call() - Call functions for the notifier call chain.
- * @mode: Pointer to a thermal mode enum to retrieve the data from.
- *
- * Call blocking_notifier_call_chain to retrieve the thermal mode from the
- * lenovo-wmi-gamezone driver.
- *
- * Return: 0 on success, or an error code.
- */
-static int lwmi_om_notifier_call(enum thermal_mode *mode)
-{
- int ret;
-
- ret = blocking_notifier_call_chain(&om_chain_head,
- LWMI_GZ_GET_THERMAL_MODE, &mode);
- if ((ret & ~NOTIFY_STOP_MASK) != NOTIFY_OK)
- return -EINVAL;
-
- return 0;
-}
-
/* Attribute Methods */
/**
@@ -716,12 +627,7 @@ static ssize_t attr_capdata01_show(struct kobject *kobj,
u32 attribute_id;
int value, ret;
- attribute_id =
- FIELD_PREP(LWMI_ATTR_DEV_ID_MASK, tunable_attr->device_id) |
- FIELD_PREP(LWMI_ATTR_FEAT_ID_MASK, tunable_attr->feature_id) |
- FIELD_PREP(LWMI_ATTR_MODE_ID_MASK,
- LWMI_GZ_THERMAL_MODE_CUSTOM) |
- FIELD_PREP(LWMI_ATTR_TYPE_ID_MASK, tunable_attr->type_id);
+ attribute_id = tunable_attr_01_id(tunable_attr, tunable_attr->cd_mode_id);
ret = lwmi_cd01_get_data(priv->cd01_list, attribute_id, &capdata);
if (ret)
@@ -773,27 +679,22 @@ static ssize_t attr_current_value_store(struct kobject *kobj,
struct tunable_attr_01 *tunable_attr)
{
struct lwmi_om_priv *priv = dev_get_drvdata(tunable_attr->dev);
- struct wmi_method_args_32 args;
+ struct wmi_method_args_32 args = {};
struct capdata01 capdata;
enum thermal_mode mode;
- u32 attribute_id;
u32 value;
int ret;
- ret = lwmi_om_notifier_call(&mode);
+ ret = lwmi_tm_notifier_call(&mode);
if (ret)
return ret;
if (mode != LWMI_GZ_THERMAL_MODE_CUSTOM)
return -EBUSY;
- attribute_id =
- FIELD_PREP(LWMI_ATTR_DEV_ID_MASK, tunable_attr->device_id) |
- FIELD_PREP(LWMI_ATTR_FEAT_ID_MASK, tunable_attr->feature_id) |
- FIELD_PREP(LWMI_ATTR_MODE_ID_MASK, mode) |
- FIELD_PREP(LWMI_ATTR_TYPE_ID_MASK, tunable_attr->type_id);
+ args.arg0 = tunable_attr_01_id(tunable_attr, tunable_attr->cd_mode_id);
- ret = lwmi_cd01_get_data(priv->cd01_list, attribute_id, &capdata);
+ ret = lwmi_cd01_get_data(priv->cd01_list, args.arg0, &capdata);
if (ret)
return ret;
@@ -804,7 +705,7 @@ static ssize_t attr_current_value_store(struct kobject *kobj,
if (value < capdata.min_value || value > capdata.max_value)
return -EINVAL;
- args.arg0 = attribute_id;
+ args.arg0 = tunable_attr_01_id(tunable_attr, tunable_attr->cv_mode_id);
args.arg1 = value;
ret = lwmi_dev_evaluate_int(priv->wdev, 0x0, LWMI_FEATURE_VALUE_SET,
@@ -836,23 +737,20 @@ static ssize_t attr_current_value_show(struct kobject *kobj,
struct tunable_attr_01 *tunable_attr)
{
struct lwmi_om_priv *priv = dev_get_drvdata(tunable_attr->dev);
- struct wmi_method_args_32 args;
+ struct wmi_method_args_32 args = {};
enum thermal_mode mode;
- u32 attribute_id;
int retval;
int ret;
- ret = lwmi_om_notifier_call(&mode);
+ ret = lwmi_tm_notifier_call(&mode);
if (ret)
return ret;
- attribute_id =
- FIELD_PREP(LWMI_ATTR_DEV_ID_MASK, tunable_attr->device_id) |
- FIELD_PREP(LWMI_ATTR_FEAT_ID_MASK, tunable_attr->feature_id) |
- FIELD_PREP(LWMI_ATTR_MODE_ID_MASK, mode) |
- FIELD_PREP(LWMI_ATTR_TYPE_ID_MASK, tunable_attr->type_id);
+ /* If "no-mode" is the supported mode, ensure we never send current mode */
+ if (tunable_attr->cv_mode_id == LWMI_GZ_THERMAL_MODE_NONE)
+ mode = tunable_attr->cv_mode_id;
- args.arg0 = attribute_id;
+ args.arg0 = tunable_attr_01_id(tunable_attr, mode);
ret = lwmi_dev_evaluate_int(priv->wdev, 0x0, LWMI_FEATURE_VALUE_GET,
(unsigned char *)&args, sizeof(args),
@@ -863,6 +761,81 @@ static ssize_t attr_current_value_show(struct kobject *kobj,
return sysfs_emit(buf, "%d\n", retval);
}
+/**
+ * lwmi_attr_01_is_supported() - Determine if the given attribute is supported.
+ * @tunable_attr: The attribute to verify.
+ *
+ * For an attribute to be supported it must have a functional get/set method,
+ * as well as associated capability data stored in the capdata01 table.
+ *
+ * First check if the attribute has a corresponding data table under custom mode
+ * (0xff), then under no mode (0x00). If either of those passes, check if the
+ * supported field of the capdata struct is > 0. If it is supported, store the
+ * successful mode in the cd_mode_id field of tunable_attr.
+ *
+ * If the attribute capdata shows it is supported, attempt to determine the mode
+ * for the current value property get/set methods using a similar pattern to the
+ * capdata table check. If the value returned by either mode is 0 or an error,
+ * assume that mode is not supported. Otherwise, store the successful mode in the
+ * cv_mode_id field of tunable_attr.
+ *
+ * If any of the above checks fail then the attribute is not fully supported.
+ *
+ * Return: true if capdata and set/get modes are found, otherwise false.
+ */
+static bool lwmi_attr_01_is_supported(struct tunable_attr_01 *tunable_attr)
+{
+ u8 modes[2] = { LWMI_GZ_THERMAL_MODE_CUSTOM, LWMI_GZ_THERMAL_MODE_NONE };
+ struct lwmi_om_priv *priv = dev_get_drvdata(tunable_attr->dev);
+ struct wmi_method_args_32 args = {};
+ bool cd_mode_found = false;
+ bool cv_mode_found = false;
+ struct capdata01 capdata;
+ int retval, ret, i;
+
+ /* Determine tunable_attr->cd_mode_id */
+ for (i = 0; i < ARRAY_SIZE(modes); i++) {
+ args.arg0 = tunable_attr_01_id(tunable_attr, modes[i]);
+
+ ret = lwmi_cd01_get_data(priv->cd01_list, args.arg0, &capdata);
+ if (ret || !capdata.supported)
+ continue;
+
+ tunable_attr->cd_mode_id = modes[i];
+ cd_mode_found = true;
+ break;
+ }
+
+ if (!cd_mode_found)
+ return cd_mode_found;
+
+ dev_dbg(tunable_attr->dev,
+ "cd_mode_id: %#010x\n", args.arg0);
+
+ /* Determine tunable_attr->cv_mode_id, returns 1 if supported */
+ for (i = 0; i < ARRAY_SIZE(modes); i++) {
+ args.arg0 = tunable_attr_01_id(tunable_attr, modes[i]);
+
+ ret = lwmi_dev_evaluate_int(priv->wdev, 0x0, LWMI_FEATURE_VALUE_GET,
+ (u8 *)&args, sizeof(args),
+ &retval);
+ if (ret || !retval)
+ continue;
+
+ tunable_attr->cv_mode_id = modes[i];
+ cv_mode_found = true;
+ break;
+ }
+
+ if (!cv_mode_found)
+ return cv_mode_found;
+
+ dev_dbg(tunable_attr->dev, "cv_mode_id: %#010x, attribute support level: %#010x\n",
+ args.arg0, capdata.supported);
+
+ return capdata.supported > 0;
+}
+
/* Lenovo WMI Other Mode Attribute macros */
#define __LWMI_ATTR_RO(_func, _name) \
{ \
@@ -957,17 +930,17 @@ static struct capdata01_attr_group cd01_attr_groups[] = {
/**
* lwmi_om_fw_attr_add() - Register all firmware_attributes_class members
* @priv: The Other Mode driver data.
- *
- * Return: Either 0, or an error code.
*/
-static int lwmi_om_fw_attr_add(struct lwmi_om_priv *priv)
+static void lwmi_om_fw_attr_add(struct lwmi_om_priv *priv)
{
unsigned int i;
int err;
- priv->ida_id = ida_alloc(&lwmi_om_ida, GFP_KERNEL);
- if (priv->ida_id < 0)
- return priv->ida_id;
+ err = ida_alloc(&lwmi_om_ida, GFP_KERNEL);
+ if (err < 0)
+ goto err_no_ida;
+
+ priv->ida_id = err;
priv->fw_attr_dev = device_create(&firmware_attributes_class, NULL,
MKDEV(0, 0), NULL, "%s-%u",
@@ -986,14 +959,16 @@ static int lwmi_om_fw_attr_add(struct lwmi_om_priv *priv)
}
for (i = 0; i < ARRAY_SIZE(cd01_attr_groups) - 1; i++) {
+ cd01_attr_groups[i].tunable_attr->dev = &priv->wdev->dev;
+ if (!lwmi_attr_01_is_supported(cd01_attr_groups[i].tunable_attr))
+ continue;
+
err = sysfs_create_group(&priv->fw_attr_kset->kobj,
cd01_attr_groups[i].attr_group);
if (err)
goto err_remove_groups;
-
- cd01_attr_groups[i].tunable_attr->dev = &priv->wdev->dev;
}
- return 0;
+ return;
err_remove_groups:
while (i--)
@@ -1007,7 +982,12 @@ err_destroy_classdev:
err_free_ida:
ida_free(&lwmi_om_ida, priv->ida_id);
- return err;
+
+err_no_ida:
+ priv->ida_id = -EIDRM;
+
+ dev_warn(&priv->wdev->dev,
+ "failed to register firmware-attributes device: %d\n", err);
}
/**
@@ -1016,12 +996,17 @@ err_free_ida:
*/
static void lwmi_om_fw_attr_remove(struct lwmi_om_priv *priv)
{
+ if (priv->ida_id < 0)
+ return;
+
for (unsigned int i = 0; i < ARRAY_SIZE(cd01_attr_groups) - 1; i++)
sysfs_remove_group(&priv->fw_attr_kset->kobj,
cd01_attr_groups[i].attr_group);
kset_unregister(priv->fw_attr_kset);
device_unregister(priv->fw_attr_dev);
+ ida_free(&lwmi_om_ida, priv->ida_id);
+ priv->ida_id = -EIDRM;
}
/* ======== Self (master: lenovo-wmi-other) ======== */
@@ -1058,12 +1043,17 @@ static int lwmi_om_master_bind(struct device *dev)
priv->cd00_list = binder.cd00_list;
priv->cd01_list = binder.cd01_list;
- if (!priv->cd00_list || !priv->cd01_list)
+ if (!priv->cd00_list || !priv->cd01_list) {
+ component_unbind_all(dev, NULL);
+
return -ENODEV;
+ }
lwmi_om_fan_info_collect_cd00(priv);
- return lwmi_om_fw_attr_add(priv);
+ lwmi_om_fw_attr_add(priv);
+
+ return 0;
}
/**
@@ -1115,13 +1105,7 @@ static int lwmi_other_probe(struct wmi_device *wdev, const void *context)
static void lwmi_other_remove(struct wmi_device *wdev)
{
- struct lwmi_om_priv *priv = dev_get_drvdata(&wdev->dev);
-
component_master_del(&wdev->dev, &lwmi_om_master_ops);
-
- /* No IDA to free if the driver is never bound to its components. */
- if (priv->ida_id >= 0)
- ida_free(&lwmi_om_ida, priv->ida_id);
}
static const struct wmi_device_id lwmi_other_id_table[] = {
diff --git a/drivers/platform/x86/lenovo/wmi-other.h b/drivers/platform/x86/lenovo/wmi-other.h
deleted file mode 100644
index 8ebf5602bb99..000000000000
--- a/drivers/platform/x86/lenovo/wmi-other.h
+++ /dev/null
@@ -1,16 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-
-/* Copyright (C) 2025 Derek J. Clark <derekjohn.clark@gmail.com> */
-
-#ifndef _LENOVO_WMI_OTHER_H_
-#define _LENOVO_WMI_OTHER_H_
-
-struct device;
-struct notifier_block;
-
-int lwmi_om_register_notifier(struct notifier_block *nb);
-int lwmi_om_unregister_notifier(struct notifier_block *nb);
-int devm_lwmi_om_register_notifier(struct device *dev,
- struct notifier_block *nb);
-
-#endif /* !_LENOVO_WMI_OTHER_H_ */
diff --git a/drivers/platform/x86/lg-laptop.c b/drivers/platform/x86/lg-laptop.c
index 9681412d694b..a8f2f465ef3f 100644
--- a/drivers/platform/x86/lg-laptop.c
+++ b/drivers/platform/x86/lg-laptop.c
@@ -761,12 +761,11 @@ static void lg_laptop_remove_address_space_handler(void *data)
static int acpi_probe(struct platform_device *pdev)
{
- struct acpi_device *device = ACPI_COMPANION(&pdev->dev);
struct platform_device_info pdev_info = {
- .fwnode = acpi_fwnode_handle(device),
.name = PLATFORM_NAME,
.id = PLATFORM_DEVID_NONE,
};
+ struct acpi_device *device;
acpi_status status;
int ret;
const char *product;
@@ -775,6 +774,12 @@ static int acpi_probe(struct platform_device *pdev)
if (pf_device)
return 0;
+ device = ACPI_COMPANION(&pdev->dev);
+ if (!device)
+ return -ENODEV;
+
+ pdev_info.fwnode = acpi_fwnode_handle(device),
+
status = acpi_install_address_space_handler(device->handle, LG_ADDRESS_SPACE_ID,
&lg_laptop_address_space_handler,
NULL, &pdev->dev);
diff --git a/drivers/platform/x86/panasonic-laptop.c b/drivers/platform/x86/panasonic-laptop.c
index 1337f7c49805..b83113c26f88 100644
--- a/drivers/platform/x86/panasonic-laptop.c
+++ b/drivers/platform/x86/panasonic-laptop.c
@@ -981,11 +981,15 @@ static int acpi_pcc_hotkey_resume(struct device *dev)
static int acpi_pcc_hotkey_probe(struct platform_device *pdev)
{
- struct acpi_device *device = ACPI_COMPANION(&pdev->dev);
struct backlight_properties props;
+ struct acpi_device *device;
struct pcc_acpi *pcc;
int num_sifr, result;
+ device = ACPI_COMPANION(&pdev->dev);
+ if (!device)
+ return -ENODEV;
+
num_sifr = acpi_pcc_get_sqty(device);
/*
diff --git a/drivers/platform/x86/samsung-galaxybook.c b/drivers/platform/x86/samsung-galaxybook.c
index 755cb82bdb60..6382af0b106c 100644
--- a/drivers/platform/x86/samsung-galaxybook.c
+++ b/drivers/platform/x86/samsung-galaxybook.c
@@ -53,7 +53,7 @@ struct samsung_galaxybook {
void *i8042_filter_ptr;
struct work_struct block_recording_hotkey_work;
- struct input_dev *camera_lens_cover_switch;
+ struct input_dev *input;
struct acpi_battery_hook battery_hook;
@@ -197,6 +197,9 @@ static const guid_t performance_mode_guid =
#define GB_ACPI_NOTIFY_DEVICE_ON_TABLE 0x6c
#define GB_ACPI_NOTIFY_DEVICE_OFF_TABLE 0x6d
#define GB_ACPI_NOTIFY_HOTKEY_PERFORMANCE_MODE 0x70
+#define GB_ACPI_NOTIFY_HOTKEY_KBD_BACKLIGHT 0x7d
+#define GB_ACPI_NOTIFY_HOTKEY_MICMUTE 0x6e
+#define GB_ACPI_NOTIFY_HOTKEY_CAMERA 0x6f
#define GB_KEY_KBD_BACKLIGHT_KEYDOWN 0x2c
#define GB_KEY_KBD_BACKLIGHT_KEYUP 0xac
@@ -859,13 +862,29 @@ static int block_recording_acpi_set(struct samsung_galaxybook *galaxybook, const
if (err)
return err;
- input_report_switch(galaxybook->camera_lens_cover_switch,
+ input_report_switch(galaxybook->input,
SW_CAMERA_LENS_COVER, value ? 1 : 0);
- input_sync(galaxybook->camera_lens_cover_switch);
+ input_sync(galaxybook->input);
return 0;
}
+static int galaxybook_input_init(struct samsung_galaxybook *galaxybook)
+{
+ galaxybook->input = devm_input_allocate_device(&galaxybook->platform->dev);
+ if (!galaxybook->input)
+ return -ENOMEM;
+
+ galaxybook->input->name = "Samsung Galaxy Book Camera Lens Cover";
+ galaxybook->input->phys = DRIVER_NAME "/input0";
+ galaxybook->input->id.bustype = BUS_HOST;
+
+ input_set_capability(galaxybook->input, EV_KEY, KEY_MICMUTE);
+ input_set_capability(galaxybook->input, EV_SW, SW_CAMERA_LENS_COVER);
+
+ return input_register_device(galaxybook->input);
+}
+
static int galaxybook_block_recording_init(struct samsung_galaxybook *galaxybook)
{
bool value;
@@ -887,24 +906,8 @@ static int galaxybook_block_recording_init(struct samsung_galaxybook *galaxybook
return GB_NOT_SUPPORTED;
}
- galaxybook->camera_lens_cover_switch =
- devm_input_allocate_device(&galaxybook->platform->dev);
- if (!galaxybook->camera_lens_cover_switch)
- return -ENOMEM;
-
- galaxybook->camera_lens_cover_switch->name = "Samsung Galaxy Book Camera Lens Cover";
- galaxybook->camera_lens_cover_switch->phys = DRIVER_NAME "/input0";
- galaxybook->camera_lens_cover_switch->id.bustype = BUS_HOST;
-
- input_set_capability(galaxybook->camera_lens_cover_switch, EV_SW, SW_CAMERA_LENS_COVER);
-
- err = input_register_device(galaxybook->camera_lens_cover_switch);
- if (err)
- return err;
-
- input_report_switch(galaxybook->camera_lens_cover_switch,
- SW_CAMERA_LENS_COVER, value ? 1 : 0);
- input_sync(galaxybook->camera_lens_cover_switch);
+ input_report_switch(galaxybook->input, SW_CAMERA_LENS_COVER, value ? 1 : 0);
+ input_sync(galaxybook->input);
return 0;
}
@@ -1260,6 +1263,25 @@ static void galaxybook_acpi_notify(acpi_handle handle, u32 event, void *data)
if (galaxybook->has_performance_mode)
platform_profile_cycle();
break;
+ case GB_ACPI_NOTIFY_HOTKEY_KBD_BACKLIGHT:
+ if (galaxybook->has_kbd_backlight)
+ schedule_work(&galaxybook->kbd_backlight_hotkey_work);
+ break;
+ case GB_ACPI_NOTIFY_HOTKEY_MICMUTE:
+ input_report_key(galaxybook->input, KEY_MICMUTE, 1);
+ input_sync(galaxybook->input);
+ input_report_key(galaxybook->input, KEY_MICMUTE, 0);
+ input_sync(galaxybook->input);
+ break;
+ case GB_ACPI_NOTIFY_HOTKEY_CAMERA:
+ if (galaxybook->has_block_recording) {
+ schedule_work(&galaxybook->block_recording_hotkey_work);
+ } else {
+ input_report_switch(galaxybook->input, SW_CAMERA_LENS_COVER,
+ !test_bit(SW_CAMERA_LENS_COVER, galaxybook->input->sw));
+ input_sync(galaxybook->input);
+ }
+ break;
default:
dev_warn(&galaxybook->platform->dev,
"unknown ACPI notification event: 0x%x\n", event);
@@ -1392,6 +1414,11 @@ static int galaxybook_probe(struct platform_device *pdev)
return dev_err_probe(&galaxybook->platform->dev, err,
"failed to initialize kbd_backlight\n");
+ err = galaxybook_input_init(galaxybook);
+ if (err)
+ return dev_err_probe(&galaxybook->platform->dev, err,
+ "failed to initialize input device\n");
+
err = galaxybook_fw_attrs_init(galaxybook);
if (err)
return dev_err_probe(&galaxybook->platform->dev, err,
diff --git a/drivers/platform/x86/sony-laptop.c b/drivers/platform/x86/sony-laptop.c
index b18f00e9082f..67370967df6f 100644
--- a/drivers/platform/x86/sony-laptop.c
+++ b/drivers/platform/x86/sony-laptop.c
@@ -3147,11 +3147,15 @@ static void sony_nc_backlight_cleanup(void)
static int sony_nc_probe(struct platform_device *pdev)
{
- struct acpi_device *device = ACPI_COMPANION(&pdev->dev);
+ struct acpi_device *device;
acpi_status status;
int result = 0;
struct sony_nc_value *item;
+ device = ACPI_COMPANION(&pdev->dev);
+ if (!device)
+ return -ENODEV;
+
sony_nc_acpi_device = device;
strscpy(acpi_device_class(device), "sony/hotkey");
@@ -4509,11 +4513,15 @@ static void sony_pic_remove(struct platform_device *pdev)
static int sony_pic_probe(struct platform_device *pdev)
{
- struct acpi_device *device = ACPI_COMPANION(&pdev->dev);
struct sony_pic_ioport *io, *tmp_io;
struct sony_pic_irq *irq, *tmp_irq;
+ struct acpi_device *device;
int result;
+ device = ACPI_COMPANION(&pdev->dev);
+ if (!device)
+ return -ENODEV;
+
spic_dev.acpi_dev = device;
strscpy(acpi_device_class(device), "sony/hotkey");
sony_pic_detect_device_type(&spic_dev);
diff --git a/drivers/platform/x86/system76_acpi.c b/drivers/platform/x86/system76_acpi.c
index 693cbb461382..dd7b1b07c316 100644
--- a/drivers/platform/x86/system76_acpi.c
+++ b/drivers/platform/x86/system76_acpi.c
@@ -674,10 +674,14 @@ static void system76_notify(acpi_handle handle, u32 event, void *context)
// Probe a System76 platform device
static int system76_probe(struct platform_device *pdev)
{
- struct acpi_device *acpi_dev = ACPI_COMPANION(&pdev->dev);
+ struct acpi_device *acpi_dev;
struct system76_data *data;
int err;
+ acpi_dev = ACPI_COMPANION(&pdev->dev);
+ if (!acpi_dev)
+ return -ENODEV;
+
data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
if (!data)
return -ENOMEM;
diff --git a/drivers/platform/x86/toshiba_acpi.c b/drivers/platform/x86/toshiba_acpi.c
index 35d899c01740..7cecb3a70b9c 100644
--- a/drivers/platform/x86/toshiba_acpi.c
+++ b/drivers/platform/x86/toshiba_acpi.c
@@ -3374,7 +3374,7 @@ static const struct dmi_system_id toshiba_dmi_quirks[] __initconst = {
static int toshiba_acpi_probe(struct platform_device *pdev)
{
- struct acpi_device *acpi_dev = ACPI_COMPANION(&pdev->dev);
+ struct acpi_device *acpi_dev;
struct toshiba_acpi_dev *dev;
const char *hci_method;
u32 dummy;
@@ -3383,6 +3383,10 @@ static int toshiba_acpi_probe(struct platform_device *pdev)
if (toshiba_acpi)
return -EBUSY;
+ acpi_dev = ACPI_COMPANION(&pdev->dev);
+ if (!acpi_dev)
+ return -ENODEV;
+
pr_info("Toshiba Laptop ACPI Extras version %s\n",
TOSHIBA_ACPI_VERSION);
diff --git a/drivers/platform/x86/toshiba_bluetooth.c b/drivers/platform/x86/toshiba_bluetooth.c
index e50d4fc1e603..e00abba58c7c 100644
--- a/drivers/platform/x86/toshiba_bluetooth.c
+++ b/drivers/platform/x86/toshiba_bluetooth.c
@@ -230,10 +230,14 @@ static int toshiba_bt_resume(struct device *dev)
static int toshiba_bt_rfkill_probe(struct platform_device *pdev)
{
- struct acpi_device *device = ACPI_COMPANION(&pdev->dev);
struct toshiba_bluetooth_dev *bt_dev;
+ struct acpi_device *device;
int result;
+ device = ACPI_COMPANION(&pdev->dev);
+ if (!device)
+ return -ENODEV;
+
result = toshiba_bluetooth_present(device->handle);
if (result)
return result;
diff --git a/drivers/platform/x86/toshiba_haps.c b/drivers/platform/x86/toshiba_haps.c
index 1486252b5983..8d12241924df 100644
--- a/drivers/platform/x86/toshiba_haps.c
+++ b/drivers/platform/x86/toshiba_haps.c
@@ -182,13 +182,17 @@ static int toshiba_haps_available(acpi_handle handle)
static int toshiba_haps_probe(struct platform_device *pdev)
{
- struct acpi_device *acpi_dev = ACPI_COMPANION(&pdev->dev);
struct toshiba_haps_dev *haps;
+ struct acpi_device *acpi_dev;
int ret;
if (toshiba_haps)
return -EBUSY;
+ acpi_dev = ACPI_COMPANION(&pdev->dev);
+ if (!acpi_dev)
+ return -ENODEV;
+
if (!toshiba_haps_available(acpi_dev->handle))
return -ENODEV;
diff --git a/drivers/platform/x86/uniwill/uniwill-acpi.c b/drivers/platform/x86/uniwill/uniwill-acpi.c
index 945df5092637..8cc01bec77b9 100644
--- a/drivers/platform/x86/uniwill/uniwill-acpi.c
+++ b/drivers/platform/x86/uniwill/uniwill-acpi.c
@@ -1359,6 +1359,16 @@ static int uniwill_led_init(struct uniwill_data *data)
&init_data);
}
+static unsigned int uniwill_sanitize_battery_threshold(unsigned int value)
+{
+ /* 0 means "charging threshold not active" */
+ if (!value)
+ return 100;
+
+ /* Guard against invalid values */
+ return min(value, 100);
+}
+
static int uniwill_get_property(struct power_supply *psy, const struct power_supply_ext *ext,
void *drvdata, enum power_supply_property psp,
union power_supply_propval *val)
@@ -1405,7 +1415,8 @@ static int uniwill_get_property(struct power_supply *psy, const struct power_sup
if (ret < 0)
return ret;
- val->intval = clamp_val(FIELD_GET(CHARGE_CTRL_MASK, regval), 0, 100);
+ regval = FIELD_GET(CHARGE_CTRL_MASK, regval);
+ val->intval = uniwill_sanitize_battery_threshold(regval);
return 0;
default:
return -EINVAL;
@@ -1420,11 +1431,11 @@ static int uniwill_set_property(struct power_supply *psy, const struct power_sup
switch (psp) {
case POWER_SUPPLY_PROP_CHARGE_CONTROL_END_THRESHOLD:
- if (val->intval < 1 || val->intval > 100)
+ if (val->intval < 0 || val->intval > 100)
return -EINVAL;
return regmap_update_bits(data->regmap, EC_ADDR_CHARGE_CTRL, CHARGE_CTRL_MASK,
- val->intval);
+ max(val->intval, 1));
default:
return -EINVAL;
}
@@ -1500,11 +1511,33 @@ static int uniwill_remove_battery(struct power_supply *battery, struct acpi_batt
static int uniwill_battery_init(struct uniwill_data *data)
{
+ unsigned int value, threshold, sanitized;
int ret;
if (!uniwill_device_supports(data, UNIWILL_FEATURE_BATTERY))
return 0;
+ ret = regmap_read(data->regmap, EC_ADDR_CHARGE_CTRL, &value);
+ if (ret < 0)
+ return ret;
+
+ /*
+ * The charge control threshold might be initialized with 0 by
+ * the EC to signal that said threshold is uninitialized. We thus
+ * need to replace this placeholder value with a valid one (100)
+ * to signal that we want to take control of battery charging.
+ * For the sake of completeness we also apply this to other
+ * invalid threshold values.
+ */
+ threshold = FIELD_GET(CHARGE_CTRL_MASK, value);
+ sanitized = uniwill_sanitize_battery_threshold(threshold);
+ if (threshold != sanitized) {
+ FIELD_MODIFY(CHARGE_CTRL_MASK, &value, sanitized);
+ ret = regmap_write(data->regmap, EC_ADDR_CHARGE_CTRL, value);
+ if (ret < 0)
+ return ret;
+ }
+
ret = devm_mutex_init(data->dev, &data->battery_lock);
if (ret < 0)
return ret;
@@ -2456,8 +2489,6 @@ static int __init uniwill_init(void)
if (!force)
return -ENODEV;
- /* Assume that the device supports all features */
- device_descriptor.features = UINT_MAX;
pr_warn("Loading on a potentially unsupported device\n");
} else {
/*
@@ -2475,6 +2506,12 @@ static int __init uniwill_init(void)
device_descriptor = *descriptor;
}
+ if (force) {
+ /* Assume that the device supports all features except the charge limit */
+ device_descriptor.features = UINT_MAX & ~UNIWILL_FEATURE_BATTERY;
+ pr_warn("Enabling potentially unsupported features\n");
+ }
+
ret = platform_driver_register(&uniwill_driver);
if (ret < 0)
return ret;
diff --git a/drivers/platform/x86/wireless-hotkey.c b/drivers/platform/x86/wireless-hotkey.c
index f680d8ff8e87..3151844d1699 100644
--- a/drivers/platform/x86/wireless-hotkey.c
+++ b/drivers/platform/x86/wireless-hotkey.c
@@ -89,9 +89,14 @@ static void wl_notify(acpi_handle handle, u32 event, void *data)
static int wl_probe(struct platform_device *pdev)
{
+ struct acpi_device *adev;
struct wl_button *button;
int err;
+ adev = ACPI_COMPANION(&pdev->dev);
+ if (!adev)
+ return -ENODEV;
+
button = kzalloc_obj(struct wl_button);
if (!button)
return -ENOMEM;
@@ -104,8 +109,8 @@ static int wl_probe(struct platform_device *pdev)
kfree(button);
return err;
}
- err = acpi_dev_install_notify_handler(ACPI_COMPANION(&pdev->dev),
- ACPI_DEVICE_NOTIFY, wl_notify, button);
+ err = acpi_dev_install_notify_handler(adev, ACPI_DEVICE_NOTIFY,
+ wl_notify, button);
if (err) {
pr_err("Failed to install ACPI notify handler\n");
wireless_input_destroy(&pdev->dev);