brintos

brintos / linux-shallow public Read only

0
0
Text · 21.9 KiB · ebd1edd Raw
876 lines · c
1// SPDX-License-Identifier: GPL-2.0+2/*3 * Battery driver for 7th-generation Microsoft Surface devices via Surface4 * System Aggregator Module (SSAM).5 *6 * Copyright (C) 2019-2021 Maximilian Luz <luzmaximilian@gmail.com>7 */8 9#include <linux/unaligned.h>10#include <linux/jiffies.h>11#include <linux/kernel.h>12#include <linux/module.h>13#include <linux/mutex.h>14#include <linux/power_supply.h>15#include <linux/sysfs.h>16#include <linux/types.h>17#include <linux/workqueue.h>18 19#include <linux/surface_aggregator/device.h>20 21 22/* -- SAM interface. -------------------------------------------------------- */23 24enum sam_event_cid_bat {25	SAM_EVENT_CID_BAT_BIX         = 0x15,26	SAM_EVENT_CID_BAT_BST         = 0x16,27	SAM_EVENT_CID_BAT_ADP         = 0x17,28	SAM_EVENT_CID_BAT_PROT        = 0x18,29	SAM_EVENT_CID_BAT_DPTF        = 0x53,30};31 32enum sam_battery_sta {33	SAM_BATTERY_STA_OK            = 0x0f,34	SAM_BATTERY_STA_PRESENT	      = 0x10,35};36 37enum sam_battery_state {38	SAM_BATTERY_STATE_DISCHARGING = BIT(0),39	SAM_BATTERY_STATE_CHARGING    = BIT(1),40	SAM_BATTERY_STATE_CRITICAL    = BIT(2),41};42 43enum sam_battery_power_unit {44	SAM_BATTERY_POWER_UNIT_mW     = 0,45	SAM_BATTERY_POWER_UNIT_mA     = 1,46};47 48/* Equivalent to data returned in ACPI _BIX method, revision 0. */49struct spwr_bix {50	u8  revision;51	__le32 power_unit;52	__le32 design_cap;53	__le32 last_full_charge_cap;54	__le32 technology;55	__le32 design_voltage;56	__le32 design_cap_warn;57	__le32 design_cap_low;58	__le32 cycle_count;59	__le32 measurement_accuracy;60	__le32 max_sampling_time;61	__le32 min_sampling_time;62	__le32 max_avg_interval;63	__le32 min_avg_interval;64	__le32 bat_cap_granularity_1;65	__le32 bat_cap_granularity_2;66	__u8 model[21];67	__u8 serial[11];68	__u8 type[5];69	__u8 oem_info[21];70} __packed;71 72static_assert(sizeof(struct spwr_bix) == 119);73 74/* Equivalent to data returned in ACPI _BST method. */75struct spwr_bst {76	__le32 state;77	__le32 present_rate;78	__le32 remaining_cap;79	__le32 present_voltage;80} __packed;81 82static_assert(sizeof(struct spwr_bst) == 16);83 84#define SPWR_BIX_REVISION		085#define SPWR_BATTERY_VALUE_UNKNOWN	0xffffffff86 87/* Get battery status (_STA) */88SSAM_DEFINE_SYNC_REQUEST_CL_R(ssam_bat_get_sta, __le32, {89	.target_category = SSAM_SSH_TC_BAT,90	.command_id      = 0x01,91});92 93/* Get battery static information (_BIX). */94SSAM_DEFINE_SYNC_REQUEST_CL_R(ssam_bat_get_bix, struct spwr_bix, {95	.target_category = SSAM_SSH_TC_BAT,96	.command_id      = 0x02,97});98 99/* Get battery dynamic information (_BST). */100SSAM_DEFINE_SYNC_REQUEST_CL_R(ssam_bat_get_bst, struct spwr_bst, {101	.target_category = SSAM_SSH_TC_BAT,102	.command_id      = 0x03,103});104 105/* Set battery trip point (_BTP). */106SSAM_DEFINE_SYNC_REQUEST_CL_W(ssam_bat_set_btp, __le32, {107	.target_category = SSAM_SSH_TC_BAT,108	.command_id      = 0x04,109});110 111 112/* -- Device structures. ---------------------------------------------------- */113 114struct spwr_psy_properties {115	const char *name;116	struct ssam_event_registry registry;117};118 119struct spwr_battery_device {120	struct ssam_device *sdev;121 122	char name[32];123	struct power_supply *psy;124	struct power_supply_desc psy_desc;125 126	struct delayed_work update_work;127 128	struct ssam_event_notifier notif;129 130	struct mutex lock;  /* Guards access to state data below. */131	unsigned long timestamp;132 133	__le32 sta;134	struct spwr_bix bix;135	struct spwr_bst bst;136	u32 alarm;137};138 139 140/* -- Module parameters. ---------------------------------------------------- */141 142static unsigned int cache_time = 1000;143module_param(cache_time, uint, 0644);144MODULE_PARM_DESC(cache_time, "battery state caching time in milliseconds [default: 1000]");145 146 147/* -- State management. ----------------------------------------------------- */148 149/*150 * Delay for battery update quirk. See spwr_external_power_changed() below151 * for more details.152 */153#define SPWR_AC_BAT_UPDATE_DELAY	msecs_to_jiffies(5000)154 155static bool spwr_battery_present(struct spwr_battery_device *bat)156{157	lockdep_assert_held(&bat->lock);158 159	return le32_to_cpu(bat->sta) & SAM_BATTERY_STA_PRESENT;160}161 162static int spwr_battery_load_sta(struct spwr_battery_device *bat)163{164	lockdep_assert_held(&bat->lock);165 166	return ssam_retry(ssam_bat_get_sta, bat->sdev, &bat->sta);167}168 169static int spwr_battery_load_bix(struct spwr_battery_device *bat)170{171	int status;172 173	lockdep_assert_held(&bat->lock);174 175	if (!spwr_battery_present(bat))176		return 0;177 178	status = ssam_retry(ssam_bat_get_bix, bat->sdev, &bat->bix);179 180	/* Enforce NULL terminated strings in case anything goes wrong... */181	bat->bix.model[ARRAY_SIZE(bat->bix.model) - 1] = 0;182	bat->bix.serial[ARRAY_SIZE(bat->bix.serial) - 1] = 0;183	bat->bix.type[ARRAY_SIZE(bat->bix.type) - 1] = 0;184	bat->bix.oem_info[ARRAY_SIZE(bat->bix.oem_info) - 1] = 0;185 186	return status;187}188 189static int spwr_battery_load_bst(struct spwr_battery_device *bat)190{191	lockdep_assert_held(&bat->lock);192 193	if (!spwr_battery_present(bat))194		return 0;195 196	return ssam_retry(ssam_bat_get_bst, bat->sdev, &bat->bst);197}198 199static int spwr_battery_set_alarm_unlocked(struct spwr_battery_device *bat, u32 value)200{201	__le32 value_le = cpu_to_le32(value);202 203	lockdep_assert_held(&bat->lock);204 205	bat->alarm = value;206	return ssam_retry(ssam_bat_set_btp, bat->sdev, &value_le);207}208 209static int spwr_battery_update_bst_unlocked(struct spwr_battery_device *bat, bool cached)210{211	unsigned long cache_deadline = bat->timestamp + msecs_to_jiffies(cache_time);212	int status;213 214	lockdep_assert_held(&bat->lock);215 216	if (cached && bat->timestamp && time_is_after_jiffies(cache_deadline))217		return 0;218 219	status = spwr_battery_load_sta(bat);220	if (status)221		return status;222 223	status = spwr_battery_load_bst(bat);224	if (status)225		return status;226 227	bat->timestamp = jiffies;228	return 0;229}230 231static int spwr_battery_update_bst(struct spwr_battery_device *bat, bool cached)232{233	int status;234 235	mutex_lock(&bat->lock);236	status = spwr_battery_update_bst_unlocked(bat, cached);237	mutex_unlock(&bat->lock);238 239	return status;240}241 242static int spwr_battery_update_bix_unlocked(struct spwr_battery_device *bat)243{244	int status;245 246	lockdep_assert_held(&bat->lock);247 248	status = spwr_battery_load_sta(bat);249	if (status)250		return status;251 252	status = spwr_battery_load_bix(bat);253	if (status)254		return status;255 256	status = spwr_battery_load_bst(bat);257	if (status)258		return status;259 260	if (bat->bix.revision != SPWR_BIX_REVISION)261		dev_warn(&bat->sdev->dev, "unsupported battery revision: %u\n", bat->bix.revision);262 263	bat->timestamp = jiffies;264	return 0;265}266 267static u32 sprw_battery_get_full_cap_safe(struct spwr_battery_device *bat)268{269	u32 full_cap = get_unaligned_le32(&bat->bix.last_full_charge_cap);270 271	lockdep_assert_held(&bat->lock);272 273	if (full_cap == 0 || full_cap == SPWR_BATTERY_VALUE_UNKNOWN)274		full_cap = get_unaligned_le32(&bat->bix.design_cap);275 276	return full_cap;277}278 279static bool spwr_battery_is_full(struct spwr_battery_device *bat)280{281	u32 state = get_unaligned_le32(&bat->bst.state);282	u32 full_cap = sprw_battery_get_full_cap_safe(bat);283	u32 remaining_cap = get_unaligned_le32(&bat->bst.remaining_cap);284 285	lockdep_assert_held(&bat->lock);286 287	return full_cap != SPWR_BATTERY_VALUE_UNKNOWN && full_cap != 0 &&288		remaining_cap != SPWR_BATTERY_VALUE_UNKNOWN &&289		remaining_cap >= full_cap &&290		state == 0;291}292 293static int spwr_battery_recheck_full(struct spwr_battery_device *bat)294{295	bool present;296	u32 unit;297	int status;298 299	mutex_lock(&bat->lock);300	unit = get_unaligned_le32(&bat->bix.power_unit);301	present = spwr_battery_present(bat);302 303	status = spwr_battery_update_bix_unlocked(bat);304	if (status)305		goto out;306 307	/* If battery has been attached, (re-)initialize alarm. */308	if (!present && spwr_battery_present(bat)) {309		u32 cap_warn = get_unaligned_le32(&bat->bix.design_cap_warn);310 311		status = spwr_battery_set_alarm_unlocked(bat, cap_warn);312		if (status)313			goto out;314	}315 316	/*317	 * Warn if the unit has changed. This is something we genuinely don't318	 * expect to happen, so make this a big warning. If it does, we'll319	 * need to add support for it.320	 */321	WARN_ON(unit != get_unaligned_le32(&bat->bix.power_unit));322 323out:324	mutex_unlock(&bat->lock);325 326	if (!status)327		power_supply_changed(bat->psy);328 329	return status;330}331 332static int spwr_battery_recheck_status(struct spwr_battery_device *bat)333{334	int status;335 336	status = spwr_battery_update_bst(bat, false);337	if (!status)338		power_supply_changed(bat->psy);339 340	return status;341}342 343static u32 spwr_notify_bat(struct ssam_event_notifier *nf, const struct ssam_event *event)344{345	struct spwr_battery_device *bat = container_of(nf, struct spwr_battery_device, notif);346	int status;347 348	/*349	 * We cannot use strict matching when registering the notifier as the350	 * EC expects us to register it against instance ID 0. Strict matching351	 * would thus drop events, as those may have non-zero instance IDs in352	 * this subsystem. So we need to check the instance ID of the event353	 * here manually.354	 */355	if (event->instance_id != bat->sdev->uid.instance)356		return 0;357 358	dev_dbg(&bat->sdev->dev, "power event (cid = %#04x, iid = %#04x, tid = %#04x)\n",359		event->command_id, event->instance_id, event->target_id);360 361	switch (event->command_id) {362	case SAM_EVENT_CID_BAT_BIX:363		status = spwr_battery_recheck_full(bat);364		break;365 366	case SAM_EVENT_CID_BAT_BST:367		status = spwr_battery_recheck_status(bat);368		break;369 370	case SAM_EVENT_CID_BAT_PROT:371		/*372		 * TODO: Implement support for battery protection status change373		 *       event.374		 */375		status = 0;376		break;377 378	case SAM_EVENT_CID_BAT_DPTF:379		/*380		 * TODO: Implement support for DPTF event.381		 */382		status = 0;383		break;384 385	default:386		return 0;387	}388 389	return ssam_notifier_from_errno(status) | SSAM_NOTIF_HANDLED;390}391 392static void spwr_battery_update_bst_workfn(struct work_struct *work)393{394	struct delayed_work *dwork = to_delayed_work(work);395	struct spwr_battery_device *bat;396	int status;397 398	bat = container_of(dwork, struct spwr_battery_device, update_work);399 400	status = spwr_battery_update_bst(bat, false);401	if (status) {402		dev_err(&bat->sdev->dev, "failed to update battery state: %d\n", status);403		return;404	}405 406	power_supply_changed(bat->psy);407}408 409static void spwr_external_power_changed(struct power_supply *psy)410{411	struct spwr_battery_device *bat = power_supply_get_drvdata(psy);412 413	/*414	 * Handle battery update quirk: When the battery is fully charged (or415	 * charged up to the limit imposed by the UEFI battery limit) and the416	 * adapter is plugged in or removed, the EC does not send a separate417	 * event for the state (charging/discharging) change. Furthermore it418	 * may take some time until the state is updated on the battery.419	 * Schedule an update to solve this.420	 */421 422	schedule_delayed_work(&bat->update_work, SPWR_AC_BAT_UPDATE_DELAY);423}424 425 426/* -- Properties. ----------------------------------------------------------- */427 428static const enum power_supply_property spwr_battery_props_chg[] = {429	POWER_SUPPLY_PROP_STATUS,430	POWER_SUPPLY_PROP_PRESENT,431	POWER_SUPPLY_PROP_TECHNOLOGY,432	POWER_SUPPLY_PROP_CYCLE_COUNT,433	POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,434	POWER_SUPPLY_PROP_VOLTAGE_NOW,435	POWER_SUPPLY_PROP_CURRENT_NOW,436	POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,437	POWER_SUPPLY_PROP_CHARGE_FULL,438	POWER_SUPPLY_PROP_CHARGE_NOW,439	POWER_SUPPLY_PROP_CAPACITY,440	POWER_SUPPLY_PROP_CAPACITY_LEVEL,441	POWER_SUPPLY_PROP_MODEL_NAME,442	POWER_SUPPLY_PROP_MANUFACTURER,443	POWER_SUPPLY_PROP_SERIAL_NUMBER,444};445 446static const enum power_supply_property spwr_battery_props_eng[] = {447	POWER_SUPPLY_PROP_STATUS,448	POWER_SUPPLY_PROP_PRESENT,449	POWER_SUPPLY_PROP_TECHNOLOGY,450	POWER_SUPPLY_PROP_CYCLE_COUNT,451	POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,452	POWER_SUPPLY_PROP_VOLTAGE_NOW,453	POWER_SUPPLY_PROP_POWER_NOW,454	POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN,455	POWER_SUPPLY_PROP_ENERGY_FULL,456	POWER_SUPPLY_PROP_ENERGY_NOW,457	POWER_SUPPLY_PROP_CAPACITY,458	POWER_SUPPLY_PROP_CAPACITY_LEVEL,459	POWER_SUPPLY_PROP_MODEL_NAME,460	POWER_SUPPLY_PROP_MANUFACTURER,461	POWER_SUPPLY_PROP_SERIAL_NUMBER,462};463 464static int spwr_battery_prop_status(struct spwr_battery_device *bat)465{466	u32 state = get_unaligned_le32(&bat->bst.state);467	u32 present_rate = get_unaligned_le32(&bat->bst.present_rate);468 469	lockdep_assert_held(&bat->lock);470 471	if (state & SAM_BATTERY_STATE_DISCHARGING)472		return POWER_SUPPLY_STATUS_DISCHARGING;473 474	if (state & SAM_BATTERY_STATE_CHARGING)475		return POWER_SUPPLY_STATUS_CHARGING;476 477	if (spwr_battery_is_full(bat))478		return POWER_SUPPLY_STATUS_FULL;479 480	if (present_rate == 0)481		return POWER_SUPPLY_STATUS_NOT_CHARGING;482 483	return POWER_SUPPLY_STATUS_UNKNOWN;484}485 486static int spwr_battery_prop_technology(struct spwr_battery_device *bat)487{488	lockdep_assert_held(&bat->lock);489 490	if (!strcasecmp("NiCd", bat->bix.type))491		return POWER_SUPPLY_TECHNOLOGY_NiCd;492 493	if (!strcasecmp("NiMH", bat->bix.type))494		return POWER_SUPPLY_TECHNOLOGY_NiMH;495 496	if (!strcasecmp("LION", bat->bix.type))497		return POWER_SUPPLY_TECHNOLOGY_LION;498 499	if (!strncasecmp("LI-ION", bat->bix.type, 6))500		return POWER_SUPPLY_TECHNOLOGY_LION;501 502	if (!strcasecmp("LiP", bat->bix.type))503		return POWER_SUPPLY_TECHNOLOGY_LIPO;504 505	return POWER_SUPPLY_TECHNOLOGY_UNKNOWN;506}507 508static int spwr_battery_prop_capacity(struct spwr_battery_device *bat)509{510	u32 full_cap = sprw_battery_get_full_cap_safe(bat);511	u32 remaining_cap = get_unaligned_le32(&bat->bst.remaining_cap);512 513	lockdep_assert_held(&bat->lock);514 515	if (full_cap == 0 || full_cap == SPWR_BATTERY_VALUE_UNKNOWN)516		return -ENODATA;517 518	if (remaining_cap == SPWR_BATTERY_VALUE_UNKNOWN)519		return -ENODATA;520 521	return remaining_cap * 100 / full_cap;522}523 524static int spwr_battery_prop_capacity_level(struct spwr_battery_device *bat)525{526	u32 state = get_unaligned_le32(&bat->bst.state);527	u32 remaining_cap = get_unaligned_le32(&bat->bst.remaining_cap);528 529	lockdep_assert_held(&bat->lock);530 531	if (state & SAM_BATTERY_STATE_CRITICAL)532		return POWER_SUPPLY_CAPACITY_LEVEL_CRITICAL;533 534	if (spwr_battery_is_full(bat))535		return POWER_SUPPLY_CAPACITY_LEVEL_FULL;536 537	if (remaining_cap <= bat->alarm)538		return POWER_SUPPLY_CAPACITY_LEVEL_LOW;539 540	return POWER_SUPPLY_CAPACITY_LEVEL_NORMAL;541}542 543static int spwr_battery_get_property(struct power_supply *psy, enum power_supply_property psp,544				     union power_supply_propval *val)545{546	struct spwr_battery_device *bat = power_supply_get_drvdata(psy);547	u32 value;548	int status;549 550	mutex_lock(&bat->lock);551 552	status = spwr_battery_update_bst_unlocked(bat, true);553	if (status)554		goto out;555 556	/* Abort if battery is not present. */557	if (!spwr_battery_present(bat) && psp != POWER_SUPPLY_PROP_PRESENT) {558		status = -ENODEV;559		goto out;560	}561 562	switch (psp) {563	case POWER_SUPPLY_PROP_STATUS:564		val->intval = spwr_battery_prop_status(bat);565		break;566 567	case POWER_SUPPLY_PROP_PRESENT:568		val->intval = spwr_battery_present(bat);569		break;570 571	case POWER_SUPPLY_PROP_TECHNOLOGY:572		val->intval = spwr_battery_prop_technology(bat);573		break;574 575	case POWER_SUPPLY_PROP_CYCLE_COUNT:576		value = get_unaligned_le32(&bat->bix.cycle_count);577		if (value != SPWR_BATTERY_VALUE_UNKNOWN)578			val->intval = value;579		else580			status = -ENODATA;581		break;582 583	case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN:584		value = get_unaligned_le32(&bat->bix.design_voltage);585		if (value != SPWR_BATTERY_VALUE_UNKNOWN)586			val->intval = value * 1000;587		else588			status = -ENODATA;589		break;590 591	case POWER_SUPPLY_PROP_VOLTAGE_NOW:592		value = get_unaligned_le32(&bat->bst.present_voltage);593		if (value != SPWR_BATTERY_VALUE_UNKNOWN)594			val->intval = value * 1000;595		else596			status = -ENODATA;597		break;598 599	case POWER_SUPPLY_PROP_CURRENT_NOW:600	case POWER_SUPPLY_PROP_POWER_NOW:601		value = get_unaligned_le32(&bat->bst.present_rate);602		if (value != SPWR_BATTERY_VALUE_UNKNOWN)603			val->intval = value * 1000;604		else605			status = -ENODATA;606		break;607 608	case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN:609	case POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN:610		value = get_unaligned_le32(&bat->bix.design_cap);611		if (value != SPWR_BATTERY_VALUE_UNKNOWN)612			val->intval = value * 1000;613		else614			status = -ENODATA;615		break;616 617	case POWER_SUPPLY_PROP_CHARGE_FULL:618	case POWER_SUPPLY_PROP_ENERGY_FULL:619		value = get_unaligned_le32(&bat->bix.last_full_charge_cap);620		if (value != SPWR_BATTERY_VALUE_UNKNOWN)621			val->intval = value * 1000;622		else623			status = -ENODATA;624		break;625 626	case POWER_SUPPLY_PROP_CHARGE_NOW:627	case POWER_SUPPLY_PROP_ENERGY_NOW:628		value = get_unaligned_le32(&bat->bst.remaining_cap);629		if (value != SPWR_BATTERY_VALUE_UNKNOWN)630			val->intval = value * 1000;631		else632			status = -ENODATA;633		break;634 635	case POWER_SUPPLY_PROP_CAPACITY:636		val->intval = spwr_battery_prop_capacity(bat);637		break;638 639	case POWER_SUPPLY_PROP_CAPACITY_LEVEL:640		val->intval = spwr_battery_prop_capacity_level(bat);641		break;642 643	case POWER_SUPPLY_PROP_MODEL_NAME:644		val->strval = bat->bix.model;645		break;646 647	case POWER_SUPPLY_PROP_MANUFACTURER:648		val->strval = bat->bix.oem_info;649		break;650 651	case POWER_SUPPLY_PROP_SERIAL_NUMBER:652		val->strval = bat->bix.serial;653		break;654 655	default:656		status = -EINVAL;657		break;658	}659 660out:661	mutex_unlock(&bat->lock);662	return status;663}664 665 666/* -- Alarm attribute. ------------------------------------------------------ */667 668static ssize_t alarm_show(struct device *dev, struct device_attribute *attr, char *buf)669{670	struct power_supply *psy = dev_get_drvdata(dev);671	struct spwr_battery_device *bat = power_supply_get_drvdata(psy);672	int status;673 674	mutex_lock(&bat->lock);675	status = sysfs_emit(buf, "%d\n", bat->alarm * 1000);676	mutex_unlock(&bat->lock);677 678	return status;679}680 681static ssize_t alarm_store(struct device *dev, struct device_attribute *attr, const char *buf,682			   size_t count)683{684	struct power_supply *psy = dev_get_drvdata(dev);685	struct spwr_battery_device *bat = power_supply_get_drvdata(psy);686	unsigned long value;687	int status;688 689	status = kstrtoul(buf, 0, &value);690	if (status)691		return status;692 693	mutex_lock(&bat->lock);694 695	if (!spwr_battery_present(bat)) {696		mutex_unlock(&bat->lock);697		return -ENODEV;698	}699 700	status = spwr_battery_set_alarm_unlocked(bat, value / 1000);701	if (status) {702		mutex_unlock(&bat->lock);703		return status;704	}705 706	mutex_unlock(&bat->lock);707	return count;708}709 710static DEVICE_ATTR_RW(alarm);711 712static struct attribute *spwr_battery_attrs[] = {713	&dev_attr_alarm.attr,714	NULL,715};716ATTRIBUTE_GROUPS(spwr_battery);717 718 719/* -- Device setup. --------------------------------------------------------- */720 721static void spwr_battery_init(struct spwr_battery_device *bat, struct ssam_device *sdev,722			      struct ssam_event_registry registry, const char *name)723{724	mutex_init(&bat->lock);725	strscpy(bat->name, name, sizeof(bat->name));726 727	bat->sdev = sdev;728 729	bat->notif.base.priority = 1;730	bat->notif.base.fn = spwr_notify_bat;731	bat->notif.event.reg = registry;732	bat->notif.event.id.target_category = sdev->uid.category;733	bat->notif.event.id.instance = 0;	/* need to register with instance 0 */734	bat->notif.event.mask = SSAM_EVENT_MASK_TARGET;735	bat->notif.event.flags = SSAM_EVENT_SEQUENCED;736 737	bat->psy_desc.name = bat->name;738	bat->psy_desc.type = POWER_SUPPLY_TYPE_BATTERY;739	bat->psy_desc.get_property = spwr_battery_get_property;740 741	INIT_DELAYED_WORK(&bat->update_work, spwr_battery_update_bst_workfn);742}743 744static int spwr_battery_register(struct spwr_battery_device *bat)745{746	struct power_supply_config psy_cfg = {};747	__le32 sta;748	int status;749 750	/* Make sure the device is there and functioning properly. */751	status = ssam_retry(ssam_bat_get_sta, bat->sdev, &sta);752	if (status)753		return status;754 755	if ((le32_to_cpu(sta) & SAM_BATTERY_STA_OK) != SAM_BATTERY_STA_OK)756		return -ENODEV;757 758	/* Satisfy lockdep although we are in an exclusive context here. */759	mutex_lock(&bat->lock);760 761	status = spwr_battery_update_bix_unlocked(bat);762	if (status) {763		mutex_unlock(&bat->lock);764		return status;765	}766 767	if (spwr_battery_present(bat)) {768		u32 cap_warn = get_unaligned_le32(&bat->bix.design_cap_warn);769 770		status = spwr_battery_set_alarm_unlocked(bat, cap_warn);771		if (status) {772			mutex_unlock(&bat->lock);773			return status;774		}775	}776 777	mutex_unlock(&bat->lock);778 779	bat->psy_desc.external_power_changed = spwr_external_power_changed;780 781	switch (get_unaligned_le32(&bat->bix.power_unit)) {782	case SAM_BATTERY_POWER_UNIT_mW:783		bat->psy_desc.properties = spwr_battery_props_eng;784		bat->psy_desc.num_properties = ARRAY_SIZE(spwr_battery_props_eng);785		break;786 787	case SAM_BATTERY_POWER_UNIT_mA:788		bat->psy_desc.properties = spwr_battery_props_chg;789		bat->psy_desc.num_properties = ARRAY_SIZE(spwr_battery_props_chg);790		break;791 792	default:793		dev_err(&bat->sdev->dev, "unsupported battery power unit: %u\n",794			get_unaligned_le32(&bat->bix.power_unit));795		return -EINVAL;796	}797 798	psy_cfg.drv_data = bat;799	psy_cfg.attr_grp = spwr_battery_groups;800 801	bat->psy = devm_power_supply_register(&bat->sdev->dev, &bat->psy_desc, &psy_cfg);802	if (IS_ERR(bat->psy))803		return PTR_ERR(bat->psy);804 805	return ssam_device_notifier_register(bat->sdev, &bat->notif);806}807 808 809/* -- Driver setup. --------------------------------------------------------- */810 811static int __maybe_unused surface_battery_resume(struct device *dev)812{813	return spwr_battery_recheck_full(dev_get_drvdata(dev));814}815static SIMPLE_DEV_PM_OPS(surface_battery_pm_ops, NULL, surface_battery_resume);816 817static int surface_battery_probe(struct ssam_device *sdev)818{819	const struct spwr_psy_properties *p;820	struct spwr_battery_device *bat;821 822	p = ssam_device_get_match_data(sdev);823	if (!p)824		return -ENODEV;825 826	bat = devm_kzalloc(&sdev->dev, sizeof(*bat), GFP_KERNEL);827	if (!bat)828		return -ENOMEM;829 830	spwr_battery_init(bat, sdev, p->registry, p->name);831	ssam_device_set_drvdata(sdev, bat);832 833	return spwr_battery_register(bat);834}835 836static void surface_battery_remove(struct ssam_device *sdev)837{838	struct spwr_battery_device *bat = ssam_device_get_drvdata(sdev);839 840	ssam_device_notifier_unregister(sdev, &bat->notif);841	cancel_delayed_work_sync(&bat->update_work);842}843 844static const struct spwr_psy_properties spwr_psy_props_bat1 = {845	.name = "BAT1",846	.registry = SSAM_EVENT_REGISTRY_SAM,847};848 849static const struct spwr_psy_properties spwr_psy_props_bat2_sb3 = {850	.name = "BAT2",851	.registry = SSAM_EVENT_REGISTRY_KIP,852};853 854static const struct ssam_device_id surface_battery_match[] = {855	{ SSAM_SDEV(BAT, SAM, 0x01, 0x00), (unsigned long)&spwr_psy_props_bat1     },856	{ SSAM_SDEV(BAT, KIP, 0x01, 0x00), (unsigned long)&spwr_psy_props_bat2_sb3 },857	{ },858};859MODULE_DEVICE_TABLE(ssam, surface_battery_match);860 861static struct ssam_device_driver surface_battery_driver = {862	.probe = surface_battery_probe,863	.remove = surface_battery_remove,864	.match_table = surface_battery_match,865	.driver = {866		.name = "surface_battery",867		.pm = &surface_battery_pm_ops,868		.probe_type = PROBE_PREFER_ASYNCHRONOUS,869	},870};871module_ssam_device_driver(surface_battery_driver);872 873MODULE_AUTHOR("Maximilian Luz <luzmaximilian@gmail.com>");874MODULE_DESCRIPTION("Battery driver for Surface System Aggregator Module");875MODULE_LICENSE("GPL");876