xref: /kernel/linux/linux-5.10/drivers/acpi/battery.c (revision 8c2ecf20)
18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci *  battery.c - ACPI Battery Driver (Revision: 2.0)
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci *  Copyright (C) 2007 Alexey Starikovskiy <astarikovskiy@suse.de>
68c2ecf20Sopenharmony_ci *  Copyright (C) 2004-2007 Vladimir Lebedev <vladimir.p.lebedev@intel.com>
78c2ecf20Sopenharmony_ci *  Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com>
88c2ecf20Sopenharmony_ci *  Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
98c2ecf20Sopenharmony_ci */
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
128c2ecf20Sopenharmony_ci
138c2ecf20Sopenharmony_ci#include <linux/async.h>
148c2ecf20Sopenharmony_ci#include <linux/delay.h>
158c2ecf20Sopenharmony_ci#include <linux/dmi.h>
168c2ecf20Sopenharmony_ci#include <linux/jiffies.h>
178c2ecf20Sopenharmony_ci#include <linux/kernel.h>
188c2ecf20Sopenharmony_ci#include <linux/list.h>
198c2ecf20Sopenharmony_ci#include <linux/module.h>
208c2ecf20Sopenharmony_ci#include <linux/mutex.h>
218c2ecf20Sopenharmony_ci#include <linux/slab.h>
228c2ecf20Sopenharmony_ci#include <linux/suspend.h>
238c2ecf20Sopenharmony_ci#include <linux/types.h>
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_ci#include <asm/unaligned.h>
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_ci#include <linux/acpi.h>
288c2ecf20Sopenharmony_ci#include <linux/power_supply.h>
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_ci#include <acpi/battery.h>
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_ci#define PREFIX "ACPI: "
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_ci#define ACPI_BATTERY_VALUE_UNKNOWN 0xFFFFFFFF
358c2ecf20Sopenharmony_ci#define ACPI_BATTERY_CAPACITY_VALID(capacity) \
368c2ecf20Sopenharmony_ci	((capacity) != 0 && (capacity) != ACPI_BATTERY_VALUE_UNKNOWN)
378c2ecf20Sopenharmony_ci
388c2ecf20Sopenharmony_ci#define ACPI_BATTERY_DEVICE_NAME	"Battery"
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_ci/* Battery power unit: 0 means mW, 1 means mA */
418c2ecf20Sopenharmony_ci#define ACPI_BATTERY_POWER_UNIT_MA	1
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_ci#define ACPI_BATTERY_STATE_DISCHARGING	0x1
448c2ecf20Sopenharmony_ci#define ACPI_BATTERY_STATE_CHARGING	0x2
458c2ecf20Sopenharmony_ci#define ACPI_BATTERY_STATE_CRITICAL	0x4
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_ci#define _COMPONENT		ACPI_BATTERY_COMPONENT
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_ciACPI_MODULE_NAME("battery");
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_ciMODULE_AUTHOR("Paul Diefenbaugh");
528c2ecf20Sopenharmony_ciMODULE_AUTHOR("Alexey Starikovskiy <astarikovskiy@suse.de>");
538c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("ACPI Battery Driver");
548c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_cistatic async_cookie_t async_cookie;
578c2ecf20Sopenharmony_cistatic bool battery_driver_registered;
588c2ecf20Sopenharmony_cistatic int battery_bix_broken_package;
598c2ecf20Sopenharmony_cistatic int battery_notification_delay_ms;
608c2ecf20Sopenharmony_cistatic int battery_ac_is_broken;
618c2ecf20Sopenharmony_cistatic int battery_check_pmic = 1;
628c2ecf20Sopenharmony_cistatic int battery_quirk_notcharging;
638c2ecf20Sopenharmony_cistatic unsigned int cache_time = 1000;
648c2ecf20Sopenharmony_cimodule_param(cache_time, uint, 0644);
658c2ecf20Sopenharmony_ciMODULE_PARM_DESC(cache_time, "cache time in milliseconds");
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_cistatic const struct acpi_device_id battery_device_ids[] = {
688c2ecf20Sopenharmony_ci	{"PNP0C0A", 0},
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_ci	/* Microsoft Surface Go 3 */
718c2ecf20Sopenharmony_ci	{"MSHW0146", 0},
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_ci	{"", 0},
748c2ecf20Sopenharmony_ci};
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(acpi, battery_device_ids);
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_ci/* Lists of PMIC ACPI HIDs with an (often better) native battery driver */
798c2ecf20Sopenharmony_cistatic const char * const acpi_battery_blacklist[] = {
808c2ecf20Sopenharmony_ci	"INT33F4", /* X-Powers AXP288 PMIC */
818c2ecf20Sopenharmony_ci};
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_cienum {
848c2ecf20Sopenharmony_ci	ACPI_BATTERY_ALARM_PRESENT,
858c2ecf20Sopenharmony_ci	ACPI_BATTERY_XINFO_PRESENT,
868c2ecf20Sopenharmony_ci	ACPI_BATTERY_QUIRK_PERCENTAGE_CAPACITY,
878c2ecf20Sopenharmony_ci	/* On Lenovo Thinkpad models from 2010 and 2011, the power unit
888c2ecf20Sopenharmony_ci	   switches between mWh and mAh depending on whether the system
898c2ecf20Sopenharmony_ci	   is running on battery or not.  When mAh is the unit, most
908c2ecf20Sopenharmony_ci	   reported values are incorrect and need to be adjusted by
918c2ecf20Sopenharmony_ci	   10000/design_voltage.  Verified on x201, t410, t410s, and x220.
928c2ecf20Sopenharmony_ci	   Pre-2010 and 2012 models appear to always report in mWh and
938c2ecf20Sopenharmony_ci	   are thus unaffected (tested with t42, t61, t500, x200, x300,
948c2ecf20Sopenharmony_ci	   and x230).  Also, in mid-2012 Lenovo issued a BIOS update for
958c2ecf20Sopenharmony_ci	   the 2011 models that fixes the issue (tested on x220 with a
968c2ecf20Sopenharmony_ci	   post-1.29 BIOS), but as of Nov. 2012, no such update is
978c2ecf20Sopenharmony_ci	   available for the 2010 models.  */
988c2ecf20Sopenharmony_ci	ACPI_BATTERY_QUIRK_THINKPAD_MAH,
998c2ecf20Sopenharmony_ci	/* for batteries reporting current capacity with design capacity
1008c2ecf20Sopenharmony_ci	 * on a full charge, but showing degradation in full charge cap.
1018c2ecf20Sopenharmony_ci	 */
1028c2ecf20Sopenharmony_ci	ACPI_BATTERY_QUIRK_DEGRADED_FULL_CHARGE,
1038c2ecf20Sopenharmony_ci};
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_cistruct acpi_battery {
1068c2ecf20Sopenharmony_ci	struct mutex lock;
1078c2ecf20Sopenharmony_ci	struct mutex sysfs_lock;
1088c2ecf20Sopenharmony_ci	struct power_supply *bat;
1098c2ecf20Sopenharmony_ci	struct power_supply_desc bat_desc;
1108c2ecf20Sopenharmony_ci	struct acpi_device *device;
1118c2ecf20Sopenharmony_ci	struct notifier_block pm_nb;
1128c2ecf20Sopenharmony_ci	struct list_head list;
1138c2ecf20Sopenharmony_ci	unsigned long update_time;
1148c2ecf20Sopenharmony_ci	int revision;
1158c2ecf20Sopenharmony_ci	int rate_now;
1168c2ecf20Sopenharmony_ci	int capacity_now;
1178c2ecf20Sopenharmony_ci	int voltage_now;
1188c2ecf20Sopenharmony_ci	int design_capacity;
1198c2ecf20Sopenharmony_ci	int full_charge_capacity;
1208c2ecf20Sopenharmony_ci	int technology;
1218c2ecf20Sopenharmony_ci	int design_voltage;
1228c2ecf20Sopenharmony_ci	int design_capacity_warning;
1238c2ecf20Sopenharmony_ci	int design_capacity_low;
1248c2ecf20Sopenharmony_ci	int cycle_count;
1258c2ecf20Sopenharmony_ci	int measurement_accuracy;
1268c2ecf20Sopenharmony_ci	int max_sampling_time;
1278c2ecf20Sopenharmony_ci	int min_sampling_time;
1288c2ecf20Sopenharmony_ci	int max_averaging_interval;
1298c2ecf20Sopenharmony_ci	int min_averaging_interval;
1308c2ecf20Sopenharmony_ci	int capacity_granularity_1;
1318c2ecf20Sopenharmony_ci	int capacity_granularity_2;
1328c2ecf20Sopenharmony_ci	int alarm;
1338c2ecf20Sopenharmony_ci	char model_number[32];
1348c2ecf20Sopenharmony_ci	char serial_number[32];
1358c2ecf20Sopenharmony_ci	char type[32];
1368c2ecf20Sopenharmony_ci	char oem_info[32];
1378c2ecf20Sopenharmony_ci	int state;
1388c2ecf20Sopenharmony_ci	int power_unit;
1398c2ecf20Sopenharmony_ci	unsigned long flags;
1408c2ecf20Sopenharmony_ci};
1418c2ecf20Sopenharmony_ci
1428c2ecf20Sopenharmony_ci#define to_acpi_battery(x) power_supply_get_drvdata(x)
1438c2ecf20Sopenharmony_ci
1448c2ecf20Sopenharmony_cistatic inline int acpi_battery_present(struct acpi_battery *battery)
1458c2ecf20Sopenharmony_ci{
1468c2ecf20Sopenharmony_ci	return battery->device->status.battery_present;
1478c2ecf20Sopenharmony_ci}
1488c2ecf20Sopenharmony_ci
1498c2ecf20Sopenharmony_cistatic int acpi_battery_technology(struct acpi_battery *battery)
1508c2ecf20Sopenharmony_ci{
1518c2ecf20Sopenharmony_ci	if (!strcasecmp("NiCd", battery->type))
1528c2ecf20Sopenharmony_ci		return POWER_SUPPLY_TECHNOLOGY_NiCd;
1538c2ecf20Sopenharmony_ci	if (!strcasecmp("NiMH", battery->type))
1548c2ecf20Sopenharmony_ci		return POWER_SUPPLY_TECHNOLOGY_NiMH;
1558c2ecf20Sopenharmony_ci	if (!strcasecmp("LION", battery->type))
1568c2ecf20Sopenharmony_ci		return POWER_SUPPLY_TECHNOLOGY_LION;
1578c2ecf20Sopenharmony_ci	if (!strncasecmp("LI-ION", battery->type, 6))
1588c2ecf20Sopenharmony_ci		return POWER_SUPPLY_TECHNOLOGY_LION;
1598c2ecf20Sopenharmony_ci	if (!strcasecmp("LiP", battery->type))
1608c2ecf20Sopenharmony_ci		return POWER_SUPPLY_TECHNOLOGY_LIPO;
1618c2ecf20Sopenharmony_ci	return POWER_SUPPLY_TECHNOLOGY_UNKNOWN;
1628c2ecf20Sopenharmony_ci}
1638c2ecf20Sopenharmony_ci
1648c2ecf20Sopenharmony_cistatic int acpi_battery_get_state(struct acpi_battery *battery);
1658c2ecf20Sopenharmony_ci
1668c2ecf20Sopenharmony_cistatic int acpi_battery_is_charged(struct acpi_battery *battery)
1678c2ecf20Sopenharmony_ci{
1688c2ecf20Sopenharmony_ci	/* charging, discharging or critical low */
1698c2ecf20Sopenharmony_ci	if (battery->state != 0)
1708c2ecf20Sopenharmony_ci		return 0;
1718c2ecf20Sopenharmony_ci
1728c2ecf20Sopenharmony_ci	/* battery not reporting charge */
1738c2ecf20Sopenharmony_ci	if (battery->capacity_now == ACPI_BATTERY_VALUE_UNKNOWN ||
1748c2ecf20Sopenharmony_ci	    battery->capacity_now == 0)
1758c2ecf20Sopenharmony_ci		return 0;
1768c2ecf20Sopenharmony_ci
1778c2ecf20Sopenharmony_ci	/* good batteries update full_charge as the batteries degrade */
1788c2ecf20Sopenharmony_ci	if (battery->full_charge_capacity == battery->capacity_now)
1798c2ecf20Sopenharmony_ci		return 1;
1808c2ecf20Sopenharmony_ci
1818c2ecf20Sopenharmony_ci	/* fallback to using design values for broken batteries */
1828c2ecf20Sopenharmony_ci	if (battery->design_capacity <= battery->capacity_now)
1838c2ecf20Sopenharmony_ci		return 1;
1848c2ecf20Sopenharmony_ci
1858c2ecf20Sopenharmony_ci	/* we don't do any sort of metric based on percentages */
1868c2ecf20Sopenharmony_ci	return 0;
1878c2ecf20Sopenharmony_ci}
1888c2ecf20Sopenharmony_ci
1898c2ecf20Sopenharmony_cistatic bool acpi_battery_is_degraded(struct acpi_battery *battery)
1908c2ecf20Sopenharmony_ci{
1918c2ecf20Sopenharmony_ci	return ACPI_BATTERY_CAPACITY_VALID(battery->full_charge_capacity) &&
1928c2ecf20Sopenharmony_ci		ACPI_BATTERY_CAPACITY_VALID(battery->design_capacity) &&
1938c2ecf20Sopenharmony_ci		battery->full_charge_capacity < battery->design_capacity;
1948c2ecf20Sopenharmony_ci}
1958c2ecf20Sopenharmony_ci
1968c2ecf20Sopenharmony_cistatic int acpi_battery_handle_discharging(struct acpi_battery *battery)
1978c2ecf20Sopenharmony_ci{
1988c2ecf20Sopenharmony_ci	/*
1998c2ecf20Sopenharmony_ci	 * Some devices wrongly report discharging if the battery's charge level
2008c2ecf20Sopenharmony_ci	 * was above the device's start charging threshold atm the AC adapter
2018c2ecf20Sopenharmony_ci	 * was plugged in and the device thus did not start a new charge cycle.
2028c2ecf20Sopenharmony_ci	 */
2038c2ecf20Sopenharmony_ci	if ((battery_ac_is_broken || power_supply_is_system_supplied()) &&
2048c2ecf20Sopenharmony_ci	    battery->rate_now == 0)
2058c2ecf20Sopenharmony_ci		return POWER_SUPPLY_STATUS_NOT_CHARGING;
2068c2ecf20Sopenharmony_ci
2078c2ecf20Sopenharmony_ci	return POWER_SUPPLY_STATUS_DISCHARGING;
2088c2ecf20Sopenharmony_ci}
2098c2ecf20Sopenharmony_ci
2108c2ecf20Sopenharmony_cistatic int acpi_battery_get_property(struct power_supply *psy,
2118c2ecf20Sopenharmony_ci				     enum power_supply_property psp,
2128c2ecf20Sopenharmony_ci				     union power_supply_propval *val)
2138c2ecf20Sopenharmony_ci{
2148c2ecf20Sopenharmony_ci	int full_capacity = ACPI_BATTERY_VALUE_UNKNOWN, ret = 0;
2158c2ecf20Sopenharmony_ci	struct acpi_battery *battery = to_acpi_battery(psy);
2168c2ecf20Sopenharmony_ci
2178c2ecf20Sopenharmony_ci	if (acpi_battery_present(battery)) {
2188c2ecf20Sopenharmony_ci		/* run battery update only if it is present */
2198c2ecf20Sopenharmony_ci		acpi_battery_get_state(battery);
2208c2ecf20Sopenharmony_ci	} else if (psp != POWER_SUPPLY_PROP_PRESENT)
2218c2ecf20Sopenharmony_ci		return -ENODEV;
2228c2ecf20Sopenharmony_ci	switch (psp) {
2238c2ecf20Sopenharmony_ci	case POWER_SUPPLY_PROP_STATUS:
2248c2ecf20Sopenharmony_ci		if (battery->state & ACPI_BATTERY_STATE_DISCHARGING)
2258c2ecf20Sopenharmony_ci			val->intval = acpi_battery_handle_discharging(battery);
2268c2ecf20Sopenharmony_ci		else if (battery->state & ACPI_BATTERY_STATE_CHARGING)
2278c2ecf20Sopenharmony_ci			val->intval = POWER_SUPPLY_STATUS_CHARGING;
2288c2ecf20Sopenharmony_ci		else if (acpi_battery_is_charged(battery))
2298c2ecf20Sopenharmony_ci			val->intval = POWER_SUPPLY_STATUS_FULL;
2308c2ecf20Sopenharmony_ci		else if (battery_quirk_notcharging)
2318c2ecf20Sopenharmony_ci			val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
2328c2ecf20Sopenharmony_ci		else
2338c2ecf20Sopenharmony_ci			val->intval = POWER_SUPPLY_STATUS_UNKNOWN;
2348c2ecf20Sopenharmony_ci		break;
2358c2ecf20Sopenharmony_ci	case POWER_SUPPLY_PROP_PRESENT:
2368c2ecf20Sopenharmony_ci		val->intval = acpi_battery_present(battery);
2378c2ecf20Sopenharmony_ci		break;
2388c2ecf20Sopenharmony_ci	case POWER_SUPPLY_PROP_TECHNOLOGY:
2398c2ecf20Sopenharmony_ci		val->intval = acpi_battery_technology(battery);
2408c2ecf20Sopenharmony_ci		break;
2418c2ecf20Sopenharmony_ci	case POWER_SUPPLY_PROP_CYCLE_COUNT:
2428c2ecf20Sopenharmony_ci		val->intval = battery->cycle_count;
2438c2ecf20Sopenharmony_ci		break;
2448c2ecf20Sopenharmony_ci	case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN:
2458c2ecf20Sopenharmony_ci		if (battery->design_voltage == ACPI_BATTERY_VALUE_UNKNOWN)
2468c2ecf20Sopenharmony_ci			ret = -ENODEV;
2478c2ecf20Sopenharmony_ci		else
2488c2ecf20Sopenharmony_ci			val->intval = battery->design_voltage * 1000;
2498c2ecf20Sopenharmony_ci		break;
2508c2ecf20Sopenharmony_ci	case POWER_SUPPLY_PROP_VOLTAGE_NOW:
2518c2ecf20Sopenharmony_ci		if (battery->voltage_now == ACPI_BATTERY_VALUE_UNKNOWN)
2528c2ecf20Sopenharmony_ci			ret = -ENODEV;
2538c2ecf20Sopenharmony_ci		else
2548c2ecf20Sopenharmony_ci			val->intval = battery->voltage_now * 1000;
2558c2ecf20Sopenharmony_ci		break;
2568c2ecf20Sopenharmony_ci	case POWER_SUPPLY_PROP_CURRENT_NOW:
2578c2ecf20Sopenharmony_ci	case POWER_SUPPLY_PROP_POWER_NOW:
2588c2ecf20Sopenharmony_ci		if (battery->rate_now == ACPI_BATTERY_VALUE_UNKNOWN)
2598c2ecf20Sopenharmony_ci			ret = -ENODEV;
2608c2ecf20Sopenharmony_ci		else
2618c2ecf20Sopenharmony_ci			val->intval = battery->rate_now * 1000;
2628c2ecf20Sopenharmony_ci		break;
2638c2ecf20Sopenharmony_ci	case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN:
2648c2ecf20Sopenharmony_ci	case POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN:
2658c2ecf20Sopenharmony_ci		if (!ACPI_BATTERY_CAPACITY_VALID(battery->design_capacity))
2668c2ecf20Sopenharmony_ci			ret = -ENODEV;
2678c2ecf20Sopenharmony_ci		else
2688c2ecf20Sopenharmony_ci			val->intval = battery->design_capacity * 1000;
2698c2ecf20Sopenharmony_ci		break;
2708c2ecf20Sopenharmony_ci	case POWER_SUPPLY_PROP_CHARGE_FULL:
2718c2ecf20Sopenharmony_ci	case POWER_SUPPLY_PROP_ENERGY_FULL:
2728c2ecf20Sopenharmony_ci		if (!ACPI_BATTERY_CAPACITY_VALID(battery->full_charge_capacity))
2738c2ecf20Sopenharmony_ci			ret = -ENODEV;
2748c2ecf20Sopenharmony_ci		else
2758c2ecf20Sopenharmony_ci			val->intval = battery->full_charge_capacity * 1000;
2768c2ecf20Sopenharmony_ci		break;
2778c2ecf20Sopenharmony_ci	case POWER_SUPPLY_PROP_CHARGE_NOW:
2788c2ecf20Sopenharmony_ci	case POWER_SUPPLY_PROP_ENERGY_NOW:
2798c2ecf20Sopenharmony_ci		if (battery->capacity_now == ACPI_BATTERY_VALUE_UNKNOWN)
2808c2ecf20Sopenharmony_ci			ret = -ENODEV;
2818c2ecf20Sopenharmony_ci		else
2828c2ecf20Sopenharmony_ci			val->intval = battery->capacity_now * 1000;
2838c2ecf20Sopenharmony_ci		break;
2848c2ecf20Sopenharmony_ci	case POWER_SUPPLY_PROP_CAPACITY:
2858c2ecf20Sopenharmony_ci		if (ACPI_BATTERY_CAPACITY_VALID(battery->full_charge_capacity))
2868c2ecf20Sopenharmony_ci			full_capacity = battery->full_charge_capacity;
2878c2ecf20Sopenharmony_ci		else if (ACPI_BATTERY_CAPACITY_VALID(battery->design_capacity))
2888c2ecf20Sopenharmony_ci			full_capacity = battery->design_capacity;
2898c2ecf20Sopenharmony_ci
2908c2ecf20Sopenharmony_ci		if (battery->capacity_now == ACPI_BATTERY_VALUE_UNKNOWN ||
2918c2ecf20Sopenharmony_ci		    full_capacity == ACPI_BATTERY_VALUE_UNKNOWN)
2928c2ecf20Sopenharmony_ci			ret = -ENODEV;
2938c2ecf20Sopenharmony_ci		else
2948c2ecf20Sopenharmony_ci			val->intval = battery->capacity_now * 100/
2958c2ecf20Sopenharmony_ci					full_capacity;
2968c2ecf20Sopenharmony_ci		break;
2978c2ecf20Sopenharmony_ci	case POWER_SUPPLY_PROP_CAPACITY_LEVEL:
2988c2ecf20Sopenharmony_ci		if (battery->state & ACPI_BATTERY_STATE_CRITICAL)
2998c2ecf20Sopenharmony_ci			val->intval = POWER_SUPPLY_CAPACITY_LEVEL_CRITICAL;
3008c2ecf20Sopenharmony_ci		else if (test_bit(ACPI_BATTERY_ALARM_PRESENT, &battery->flags) &&
3018c2ecf20Sopenharmony_ci			(battery->capacity_now <= battery->alarm))
3028c2ecf20Sopenharmony_ci			val->intval = POWER_SUPPLY_CAPACITY_LEVEL_LOW;
3038c2ecf20Sopenharmony_ci		else if (acpi_battery_is_charged(battery))
3048c2ecf20Sopenharmony_ci			val->intval = POWER_SUPPLY_CAPACITY_LEVEL_FULL;
3058c2ecf20Sopenharmony_ci		else
3068c2ecf20Sopenharmony_ci			val->intval = POWER_SUPPLY_CAPACITY_LEVEL_NORMAL;
3078c2ecf20Sopenharmony_ci		break;
3088c2ecf20Sopenharmony_ci	case POWER_SUPPLY_PROP_MODEL_NAME:
3098c2ecf20Sopenharmony_ci		val->strval = battery->model_number;
3108c2ecf20Sopenharmony_ci		break;
3118c2ecf20Sopenharmony_ci	case POWER_SUPPLY_PROP_MANUFACTURER:
3128c2ecf20Sopenharmony_ci		val->strval = battery->oem_info;
3138c2ecf20Sopenharmony_ci		break;
3148c2ecf20Sopenharmony_ci	case POWER_SUPPLY_PROP_SERIAL_NUMBER:
3158c2ecf20Sopenharmony_ci		val->strval = battery->serial_number;
3168c2ecf20Sopenharmony_ci		break;
3178c2ecf20Sopenharmony_ci	default:
3188c2ecf20Sopenharmony_ci		ret = -EINVAL;
3198c2ecf20Sopenharmony_ci	}
3208c2ecf20Sopenharmony_ci	return ret;
3218c2ecf20Sopenharmony_ci}
3228c2ecf20Sopenharmony_ci
3238c2ecf20Sopenharmony_cistatic enum power_supply_property charge_battery_props[] = {
3248c2ecf20Sopenharmony_ci	POWER_SUPPLY_PROP_STATUS,
3258c2ecf20Sopenharmony_ci	POWER_SUPPLY_PROP_PRESENT,
3268c2ecf20Sopenharmony_ci	POWER_SUPPLY_PROP_TECHNOLOGY,
3278c2ecf20Sopenharmony_ci	POWER_SUPPLY_PROP_CYCLE_COUNT,
3288c2ecf20Sopenharmony_ci	POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,
3298c2ecf20Sopenharmony_ci	POWER_SUPPLY_PROP_VOLTAGE_NOW,
3308c2ecf20Sopenharmony_ci	POWER_SUPPLY_PROP_CURRENT_NOW,
3318c2ecf20Sopenharmony_ci	POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
3328c2ecf20Sopenharmony_ci	POWER_SUPPLY_PROP_CHARGE_FULL,
3338c2ecf20Sopenharmony_ci	POWER_SUPPLY_PROP_CHARGE_NOW,
3348c2ecf20Sopenharmony_ci	POWER_SUPPLY_PROP_CAPACITY,
3358c2ecf20Sopenharmony_ci	POWER_SUPPLY_PROP_CAPACITY_LEVEL,
3368c2ecf20Sopenharmony_ci	POWER_SUPPLY_PROP_MODEL_NAME,
3378c2ecf20Sopenharmony_ci	POWER_SUPPLY_PROP_MANUFACTURER,
3388c2ecf20Sopenharmony_ci	POWER_SUPPLY_PROP_SERIAL_NUMBER,
3398c2ecf20Sopenharmony_ci};
3408c2ecf20Sopenharmony_ci
3418c2ecf20Sopenharmony_cistatic enum power_supply_property charge_battery_full_cap_broken_props[] = {
3428c2ecf20Sopenharmony_ci	POWER_SUPPLY_PROP_STATUS,
3438c2ecf20Sopenharmony_ci	POWER_SUPPLY_PROP_PRESENT,
3448c2ecf20Sopenharmony_ci	POWER_SUPPLY_PROP_TECHNOLOGY,
3458c2ecf20Sopenharmony_ci	POWER_SUPPLY_PROP_CYCLE_COUNT,
3468c2ecf20Sopenharmony_ci	POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,
3478c2ecf20Sopenharmony_ci	POWER_SUPPLY_PROP_VOLTAGE_NOW,
3488c2ecf20Sopenharmony_ci	POWER_SUPPLY_PROP_CURRENT_NOW,
3498c2ecf20Sopenharmony_ci	POWER_SUPPLY_PROP_CHARGE_NOW,
3508c2ecf20Sopenharmony_ci	POWER_SUPPLY_PROP_MODEL_NAME,
3518c2ecf20Sopenharmony_ci	POWER_SUPPLY_PROP_MANUFACTURER,
3528c2ecf20Sopenharmony_ci	POWER_SUPPLY_PROP_SERIAL_NUMBER,
3538c2ecf20Sopenharmony_ci};
3548c2ecf20Sopenharmony_ci
3558c2ecf20Sopenharmony_cistatic enum power_supply_property energy_battery_props[] = {
3568c2ecf20Sopenharmony_ci	POWER_SUPPLY_PROP_STATUS,
3578c2ecf20Sopenharmony_ci	POWER_SUPPLY_PROP_PRESENT,
3588c2ecf20Sopenharmony_ci	POWER_SUPPLY_PROP_TECHNOLOGY,
3598c2ecf20Sopenharmony_ci	POWER_SUPPLY_PROP_CYCLE_COUNT,
3608c2ecf20Sopenharmony_ci	POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,
3618c2ecf20Sopenharmony_ci	POWER_SUPPLY_PROP_VOLTAGE_NOW,
3628c2ecf20Sopenharmony_ci	POWER_SUPPLY_PROP_POWER_NOW,
3638c2ecf20Sopenharmony_ci	POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN,
3648c2ecf20Sopenharmony_ci	POWER_SUPPLY_PROP_ENERGY_FULL,
3658c2ecf20Sopenharmony_ci	POWER_SUPPLY_PROP_ENERGY_NOW,
3668c2ecf20Sopenharmony_ci	POWER_SUPPLY_PROP_CAPACITY,
3678c2ecf20Sopenharmony_ci	POWER_SUPPLY_PROP_CAPACITY_LEVEL,
3688c2ecf20Sopenharmony_ci	POWER_SUPPLY_PROP_MODEL_NAME,
3698c2ecf20Sopenharmony_ci	POWER_SUPPLY_PROP_MANUFACTURER,
3708c2ecf20Sopenharmony_ci	POWER_SUPPLY_PROP_SERIAL_NUMBER,
3718c2ecf20Sopenharmony_ci};
3728c2ecf20Sopenharmony_ci
3738c2ecf20Sopenharmony_cistatic enum power_supply_property energy_battery_full_cap_broken_props[] = {
3748c2ecf20Sopenharmony_ci	POWER_SUPPLY_PROP_STATUS,
3758c2ecf20Sopenharmony_ci	POWER_SUPPLY_PROP_PRESENT,
3768c2ecf20Sopenharmony_ci	POWER_SUPPLY_PROP_TECHNOLOGY,
3778c2ecf20Sopenharmony_ci	POWER_SUPPLY_PROP_CYCLE_COUNT,
3788c2ecf20Sopenharmony_ci	POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,
3798c2ecf20Sopenharmony_ci	POWER_SUPPLY_PROP_VOLTAGE_NOW,
3808c2ecf20Sopenharmony_ci	POWER_SUPPLY_PROP_POWER_NOW,
3818c2ecf20Sopenharmony_ci	POWER_SUPPLY_PROP_ENERGY_NOW,
3828c2ecf20Sopenharmony_ci	POWER_SUPPLY_PROP_MODEL_NAME,
3838c2ecf20Sopenharmony_ci	POWER_SUPPLY_PROP_MANUFACTURER,
3848c2ecf20Sopenharmony_ci	POWER_SUPPLY_PROP_SERIAL_NUMBER,
3858c2ecf20Sopenharmony_ci};
3868c2ecf20Sopenharmony_ci
3878c2ecf20Sopenharmony_ci/* --------------------------------------------------------------------------
3888c2ecf20Sopenharmony_ci                               Battery Management
3898c2ecf20Sopenharmony_ci   -------------------------------------------------------------------------- */
3908c2ecf20Sopenharmony_cistruct acpi_offsets {
3918c2ecf20Sopenharmony_ci	size_t offset;		/* offset inside struct acpi_sbs_battery */
3928c2ecf20Sopenharmony_ci	u8 mode;		/* int or string? */
3938c2ecf20Sopenharmony_ci};
3948c2ecf20Sopenharmony_ci
3958c2ecf20Sopenharmony_cistatic const struct acpi_offsets state_offsets[] = {
3968c2ecf20Sopenharmony_ci	{offsetof(struct acpi_battery, state), 0},
3978c2ecf20Sopenharmony_ci	{offsetof(struct acpi_battery, rate_now), 0},
3988c2ecf20Sopenharmony_ci	{offsetof(struct acpi_battery, capacity_now), 0},
3998c2ecf20Sopenharmony_ci	{offsetof(struct acpi_battery, voltage_now), 0},
4008c2ecf20Sopenharmony_ci};
4018c2ecf20Sopenharmony_ci
4028c2ecf20Sopenharmony_cistatic const struct acpi_offsets info_offsets[] = {
4038c2ecf20Sopenharmony_ci	{offsetof(struct acpi_battery, power_unit), 0},
4048c2ecf20Sopenharmony_ci	{offsetof(struct acpi_battery, design_capacity), 0},
4058c2ecf20Sopenharmony_ci	{offsetof(struct acpi_battery, full_charge_capacity), 0},
4068c2ecf20Sopenharmony_ci	{offsetof(struct acpi_battery, technology), 0},
4078c2ecf20Sopenharmony_ci	{offsetof(struct acpi_battery, design_voltage), 0},
4088c2ecf20Sopenharmony_ci	{offsetof(struct acpi_battery, design_capacity_warning), 0},
4098c2ecf20Sopenharmony_ci	{offsetof(struct acpi_battery, design_capacity_low), 0},
4108c2ecf20Sopenharmony_ci	{offsetof(struct acpi_battery, capacity_granularity_1), 0},
4118c2ecf20Sopenharmony_ci	{offsetof(struct acpi_battery, capacity_granularity_2), 0},
4128c2ecf20Sopenharmony_ci	{offsetof(struct acpi_battery, model_number), 1},
4138c2ecf20Sopenharmony_ci	{offsetof(struct acpi_battery, serial_number), 1},
4148c2ecf20Sopenharmony_ci	{offsetof(struct acpi_battery, type), 1},
4158c2ecf20Sopenharmony_ci	{offsetof(struct acpi_battery, oem_info), 1},
4168c2ecf20Sopenharmony_ci};
4178c2ecf20Sopenharmony_ci
4188c2ecf20Sopenharmony_cistatic const struct acpi_offsets extended_info_offsets[] = {
4198c2ecf20Sopenharmony_ci	{offsetof(struct acpi_battery, revision), 0},
4208c2ecf20Sopenharmony_ci	{offsetof(struct acpi_battery, power_unit), 0},
4218c2ecf20Sopenharmony_ci	{offsetof(struct acpi_battery, design_capacity), 0},
4228c2ecf20Sopenharmony_ci	{offsetof(struct acpi_battery, full_charge_capacity), 0},
4238c2ecf20Sopenharmony_ci	{offsetof(struct acpi_battery, technology), 0},
4248c2ecf20Sopenharmony_ci	{offsetof(struct acpi_battery, design_voltage), 0},
4258c2ecf20Sopenharmony_ci	{offsetof(struct acpi_battery, design_capacity_warning), 0},
4268c2ecf20Sopenharmony_ci	{offsetof(struct acpi_battery, design_capacity_low), 0},
4278c2ecf20Sopenharmony_ci	{offsetof(struct acpi_battery, cycle_count), 0},
4288c2ecf20Sopenharmony_ci	{offsetof(struct acpi_battery, measurement_accuracy), 0},
4298c2ecf20Sopenharmony_ci	{offsetof(struct acpi_battery, max_sampling_time), 0},
4308c2ecf20Sopenharmony_ci	{offsetof(struct acpi_battery, min_sampling_time), 0},
4318c2ecf20Sopenharmony_ci	{offsetof(struct acpi_battery, max_averaging_interval), 0},
4328c2ecf20Sopenharmony_ci	{offsetof(struct acpi_battery, min_averaging_interval), 0},
4338c2ecf20Sopenharmony_ci	{offsetof(struct acpi_battery, capacity_granularity_1), 0},
4348c2ecf20Sopenharmony_ci	{offsetof(struct acpi_battery, capacity_granularity_2), 0},
4358c2ecf20Sopenharmony_ci	{offsetof(struct acpi_battery, model_number), 1},
4368c2ecf20Sopenharmony_ci	{offsetof(struct acpi_battery, serial_number), 1},
4378c2ecf20Sopenharmony_ci	{offsetof(struct acpi_battery, type), 1},
4388c2ecf20Sopenharmony_ci	{offsetof(struct acpi_battery, oem_info), 1},
4398c2ecf20Sopenharmony_ci};
4408c2ecf20Sopenharmony_ci
4418c2ecf20Sopenharmony_cistatic int extract_package(struct acpi_battery *battery,
4428c2ecf20Sopenharmony_ci			   union acpi_object *package,
4438c2ecf20Sopenharmony_ci			   const struct acpi_offsets *offsets, int num)
4448c2ecf20Sopenharmony_ci{
4458c2ecf20Sopenharmony_ci	int i;
4468c2ecf20Sopenharmony_ci	union acpi_object *element;
4478c2ecf20Sopenharmony_ci	if (package->type != ACPI_TYPE_PACKAGE)
4488c2ecf20Sopenharmony_ci		return -EFAULT;
4498c2ecf20Sopenharmony_ci	for (i = 0; i < num; ++i) {
4508c2ecf20Sopenharmony_ci		if (package->package.count <= i)
4518c2ecf20Sopenharmony_ci			return -EFAULT;
4528c2ecf20Sopenharmony_ci		element = &package->package.elements[i];
4538c2ecf20Sopenharmony_ci		if (offsets[i].mode) {
4548c2ecf20Sopenharmony_ci			u8 *ptr = (u8 *)battery + offsets[i].offset;
4558c2ecf20Sopenharmony_ci			if (element->type == ACPI_TYPE_STRING ||
4568c2ecf20Sopenharmony_ci			    element->type == ACPI_TYPE_BUFFER)
4578c2ecf20Sopenharmony_ci				strscpy(ptr, element->string.pointer, 32);
4588c2ecf20Sopenharmony_ci			else if (element->type == ACPI_TYPE_INTEGER) {
4598c2ecf20Sopenharmony_ci				strncpy(ptr, (u8 *)&element->integer.value,
4608c2ecf20Sopenharmony_ci					sizeof(u64));
4618c2ecf20Sopenharmony_ci				ptr[sizeof(u64)] = 0;
4628c2ecf20Sopenharmony_ci			} else
4638c2ecf20Sopenharmony_ci				*ptr = 0; /* don't have value */
4648c2ecf20Sopenharmony_ci		} else {
4658c2ecf20Sopenharmony_ci			int *x = (int *)((u8 *)battery + offsets[i].offset);
4668c2ecf20Sopenharmony_ci			*x = (element->type == ACPI_TYPE_INTEGER) ?
4678c2ecf20Sopenharmony_ci				element->integer.value : -1;
4688c2ecf20Sopenharmony_ci		}
4698c2ecf20Sopenharmony_ci	}
4708c2ecf20Sopenharmony_ci	return 0;
4718c2ecf20Sopenharmony_ci}
4728c2ecf20Sopenharmony_ci
4738c2ecf20Sopenharmony_cistatic int acpi_battery_get_status(struct acpi_battery *battery)
4748c2ecf20Sopenharmony_ci{
4758c2ecf20Sopenharmony_ci	if (acpi_bus_get_status(battery->device)) {
4768c2ecf20Sopenharmony_ci		ACPI_EXCEPTION((AE_INFO, AE_ERROR, "Evaluating _STA"));
4778c2ecf20Sopenharmony_ci		return -ENODEV;
4788c2ecf20Sopenharmony_ci	}
4798c2ecf20Sopenharmony_ci	return 0;
4808c2ecf20Sopenharmony_ci}
4818c2ecf20Sopenharmony_ci
4828c2ecf20Sopenharmony_ci
4838c2ecf20Sopenharmony_cistatic int extract_battery_info(const int use_bix,
4848c2ecf20Sopenharmony_ci			 struct acpi_battery *battery,
4858c2ecf20Sopenharmony_ci			 const struct acpi_buffer *buffer)
4868c2ecf20Sopenharmony_ci{
4878c2ecf20Sopenharmony_ci	int result = -EFAULT;
4888c2ecf20Sopenharmony_ci
4898c2ecf20Sopenharmony_ci	if (use_bix && battery_bix_broken_package)
4908c2ecf20Sopenharmony_ci		result = extract_package(battery, buffer->pointer,
4918c2ecf20Sopenharmony_ci				extended_info_offsets + 1,
4928c2ecf20Sopenharmony_ci				ARRAY_SIZE(extended_info_offsets) - 1);
4938c2ecf20Sopenharmony_ci	else if (use_bix)
4948c2ecf20Sopenharmony_ci		result = extract_package(battery, buffer->pointer,
4958c2ecf20Sopenharmony_ci				extended_info_offsets,
4968c2ecf20Sopenharmony_ci				ARRAY_SIZE(extended_info_offsets));
4978c2ecf20Sopenharmony_ci	else
4988c2ecf20Sopenharmony_ci		result = extract_package(battery, buffer->pointer,
4998c2ecf20Sopenharmony_ci				info_offsets, ARRAY_SIZE(info_offsets));
5008c2ecf20Sopenharmony_ci	if (test_bit(ACPI_BATTERY_QUIRK_PERCENTAGE_CAPACITY, &battery->flags))
5018c2ecf20Sopenharmony_ci		battery->full_charge_capacity = battery->design_capacity;
5028c2ecf20Sopenharmony_ci	if (test_bit(ACPI_BATTERY_QUIRK_THINKPAD_MAH, &battery->flags) &&
5038c2ecf20Sopenharmony_ci	    battery->power_unit && battery->design_voltage) {
5048c2ecf20Sopenharmony_ci		battery->design_capacity = battery->design_capacity *
5058c2ecf20Sopenharmony_ci		    10000 / battery->design_voltage;
5068c2ecf20Sopenharmony_ci		battery->full_charge_capacity = battery->full_charge_capacity *
5078c2ecf20Sopenharmony_ci		    10000 / battery->design_voltage;
5088c2ecf20Sopenharmony_ci		battery->design_capacity_warning =
5098c2ecf20Sopenharmony_ci		    battery->design_capacity_warning *
5108c2ecf20Sopenharmony_ci		    10000 / battery->design_voltage;
5118c2ecf20Sopenharmony_ci		/* Curiously, design_capacity_low, unlike the rest of them,
5128c2ecf20Sopenharmony_ci		   is correct.  */
5138c2ecf20Sopenharmony_ci		/* capacity_granularity_* equal 1 on the systems tested, so
5148c2ecf20Sopenharmony_ci		   it's impossible to tell if they would need an adjustment
5158c2ecf20Sopenharmony_ci		   or not if their values were higher.  */
5168c2ecf20Sopenharmony_ci	}
5178c2ecf20Sopenharmony_ci	if (test_bit(ACPI_BATTERY_QUIRK_DEGRADED_FULL_CHARGE, &battery->flags) &&
5188c2ecf20Sopenharmony_ci	    battery->capacity_now > battery->full_charge_capacity)
5198c2ecf20Sopenharmony_ci		battery->capacity_now = battery->full_charge_capacity;
5208c2ecf20Sopenharmony_ci
5218c2ecf20Sopenharmony_ci	return result;
5228c2ecf20Sopenharmony_ci}
5238c2ecf20Sopenharmony_ci
5248c2ecf20Sopenharmony_cistatic int acpi_battery_get_info(struct acpi_battery *battery)
5258c2ecf20Sopenharmony_ci{
5268c2ecf20Sopenharmony_ci	const int xinfo = test_bit(ACPI_BATTERY_XINFO_PRESENT, &battery->flags);
5278c2ecf20Sopenharmony_ci	int use_bix;
5288c2ecf20Sopenharmony_ci	int result = -ENODEV;
5298c2ecf20Sopenharmony_ci
5308c2ecf20Sopenharmony_ci	if (!acpi_battery_present(battery))
5318c2ecf20Sopenharmony_ci		return 0;
5328c2ecf20Sopenharmony_ci
5338c2ecf20Sopenharmony_ci
5348c2ecf20Sopenharmony_ci	for (use_bix = xinfo ? 1 : 0; use_bix >= 0; use_bix--) {
5358c2ecf20Sopenharmony_ci		struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
5368c2ecf20Sopenharmony_ci		acpi_status status = AE_ERROR;
5378c2ecf20Sopenharmony_ci
5388c2ecf20Sopenharmony_ci		mutex_lock(&battery->lock);
5398c2ecf20Sopenharmony_ci		status = acpi_evaluate_object(battery->device->handle,
5408c2ecf20Sopenharmony_ci					      use_bix ? "_BIX":"_BIF",
5418c2ecf20Sopenharmony_ci					      NULL, &buffer);
5428c2ecf20Sopenharmony_ci		mutex_unlock(&battery->lock);
5438c2ecf20Sopenharmony_ci
5448c2ecf20Sopenharmony_ci		if (ACPI_FAILURE(status)) {
5458c2ecf20Sopenharmony_ci			ACPI_EXCEPTION((AE_INFO, status, "Evaluating %s",
5468c2ecf20Sopenharmony_ci					use_bix ? "_BIX":"_BIF"));
5478c2ecf20Sopenharmony_ci		} else {
5488c2ecf20Sopenharmony_ci			result = extract_battery_info(use_bix,
5498c2ecf20Sopenharmony_ci						      battery,
5508c2ecf20Sopenharmony_ci						      &buffer);
5518c2ecf20Sopenharmony_ci
5528c2ecf20Sopenharmony_ci			kfree(buffer.pointer);
5538c2ecf20Sopenharmony_ci			break;
5548c2ecf20Sopenharmony_ci		}
5558c2ecf20Sopenharmony_ci	}
5568c2ecf20Sopenharmony_ci
5578c2ecf20Sopenharmony_ci	if (!result && !use_bix && xinfo)
5588c2ecf20Sopenharmony_ci		pr_warn(FW_BUG "The _BIX method is broken, using _BIF.\n");
5598c2ecf20Sopenharmony_ci
5608c2ecf20Sopenharmony_ci	return result;
5618c2ecf20Sopenharmony_ci}
5628c2ecf20Sopenharmony_ci
5638c2ecf20Sopenharmony_cistatic int acpi_battery_get_state(struct acpi_battery *battery)
5648c2ecf20Sopenharmony_ci{
5658c2ecf20Sopenharmony_ci	int result = 0;
5668c2ecf20Sopenharmony_ci	acpi_status status = 0;
5678c2ecf20Sopenharmony_ci	struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
5688c2ecf20Sopenharmony_ci
5698c2ecf20Sopenharmony_ci	if (!acpi_battery_present(battery))
5708c2ecf20Sopenharmony_ci		return 0;
5718c2ecf20Sopenharmony_ci
5728c2ecf20Sopenharmony_ci	if (battery->update_time &&
5738c2ecf20Sopenharmony_ci	    time_before(jiffies, battery->update_time +
5748c2ecf20Sopenharmony_ci			msecs_to_jiffies(cache_time)))
5758c2ecf20Sopenharmony_ci		return 0;
5768c2ecf20Sopenharmony_ci
5778c2ecf20Sopenharmony_ci	mutex_lock(&battery->lock);
5788c2ecf20Sopenharmony_ci	status = acpi_evaluate_object(battery->device->handle, "_BST",
5798c2ecf20Sopenharmony_ci				      NULL, &buffer);
5808c2ecf20Sopenharmony_ci	mutex_unlock(&battery->lock);
5818c2ecf20Sopenharmony_ci
5828c2ecf20Sopenharmony_ci	if (ACPI_FAILURE(status)) {
5838c2ecf20Sopenharmony_ci		ACPI_EXCEPTION((AE_INFO, status, "Evaluating _BST"));
5848c2ecf20Sopenharmony_ci		return -ENODEV;
5858c2ecf20Sopenharmony_ci	}
5868c2ecf20Sopenharmony_ci
5878c2ecf20Sopenharmony_ci	result = extract_package(battery, buffer.pointer,
5888c2ecf20Sopenharmony_ci				 state_offsets, ARRAY_SIZE(state_offsets));
5898c2ecf20Sopenharmony_ci	battery->update_time = jiffies;
5908c2ecf20Sopenharmony_ci	kfree(buffer.pointer);
5918c2ecf20Sopenharmony_ci
5928c2ecf20Sopenharmony_ci	/* For buggy DSDTs that report negative 16-bit values for either
5938c2ecf20Sopenharmony_ci	 * charging or discharging current and/or report 0 as 65536
5948c2ecf20Sopenharmony_ci	 * due to bad math.
5958c2ecf20Sopenharmony_ci	 */
5968c2ecf20Sopenharmony_ci	if (battery->power_unit == ACPI_BATTERY_POWER_UNIT_MA &&
5978c2ecf20Sopenharmony_ci		battery->rate_now != ACPI_BATTERY_VALUE_UNKNOWN &&
5988c2ecf20Sopenharmony_ci		(s16)(battery->rate_now) < 0) {
5998c2ecf20Sopenharmony_ci		battery->rate_now = abs((s16)battery->rate_now);
6008c2ecf20Sopenharmony_ci		pr_warn_once(FW_BUG "battery: (dis)charge rate invalid.\n");
6018c2ecf20Sopenharmony_ci	}
6028c2ecf20Sopenharmony_ci
6038c2ecf20Sopenharmony_ci	if (test_bit(ACPI_BATTERY_QUIRK_PERCENTAGE_CAPACITY, &battery->flags)
6048c2ecf20Sopenharmony_ci	    && battery->capacity_now >= 0 && battery->capacity_now <= 100)
6058c2ecf20Sopenharmony_ci		battery->capacity_now = (battery->capacity_now *
6068c2ecf20Sopenharmony_ci				battery->full_charge_capacity) / 100;
6078c2ecf20Sopenharmony_ci	if (test_bit(ACPI_BATTERY_QUIRK_THINKPAD_MAH, &battery->flags) &&
6088c2ecf20Sopenharmony_ci	    battery->power_unit && battery->design_voltage) {
6098c2ecf20Sopenharmony_ci		battery->capacity_now = battery->capacity_now *
6108c2ecf20Sopenharmony_ci		    10000 / battery->design_voltage;
6118c2ecf20Sopenharmony_ci	}
6128c2ecf20Sopenharmony_ci	if (test_bit(ACPI_BATTERY_QUIRK_DEGRADED_FULL_CHARGE, &battery->flags) &&
6138c2ecf20Sopenharmony_ci	    battery->capacity_now > battery->full_charge_capacity)
6148c2ecf20Sopenharmony_ci		battery->capacity_now = battery->full_charge_capacity;
6158c2ecf20Sopenharmony_ci
6168c2ecf20Sopenharmony_ci	return result;
6178c2ecf20Sopenharmony_ci}
6188c2ecf20Sopenharmony_ci
6198c2ecf20Sopenharmony_cistatic int acpi_battery_set_alarm(struct acpi_battery *battery)
6208c2ecf20Sopenharmony_ci{
6218c2ecf20Sopenharmony_ci	acpi_status status = 0;
6228c2ecf20Sopenharmony_ci
6238c2ecf20Sopenharmony_ci	if (!acpi_battery_present(battery) ||
6248c2ecf20Sopenharmony_ci	    !test_bit(ACPI_BATTERY_ALARM_PRESENT, &battery->flags))
6258c2ecf20Sopenharmony_ci		return -ENODEV;
6268c2ecf20Sopenharmony_ci
6278c2ecf20Sopenharmony_ci	mutex_lock(&battery->lock);
6288c2ecf20Sopenharmony_ci	status = acpi_execute_simple_method(battery->device->handle, "_BTP",
6298c2ecf20Sopenharmony_ci					    battery->alarm);
6308c2ecf20Sopenharmony_ci	mutex_unlock(&battery->lock);
6318c2ecf20Sopenharmony_ci
6328c2ecf20Sopenharmony_ci	if (ACPI_FAILURE(status))
6338c2ecf20Sopenharmony_ci		return -ENODEV;
6348c2ecf20Sopenharmony_ci
6358c2ecf20Sopenharmony_ci	ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Alarm set to %d\n", battery->alarm));
6368c2ecf20Sopenharmony_ci	return 0;
6378c2ecf20Sopenharmony_ci}
6388c2ecf20Sopenharmony_ci
6398c2ecf20Sopenharmony_cistatic int acpi_battery_init_alarm(struct acpi_battery *battery)
6408c2ecf20Sopenharmony_ci{
6418c2ecf20Sopenharmony_ci	/* See if alarms are supported, and if so, set default */
6428c2ecf20Sopenharmony_ci	if (!acpi_has_method(battery->device->handle, "_BTP")) {
6438c2ecf20Sopenharmony_ci		clear_bit(ACPI_BATTERY_ALARM_PRESENT, &battery->flags);
6448c2ecf20Sopenharmony_ci		return 0;
6458c2ecf20Sopenharmony_ci	}
6468c2ecf20Sopenharmony_ci	set_bit(ACPI_BATTERY_ALARM_PRESENT, &battery->flags);
6478c2ecf20Sopenharmony_ci	if (!battery->alarm)
6488c2ecf20Sopenharmony_ci		battery->alarm = battery->design_capacity_warning;
6498c2ecf20Sopenharmony_ci	return acpi_battery_set_alarm(battery);
6508c2ecf20Sopenharmony_ci}
6518c2ecf20Sopenharmony_ci
6528c2ecf20Sopenharmony_cistatic ssize_t acpi_battery_alarm_show(struct device *dev,
6538c2ecf20Sopenharmony_ci					struct device_attribute *attr,
6548c2ecf20Sopenharmony_ci					char *buf)
6558c2ecf20Sopenharmony_ci{
6568c2ecf20Sopenharmony_ci	struct acpi_battery *battery = to_acpi_battery(dev_get_drvdata(dev));
6578c2ecf20Sopenharmony_ci	return sprintf(buf, "%d\n", battery->alarm * 1000);
6588c2ecf20Sopenharmony_ci}
6598c2ecf20Sopenharmony_ci
6608c2ecf20Sopenharmony_cistatic ssize_t acpi_battery_alarm_store(struct device *dev,
6618c2ecf20Sopenharmony_ci					struct device_attribute *attr,
6628c2ecf20Sopenharmony_ci					const char *buf, size_t count)
6638c2ecf20Sopenharmony_ci{
6648c2ecf20Sopenharmony_ci	unsigned long x;
6658c2ecf20Sopenharmony_ci	struct acpi_battery *battery = to_acpi_battery(dev_get_drvdata(dev));
6668c2ecf20Sopenharmony_ci	if (sscanf(buf, "%lu\n", &x) == 1)
6678c2ecf20Sopenharmony_ci		battery->alarm = x/1000;
6688c2ecf20Sopenharmony_ci	if (acpi_battery_present(battery))
6698c2ecf20Sopenharmony_ci		acpi_battery_set_alarm(battery);
6708c2ecf20Sopenharmony_ci	return count;
6718c2ecf20Sopenharmony_ci}
6728c2ecf20Sopenharmony_ci
6738c2ecf20Sopenharmony_cistatic const struct device_attribute alarm_attr = {
6748c2ecf20Sopenharmony_ci	.attr = {.name = "alarm", .mode = 0644},
6758c2ecf20Sopenharmony_ci	.show = acpi_battery_alarm_show,
6768c2ecf20Sopenharmony_ci	.store = acpi_battery_alarm_store,
6778c2ecf20Sopenharmony_ci};
6788c2ecf20Sopenharmony_ci
6798c2ecf20Sopenharmony_ci/*
6808c2ecf20Sopenharmony_ci * The Battery Hooking API
6818c2ecf20Sopenharmony_ci *
6828c2ecf20Sopenharmony_ci * This API is used inside other drivers that need to expose
6838c2ecf20Sopenharmony_ci * platform-specific behaviour within the generic driver in a
6848c2ecf20Sopenharmony_ci * generic way.
6858c2ecf20Sopenharmony_ci *
6868c2ecf20Sopenharmony_ci */
6878c2ecf20Sopenharmony_ci
6888c2ecf20Sopenharmony_cistatic LIST_HEAD(acpi_battery_list);
6898c2ecf20Sopenharmony_cistatic LIST_HEAD(battery_hook_list);
6908c2ecf20Sopenharmony_cistatic DEFINE_MUTEX(hook_mutex);
6918c2ecf20Sopenharmony_ci
6928c2ecf20Sopenharmony_cistatic void __battery_hook_unregister(struct acpi_battery_hook *hook, int lock)
6938c2ecf20Sopenharmony_ci{
6948c2ecf20Sopenharmony_ci	struct acpi_battery *battery;
6958c2ecf20Sopenharmony_ci	/*
6968c2ecf20Sopenharmony_ci	 * In order to remove a hook, we first need to
6978c2ecf20Sopenharmony_ci	 * de-register all the batteries that are registered.
6988c2ecf20Sopenharmony_ci	 */
6998c2ecf20Sopenharmony_ci	if (lock)
7008c2ecf20Sopenharmony_ci		mutex_lock(&hook_mutex);
7018c2ecf20Sopenharmony_ci	list_for_each_entry(battery, &acpi_battery_list, list) {
7028c2ecf20Sopenharmony_ci		hook->remove_battery(battery->bat);
7038c2ecf20Sopenharmony_ci	}
7048c2ecf20Sopenharmony_ci	list_del(&hook->list);
7058c2ecf20Sopenharmony_ci	if (lock)
7068c2ecf20Sopenharmony_ci		mutex_unlock(&hook_mutex);
7078c2ecf20Sopenharmony_ci	pr_info("extension unregistered: %s\n", hook->name);
7088c2ecf20Sopenharmony_ci}
7098c2ecf20Sopenharmony_ci
7108c2ecf20Sopenharmony_civoid battery_hook_unregister(struct acpi_battery_hook *hook)
7118c2ecf20Sopenharmony_ci{
7128c2ecf20Sopenharmony_ci	__battery_hook_unregister(hook, 1);
7138c2ecf20Sopenharmony_ci}
7148c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(battery_hook_unregister);
7158c2ecf20Sopenharmony_ci
7168c2ecf20Sopenharmony_civoid battery_hook_register(struct acpi_battery_hook *hook)
7178c2ecf20Sopenharmony_ci{
7188c2ecf20Sopenharmony_ci	struct acpi_battery *battery;
7198c2ecf20Sopenharmony_ci
7208c2ecf20Sopenharmony_ci	mutex_lock(&hook_mutex);
7218c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&hook->list);
7228c2ecf20Sopenharmony_ci	list_add(&hook->list, &battery_hook_list);
7238c2ecf20Sopenharmony_ci	/*
7248c2ecf20Sopenharmony_ci	 * Now that the driver is registered, we need
7258c2ecf20Sopenharmony_ci	 * to notify the hook that a battery is available
7268c2ecf20Sopenharmony_ci	 * for each battery, so that the driver may add
7278c2ecf20Sopenharmony_ci	 * its attributes.
7288c2ecf20Sopenharmony_ci	 */
7298c2ecf20Sopenharmony_ci	list_for_each_entry(battery, &acpi_battery_list, list) {
7308c2ecf20Sopenharmony_ci		if (hook->add_battery(battery->bat)) {
7318c2ecf20Sopenharmony_ci			/*
7328c2ecf20Sopenharmony_ci			 * If a add-battery returns non-zero,
7338c2ecf20Sopenharmony_ci			 * the registration of the extension has failed,
7348c2ecf20Sopenharmony_ci			 * and we will not add it to the list of loaded
7358c2ecf20Sopenharmony_ci			 * hooks.
7368c2ecf20Sopenharmony_ci			 */
7378c2ecf20Sopenharmony_ci			pr_err("extension failed to load: %s", hook->name);
7388c2ecf20Sopenharmony_ci			__battery_hook_unregister(hook, 0);
7398c2ecf20Sopenharmony_ci			goto end;
7408c2ecf20Sopenharmony_ci		}
7418c2ecf20Sopenharmony_ci	}
7428c2ecf20Sopenharmony_ci	pr_info("new extension: %s\n", hook->name);
7438c2ecf20Sopenharmony_ciend:
7448c2ecf20Sopenharmony_ci	mutex_unlock(&hook_mutex);
7458c2ecf20Sopenharmony_ci}
7468c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(battery_hook_register);
7478c2ecf20Sopenharmony_ci
7488c2ecf20Sopenharmony_ci/*
7498c2ecf20Sopenharmony_ci * This function gets called right after the battery sysfs
7508c2ecf20Sopenharmony_ci * attributes have been added, so that the drivers that
7518c2ecf20Sopenharmony_ci * define custom sysfs attributes can add their own.
7528c2ecf20Sopenharmony_ci*/
7538c2ecf20Sopenharmony_cistatic void battery_hook_add_battery(struct acpi_battery *battery)
7548c2ecf20Sopenharmony_ci{
7558c2ecf20Sopenharmony_ci	struct acpi_battery_hook *hook_node, *tmp;
7568c2ecf20Sopenharmony_ci
7578c2ecf20Sopenharmony_ci	mutex_lock(&hook_mutex);
7588c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&battery->list);
7598c2ecf20Sopenharmony_ci	list_add(&battery->list, &acpi_battery_list);
7608c2ecf20Sopenharmony_ci	/*
7618c2ecf20Sopenharmony_ci	 * Since we added a new battery to the list, we need to
7628c2ecf20Sopenharmony_ci	 * iterate over the hooks and call add_battery for each
7638c2ecf20Sopenharmony_ci	 * hook that was registered. This usually happens
7648c2ecf20Sopenharmony_ci	 * when a battery gets hotplugged or initialized
7658c2ecf20Sopenharmony_ci	 * during the battery module initialization.
7668c2ecf20Sopenharmony_ci	 */
7678c2ecf20Sopenharmony_ci	list_for_each_entry_safe(hook_node, tmp, &battery_hook_list, list) {
7688c2ecf20Sopenharmony_ci		if (hook_node->add_battery(battery->bat)) {
7698c2ecf20Sopenharmony_ci			/*
7708c2ecf20Sopenharmony_ci			 * The notification of the extensions has failed, to
7718c2ecf20Sopenharmony_ci			 * prevent further errors we will unload the extension.
7728c2ecf20Sopenharmony_ci			 */
7738c2ecf20Sopenharmony_ci			pr_err("error in extension, unloading: %s",
7748c2ecf20Sopenharmony_ci					hook_node->name);
7758c2ecf20Sopenharmony_ci			__battery_hook_unregister(hook_node, 0);
7768c2ecf20Sopenharmony_ci		}
7778c2ecf20Sopenharmony_ci	}
7788c2ecf20Sopenharmony_ci	mutex_unlock(&hook_mutex);
7798c2ecf20Sopenharmony_ci}
7808c2ecf20Sopenharmony_ci
7818c2ecf20Sopenharmony_cistatic void battery_hook_remove_battery(struct acpi_battery *battery)
7828c2ecf20Sopenharmony_ci{
7838c2ecf20Sopenharmony_ci	struct acpi_battery_hook *hook;
7848c2ecf20Sopenharmony_ci
7858c2ecf20Sopenharmony_ci	mutex_lock(&hook_mutex);
7868c2ecf20Sopenharmony_ci	/*
7878c2ecf20Sopenharmony_ci	 * Before removing the hook, we need to remove all
7888c2ecf20Sopenharmony_ci	 * custom attributes from the battery.
7898c2ecf20Sopenharmony_ci	 */
7908c2ecf20Sopenharmony_ci	list_for_each_entry(hook, &battery_hook_list, list) {
7918c2ecf20Sopenharmony_ci		hook->remove_battery(battery->bat);
7928c2ecf20Sopenharmony_ci	}
7938c2ecf20Sopenharmony_ci	/* Then, just remove the battery from the list */
7948c2ecf20Sopenharmony_ci	list_del(&battery->list);
7958c2ecf20Sopenharmony_ci	mutex_unlock(&hook_mutex);
7968c2ecf20Sopenharmony_ci}
7978c2ecf20Sopenharmony_ci
7988c2ecf20Sopenharmony_cistatic void __exit battery_hook_exit(void)
7998c2ecf20Sopenharmony_ci{
8008c2ecf20Sopenharmony_ci	struct acpi_battery_hook *hook;
8018c2ecf20Sopenharmony_ci	struct acpi_battery_hook *ptr;
8028c2ecf20Sopenharmony_ci	/*
8038c2ecf20Sopenharmony_ci	 * At this point, the acpi_bus_unregister_driver()
8048c2ecf20Sopenharmony_ci	 * has called remove for all batteries. We just
8058c2ecf20Sopenharmony_ci	 * need to remove the hooks.
8068c2ecf20Sopenharmony_ci	 */
8078c2ecf20Sopenharmony_ci	list_for_each_entry_safe(hook, ptr, &battery_hook_list, list) {
8088c2ecf20Sopenharmony_ci		__battery_hook_unregister(hook, 1);
8098c2ecf20Sopenharmony_ci	}
8108c2ecf20Sopenharmony_ci	mutex_destroy(&hook_mutex);
8118c2ecf20Sopenharmony_ci}
8128c2ecf20Sopenharmony_ci
8138c2ecf20Sopenharmony_cistatic int sysfs_add_battery(struct acpi_battery *battery)
8148c2ecf20Sopenharmony_ci{
8158c2ecf20Sopenharmony_ci	struct power_supply_config psy_cfg = { .drv_data = battery, };
8168c2ecf20Sopenharmony_ci	bool full_cap_broken = false;
8178c2ecf20Sopenharmony_ci
8188c2ecf20Sopenharmony_ci	if (!ACPI_BATTERY_CAPACITY_VALID(battery->full_charge_capacity) &&
8198c2ecf20Sopenharmony_ci	    !ACPI_BATTERY_CAPACITY_VALID(battery->design_capacity))
8208c2ecf20Sopenharmony_ci		full_cap_broken = true;
8218c2ecf20Sopenharmony_ci
8228c2ecf20Sopenharmony_ci	if (battery->power_unit == ACPI_BATTERY_POWER_UNIT_MA) {
8238c2ecf20Sopenharmony_ci		if (full_cap_broken) {
8248c2ecf20Sopenharmony_ci			battery->bat_desc.properties =
8258c2ecf20Sopenharmony_ci			    charge_battery_full_cap_broken_props;
8268c2ecf20Sopenharmony_ci			battery->bat_desc.num_properties =
8278c2ecf20Sopenharmony_ci			    ARRAY_SIZE(charge_battery_full_cap_broken_props);
8288c2ecf20Sopenharmony_ci		} else {
8298c2ecf20Sopenharmony_ci			battery->bat_desc.properties = charge_battery_props;
8308c2ecf20Sopenharmony_ci			battery->bat_desc.num_properties =
8318c2ecf20Sopenharmony_ci			    ARRAY_SIZE(charge_battery_props);
8328c2ecf20Sopenharmony_ci		}
8338c2ecf20Sopenharmony_ci	} else {
8348c2ecf20Sopenharmony_ci		if (full_cap_broken) {
8358c2ecf20Sopenharmony_ci			battery->bat_desc.properties =
8368c2ecf20Sopenharmony_ci			    energy_battery_full_cap_broken_props;
8378c2ecf20Sopenharmony_ci			battery->bat_desc.num_properties =
8388c2ecf20Sopenharmony_ci			    ARRAY_SIZE(energy_battery_full_cap_broken_props);
8398c2ecf20Sopenharmony_ci		} else {
8408c2ecf20Sopenharmony_ci			battery->bat_desc.properties = energy_battery_props;
8418c2ecf20Sopenharmony_ci			battery->bat_desc.num_properties =
8428c2ecf20Sopenharmony_ci			    ARRAY_SIZE(energy_battery_props);
8438c2ecf20Sopenharmony_ci		}
8448c2ecf20Sopenharmony_ci	}
8458c2ecf20Sopenharmony_ci
8468c2ecf20Sopenharmony_ci	battery->bat_desc.name = acpi_device_bid(battery->device);
8478c2ecf20Sopenharmony_ci	battery->bat_desc.type = POWER_SUPPLY_TYPE_BATTERY;
8488c2ecf20Sopenharmony_ci	battery->bat_desc.get_property = acpi_battery_get_property;
8498c2ecf20Sopenharmony_ci
8508c2ecf20Sopenharmony_ci	battery->bat = power_supply_register_no_ws(&battery->device->dev,
8518c2ecf20Sopenharmony_ci				&battery->bat_desc, &psy_cfg);
8528c2ecf20Sopenharmony_ci
8538c2ecf20Sopenharmony_ci	if (IS_ERR(battery->bat)) {
8548c2ecf20Sopenharmony_ci		int result = PTR_ERR(battery->bat);
8558c2ecf20Sopenharmony_ci
8568c2ecf20Sopenharmony_ci		battery->bat = NULL;
8578c2ecf20Sopenharmony_ci		return result;
8588c2ecf20Sopenharmony_ci	}
8598c2ecf20Sopenharmony_ci	battery_hook_add_battery(battery);
8608c2ecf20Sopenharmony_ci	return device_create_file(&battery->bat->dev, &alarm_attr);
8618c2ecf20Sopenharmony_ci}
8628c2ecf20Sopenharmony_ci
8638c2ecf20Sopenharmony_cistatic void sysfs_remove_battery(struct acpi_battery *battery)
8648c2ecf20Sopenharmony_ci{
8658c2ecf20Sopenharmony_ci	mutex_lock(&battery->sysfs_lock);
8668c2ecf20Sopenharmony_ci	if (!battery->bat) {
8678c2ecf20Sopenharmony_ci		mutex_unlock(&battery->sysfs_lock);
8688c2ecf20Sopenharmony_ci		return;
8698c2ecf20Sopenharmony_ci	}
8708c2ecf20Sopenharmony_ci	battery_hook_remove_battery(battery);
8718c2ecf20Sopenharmony_ci	device_remove_file(&battery->bat->dev, &alarm_attr);
8728c2ecf20Sopenharmony_ci	power_supply_unregister(battery->bat);
8738c2ecf20Sopenharmony_ci	battery->bat = NULL;
8748c2ecf20Sopenharmony_ci	mutex_unlock(&battery->sysfs_lock);
8758c2ecf20Sopenharmony_ci}
8768c2ecf20Sopenharmony_ci
8778c2ecf20Sopenharmony_cistatic void find_battery(const struct dmi_header *dm, void *private)
8788c2ecf20Sopenharmony_ci{
8798c2ecf20Sopenharmony_ci	struct acpi_battery *battery = (struct acpi_battery *)private;
8808c2ecf20Sopenharmony_ci	/* Note: the hardcoded offsets below have been extracted from
8818c2ecf20Sopenharmony_ci	   the source code of dmidecode.  */
8828c2ecf20Sopenharmony_ci	if (dm->type == DMI_ENTRY_PORTABLE_BATTERY && dm->length >= 8) {
8838c2ecf20Sopenharmony_ci		const u8 *dmi_data = (const u8 *)(dm + 1);
8848c2ecf20Sopenharmony_ci		int dmi_capacity = get_unaligned((const u16 *)(dmi_data + 6));
8858c2ecf20Sopenharmony_ci		if (dm->length >= 18)
8868c2ecf20Sopenharmony_ci			dmi_capacity *= dmi_data[17];
8878c2ecf20Sopenharmony_ci		if (battery->design_capacity * battery->design_voltage / 1000
8888c2ecf20Sopenharmony_ci		    != dmi_capacity &&
8898c2ecf20Sopenharmony_ci		    battery->design_capacity * 10 == dmi_capacity)
8908c2ecf20Sopenharmony_ci			set_bit(ACPI_BATTERY_QUIRK_THINKPAD_MAH,
8918c2ecf20Sopenharmony_ci				&battery->flags);
8928c2ecf20Sopenharmony_ci	}
8938c2ecf20Sopenharmony_ci}
8948c2ecf20Sopenharmony_ci
8958c2ecf20Sopenharmony_ci/*
8968c2ecf20Sopenharmony_ci * According to the ACPI spec, some kinds of primary batteries can
8978c2ecf20Sopenharmony_ci * report percentage battery remaining capacity directly to OS.
8988c2ecf20Sopenharmony_ci * In this case, it reports the Last Full Charged Capacity == 100
8998c2ecf20Sopenharmony_ci * and BatteryPresentRate == 0xFFFFFFFF.
9008c2ecf20Sopenharmony_ci *
9018c2ecf20Sopenharmony_ci * Now we found some battery reports percentage remaining capacity
9028c2ecf20Sopenharmony_ci * even if it's rechargeable.
9038c2ecf20Sopenharmony_ci * https://bugzilla.kernel.org/show_bug.cgi?id=15979
9048c2ecf20Sopenharmony_ci *
9058c2ecf20Sopenharmony_ci * Handle this correctly so that they won't break userspace.
9068c2ecf20Sopenharmony_ci */
9078c2ecf20Sopenharmony_cistatic void acpi_battery_quirks(struct acpi_battery *battery)
9088c2ecf20Sopenharmony_ci{
9098c2ecf20Sopenharmony_ci	if (test_bit(ACPI_BATTERY_QUIRK_PERCENTAGE_CAPACITY, &battery->flags))
9108c2ecf20Sopenharmony_ci		return;
9118c2ecf20Sopenharmony_ci
9128c2ecf20Sopenharmony_ci	if (battery->full_charge_capacity == 100 &&
9138c2ecf20Sopenharmony_ci		battery->rate_now == ACPI_BATTERY_VALUE_UNKNOWN &&
9148c2ecf20Sopenharmony_ci		battery->capacity_now >= 0 && battery->capacity_now <= 100) {
9158c2ecf20Sopenharmony_ci		set_bit(ACPI_BATTERY_QUIRK_PERCENTAGE_CAPACITY, &battery->flags);
9168c2ecf20Sopenharmony_ci		battery->full_charge_capacity = battery->design_capacity;
9178c2ecf20Sopenharmony_ci		battery->capacity_now = (battery->capacity_now *
9188c2ecf20Sopenharmony_ci				battery->full_charge_capacity) / 100;
9198c2ecf20Sopenharmony_ci	}
9208c2ecf20Sopenharmony_ci
9218c2ecf20Sopenharmony_ci	if (test_bit(ACPI_BATTERY_QUIRK_THINKPAD_MAH, &battery->flags))
9228c2ecf20Sopenharmony_ci		return;
9238c2ecf20Sopenharmony_ci
9248c2ecf20Sopenharmony_ci	if (battery->power_unit && dmi_name_in_vendors("LENOVO")) {
9258c2ecf20Sopenharmony_ci		const char *s;
9268c2ecf20Sopenharmony_ci		s = dmi_get_system_info(DMI_PRODUCT_VERSION);
9278c2ecf20Sopenharmony_ci		if (s && !strncasecmp(s, "ThinkPad", 8)) {
9288c2ecf20Sopenharmony_ci			dmi_walk(find_battery, battery);
9298c2ecf20Sopenharmony_ci			if (test_bit(ACPI_BATTERY_QUIRK_THINKPAD_MAH,
9308c2ecf20Sopenharmony_ci				     &battery->flags) &&
9318c2ecf20Sopenharmony_ci			    battery->design_voltage) {
9328c2ecf20Sopenharmony_ci				battery->design_capacity =
9338c2ecf20Sopenharmony_ci				    battery->design_capacity *
9348c2ecf20Sopenharmony_ci				    10000 / battery->design_voltage;
9358c2ecf20Sopenharmony_ci				battery->full_charge_capacity =
9368c2ecf20Sopenharmony_ci				    battery->full_charge_capacity *
9378c2ecf20Sopenharmony_ci				    10000 / battery->design_voltage;
9388c2ecf20Sopenharmony_ci				battery->design_capacity_warning =
9398c2ecf20Sopenharmony_ci				    battery->design_capacity_warning *
9408c2ecf20Sopenharmony_ci				    10000 / battery->design_voltage;
9418c2ecf20Sopenharmony_ci				battery->capacity_now = battery->capacity_now *
9428c2ecf20Sopenharmony_ci				    10000 / battery->design_voltage;
9438c2ecf20Sopenharmony_ci			}
9448c2ecf20Sopenharmony_ci		}
9458c2ecf20Sopenharmony_ci	}
9468c2ecf20Sopenharmony_ci
9478c2ecf20Sopenharmony_ci	if (test_bit(ACPI_BATTERY_QUIRK_DEGRADED_FULL_CHARGE, &battery->flags))
9488c2ecf20Sopenharmony_ci		return;
9498c2ecf20Sopenharmony_ci
9508c2ecf20Sopenharmony_ci	if (acpi_battery_is_degraded(battery) &&
9518c2ecf20Sopenharmony_ci	    battery->capacity_now > battery->full_charge_capacity) {
9528c2ecf20Sopenharmony_ci		set_bit(ACPI_BATTERY_QUIRK_DEGRADED_FULL_CHARGE, &battery->flags);
9538c2ecf20Sopenharmony_ci		battery->capacity_now = battery->full_charge_capacity;
9548c2ecf20Sopenharmony_ci	}
9558c2ecf20Sopenharmony_ci}
9568c2ecf20Sopenharmony_ci
9578c2ecf20Sopenharmony_cistatic int acpi_battery_update(struct acpi_battery *battery, bool resume)
9588c2ecf20Sopenharmony_ci{
9598c2ecf20Sopenharmony_ci	int result = acpi_battery_get_status(battery);
9608c2ecf20Sopenharmony_ci
9618c2ecf20Sopenharmony_ci	if (result)
9628c2ecf20Sopenharmony_ci		return result;
9638c2ecf20Sopenharmony_ci
9648c2ecf20Sopenharmony_ci	if (!acpi_battery_present(battery)) {
9658c2ecf20Sopenharmony_ci		sysfs_remove_battery(battery);
9668c2ecf20Sopenharmony_ci		battery->update_time = 0;
9678c2ecf20Sopenharmony_ci		return 0;
9688c2ecf20Sopenharmony_ci	}
9698c2ecf20Sopenharmony_ci
9708c2ecf20Sopenharmony_ci	if (resume)
9718c2ecf20Sopenharmony_ci		return 0;
9728c2ecf20Sopenharmony_ci
9738c2ecf20Sopenharmony_ci	if (!battery->update_time) {
9748c2ecf20Sopenharmony_ci		result = acpi_battery_get_info(battery);
9758c2ecf20Sopenharmony_ci		if (result)
9768c2ecf20Sopenharmony_ci			return result;
9778c2ecf20Sopenharmony_ci		acpi_battery_init_alarm(battery);
9788c2ecf20Sopenharmony_ci	}
9798c2ecf20Sopenharmony_ci
9808c2ecf20Sopenharmony_ci	result = acpi_battery_get_state(battery);
9818c2ecf20Sopenharmony_ci	if (result)
9828c2ecf20Sopenharmony_ci		return result;
9838c2ecf20Sopenharmony_ci	acpi_battery_quirks(battery);
9848c2ecf20Sopenharmony_ci
9858c2ecf20Sopenharmony_ci	if (!battery->bat) {
9868c2ecf20Sopenharmony_ci		result = sysfs_add_battery(battery);
9878c2ecf20Sopenharmony_ci		if (result)
9888c2ecf20Sopenharmony_ci			return result;
9898c2ecf20Sopenharmony_ci	}
9908c2ecf20Sopenharmony_ci
9918c2ecf20Sopenharmony_ci	/*
9928c2ecf20Sopenharmony_ci	 * Wakeup the system if battery is critical low
9938c2ecf20Sopenharmony_ci	 * or lower than the alarm level
9948c2ecf20Sopenharmony_ci	 */
9958c2ecf20Sopenharmony_ci	if ((battery->state & ACPI_BATTERY_STATE_CRITICAL) ||
9968c2ecf20Sopenharmony_ci	    (test_bit(ACPI_BATTERY_ALARM_PRESENT, &battery->flags) &&
9978c2ecf20Sopenharmony_ci	     (battery->capacity_now <= battery->alarm)))
9988c2ecf20Sopenharmony_ci		acpi_pm_wakeup_event(&battery->device->dev);
9998c2ecf20Sopenharmony_ci
10008c2ecf20Sopenharmony_ci	return result;
10018c2ecf20Sopenharmony_ci}
10028c2ecf20Sopenharmony_ci
10038c2ecf20Sopenharmony_cistatic void acpi_battery_refresh(struct acpi_battery *battery)
10048c2ecf20Sopenharmony_ci{
10058c2ecf20Sopenharmony_ci	int power_unit;
10068c2ecf20Sopenharmony_ci
10078c2ecf20Sopenharmony_ci	if (!battery->bat)
10088c2ecf20Sopenharmony_ci		return;
10098c2ecf20Sopenharmony_ci
10108c2ecf20Sopenharmony_ci	power_unit = battery->power_unit;
10118c2ecf20Sopenharmony_ci
10128c2ecf20Sopenharmony_ci	acpi_battery_get_info(battery);
10138c2ecf20Sopenharmony_ci
10148c2ecf20Sopenharmony_ci	if (power_unit == battery->power_unit)
10158c2ecf20Sopenharmony_ci		return;
10168c2ecf20Sopenharmony_ci
10178c2ecf20Sopenharmony_ci	/* The battery has changed its reporting units. */
10188c2ecf20Sopenharmony_ci	sysfs_remove_battery(battery);
10198c2ecf20Sopenharmony_ci	sysfs_add_battery(battery);
10208c2ecf20Sopenharmony_ci}
10218c2ecf20Sopenharmony_ci
10228c2ecf20Sopenharmony_ci/* --------------------------------------------------------------------------
10238c2ecf20Sopenharmony_ci                                 Driver Interface
10248c2ecf20Sopenharmony_ci   -------------------------------------------------------------------------- */
10258c2ecf20Sopenharmony_ci
10268c2ecf20Sopenharmony_cistatic void acpi_battery_notify(struct acpi_device *device, u32 event)
10278c2ecf20Sopenharmony_ci{
10288c2ecf20Sopenharmony_ci	struct acpi_battery *battery = acpi_driver_data(device);
10298c2ecf20Sopenharmony_ci	struct power_supply *old;
10308c2ecf20Sopenharmony_ci
10318c2ecf20Sopenharmony_ci	if (!battery)
10328c2ecf20Sopenharmony_ci		return;
10338c2ecf20Sopenharmony_ci	old = battery->bat;
10348c2ecf20Sopenharmony_ci	/*
10358c2ecf20Sopenharmony_ci	* On Acer Aspire V5-573G notifications are sometimes triggered too
10368c2ecf20Sopenharmony_ci	* early. For example, when AC is unplugged and notification is
10378c2ecf20Sopenharmony_ci	* triggered, battery state is still reported as "Full", and changes to
10388c2ecf20Sopenharmony_ci	* "Discharging" only after short delay, without any notification.
10398c2ecf20Sopenharmony_ci	*/
10408c2ecf20Sopenharmony_ci	if (battery_notification_delay_ms > 0)
10418c2ecf20Sopenharmony_ci		msleep(battery_notification_delay_ms);
10428c2ecf20Sopenharmony_ci	if (event == ACPI_BATTERY_NOTIFY_INFO)
10438c2ecf20Sopenharmony_ci		acpi_battery_refresh(battery);
10448c2ecf20Sopenharmony_ci	acpi_battery_update(battery, false);
10458c2ecf20Sopenharmony_ci	acpi_bus_generate_netlink_event(device->pnp.device_class,
10468c2ecf20Sopenharmony_ci					dev_name(&device->dev), event,
10478c2ecf20Sopenharmony_ci					acpi_battery_present(battery));
10488c2ecf20Sopenharmony_ci	acpi_notifier_call_chain(device, event, acpi_battery_present(battery));
10498c2ecf20Sopenharmony_ci	/* acpi_battery_update could remove power_supply object */
10508c2ecf20Sopenharmony_ci	if (old && battery->bat)
10518c2ecf20Sopenharmony_ci		power_supply_changed(battery->bat);
10528c2ecf20Sopenharmony_ci}
10538c2ecf20Sopenharmony_ci
10548c2ecf20Sopenharmony_cistatic int battery_notify(struct notifier_block *nb,
10558c2ecf20Sopenharmony_ci			       unsigned long mode, void *_unused)
10568c2ecf20Sopenharmony_ci{
10578c2ecf20Sopenharmony_ci	struct acpi_battery *battery = container_of(nb, struct acpi_battery,
10588c2ecf20Sopenharmony_ci						    pm_nb);
10598c2ecf20Sopenharmony_ci	int result;
10608c2ecf20Sopenharmony_ci
10618c2ecf20Sopenharmony_ci	switch (mode) {
10628c2ecf20Sopenharmony_ci	case PM_POST_HIBERNATION:
10638c2ecf20Sopenharmony_ci	case PM_POST_SUSPEND:
10648c2ecf20Sopenharmony_ci		if (!acpi_battery_present(battery))
10658c2ecf20Sopenharmony_ci			return 0;
10668c2ecf20Sopenharmony_ci
10678c2ecf20Sopenharmony_ci		if (battery->bat) {
10688c2ecf20Sopenharmony_ci			acpi_battery_refresh(battery);
10698c2ecf20Sopenharmony_ci		} else {
10708c2ecf20Sopenharmony_ci			result = acpi_battery_get_info(battery);
10718c2ecf20Sopenharmony_ci			if (result)
10728c2ecf20Sopenharmony_ci				return result;
10738c2ecf20Sopenharmony_ci
10748c2ecf20Sopenharmony_ci			result = sysfs_add_battery(battery);
10758c2ecf20Sopenharmony_ci			if (result)
10768c2ecf20Sopenharmony_ci				return result;
10778c2ecf20Sopenharmony_ci		}
10788c2ecf20Sopenharmony_ci
10798c2ecf20Sopenharmony_ci		acpi_battery_init_alarm(battery);
10808c2ecf20Sopenharmony_ci		acpi_battery_get_state(battery);
10818c2ecf20Sopenharmony_ci		break;
10828c2ecf20Sopenharmony_ci	}
10838c2ecf20Sopenharmony_ci
10848c2ecf20Sopenharmony_ci	return 0;
10858c2ecf20Sopenharmony_ci}
10868c2ecf20Sopenharmony_ci
10878c2ecf20Sopenharmony_cistatic int __init
10888c2ecf20Sopenharmony_cibattery_bix_broken_package_quirk(const struct dmi_system_id *d)
10898c2ecf20Sopenharmony_ci{
10908c2ecf20Sopenharmony_ci	battery_bix_broken_package = 1;
10918c2ecf20Sopenharmony_ci	return 0;
10928c2ecf20Sopenharmony_ci}
10938c2ecf20Sopenharmony_ci
10948c2ecf20Sopenharmony_cistatic int __init
10958c2ecf20Sopenharmony_cibattery_notification_delay_quirk(const struct dmi_system_id *d)
10968c2ecf20Sopenharmony_ci{
10978c2ecf20Sopenharmony_ci	battery_notification_delay_ms = 1000;
10988c2ecf20Sopenharmony_ci	return 0;
10998c2ecf20Sopenharmony_ci}
11008c2ecf20Sopenharmony_ci
11018c2ecf20Sopenharmony_cistatic int __init
11028c2ecf20Sopenharmony_cibattery_ac_is_broken_quirk(const struct dmi_system_id *d)
11038c2ecf20Sopenharmony_ci{
11048c2ecf20Sopenharmony_ci	battery_ac_is_broken = 1;
11058c2ecf20Sopenharmony_ci	return 0;
11068c2ecf20Sopenharmony_ci}
11078c2ecf20Sopenharmony_ci
11088c2ecf20Sopenharmony_cistatic int __init
11098c2ecf20Sopenharmony_cibattery_do_not_check_pmic_quirk(const struct dmi_system_id *d)
11108c2ecf20Sopenharmony_ci{
11118c2ecf20Sopenharmony_ci	battery_check_pmic = 0;
11128c2ecf20Sopenharmony_ci	return 0;
11138c2ecf20Sopenharmony_ci}
11148c2ecf20Sopenharmony_ci
11158c2ecf20Sopenharmony_cistatic int __init battery_quirk_not_charging(const struct dmi_system_id *d)
11168c2ecf20Sopenharmony_ci{
11178c2ecf20Sopenharmony_ci	battery_quirk_notcharging = 1;
11188c2ecf20Sopenharmony_ci	return 0;
11198c2ecf20Sopenharmony_ci}
11208c2ecf20Sopenharmony_ci
11218c2ecf20Sopenharmony_cistatic const struct dmi_system_id bat_dmi_table[] __initconst = {
11228c2ecf20Sopenharmony_ci	{
11238c2ecf20Sopenharmony_ci		/* NEC LZ750/LS */
11248c2ecf20Sopenharmony_ci		.callback = battery_bix_broken_package_quirk,
11258c2ecf20Sopenharmony_ci		.matches = {
11268c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_SYS_VENDOR, "NEC"),
11278c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_PRODUCT_NAME, "PC-LZ750LS"),
11288c2ecf20Sopenharmony_ci		},
11298c2ecf20Sopenharmony_ci	},
11308c2ecf20Sopenharmony_ci	{
11318c2ecf20Sopenharmony_ci		/* Acer Aspire V5-573G */
11328c2ecf20Sopenharmony_ci		.callback = battery_notification_delay_quirk,
11338c2ecf20Sopenharmony_ci		.matches = {
11348c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
11358c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_PRODUCT_NAME, "Aspire V5-573G"),
11368c2ecf20Sopenharmony_ci		},
11378c2ecf20Sopenharmony_ci	},
11388c2ecf20Sopenharmony_ci	{
11398c2ecf20Sopenharmony_ci		/* Point of View mobii wintab p800w */
11408c2ecf20Sopenharmony_ci		.callback = battery_ac_is_broken_quirk,
11418c2ecf20Sopenharmony_ci		.matches = {
11428c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_BOARD_VENDOR, "AMI Corporation"),
11438c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_BOARD_NAME, "Aptio CRB"),
11448c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_BIOS_VERSION, "3BAIR1013"),
11458c2ecf20Sopenharmony_ci			/* Above matches are too generic, add bios-date match */
11468c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_BIOS_DATE, "08/22/2014"),
11478c2ecf20Sopenharmony_ci		},
11488c2ecf20Sopenharmony_ci	},
11498c2ecf20Sopenharmony_ci	{
11508c2ecf20Sopenharmony_ci		/* ECS EF20EA, AXP288 PMIC but uses separate fuel-gauge */
11518c2ecf20Sopenharmony_ci		.callback = battery_do_not_check_pmic_quirk,
11528c2ecf20Sopenharmony_ci		.matches = {
11538c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_PRODUCT_NAME, "EF20EA"),
11548c2ecf20Sopenharmony_ci		},
11558c2ecf20Sopenharmony_ci	},
11568c2ecf20Sopenharmony_ci	{
11578c2ecf20Sopenharmony_ci		/* Lenovo Ideapad Miix 320, AXP288 PMIC, separate fuel-gauge */
11588c2ecf20Sopenharmony_ci		.callback = battery_do_not_check_pmic_quirk,
11598c2ecf20Sopenharmony_ci		.matches = {
11608c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
11618c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_PRODUCT_NAME, "80XF"),
11628c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo MIIX 320-10ICR"),
11638c2ecf20Sopenharmony_ci		},
11648c2ecf20Sopenharmony_ci	},
11658c2ecf20Sopenharmony_ci	{
11668c2ecf20Sopenharmony_ci		/*
11678c2ecf20Sopenharmony_ci		 * On Lenovo ThinkPads the BIOS specification defines
11688c2ecf20Sopenharmony_ci		 * a state when the bits for charging and discharging
11698c2ecf20Sopenharmony_ci		 * are both set to 0. That state is "Not Charging".
11708c2ecf20Sopenharmony_ci		 */
11718c2ecf20Sopenharmony_ci		.callback = battery_quirk_not_charging,
11728c2ecf20Sopenharmony_ci		.ident = "Lenovo ThinkPad",
11738c2ecf20Sopenharmony_ci		.matches = {
11748c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
11758c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad"),
11768c2ecf20Sopenharmony_ci		},
11778c2ecf20Sopenharmony_ci	},
11788c2ecf20Sopenharmony_ci	{
11798c2ecf20Sopenharmony_ci		/* Microsoft Surface Go 3 */
11808c2ecf20Sopenharmony_ci		.callback = battery_notification_delay_quirk,
11818c2ecf20Sopenharmony_ci		.matches = {
11828c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"),
11838c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_PRODUCT_NAME, "Surface Go 3"),
11848c2ecf20Sopenharmony_ci		},
11858c2ecf20Sopenharmony_ci	},
11868c2ecf20Sopenharmony_ci	{},
11878c2ecf20Sopenharmony_ci};
11888c2ecf20Sopenharmony_ci
11898c2ecf20Sopenharmony_ci/*
11908c2ecf20Sopenharmony_ci * Some machines'(E,G Lenovo Z480) ECs are not stable
11918c2ecf20Sopenharmony_ci * during boot up and this causes battery driver fails to be
11928c2ecf20Sopenharmony_ci * probed due to failure of getting battery information
11938c2ecf20Sopenharmony_ci * from EC sometimes. After several retries, the operation
11948c2ecf20Sopenharmony_ci * may work. So add retry code here and 20ms sleep between
11958c2ecf20Sopenharmony_ci * every retries.
11968c2ecf20Sopenharmony_ci */
11978c2ecf20Sopenharmony_cistatic int acpi_battery_update_retry(struct acpi_battery *battery)
11988c2ecf20Sopenharmony_ci{
11998c2ecf20Sopenharmony_ci	int retry, ret;
12008c2ecf20Sopenharmony_ci
12018c2ecf20Sopenharmony_ci	for (retry = 5; retry; retry--) {
12028c2ecf20Sopenharmony_ci		ret = acpi_battery_update(battery, false);
12038c2ecf20Sopenharmony_ci		if (!ret)
12048c2ecf20Sopenharmony_ci			break;
12058c2ecf20Sopenharmony_ci
12068c2ecf20Sopenharmony_ci		msleep(20);
12078c2ecf20Sopenharmony_ci	}
12088c2ecf20Sopenharmony_ci	return ret;
12098c2ecf20Sopenharmony_ci}
12108c2ecf20Sopenharmony_ci
12118c2ecf20Sopenharmony_cistatic int acpi_battery_add(struct acpi_device *device)
12128c2ecf20Sopenharmony_ci{
12138c2ecf20Sopenharmony_ci	int result = 0;
12148c2ecf20Sopenharmony_ci	struct acpi_battery *battery = NULL;
12158c2ecf20Sopenharmony_ci
12168c2ecf20Sopenharmony_ci	if (!device)
12178c2ecf20Sopenharmony_ci		return -EINVAL;
12188c2ecf20Sopenharmony_ci
12198c2ecf20Sopenharmony_ci	if (device->dep_unmet)
12208c2ecf20Sopenharmony_ci		return -EPROBE_DEFER;
12218c2ecf20Sopenharmony_ci
12228c2ecf20Sopenharmony_ci	battery = kzalloc(sizeof(struct acpi_battery), GFP_KERNEL);
12238c2ecf20Sopenharmony_ci	if (!battery)
12248c2ecf20Sopenharmony_ci		return -ENOMEM;
12258c2ecf20Sopenharmony_ci	battery->device = device;
12268c2ecf20Sopenharmony_ci	strcpy(acpi_device_name(device), ACPI_BATTERY_DEVICE_NAME);
12278c2ecf20Sopenharmony_ci	strcpy(acpi_device_class(device), ACPI_BATTERY_CLASS);
12288c2ecf20Sopenharmony_ci	device->driver_data = battery;
12298c2ecf20Sopenharmony_ci	mutex_init(&battery->lock);
12308c2ecf20Sopenharmony_ci	mutex_init(&battery->sysfs_lock);
12318c2ecf20Sopenharmony_ci	if (acpi_has_method(battery->device->handle, "_BIX"))
12328c2ecf20Sopenharmony_ci		set_bit(ACPI_BATTERY_XINFO_PRESENT, &battery->flags);
12338c2ecf20Sopenharmony_ci
12348c2ecf20Sopenharmony_ci	result = acpi_battery_update_retry(battery);
12358c2ecf20Sopenharmony_ci	if (result)
12368c2ecf20Sopenharmony_ci		goto fail;
12378c2ecf20Sopenharmony_ci
12388c2ecf20Sopenharmony_ci	pr_info(PREFIX "%s Slot [%s] (battery %s)\n",
12398c2ecf20Sopenharmony_ci		ACPI_BATTERY_DEVICE_NAME, acpi_device_bid(device),
12408c2ecf20Sopenharmony_ci		device->status.battery_present ? "present" : "absent");
12418c2ecf20Sopenharmony_ci
12428c2ecf20Sopenharmony_ci	battery->pm_nb.notifier_call = battery_notify;
12438c2ecf20Sopenharmony_ci	register_pm_notifier(&battery->pm_nb);
12448c2ecf20Sopenharmony_ci
12458c2ecf20Sopenharmony_ci	device_init_wakeup(&device->dev, 1);
12468c2ecf20Sopenharmony_ci
12478c2ecf20Sopenharmony_ci	return result;
12488c2ecf20Sopenharmony_ci
12498c2ecf20Sopenharmony_cifail:
12508c2ecf20Sopenharmony_ci	sysfs_remove_battery(battery);
12518c2ecf20Sopenharmony_ci	mutex_destroy(&battery->lock);
12528c2ecf20Sopenharmony_ci	mutex_destroy(&battery->sysfs_lock);
12538c2ecf20Sopenharmony_ci	kfree(battery);
12548c2ecf20Sopenharmony_ci	return result;
12558c2ecf20Sopenharmony_ci}
12568c2ecf20Sopenharmony_ci
12578c2ecf20Sopenharmony_cistatic int acpi_battery_remove(struct acpi_device *device)
12588c2ecf20Sopenharmony_ci{
12598c2ecf20Sopenharmony_ci	struct acpi_battery *battery = NULL;
12608c2ecf20Sopenharmony_ci
12618c2ecf20Sopenharmony_ci	if (!device || !acpi_driver_data(device))
12628c2ecf20Sopenharmony_ci		return -EINVAL;
12638c2ecf20Sopenharmony_ci	device_init_wakeup(&device->dev, 0);
12648c2ecf20Sopenharmony_ci	battery = acpi_driver_data(device);
12658c2ecf20Sopenharmony_ci	unregister_pm_notifier(&battery->pm_nb);
12668c2ecf20Sopenharmony_ci	sysfs_remove_battery(battery);
12678c2ecf20Sopenharmony_ci	mutex_destroy(&battery->lock);
12688c2ecf20Sopenharmony_ci	mutex_destroy(&battery->sysfs_lock);
12698c2ecf20Sopenharmony_ci	kfree(battery);
12708c2ecf20Sopenharmony_ci	return 0;
12718c2ecf20Sopenharmony_ci}
12728c2ecf20Sopenharmony_ci
12738c2ecf20Sopenharmony_ci#ifdef CONFIG_PM_SLEEP
12748c2ecf20Sopenharmony_ci/* this is needed to learn about changes made in suspended state */
12758c2ecf20Sopenharmony_cistatic int acpi_battery_resume(struct device *dev)
12768c2ecf20Sopenharmony_ci{
12778c2ecf20Sopenharmony_ci	struct acpi_battery *battery;
12788c2ecf20Sopenharmony_ci
12798c2ecf20Sopenharmony_ci	if (!dev)
12808c2ecf20Sopenharmony_ci		return -EINVAL;
12818c2ecf20Sopenharmony_ci
12828c2ecf20Sopenharmony_ci	battery = acpi_driver_data(to_acpi_device(dev));
12838c2ecf20Sopenharmony_ci	if (!battery)
12848c2ecf20Sopenharmony_ci		return -EINVAL;
12858c2ecf20Sopenharmony_ci
12868c2ecf20Sopenharmony_ci	battery->update_time = 0;
12878c2ecf20Sopenharmony_ci	acpi_battery_update(battery, true);
12888c2ecf20Sopenharmony_ci	return 0;
12898c2ecf20Sopenharmony_ci}
12908c2ecf20Sopenharmony_ci#else
12918c2ecf20Sopenharmony_ci#define acpi_battery_resume NULL
12928c2ecf20Sopenharmony_ci#endif
12938c2ecf20Sopenharmony_ci
12948c2ecf20Sopenharmony_cistatic SIMPLE_DEV_PM_OPS(acpi_battery_pm, NULL, acpi_battery_resume);
12958c2ecf20Sopenharmony_ci
12968c2ecf20Sopenharmony_cistatic struct acpi_driver acpi_battery_driver = {
12978c2ecf20Sopenharmony_ci	.name = "battery",
12988c2ecf20Sopenharmony_ci	.class = ACPI_BATTERY_CLASS,
12998c2ecf20Sopenharmony_ci	.ids = battery_device_ids,
13008c2ecf20Sopenharmony_ci	.flags = ACPI_DRIVER_ALL_NOTIFY_EVENTS,
13018c2ecf20Sopenharmony_ci	.ops = {
13028c2ecf20Sopenharmony_ci		.add = acpi_battery_add,
13038c2ecf20Sopenharmony_ci		.remove = acpi_battery_remove,
13048c2ecf20Sopenharmony_ci		.notify = acpi_battery_notify,
13058c2ecf20Sopenharmony_ci		},
13068c2ecf20Sopenharmony_ci	.drv.pm = &acpi_battery_pm,
13078c2ecf20Sopenharmony_ci};
13088c2ecf20Sopenharmony_ci
13098c2ecf20Sopenharmony_cistatic void __init acpi_battery_init_async(void *unused, async_cookie_t cookie)
13108c2ecf20Sopenharmony_ci{
13118c2ecf20Sopenharmony_ci	unsigned int i;
13128c2ecf20Sopenharmony_ci	int result;
13138c2ecf20Sopenharmony_ci
13148c2ecf20Sopenharmony_ci	dmi_check_system(bat_dmi_table);
13158c2ecf20Sopenharmony_ci
13168c2ecf20Sopenharmony_ci	if (battery_check_pmic) {
13178c2ecf20Sopenharmony_ci		for (i = 0; i < ARRAY_SIZE(acpi_battery_blacklist); i++)
13188c2ecf20Sopenharmony_ci			if (acpi_dev_present(acpi_battery_blacklist[i], "1", -1)) {
13198c2ecf20Sopenharmony_ci				pr_info(PREFIX ACPI_BATTERY_DEVICE_NAME
13208c2ecf20Sopenharmony_ci					": found native %s PMIC, not loading\n",
13218c2ecf20Sopenharmony_ci					acpi_battery_blacklist[i]);
13228c2ecf20Sopenharmony_ci				return;
13238c2ecf20Sopenharmony_ci			}
13248c2ecf20Sopenharmony_ci	}
13258c2ecf20Sopenharmony_ci
13268c2ecf20Sopenharmony_ci	result = acpi_bus_register_driver(&acpi_battery_driver);
13278c2ecf20Sopenharmony_ci	battery_driver_registered = (result == 0);
13288c2ecf20Sopenharmony_ci}
13298c2ecf20Sopenharmony_ci
13308c2ecf20Sopenharmony_cistatic int __init acpi_battery_init(void)
13318c2ecf20Sopenharmony_ci{
13328c2ecf20Sopenharmony_ci	if (acpi_disabled)
13338c2ecf20Sopenharmony_ci		return -ENODEV;
13348c2ecf20Sopenharmony_ci
13358c2ecf20Sopenharmony_ci	async_cookie = async_schedule(acpi_battery_init_async, NULL);
13368c2ecf20Sopenharmony_ci	return 0;
13378c2ecf20Sopenharmony_ci}
13388c2ecf20Sopenharmony_ci
13398c2ecf20Sopenharmony_cistatic void __exit acpi_battery_exit(void)
13408c2ecf20Sopenharmony_ci{
13418c2ecf20Sopenharmony_ci	async_synchronize_cookie(async_cookie + 1);
13428c2ecf20Sopenharmony_ci	if (battery_driver_registered) {
13438c2ecf20Sopenharmony_ci		acpi_bus_unregister_driver(&acpi_battery_driver);
13448c2ecf20Sopenharmony_ci		battery_hook_exit();
13458c2ecf20Sopenharmony_ci	}
13468c2ecf20Sopenharmony_ci}
13478c2ecf20Sopenharmony_ci
13488c2ecf20Sopenharmony_cimodule_init(acpi_battery_init);
13498c2ecf20Sopenharmony_cimodule_exit(acpi_battery_exit);
1350