Lines Matching +full:lock +full:- +full:status
1 // SPDX-License-Identifier: GPL-2.0+
3 * Battery driver for 7th-generation Microsoft Surface devices via Surface
6 * Copyright (C) 2019-2021 Maximilian Luz <[email protected]>
22 /* -- SAM interface. -------------------------------------------------------- */
87 /* Get battery status (_STA) */
112 /* -- Device structures. ---------------------------------------------------- */
130 struct mutex lock; /* Guards access to state data below. */ member
140 /* -- Module parameters. ---------------------------------------------------- */
147 /* -- State management. ----------------------------------------------------- */
157 lockdep_assert_held(&bat->lock); in spwr_battery_present()
159 return le32_to_cpu(bat->sta) & SAM_BATTERY_STA_PRESENT; in spwr_battery_present()
164 lockdep_assert_held(&bat->lock); in spwr_battery_load_sta()
166 return ssam_retry(ssam_bat_get_sta, bat->sdev, &bat->sta); in spwr_battery_load_sta()
171 int status; in spwr_battery_load_bix() local
173 lockdep_assert_held(&bat->lock); in spwr_battery_load_bix()
178 status = ssam_retry(ssam_bat_get_bix, bat->sdev, &bat->bix); in spwr_battery_load_bix()
181 bat->bix.model[ARRAY_SIZE(bat->bix.model) - 1] = 0; in spwr_battery_load_bix()
182 bat->bix.serial[ARRAY_SIZE(bat->bix.serial) - 1] = 0; in spwr_battery_load_bix()
183 bat->bix.type[ARRAY_SIZE(bat->bix.type) - 1] = 0; in spwr_battery_load_bix()
184 bat->bix.oem_info[ARRAY_SIZE(bat->bix.oem_info) - 1] = 0; in spwr_battery_load_bix()
186 return status; in spwr_battery_load_bix()
191 lockdep_assert_held(&bat->lock); in spwr_battery_load_bst()
196 return ssam_retry(ssam_bat_get_bst, bat->sdev, &bat->bst); in spwr_battery_load_bst()
203 lockdep_assert_held(&bat->lock); in spwr_battery_set_alarm_unlocked()
205 bat->alarm = value; in spwr_battery_set_alarm_unlocked()
206 return ssam_retry(ssam_bat_set_btp, bat->sdev, &value_le); in spwr_battery_set_alarm_unlocked()
211 unsigned long cache_deadline = bat->timestamp + msecs_to_jiffies(cache_time); in spwr_battery_update_bst_unlocked()
212 int status; in spwr_battery_update_bst_unlocked() local
214 lockdep_assert_held(&bat->lock); in spwr_battery_update_bst_unlocked()
216 if (cached && bat->timestamp && time_is_after_jiffies(cache_deadline)) in spwr_battery_update_bst_unlocked()
219 status = spwr_battery_load_sta(bat); in spwr_battery_update_bst_unlocked()
220 if (status) in spwr_battery_update_bst_unlocked()
221 return status; in spwr_battery_update_bst_unlocked()
223 status = spwr_battery_load_bst(bat); in spwr_battery_update_bst_unlocked()
224 if (status) in spwr_battery_update_bst_unlocked()
225 return status; in spwr_battery_update_bst_unlocked()
227 bat->timestamp = jiffies; in spwr_battery_update_bst_unlocked()
233 int status; in spwr_battery_update_bst() local
235 mutex_lock(&bat->lock); in spwr_battery_update_bst()
236 status = spwr_battery_update_bst_unlocked(bat, cached); in spwr_battery_update_bst()
237 mutex_unlock(&bat->lock); in spwr_battery_update_bst()
239 return status; in spwr_battery_update_bst()
244 int status; in spwr_battery_update_bix_unlocked() local
246 lockdep_assert_held(&bat->lock); in spwr_battery_update_bix_unlocked()
248 status = spwr_battery_load_sta(bat); in spwr_battery_update_bix_unlocked()
249 if (status) in spwr_battery_update_bix_unlocked()
250 return status; in spwr_battery_update_bix_unlocked()
252 status = spwr_battery_load_bix(bat); in spwr_battery_update_bix_unlocked()
253 if (status) in spwr_battery_update_bix_unlocked()
254 return status; in spwr_battery_update_bix_unlocked()
256 status = spwr_battery_load_bst(bat); in spwr_battery_update_bix_unlocked()
257 if (status) in spwr_battery_update_bix_unlocked()
258 return status; in spwr_battery_update_bix_unlocked()
260 if (bat->bix.revision != SPWR_BIX_REVISION) in spwr_battery_update_bix_unlocked()
261 dev_warn(&bat->sdev->dev, "unsupported battery revision: %u\n", bat->bix.revision); in spwr_battery_update_bix_unlocked()
263 bat->timestamp = jiffies; in spwr_battery_update_bix_unlocked()
269 u32 full_cap = get_unaligned_le32(&bat->bix.last_full_charge_cap); in sprw_battery_get_full_cap_safe()
271 lockdep_assert_held(&bat->lock); in sprw_battery_get_full_cap_safe()
274 full_cap = get_unaligned_le32(&bat->bix.design_cap); in sprw_battery_get_full_cap_safe()
281 u32 state = get_unaligned_le32(&bat->bst.state); in spwr_battery_is_full()
283 u32 remaining_cap = get_unaligned_le32(&bat->bst.remaining_cap); in spwr_battery_is_full()
285 lockdep_assert_held(&bat->lock); in spwr_battery_is_full()
297 int status; in spwr_battery_recheck_full() local
299 mutex_lock(&bat->lock); in spwr_battery_recheck_full()
300 unit = get_unaligned_le32(&bat->bix.power_unit); in spwr_battery_recheck_full()
303 status = spwr_battery_update_bix_unlocked(bat); in spwr_battery_recheck_full()
304 if (status) in spwr_battery_recheck_full()
307 /* If battery has been attached, (re-)initialize alarm. */ in spwr_battery_recheck_full()
309 u32 cap_warn = get_unaligned_le32(&bat->bix.design_cap_warn); in spwr_battery_recheck_full()
311 status = spwr_battery_set_alarm_unlocked(bat, cap_warn); in spwr_battery_recheck_full()
312 if (status) in spwr_battery_recheck_full()
321 WARN_ON(unit != get_unaligned_le32(&bat->bix.power_unit)); in spwr_battery_recheck_full()
324 mutex_unlock(&bat->lock); in spwr_battery_recheck_full()
326 if (!status) in spwr_battery_recheck_full()
327 power_supply_changed(bat->psy); in spwr_battery_recheck_full()
329 return status; in spwr_battery_recheck_full()
334 int status; in spwr_battery_recheck_status() local
336 status = spwr_battery_update_bst(bat, false); in spwr_battery_recheck_status()
337 if (!status) in spwr_battery_recheck_status()
338 power_supply_changed(bat->psy); in spwr_battery_recheck_status()
340 return status; in spwr_battery_recheck_status()
346 int status; in spwr_notify_bat() local
351 * would thus drop events, as those may have non-zero instance IDs in in spwr_notify_bat()
355 if (event->instance_id != bat->sdev->uid.instance) in spwr_notify_bat()
358 dev_dbg(&bat->sdev->dev, "power event (cid = %#04x, iid = %#04x, tid = %#04x)\n", in spwr_notify_bat()
359 event->command_id, event->instance_id, event->target_id); in spwr_notify_bat()
361 switch (event->command_id) { in spwr_notify_bat()
363 status = spwr_battery_recheck_full(bat); in spwr_notify_bat()
367 status = spwr_battery_recheck_status(bat); in spwr_notify_bat()
372 * TODO: Implement support for battery protection status change in spwr_notify_bat()
375 status = 0; in spwr_notify_bat()
382 status = 0; in spwr_notify_bat()
389 return ssam_notifier_from_errno(status) | SSAM_NOTIF_HANDLED; in spwr_notify_bat()
396 int status; in spwr_battery_update_bst_workfn() local
400 status = spwr_battery_update_bst(bat, false); in spwr_battery_update_bst_workfn()
401 if (status) { in spwr_battery_update_bst_workfn()
402 dev_err(&bat->sdev->dev, "failed to update battery state: %d\n", status); in spwr_battery_update_bst_workfn()
406 power_supply_changed(bat->psy); in spwr_battery_update_bst_workfn()
422 schedule_delayed_work(&bat->update_work, SPWR_AC_BAT_UPDATE_DELAY); in spwr_external_power_changed()
426 /* -- Properties. ----------------------------------------------------------- */
466 u32 state = get_unaligned_le32(&bat->bst.state); in spwr_battery_prop_status()
467 u32 present_rate = get_unaligned_le32(&bat->bst.present_rate); in spwr_battery_prop_status()
469 lockdep_assert_held(&bat->lock); in spwr_battery_prop_status()
488 lockdep_assert_held(&bat->lock); in spwr_battery_prop_technology()
490 if (!strcasecmp("NiCd", bat->bix.type)) in spwr_battery_prop_technology()
493 if (!strcasecmp("NiMH", bat->bix.type)) in spwr_battery_prop_technology()
496 if (!strcasecmp("LION", bat->bix.type)) in spwr_battery_prop_technology()
499 if (!strncasecmp("LI-ION", bat->bix.type, 6)) in spwr_battery_prop_technology()
502 if (!strcasecmp("LiP", bat->bix.type)) in spwr_battery_prop_technology()
511 u32 remaining_cap = get_unaligned_le32(&bat->bst.remaining_cap); in spwr_battery_prop_capacity()
513 lockdep_assert_held(&bat->lock); in spwr_battery_prop_capacity()
516 return -ENODATA; in spwr_battery_prop_capacity()
519 return -ENODATA; in spwr_battery_prop_capacity()
526 u32 state = get_unaligned_le32(&bat->bst.state); in spwr_battery_prop_capacity_level()
527 u32 remaining_cap = get_unaligned_le32(&bat->bst.remaining_cap); in spwr_battery_prop_capacity_level()
529 lockdep_assert_held(&bat->lock); in spwr_battery_prop_capacity_level()
537 if (remaining_cap <= bat->alarm) in spwr_battery_prop_capacity_level()
548 int status; in spwr_battery_get_property() local
550 mutex_lock(&bat->lock); in spwr_battery_get_property()
552 status = spwr_battery_update_bst_unlocked(bat, true); in spwr_battery_get_property()
553 if (status) in spwr_battery_get_property()
558 status = -ENODEV; in spwr_battery_get_property()
564 val->intval = spwr_battery_prop_status(bat); in spwr_battery_get_property()
568 val->intval = spwr_battery_present(bat); in spwr_battery_get_property()
572 val->intval = spwr_battery_prop_technology(bat); in spwr_battery_get_property()
576 value = get_unaligned_le32(&bat->bix.cycle_count); in spwr_battery_get_property()
578 val->intval = value; in spwr_battery_get_property()
580 status = -ENODATA; in spwr_battery_get_property()
584 value = get_unaligned_le32(&bat->bix.design_voltage); in spwr_battery_get_property()
586 val->intval = value * 1000; in spwr_battery_get_property()
588 status = -ENODATA; in spwr_battery_get_property()
592 value = get_unaligned_le32(&bat->bst.present_voltage); in spwr_battery_get_property()
594 val->intval = value * 1000; in spwr_battery_get_property()
596 status = -ENODATA; in spwr_battery_get_property()
601 value = get_unaligned_le32(&bat->bst.present_rate); in spwr_battery_get_property()
603 val->intval = value * 1000; in spwr_battery_get_property()
605 status = -ENODATA; in spwr_battery_get_property()
610 value = get_unaligned_le32(&bat->bix.design_cap); in spwr_battery_get_property()
612 val->intval = value * 1000; in spwr_battery_get_property()
614 status = -ENODATA; in spwr_battery_get_property()
619 value = get_unaligned_le32(&bat->bix.last_full_charge_cap); in spwr_battery_get_property()
621 val->intval = value * 1000; in spwr_battery_get_property()
623 status = -ENODATA; in spwr_battery_get_property()
628 value = get_unaligned_le32(&bat->bst.remaining_cap); in spwr_battery_get_property()
630 val->intval = value * 1000; in spwr_battery_get_property()
632 status = -ENODATA; in spwr_battery_get_property()
636 val->intval = spwr_battery_prop_capacity(bat); in spwr_battery_get_property()
640 val->intval = spwr_battery_prop_capacity_level(bat); in spwr_battery_get_property()
644 val->strval = bat->bix.model; in spwr_battery_get_property()
648 val->strval = bat->bix.oem_info; in spwr_battery_get_property()
652 val->strval = bat->bix.serial; in spwr_battery_get_property()
656 status = -EINVAL; in spwr_battery_get_property()
661 mutex_unlock(&bat->lock); in spwr_battery_get_property()
662 return status; in spwr_battery_get_property()
666 /* -- Alarm attribute. ------------------------------------------------------ */
672 int status; in alarm_show() local
674 mutex_lock(&bat->lock); in alarm_show()
675 status = sysfs_emit(buf, "%d\n", bat->alarm * 1000); in alarm_show()
676 mutex_unlock(&bat->lock); in alarm_show()
678 return status; in alarm_show()
687 int status; in alarm_store() local
689 status = kstrtoul(buf, 0, &value); in alarm_store()
690 if (status) in alarm_store()
691 return status; in alarm_store()
693 mutex_lock(&bat->lock); in alarm_store()
696 mutex_unlock(&bat->lock); in alarm_store()
697 return -ENODEV; in alarm_store()
700 status = spwr_battery_set_alarm_unlocked(bat, value / 1000); in alarm_store()
701 if (status) { in alarm_store()
702 mutex_unlock(&bat->lock); in alarm_store()
703 return status; in alarm_store()
706 mutex_unlock(&bat->lock); in alarm_store()
719 /* -- Device setup. --------------------------------------------------------- */
724 mutex_init(&bat->lock); in spwr_battery_init()
725 strscpy(bat->name, name, sizeof(bat->name)); in spwr_battery_init()
727 bat->sdev = sdev; in spwr_battery_init()
729 bat->notif.base.priority = 1; in spwr_battery_init()
730 bat->notif.base.fn = spwr_notify_bat; in spwr_battery_init()
731 bat->notif.event.reg = registry; in spwr_battery_init()
732 bat->notif.event.id.target_category = sdev->uid.category; in spwr_battery_init()
733 bat->notif.event.id.instance = 0; /* need to register with instance 0 */ in spwr_battery_init()
734 bat->notif.event.mask = SSAM_EVENT_MASK_TARGET; in spwr_battery_init()
735 bat->notif.event.flags = SSAM_EVENT_SEQUENCED; in spwr_battery_init()
737 bat->psy_desc.name = bat->name; in spwr_battery_init()
738 bat->psy_desc.type = POWER_SUPPLY_TYPE_BATTERY; in spwr_battery_init()
739 bat->psy_desc.get_property = spwr_battery_get_property; in spwr_battery_init()
741 INIT_DELAYED_WORK(&bat->update_work, spwr_battery_update_bst_workfn); in spwr_battery_init()
748 int status; in spwr_battery_register() local
751 status = ssam_retry(ssam_bat_get_sta, bat->sdev, &sta); in spwr_battery_register()
752 if (status) in spwr_battery_register()
753 return status; in spwr_battery_register()
756 return -ENODEV; in spwr_battery_register()
759 mutex_lock(&bat->lock); in spwr_battery_register()
761 status = spwr_battery_update_bix_unlocked(bat); in spwr_battery_register()
762 if (status) { in spwr_battery_register()
763 mutex_unlock(&bat->lock); in spwr_battery_register()
764 return status; in spwr_battery_register()
768 u32 cap_warn = get_unaligned_le32(&bat->bix.design_cap_warn); in spwr_battery_register()
770 status = spwr_battery_set_alarm_unlocked(bat, cap_warn); in spwr_battery_register()
771 if (status) { in spwr_battery_register()
772 mutex_unlock(&bat->lock); in spwr_battery_register()
773 return status; in spwr_battery_register()
777 mutex_unlock(&bat->lock); in spwr_battery_register()
779 bat->psy_desc.external_power_changed = spwr_external_power_changed; in spwr_battery_register()
781 switch (get_unaligned_le32(&bat->bix.power_unit)) { in spwr_battery_register()
783 bat->psy_desc.properties = spwr_battery_props_eng; in spwr_battery_register()
784 bat->psy_desc.num_properties = ARRAY_SIZE(spwr_battery_props_eng); in spwr_battery_register()
788 bat->psy_desc.properties = spwr_battery_props_chg; in spwr_battery_register()
789 bat->psy_desc.num_properties = ARRAY_SIZE(spwr_battery_props_chg); in spwr_battery_register()
793 dev_err(&bat->sdev->dev, "unsupported battery power unit: %u\n", in spwr_battery_register()
794 get_unaligned_le32(&bat->bix.power_unit)); in spwr_battery_register()
795 return -EINVAL; in spwr_battery_register()
801 bat->psy = devm_power_supply_register(&bat->sdev->dev, &bat->psy_desc, &psy_cfg); in spwr_battery_register()
802 if (IS_ERR(bat->psy)) in spwr_battery_register()
803 return PTR_ERR(bat->psy); in spwr_battery_register()
805 return ssam_device_notifier_register(bat->sdev, &bat->notif); in spwr_battery_register()
809 /* -- Driver setup. --------------------------------------------------------- */
824 return -ENODEV; in surface_battery_probe()
826 bat = devm_kzalloc(&sdev->dev, sizeof(*bat), GFP_KERNEL); in surface_battery_probe()
828 return -ENOMEM; in surface_battery_probe()
830 spwr_battery_init(bat, sdev, p->registry, p->name); in surface_battery_probe()
840 ssam_device_notifier_unregister(sdev, &bat->notif); in surface_battery_remove()
841 cancel_delayed_work_sync(&bat->update_work); in surface_battery_remove()