diff --git a/drivers/platform/x86/lenovo/wmi-other.c b/drivers/platform/x86/lenovo/wmi-other.c index bd64e7b44669..0172c4ceed58 100644 --- a/drivers/platform/x86/lenovo/wmi-other.c +++ b/drivers/platform/x86/lenovo/wmi-other.c @@ -189,10 +189,10 @@ MODULE_PARM_DESC(relax_fan_constraint, static bool force_load_psy_ext; module_param(force_load_psy_ext, bool, 0444); MODULE_PARM_DESC(force_load_psy_ext, - "This option will skip checking if the ideapad_laptop driver will conflict " + "This option will skip checking if the ideapad_laptop or thinkpad_acpi driver will conflict " "with adding an extension to set the battery charge behavior and battery charge " "control end threshold. It will also skip checking if the BIOS reports that " - "those features are fully supported. It is recommended to blacklist the ideapad " + "those features are fully supported. It is recommended to blacklist the conflicting " "driver before using this option."); /* ======== HWMON (component: lenovo-wmi-capdata 00 & fan) ======== */ @@ -905,17 +905,39 @@ static acpi_status lwmi_acpi_match(acpi_handle handle, u32 lvl, return AE_CTRL_TERMINATE; } +struct lwmi_psy_deconflict { + const char *const *hids; + const char *const *methods; +}; + +#define LWMI_PSY_DECONFLICT_STRS(...) \ + (const char *[]){ __VA_ARGS__, NULL } + +static const struct lwmi_psy_deconflict lwmi_psy_deconflict_list[] = { +#if IS_ENABLED(CONFIG_IDEAPAD_LAPTOP) + { + .hids = LWMI_PSY_DECONFLICT_STRS("VPC2004"), + .methods = LWMI_PSY_DECONFLICT_STRS("GBMD", "SBMC"), + }, +#endif /* IS_ENABLED(CONFIG_IDEAPAD_LAPTOP) */ +#if IS_ENABLED(CONFIG_THINKPAD_ACPI) + { + .hids = LWMI_PSY_DECONFLICT_STRS("LEN0268", "LEN0068", "IBM0068"), + .methods = LWMI_PSY_DECONFLICT_STRS("BDSG", "BICG"), + }, +#endif /* IS_ENABLED(CONFIG_THINKPAD_ACPI) */ +}; + /** * lwmi_om_psy_ext_init() - Hooks power supply extension to device battery * @priv: Pointer to the lwmi_om_priv drvdata. * - * Checks if the ideapad_laptop driver is going to manage charge attributes first, - * then if not, hooks the battery to our WMI methods if they are supported. + * Checks if the ideapad_laptop or thinkpad_acpi driver is going to manage + * charge attributes first, then if not, hooks the battery to our WMI methods + * if they are supported. */ static void lwmi_om_psy_ext_init(struct lwmi_om_priv *priv) { - static const char * const ideapad_hid = "VPC2004"; - acpi_handle handle = NULL; unsigned int props = 0; int ret; @@ -928,14 +950,30 @@ static void lwmi_om_psy_ext_init(struct lwmi_om_priv *priv) if (force_load_psy_ext) goto load_psy_ext; - /* Deconflict ideapad_laptop driver */ - ret = acpi_get_devices(ideapad_hid, lwmi_acpi_match, &handle, NULL); - if (ret) - return; - - if (handle && acpi_has_method(handle, "GBMD") && acpi_has_method(handle, "SBMC")) { - dev_dbg(&priv->wdev->dev, "ideapad_laptop driver manages battery for device\n"); - return; + for (unsigned int i = 0; i < ARRAY_SIZE(lwmi_psy_deconflict_list); i++) { + const struct lwmi_psy_deconflict *entry = &lwmi_psy_deconflict_list[i]; + acpi_handle handle = NULL; + + for (unsigned int j = 0; entry->hids[j]; j++) { + const char *hid = entry->hids[j]; + bool has_methods = true; + + ret = acpi_get_devices(hid, lwmi_acpi_match, &handle, NULL); + if (ret || !handle) + continue; + + for (unsigned int k = 0; entry->methods[k]; k++) { + has_methods = acpi_has_method(handle, (char *)entry->methods[k]); + if (!has_methods) + break; + } + if (!has_methods) + continue; + + dev_dbg(&priv->wdev->dev, "ACPI device %s manages battery for device\n", + hid); + return; + } } load_psy_ext: