1 // SPDX-License-Identifier: GPL-2.0+
3 * Battery driver for 7th-generation Microsoft Surface devices via Surface
4 * System Aggregator Module (SSAM).
6 * Copyright (C) 2019-2021 Maximilian Luz <luzmaximilian@gmail.com>
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>
19 #include <linux/surface_aggregator/device.h>
22 /* -- SAM interface. -------------------------------------------------------- */
24 enum 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,
32 enum sam_battery_sta
{
33 SAM_BATTERY_STA_OK
= 0x0f,
34 SAM_BATTERY_STA_PRESENT
= 0x10,
37 enum sam_battery_state
{
38 SAM_BATTERY_STATE_DISCHARGING
= BIT(0),
39 SAM_BATTERY_STATE_CHARGING
= BIT(1),
40 SAM_BATTERY_STATE_CRITICAL
= BIT(2),
43 enum sam_battery_power_unit
{
44 SAM_BATTERY_POWER_UNIT_mW
= 0,
45 SAM_BATTERY_POWER_UNIT_mA
= 1,
48 /* Equivalent to data returned in ACPI _BIX method, revision 0. */
53 __le32 last_full_charge_cap
;
55 __le32 design_voltage
;
56 __le32 design_cap_warn
;
57 __le32 design_cap_low
;
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
;
72 static_assert(sizeof(struct spwr_bix
) == 119);
74 /* Equivalent to data returned in ACPI _BST method. */
79 __le32 present_voltage
;
82 static_assert(sizeof(struct spwr_bst
) == 16);
84 #define SPWR_BIX_REVISION 0
85 #define SPWR_BATTERY_VALUE_UNKNOWN 0xffffffff
87 /* Get battery status (_STA) */
88 SSAM_DEFINE_SYNC_REQUEST_CL_R(ssam_bat_get_sta
, __le32
, {
89 .target_category
= SSAM_SSH_TC_BAT
,
93 /* Get battery static information (_BIX). */
94 SSAM_DEFINE_SYNC_REQUEST_CL_R(ssam_bat_get_bix
, struct spwr_bix
, {
95 .target_category
= SSAM_SSH_TC_BAT
,
99 /* Get battery dynamic information (_BST). */
100 SSAM_DEFINE_SYNC_REQUEST_CL_R(ssam_bat_get_bst
, struct spwr_bst
, {
101 .target_category
= SSAM_SSH_TC_BAT
,
105 /* Set battery trip point (_BTP). */
106 SSAM_DEFINE_SYNC_REQUEST_CL_W(ssam_bat_set_btp
, __le32
, {
107 .target_category
= SSAM_SSH_TC_BAT
,
112 /* -- Device structures. ---------------------------------------------------- */
114 struct spwr_psy_properties
{
116 struct ssam_event_registry registry
;
119 struct spwr_battery_device
{
120 struct ssam_device
*sdev
;
123 struct power_supply
*psy
;
124 struct power_supply_desc psy_desc
;
126 struct delayed_work update_work
;
128 struct ssam_event_notifier notif
;
130 struct mutex lock
; /* Guards access to state data below. */
131 unsigned long timestamp
;
140 /* -- Module parameters. ---------------------------------------------------- */
142 static unsigned int cache_time
= 1000;
143 module_param(cache_time
, uint
, 0644);
144 MODULE_PARM_DESC(cache_time
, "battery state caching time in milliseconds [default: 1000]");
147 /* -- State management. ----------------------------------------------------- */
150 * Delay for battery update quirk. See spwr_external_power_changed() below
153 #define SPWR_AC_BAT_UPDATE_DELAY msecs_to_jiffies(5000)
155 static bool spwr_battery_present(struct spwr_battery_device
*bat
)
157 lockdep_assert_held(&bat
->lock
);
159 return le32_to_cpu(bat
->sta
) & SAM_BATTERY_STA_PRESENT
;
162 static int spwr_battery_load_sta(struct spwr_battery_device
*bat
)
164 lockdep_assert_held(&bat
->lock
);
166 return ssam_retry(ssam_bat_get_sta
, bat
->sdev
, &bat
->sta
);
169 static int spwr_battery_load_bix(struct spwr_battery_device
*bat
)
173 lockdep_assert_held(&bat
->lock
);
175 if (!spwr_battery_present(bat
))
178 status
= ssam_retry(ssam_bat_get_bix
, bat
->sdev
, &bat
->bix
);
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;
189 static int spwr_battery_load_bst(struct spwr_battery_device
*bat
)
191 lockdep_assert_held(&bat
->lock
);
193 if (!spwr_battery_present(bat
))
196 return ssam_retry(ssam_bat_get_bst
, bat
->sdev
, &bat
->bst
);
199 static int spwr_battery_set_alarm_unlocked(struct spwr_battery_device
*bat
, u32 value
)
201 __le32 value_le
= cpu_to_le32(value
);
203 lockdep_assert_held(&bat
->lock
);
206 return ssam_retry(ssam_bat_set_btp
, bat
->sdev
, &value_le
);
209 static int spwr_battery_update_bst_unlocked(struct spwr_battery_device
*bat
, bool cached
)
211 unsigned long cache_deadline
= bat
->timestamp
+ msecs_to_jiffies(cache_time
);
214 lockdep_assert_held(&bat
->lock
);
216 if (cached
&& bat
->timestamp
&& time_is_after_jiffies(cache_deadline
))
219 status
= spwr_battery_load_sta(bat
);
223 status
= spwr_battery_load_bst(bat
);
227 bat
->timestamp
= jiffies
;
231 static int spwr_battery_update_bst(struct spwr_battery_device
*bat
, bool cached
)
235 mutex_lock(&bat
->lock
);
236 status
= spwr_battery_update_bst_unlocked(bat
, cached
);
237 mutex_unlock(&bat
->lock
);
242 static int spwr_battery_update_bix_unlocked(struct spwr_battery_device
*bat
)
246 lockdep_assert_held(&bat
->lock
);
248 status
= spwr_battery_load_sta(bat
);
252 status
= spwr_battery_load_bix(bat
);
256 status
= spwr_battery_load_bst(bat
);
260 if (bat
->bix
.revision
!= SPWR_BIX_REVISION
)
261 dev_warn(&bat
->sdev
->dev
, "unsupported battery revision: %u\n", bat
->bix
.revision
);
263 bat
->timestamp
= jiffies
;
267 static u32
sprw_battery_get_full_cap_safe(struct spwr_battery_device
*bat
)
269 u32 full_cap
= get_unaligned_le32(&bat
->bix
.last_full_charge_cap
);
271 lockdep_assert_held(&bat
->lock
);
273 if (full_cap
== 0 || full_cap
== SPWR_BATTERY_VALUE_UNKNOWN
)
274 full_cap
= get_unaligned_le32(&bat
->bix
.design_cap
);
279 static bool spwr_battery_is_full(struct spwr_battery_device
*bat
)
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
);
285 lockdep_assert_held(&bat
->lock
);
287 return full_cap
!= SPWR_BATTERY_VALUE_UNKNOWN
&& full_cap
!= 0 &&
288 remaining_cap
!= SPWR_BATTERY_VALUE_UNKNOWN
&&
289 remaining_cap
>= full_cap
&&
293 static int spwr_battery_recheck_full(struct spwr_battery_device
*bat
)
299 mutex_lock(&bat
->lock
);
300 unit
= get_unaligned_le32(&bat
->bix
.power_unit
);
301 present
= spwr_battery_present(bat
);
303 status
= spwr_battery_update_bix_unlocked(bat
);
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
);
311 status
= spwr_battery_set_alarm_unlocked(bat
, cap_warn
);
317 * Warn if the unit has changed. This is something we genuinely don't
318 * expect to happen, so make this a big warning. If it does, we'll
319 * need to add support for it.
321 WARN_ON(unit
!= get_unaligned_le32(&bat
->bix
.power_unit
));
324 mutex_unlock(&bat
->lock
);
327 power_supply_changed(bat
->psy
);
332 static int spwr_battery_recheck_status(struct spwr_battery_device
*bat
)
336 status
= spwr_battery_update_bst(bat
, false);
338 power_supply_changed(bat
->psy
);
343 static u32
spwr_notify_bat(struct ssam_event_notifier
*nf
, const struct ssam_event
*event
)
345 struct spwr_battery_device
*bat
= container_of(nf
, struct spwr_battery_device
, notif
);
349 * We cannot use strict matching when registering the notifier as the
350 * EC expects us to register it against instance ID 0. Strict matching
351 * would thus drop events, as those may have non-zero instance IDs in
352 * this subsystem. So we need to check the instance ID of the event
355 if (event
->instance_id
!= bat
->sdev
->uid
.instance
)
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
);
361 switch (event
->command_id
) {
362 case SAM_EVENT_CID_BAT_BIX
:
363 status
= spwr_battery_recheck_full(bat
);
366 case SAM_EVENT_CID_BAT_BST
:
367 status
= spwr_battery_recheck_status(bat
);
370 case SAM_EVENT_CID_BAT_PROT
:
372 * TODO: Implement support for battery protection status change
378 case SAM_EVENT_CID_BAT_DPTF
:
380 * TODO: Implement support for DPTF event.
389 return ssam_notifier_from_errno(status
) | SSAM_NOTIF_HANDLED
;
392 static void spwr_battery_update_bst_workfn(struct work_struct
*work
)
394 struct delayed_work
*dwork
= to_delayed_work(work
);
395 struct spwr_battery_device
*bat
;
398 bat
= container_of(dwork
, struct spwr_battery_device
, update_work
);
400 status
= spwr_battery_update_bst(bat
, false);
402 dev_err(&bat
->sdev
->dev
, "failed to update battery state: %d\n", status
);
406 power_supply_changed(bat
->psy
);
409 static void spwr_external_power_changed(struct power_supply
*psy
)
411 struct spwr_battery_device
*bat
= power_supply_get_drvdata(psy
);
414 * Handle battery update quirk: When the battery is fully charged (or
415 * charged up to the limit imposed by the UEFI battery limit) and the
416 * adapter is plugged in or removed, the EC does not send a separate
417 * event for the state (charging/discharging) change. Furthermore it
418 * may take some time until the state is updated on the battery.
419 * Schedule an update to solve this.
422 schedule_delayed_work(&bat
->update_work
, SPWR_AC_BAT_UPDATE_DELAY
);
426 /* -- Properties. ----------------------------------------------------------- */
428 static 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
,
446 static 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
,
464 static int spwr_battery_prop_status(struct spwr_battery_device
*bat
)
466 u32 state
= get_unaligned_le32(&bat
->bst
.state
);
467 u32 present_rate
= get_unaligned_le32(&bat
->bst
.present_rate
);
469 lockdep_assert_held(&bat
->lock
);
471 if (state
& SAM_BATTERY_STATE_DISCHARGING
)
472 return POWER_SUPPLY_STATUS_DISCHARGING
;
474 if (state
& SAM_BATTERY_STATE_CHARGING
)
475 return POWER_SUPPLY_STATUS_CHARGING
;
477 if (spwr_battery_is_full(bat
))
478 return POWER_SUPPLY_STATUS_FULL
;
480 if (present_rate
== 0)
481 return POWER_SUPPLY_STATUS_NOT_CHARGING
;
483 return POWER_SUPPLY_STATUS_UNKNOWN
;
486 static int spwr_battery_prop_technology(struct spwr_battery_device
*bat
)
488 lockdep_assert_held(&bat
->lock
);
490 if (!strcasecmp("NiCd", bat
->bix
.type
))
491 return POWER_SUPPLY_TECHNOLOGY_NiCd
;
493 if (!strcasecmp("NiMH", bat
->bix
.type
))
494 return POWER_SUPPLY_TECHNOLOGY_NiMH
;
496 if (!strcasecmp("LION", bat
->bix
.type
))
497 return POWER_SUPPLY_TECHNOLOGY_LION
;
499 if (!strncasecmp("LI-ION", bat
->bix
.type
, 6))
500 return POWER_SUPPLY_TECHNOLOGY_LION
;
502 if (!strcasecmp("LiP", bat
->bix
.type
))
503 return POWER_SUPPLY_TECHNOLOGY_LIPO
;
505 return POWER_SUPPLY_TECHNOLOGY_UNKNOWN
;
508 static int spwr_battery_prop_capacity(struct spwr_battery_device
*bat
)
510 u32 full_cap
= sprw_battery_get_full_cap_safe(bat
);
511 u32 remaining_cap
= get_unaligned_le32(&bat
->bst
.remaining_cap
);
513 lockdep_assert_held(&bat
->lock
);
515 if (full_cap
== 0 || full_cap
== SPWR_BATTERY_VALUE_UNKNOWN
)
518 if (remaining_cap
== SPWR_BATTERY_VALUE_UNKNOWN
)
521 return remaining_cap
* 100 / full_cap
;
524 static int spwr_battery_prop_capacity_level(struct spwr_battery_device
*bat
)
526 u32 state
= get_unaligned_le32(&bat
->bst
.state
);
527 u32 remaining_cap
= get_unaligned_le32(&bat
->bst
.remaining_cap
);
529 lockdep_assert_held(&bat
->lock
);
531 if (state
& SAM_BATTERY_STATE_CRITICAL
)
532 return POWER_SUPPLY_CAPACITY_LEVEL_CRITICAL
;
534 if (spwr_battery_is_full(bat
))
535 return POWER_SUPPLY_CAPACITY_LEVEL_FULL
;
537 if (remaining_cap
<= bat
->alarm
)
538 return POWER_SUPPLY_CAPACITY_LEVEL_LOW
;
540 return POWER_SUPPLY_CAPACITY_LEVEL_NORMAL
;
543 static int spwr_battery_get_property(struct power_supply
*psy
, enum power_supply_property psp
,
544 union power_supply_propval
*val
)
546 struct spwr_battery_device
*bat
= power_supply_get_drvdata(psy
);
550 mutex_lock(&bat
->lock
);
552 status
= spwr_battery_update_bst_unlocked(bat
, true);
556 /* Abort if battery is not present. */
557 if (!spwr_battery_present(bat
) && psp
!= POWER_SUPPLY_PROP_PRESENT
) {
563 case POWER_SUPPLY_PROP_STATUS
:
564 val
->intval
= spwr_battery_prop_status(bat
);
567 case POWER_SUPPLY_PROP_PRESENT
:
568 val
->intval
= spwr_battery_present(bat
);
571 case POWER_SUPPLY_PROP_TECHNOLOGY
:
572 val
->intval
= spwr_battery_prop_technology(bat
);
575 case POWER_SUPPLY_PROP_CYCLE_COUNT
:
576 value
= get_unaligned_le32(&bat
->bix
.cycle_count
);
577 if (value
!= SPWR_BATTERY_VALUE_UNKNOWN
)
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;
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;
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;
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;
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;
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;
635 case POWER_SUPPLY_PROP_CAPACITY
:
636 val
->intval
= spwr_battery_prop_capacity(bat
);
639 case POWER_SUPPLY_PROP_CAPACITY_LEVEL
:
640 val
->intval
= spwr_battery_prop_capacity_level(bat
);
643 case POWER_SUPPLY_PROP_MODEL_NAME
:
644 val
->strval
= bat
->bix
.model
;
647 case POWER_SUPPLY_PROP_MANUFACTURER
:
648 val
->strval
= bat
->bix
.oem_info
;
651 case POWER_SUPPLY_PROP_SERIAL_NUMBER
:
652 val
->strval
= bat
->bix
.serial
;
661 mutex_unlock(&bat
->lock
);
666 /* -- Alarm attribute. ------------------------------------------------------ */
668 static ssize_t
alarm_show(struct device
*dev
, struct device_attribute
*attr
, char *buf
)
670 struct power_supply
*psy
= dev_get_drvdata(dev
);
671 struct spwr_battery_device
*bat
= power_supply_get_drvdata(psy
);
674 mutex_lock(&bat
->lock
);
675 status
= sysfs_emit(buf
, "%d\n", bat
->alarm
* 1000);
676 mutex_unlock(&bat
->lock
);
681 static ssize_t
alarm_store(struct device
*dev
, struct device_attribute
*attr
, const char *buf
,
684 struct power_supply
*psy
= dev_get_drvdata(dev
);
685 struct spwr_battery_device
*bat
= power_supply_get_drvdata(psy
);
689 status
= kstrtoul(buf
, 0, &value
);
693 mutex_lock(&bat
->lock
);
695 if (!spwr_battery_present(bat
)) {
696 mutex_unlock(&bat
->lock
);
700 status
= spwr_battery_set_alarm_unlocked(bat
, value
/ 1000);
702 mutex_unlock(&bat
->lock
);
706 mutex_unlock(&bat
->lock
);
710 static DEVICE_ATTR_RW(alarm
);
712 static struct attribute
*spwr_battery_attrs
[] = {
713 &dev_attr_alarm
.attr
,
716 ATTRIBUTE_GROUPS(spwr_battery
);
719 /* -- Device setup. --------------------------------------------------------- */
721 static void spwr_battery_init(struct spwr_battery_device
*bat
, struct ssam_device
*sdev
,
722 struct ssam_event_registry registry
, const char *name
)
724 mutex_init(&bat
->lock
);
725 strscpy(bat
->name
, name
, sizeof(bat
->name
));
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
;
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
;
741 INIT_DELAYED_WORK(&bat
->update_work
, spwr_battery_update_bst_workfn
);
744 static int spwr_battery_register(struct spwr_battery_device
*bat
)
746 struct power_supply_config psy_cfg
= {};
750 /* Make sure the device is there and functioning properly. */
751 status
= ssam_retry(ssam_bat_get_sta
, bat
->sdev
, &sta
);
755 if ((le32_to_cpu(sta
) & SAM_BATTERY_STA_OK
) != SAM_BATTERY_STA_OK
)
758 /* Satisfy lockdep although we are in an exclusive context here. */
759 mutex_lock(&bat
->lock
);
761 status
= spwr_battery_update_bix_unlocked(bat
);
763 mutex_unlock(&bat
->lock
);
767 if (spwr_battery_present(bat
)) {
768 u32 cap_warn
= get_unaligned_le32(&bat
->bix
.design_cap_warn
);
770 status
= spwr_battery_set_alarm_unlocked(bat
, cap_warn
);
772 mutex_unlock(&bat
->lock
);
777 mutex_unlock(&bat
->lock
);
779 bat
->psy_desc
.external_power_changed
= spwr_external_power_changed
;
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
);
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
);
793 dev_err(&bat
->sdev
->dev
, "unsupported battery power unit: %u\n",
794 get_unaligned_le32(&bat
->bix
.power_unit
));
798 psy_cfg
.drv_data
= bat
;
799 psy_cfg
.attr_grp
= spwr_battery_groups
;
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
);
805 return ssam_device_notifier_register(bat
->sdev
, &bat
->notif
);
809 /* -- Driver setup. --------------------------------------------------------- */
811 static int __maybe_unused
surface_battery_resume(struct device
*dev
)
813 return spwr_battery_recheck_full(dev_get_drvdata(dev
));
815 static SIMPLE_DEV_PM_OPS(surface_battery_pm_ops
, NULL
, surface_battery_resume
);
817 static int surface_battery_probe(struct ssam_device
*sdev
)
819 const struct spwr_psy_properties
*p
;
820 struct spwr_battery_device
*bat
;
822 p
= ssam_device_get_match_data(sdev
);
826 bat
= devm_kzalloc(&sdev
->dev
, sizeof(*bat
), GFP_KERNEL
);
830 spwr_battery_init(bat
, sdev
, p
->registry
, p
->name
);
831 ssam_device_set_drvdata(sdev
, bat
);
833 return spwr_battery_register(bat
);
836 static void surface_battery_remove(struct ssam_device
*sdev
)
838 struct spwr_battery_device
*bat
= ssam_device_get_drvdata(sdev
);
840 ssam_device_notifier_unregister(sdev
, &bat
->notif
);
841 cancel_delayed_work_sync(&bat
->update_work
);
844 static const struct spwr_psy_properties spwr_psy_props_bat1
= {
846 .registry
= SSAM_EVENT_REGISTRY_SAM
,
849 static const struct spwr_psy_properties spwr_psy_props_bat2_sb3
= {
851 .registry
= SSAM_EVENT_REGISTRY_KIP
,
854 static 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
},
859 MODULE_DEVICE_TABLE(ssam
, surface_battery_match
);
861 static struct ssam_device_driver surface_battery_driver
= {
862 .probe
= surface_battery_probe
,
863 .remove
= surface_battery_remove
,
864 .match_table
= surface_battery_match
,
866 .name
= "surface_battery",
867 .pm
= &surface_battery_pm_ops
,
868 .probe_type
= PROBE_PREFER_ASYNCHRONOUS
,
871 module_ssam_device_driver(surface_battery_driver
);
873 MODULE_AUTHOR("Maximilian Luz <luzmaximilian@gmail.com>");
874 MODULE_DESCRIPTION("Battery driver for Surface System Aggregator Module");
875 MODULE_LICENSE("GPL");