Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0+
0002 /*
0003  * Battery driver for 7th-generation Microsoft Surface devices via Surface
0004  * System Aggregator Module (SSAM).
0005  *
0006  * Copyright (C) 2019-2021 Maximilian Luz <luzmaximilian@gmail.com>
0007  */
0008 
0009 #include <asm/unaligned.h>
0010 #include <linux/jiffies.h>
0011 #include <linux/kernel.h>
0012 #include <linux/module.h>
0013 #include <linux/mutex.h>
0014 #include <linux/power_supply.h>
0015 #include <linux/sysfs.h>
0016 #include <linux/types.h>
0017 #include <linux/workqueue.h>
0018 
0019 #include <linux/surface_aggregator/device.h>
0020 
0021 
0022 /* -- SAM interface. -------------------------------------------------------- */
0023 
0024 enum sam_event_cid_bat {
0025     SAM_EVENT_CID_BAT_BIX         = 0x15,
0026     SAM_EVENT_CID_BAT_BST         = 0x16,
0027     SAM_EVENT_CID_BAT_ADP         = 0x17,
0028     SAM_EVENT_CID_BAT_PROT        = 0x18,
0029     SAM_EVENT_CID_BAT_DPTF        = 0x53,
0030 };
0031 
0032 enum sam_battery_sta {
0033     SAM_BATTERY_STA_OK            = 0x0f,
0034     SAM_BATTERY_STA_PRESENT       = 0x10,
0035 };
0036 
0037 enum sam_battery_state {
0038     SAM_BATTERY_STATE_DISCHARGING = BIT(0),
0039     SAM_BATTERY_STATE_CHARGING    = BIT(1),
0040     SAM_BATTERY_STATE_CRITICAL    = BIT(2),
0041 };
0042 
0043 enum sam_battery_power_unit {
0044     SAM_BATTERY_POWER_UNIT_mW     = 0,
0045     SAM_BATTERY_POWER_UNIT_mA     = 1,
0046 };
0047 
0048 /* Equivalent to data returned in ACPI _BIX method, revision 0. */
0049 struct spwr_bix {
0050     u8  revision;
0051     __le32 power_unit;
0052     __le32 design_cap;
0053     __le32 last_full_charge_cap;
0054     __le32 technology;
0055     __le32 design_voltage;
0056     __le32 design_cap_warn;
0057     __le32 design_cap_low;
0058     __le32 cycle_count;
0059     __le32 measurement_accuracy;
0060     __le32 max_sampling_time;
0061     __le32 min_sampling_time;
0062     __le32 max_avg_interval;
0063     __le32 min_avg_interval;
0064     __le32 bat_cap_granularity_1;
0065     __le32 bat_cap_granularity_2;
0066     __u8 model[21];
0067     __u8 serial[11];
0068     __u8 type[5];
0069     __u8 oem_info[21];
0070 } __packed;
0071 
0072 static_assert(sizeof(struct spwr_bix) == 119);
0073 
0074 /* Equivalent to data returned in ACPI _BST method. */
0075 struct spwr_bst {
0076     __le32 state;
0077     __le32 present_rate;
0078     __le32 remaining_cap;
0079     __le32 present_voltage;
0080 } __packed;
0081 
0082 static_assert(sizeof(struct spwr_bst) == 16);
0083 
0084 #define SPWR_BIX_REVISION       0
0085 #define SPWR_BATTERY_VALUE_UNKNOWN  0xffffffff
0086 
0087 /* Get battery status (_STA) */
0088 SSAM_DEFINE_SYNC_REQUEST_CL_R(ssam_bat_get_sta, __le32, {
0089     .target_category = SSAM_SSH_TC_BAT,
0090     .command_id      = 0x01,
0091 });
0092 
0093 /* Get battery static information (_BIX). */
0094 SSAM_DEFINE_SYNC_REQUEST_CL_R(ssam_bat_get_bix, struct spwr_bix, {
0095     .target_category = SSAM_SSH_TC_BAT,
0096     .command_id      = 0x02,
0097 });
0098 
0099 /* Get battery dynamic information (_BST). */
0100 SSAM_DEFINE_SYNC_REQUEST_CL_R(ssam_bat_get_bst, struct spwr_bst, {
0101     .target_category = SSAM_SSH_TC_BAT,
0102     .command_id      = 0x03,
0103 });
0104 
0105 /* Set battery trip point (_BTP). */
0106 SSAM_DEFINE_SYNC_REQUEST_CL_W(ssam_bat_set_btp, __le32, {
0107     .target_category = SSAM_SSH_TC_BAT,
0108     .command_id      = 0x04,
0109 });
0110 
0111 
0112 /* -- Device structures. ---------------------------------------------------- */
0113 
0114 struct spwr_psy_properties {
0115     const char *name;
0116     struct ssam_event_registry registry;
0117 };
0118 
0119 struct spwr_battery_device {
0120     struct ssam_device *sdev;
0121 
0122     char name[32];
0123     struct power_supply *psy;
0124     struct power_supply_desc psy_desc;
0125 
0126     struct delayed_work update_work;
0127 
0128     struct ssam_event_notifier notif;
0129 
0130     struct mutex lock;  /* Guards access to state data below. */
0131     unsigned long timestamp;
0132 
0133     __le32 sta;
0134     struct spwr_bix bix;
0135     struct spwr_bst bst;
0136     u32 alarm;
0137 };
0138 
0139 
0140 /* -- Module parameters. ---------------------------------------------------- */
0141 
0142 static unsigned int cache_time = 1000;
0143 module_param(cache_time, uint, 0644);
0144 MODULE_PARM_DESC(cache_time, "battery state caching time in milliseconds [default: 1000]");
0145 
0146 
0147 /* -- State management. ----------------------------------------------------- */
0148 
0149 /*
0150  * Delay for battery update quirk. See spwr_external_power_changed() below
0151  * for more details.
0152  */
0153 #define SPWR_AC_BAT_UPDATE_DELAY    msecs_to_jiffies(5000)
0154 
0155 static bool spwr_battery_present(struct spwr_battery_device *bat)
0156 {
0157     lockdep_assert_held(&bat->lock);
0158 
0159     return le32_to_cpu(bat->sta) & SAM_BATTERY_STA_PRESENT;
0160 }
0161 
0162 static int spwr_battery_load_sta(struct spwr_battery_device *bat)
0163 {
0164     lockdep_assert_held(&bat->lock);
0165 
0166     return ssam_retry(ssam_bat_get_sta, bat->sdev, &bat->sta);
0167 }
0168 
0169 static int spwr_battery_load_bix(struct spwr_battery_device *bat)
0170 {
0171     int status;
0172 
0173     lockdep_assert_held(&bat->lock);
0174 
0175     if (!spwr_battery_present(bat))
0176         return 0;
0177 
0178     status = ssam_retry(ssam_bat_get_bix, bat->sdev, &bat->bix);
0179 
0180     /* Enforce NULL terminated strings in case anything goes wrong... */
0181     bat->bix.model[ARRAY_SIZE(bat->bix.model) - 1] = 0;
0182     bat->bix.serial[ARRAY_SIZE(bat->bix.serial) - 1] = 0;
0183     bat->bix.type[ARRAY_SIZE(bat->bix.type) - 1] = 0;
0184     bat->bix.oem_info[ARRAY_SIZE(bat->bix.oem_info) - 1] = 0;
0185 
0186     return status;
0187 }
0188 
0189 static int spwr_battery_load_bst(struct spwr_battery_device *bat)
0190 {
0191     lockdep_assert_held(&bat->lock);
0192 
0193     if (!spwr_battery_present(bat))
0194         return 0;
0195 
0196     return ssam_retry(ssam_bat_get_bst, bat->sdev, &bat->bst);
0197 }
0198 
0199 static int spwr_battery_set_alarm_unlocked(struct spwr_battery_device *bat, u32 value)
0200 {
0201     __le32 value_le = cpu_to_le32(value);
0202 
0203     lockdep_assert_held(&bat->lock);
0204 
0205     bat->alarm = value;
0206     return ssam_retry(ssam_bat_set_btp, bat->sdev, &value_le);
0207 }
0208 
0209 static int spwr_battery_update_bst_unlocked(struct spwr_battery_device *bat, bool cached)
0210 {
0211     unsigned long cache_deadline = bat->timestamp + msecs_to_jiffies(cache_time);
0212     int status;
0213 
0214     lockdep_assert_held(&bat->lock);
0215 
0216     if (cached && bat->timestamp && time_is_after_jiffies(cache_deadline))
0217         return 0;
0218 
0219     status = spwr_battery_load_sta(bat);
0220     if (status)
0221         return status;
0222 
0223     status = spwr_battery_load_bst(bat);
0224     if (status)
0225         return status;
0226 
0227     bat->timestamp = jiffies;
0228     return 0;
0229 }
0230 
0231 static int spwr_battery_update_bst(struct spwr_battery_device *bat, bool cached)
0232 {
0233     int status;
0234 
0235     mutex_lock(&bat->lock);
0236     status = spwr_battery_update_bst_unlocked(bat, cached);
0237     mutex_unlock(&bat->lock);
0238 
0239     return status;
0240 }
0241 
0242 static int spwr_battery_update_bix_unlocked(struct spwr_battery_device *bat)
0243 {
0244     int status;
0245 
0246     lockdep_assert_held(&bat->lock);
0247 
0248     status = spwr_battery_load_sta(bat);
0249     if (status)
0250         return status;
0251 
0252     status = spwr_battery_load_bix(bat);
0253     if (status)
0254         return status;
0255 
0256     status = spwr_battery_load_bst(bat);
0257     if (status)
0258         return status;
0259 
0260     if (bat->bix.revision != SPWR_BIX_REVISION)
0261         dev_warn(&bat->sdev->dev, "unsupported battery revision: %u\n", bat->bix.revision);
0262 
0263     bat->timestamp = jiffies;
0264     return 0;
0265 }
0266 
0267 static u32 sprw_battery_get_full_cap_safe(struct spwr_battery_device *bat)
0268 {
0269     u32 full_cap = get_unaligned_le32(&bat->bix.last_full_charge_cap);
0270 
0271     lockdep_assert_held(&bat->lock);
0272 
0273     if (full_cap == 0 || full_cap == SPWR_BATTERY_VALUE_UNKNOWN)
0274         full_cap = get_unaligned_le32(&bat->bix.design_cap);
0275 
0276     return full_cap;
0277 }
0278 
0279 static bool spwr_battery_is_full(struct spwr_battery_device *bat)
0280 {
0281     u32 state = get_unaligned_le32(&bat->bst.state);
0282     u32 full_cap = sprw_battery_get_full_cap_safe(bat);
0283     u32 remaining_cap = get_unaligned_le32(&bat->bst.remaining_cap);
0284 
0285     lockdep_assert_held(&bat->lock);
0286 
0287     return full_cap != SPWR_BATTERY_VALUE_UNKNOWN && full_cap != 0 &&
0288         remaining_cap != SPWR_BATTERY_VALUE_UNKNOWN &&
0289         remaining_cap >= full_cap &&
0290         state == 0;
0291 }
0292 
0293 static int spwr_battery_recheck_full(struct spwr_battery_device *bat)
0294 {
0295     bool present;
0296     u32 unit;
0297     int status;
0298 
0299     mutex_lock(&bat->lock);
0300     unit = get_unaligned_le32(&bat->bix.power_unit);
0301     present = spwr_battery_present(bat);
0302 
0303     status = spwr_battery_update_bix_unlocked(bat);
0304     if (status)
0305         goto out;
0306 
0307     /* If battery has been attached, (re-)initialize alarm. */
0308     if (!present && spwr_battery_present(bat)) {
0309         u32 cap_warn = get_unaligned_le32(&bat->bix.design_cap_warn);
0310 
0311         status = spwr_battery_set_alarm_unlocked(bat, cap_warn);
0312         if (status)
0313             goto out;
0314     }
0315 
0316     /*
0317      * Warn if the unit has changed. This is something we genuinely don't
0318      * expect to happen, so make this a big warning. If it does, we'll
0319      * need to add support for it.
0320      */
0321     WARN_ON(unit != get_unaligned_le32(&bat->bix.power_unit));
0322 
0323 out:
0324     mutex_unlock(&bat->lock);
0325 
0326     if (!status)
0327         power_supply_changed(bat->psy);
0328 
0329     return status;
0330 }
0331 
0332 static int spwr_battery_recheck_status(struct spwr_battery_device *bat)
0333 {
0334     int status;
0335 
0336     status = spwr_battery_update_bst(bat, false);
0337     if (!status)
0338         power_supply_changed(bat->psy);
0339 
0340     return status;
0341 }
0342 
0343 static u32 spwr_notify_bat(struct ssam_event_notifier *nf, const struct ssam_event *event)
0344 {
0345     struct spwr_battery_device *bat = container_of(nf, struct spwr_battery_device, notif);
0346     int status;
0347 
0348     /*
0349      * We cannot use strict matching when registering the notifier as the
0350      * EC expects us to register it against instance ID 0. Strict matching
0351      * would thus drop events, as those may have non-zero instance IDs in
0352      * this subsystem. So we need to check the instance ID of the event
0353      * here manually.
0354      */
0355     if (event->instance_id != bat->sdev->uid.instance)
0356         return 0;
0357 
0358     dev_dbg(&bat->sdev->dev, "power event (cid = %#04x, iid = %#04x, tid = %#04x)\n",
0359         event->command_id, event->instance_id, event->target_id);
0360 
0361     switch (event->command_id) {
0362     case SAM_EVENT_CID_BAT_BIX:
0363         status = spwr_battery_recheck_full(bat);
0364         break;
0365 
0366     case SAM_EVENT_CID_BAT_BST:
0367         status = spwr_battery_recheck_status(bat);
0368         break;
0369 
0370     case SAM_EVENT_CID_BAT_PROT:
0371         /*
0372          * TODO: Implement support for battery protection status change
0373          *       event.
0374          */
0375         status = 0;
0376         break;
0377 
0378     case SAM_EVENT_CID_BAT_DPTF:
0379         /*
0380          * TODO: Implement support for DPTF event.
0381          */
0382         status = 0;
0383         break;
0384 
0385     default:
0386         return 0;
0387     }
0388 
0389     return ssam_notifier_from_errno(status) | SSAM_NOTIF_HANDLED;
0390 }
0391 
0392 static void spwr_battery_update_bst_workfn(struct work_struct *work)
0393 {
0394     struct delayed_work *dwork = to_delayed_work(work);
0395     struct spwr_battery_device *bat;
0396     int status;
0397 
0398     bat = container_of(dwork, struct spwr_battery_device, update_work);
0399 
0400     status = spwr_battery_update_bst(bat, false);
0401     if (status) {
0402         dev_err(&bat->sdev->dev, "failed to update battery state: %d\n", status);
0403         return;
0404     }
0405 
0406     power_supply_changed(bat->psy);
0407 }
0408 
0409 static void spwr_external_power_changed(struct power_supply *psy)
0410 {
0411     struct spwr_battery_device *bat = power_supply_get_drvdata(psy);
0412 
0413     /*
0414      * Handle battery update quirk: When the battery is fully charged (or
0415      * charged up to the limit imposed by the UEFI battery limit) and the
0416      * adapter is plugged in or removed, the EC does not send a separate
0417      * event for the state (charging/discharging) change. Furthermore it
0418      * may take some time until the state is updated on the battery.
0419      * Schedule an update to solve this.
0420      */
0421 
0422     schedule_delayed_work(&bat->update_work, SPWR_AC_BAT_UPDATE_DELAY);
0423 }
0424 
0425 
0426 /* -- Properties. ----------------------------------------------------------- */
0427 
0428 static const enum power_supply_property spwr_battery_props_chg[] = {
0429     POWER_SUPPLY_PROP_STATUS,
0430     POWER_SUPPLY_PROP_PRESENT,
0431     POWER_SUPPLY_PROP_TECHNOLOGY,
0432     POWER_SUPPLY_PROP_CYCLE_COUNT,
0433     POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,
0434     POWER_SUPPLY_PROP_VOLTAGE_NOW,
0435     POWER_SUPPLY_PROP_CURRENT_NOW,
0436     POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
0437     POWER_SUPPLY_PROP_CHARGE_FULL,
0438     POWER_SUPPLY_PROP_CHARGE_NOW,
0439     POWER_SUPPLY_PROP_CAPACITY,
0440     POWER_SUPPLY_PROP_CAPACITY_LEVEL,
0441     POWER_SUPPLY_PROP_MODEL_NAME,
0442     POWER_SUPPLY_PROP_MANUFACTURER,
0443     POWER_SUPPLY_PROP_SERIAL_NUMBER,
0444 };
0445 
0446 static const enum power_supply_property spwr_battery_props_eng[] = {
0447     POWER_SUPPLY_PROP_STATUS,
0448     POWER_SUPPLY_PROP_PRESENT,
0449     POWER_SUPPLY_PROP_TECHNOLOGY,
0450     POWER_SUPPLY_PROP_CYCLE_COUNT,
0451     POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,
0452     POWER_SUPPLY_PROP_VOLTAGE_NOW,
0453     POWER_SUPPLY_PROP_POWER_NOW,
0454     POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN,
0455     POWER_SUPPLY_PROP_ENERGY_FULL,
0456     POWER_SUPPLY_PROP_ENERGY_NOW,
0457     POWER_SUPPLY_PROP_CAPACITY,
0458     POWER_SUPPLY_PROP_CAPACITY_LEVEL,
0459     POWER_SUPPLY_PROP_MODEL_NAME,
0460     POWER_SUPPLY_PROP_MANUFACTURER,
0461     POWER_SUPPLY_PROP_SERIAL_NUMBER,
0462 };
0463 
0464 static int spwr_battery_prop_status(struct spwr_battery_device *bat)
0465 {
0466     u32 state = get_unaligned_le32(&bat->bst.state);
0467     u32 present_rate = get_unaligned_le32(&bat->bst.present_rate);
0468 
0469     lockdep_assert_held(&bat->lock);
0470 
0471     if (state & SAM_BATTERY_STATE_DISCHARGING)
0472         return POWER_SUPPLY_STATUS_DISCHARGING;
0473 
0474     if (state & SAM_BATTERY_STATE_CHARGING)
0475         return POWER_SUPPLY_STATUS_CHARGING;
0476 
0477     if (spwr_battery_is_full(bat))
0478         return POWER_SUPPLY_STATUS_FULL;
0479 
0480     if (present_rate == 0)
0481         return POWER_SUPPLY_STATUS_NOT_CHARGING;
0482 
0483     return POWER_SUPPLY_STATUS_UNKNOWN;
0484 }
0485 
0486 static int spwr_battery_prop_technology(struct spwr_battery_device *bat)
0487 {
0488     lockdep_assert_held(&bat->lock);
0489 
0490     if (!strcasecmp("NiCd", bat->bix.type))
0491         return POWER_SUPPLY_TECHNOLOGY_NiCd;
0492 
0493     if (!strcasecmp("NiMH", bat->bix.type))
0494         return POWER_SUPPLY_TECHNOLOGY_NiMH;
0495 
0496     if (!strcasecmp("LION", bat->bix.type))
0497         return POWER_SUPPLY_TECHNOLOGY_LION;
0498 
0499     if (!strncasecmp("LI-ION", bat->bix.type, 6))
0500         return POWER_SUPPLY_TECHNOLOGY_LION;
0501 
0502     if (!strcasecmp("LiP", bat->bix.type))
0503         return POWER_SUPPLY_TECHNOLOGY_LIPO;
0504 
0505     return POWER_SUPPLY_TECHNOLOGY_UNKNOWN;
0506 }
0507 
0508 static int spwr_battery_prop_capacity(struct spwr_battery_device *bat)
0509 {
0510     u32 full_cap = sprw_battery_get_full_cap_safe(bat);
0511     u32 remaining_cap = get_unaligned_le32(&bat->bst.remaining_cap);
0512 
0513     lockdep_assert_held(&bat->lock);
0514 
0515     if (full_cap == 0 || full_cap == SPWR_BATTERY_VALUE_UNKNOWN)
0516         return -ENODATA;
0517 
0518     if (remaining_cap == SPWR_BATTERY_VALUE_UNKNOWN)
0519         return -ENODATA;
0520 
0521     return remaining_cap * 100 / full_cap;
0522 }
0523 
0524 static int spwr_battery_prop_capacity_level(struct spwr_battery_device *bat)
0525 {
0526     u32 state = get_unaligned_le32(&bat->bst.state);
0527     u32 remaining_cap = get_unaligned_le32(&bat->bst.remaining_cap);
0528 
0529     lockdep_assert_held(&bat->lock);
0530 
0531     if (state & SAM_BATTERY_STATE_CRITICAL)
0532         return POWER_SUPPLY_CAPACITY_LEVEL_CRITICAL;
0533 
0534     if (spwr_battery_is_full(bat))
0535         return POWER_SUPPLY_CAPACITY_LEVEL_FULL;
0536 
0537     if (remaining_cap <= bat->alarm)
0538         return POWER_SUPPLY_CAPACITY_LEVEL_LOW;
0539 
0540     return POWER_SUPPLY_CAPACITY_LEVEL_NORMAL;
0541 }
0542 
0543 static int spwr_battery_get_property(struct power_supply *psy, enum power_supply_property psp,
0544                      union power_supply_propval *val)
0545 {
0546     struct spwr_battery_device *bat = power_supply_get_drvdata(psy);
0547     u32 value;
0548     int status;
0549 
0550     mutex_lock(&bat->lock);
0551 
0552     status = spwr_battery_update_bst_unlocked(bat, true);
0553     if (status)
0554         goto out;
0555 
0556     /* Abort if battery is not present. */
0557     if (!spwr_battery_present(bat) && psp != POWER_SUPPLY_PROP_PRESENT) {
0558         status = -ENODEV;
0559         goto out;
0560     }
0561 
0562     switch (psp) {
0563     case POWER_SUPPLY_PROP_STATUS:
0564         val->intval = spwr_battery_prop_status(bat);
0565         break;
0566 
0567     case POWER_SUPPLY_PROP_PRESENT:
0568         val->intval = spwr_battery_present(bat);
0569         break;
0570 
0571     case POWER_SUPPLY_PROP_TECHNOLOGY:
0572         val->intval = spwr_battery_prop_technology(bat);
0573         break;
0574 
0575     case POWER_SUPPLY_PROP_CYCLE_COUNT:
0576         value = get_unaligned_le32(&bat->bix.cycle_count);
0577         if (value != SPWR_BATTERY_VALUE_UNKNOWN)
0578             val->intval = value;
0579         else
0580             status = -ENODATA;
0581         break;
0582 
0583     case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN:
0584         value = get_unaligned_le32(&bat->bix.design_voltage);
0585         if (value != SPWR_BATTERY_VALUE_UNKNOWN)
0586             val->intval = value * 1000;
0587         else
0588             status = -ENODATA;
0589         break;
0590 
0591     case POWER_SUPPLY_PROP_VOLTAGE_NOW:
0592         value = get_unaligned_le32(&bat->bst.present_voltage);
0593         if (value != SPWR_BATTERY_VALUE_UNKNOWN)
0594             val->intval = value * 1000;
0595         else
0596             status = -ENODATA;
0597         break;
0598 
0599     case POWER_SUPPLY_PROP_CURRENT_NOW:
0600     case POWER_SUPPLY_PROP_POWER_NOW:
0601         value = get_unaligned_le32(&bat->bst.present_rate);
0602         if (value != SPWR_BATTERY_VALUE_UNKNOWN)
0603             val->intval = value * 1000;
0604         else
0605             status = -ENODATA;
0606         break;
0607 
0608     case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN:
0609     case POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN:
0610         value = get_unaligned_le32(&bat->bix.design_cap);
0611         if (value != SPWR_BATTERY_VALUE_UNKNOWN)
0612             val->intval = value * 1000;
0613         else
0614             status = -ENODATA;
0615         break;
0616 
0617     case POWER_SUPPLY_PROP_CHARGE_FULL:
0618     case POWER_SUPPLY_PROP_ENERGY_FULL:
0619         value = get_unaligned_le32(&bat->bix.last_full_charge_cap);
0620         if (value != SPWR_BATTERY_VALUE_UNKNOWN)
0621             val->intval = value * 1000;
0622         else
0623             status = -ENODATA;
0624         break;
0625 
0626     case POWER_SUPPLY_PROP_CHARGE_NOW:
0627     case POWER_SUPPLY_PROP_ENERGY_NOW:
0628         value = get_unaligned_le32(&bat->bst.remaining_cap);
0629         if (value != SPWR_BATTERY_VALUE_UNKNOWN)
0630             val->intval = value * 1000;
0631         else
0632             status = -ENODATA;
0633         break;
0634 
0635     case POWER_SUPPLY_PROP_CAPACITY:
0636         val->intval = spwr_battery_prop_capacity(bat);
0637         break;
0638 
0639     case POWER_SUPPLY_PROP_CAPACITY_LEVEL:
0640         val->intval = spwr_battery_prop_capacity_level(bat);
0641         break;
0642 
0643     case POWER_SUPPLY_PROP_MODEL_NAME:
0644         val->strval = bat->bix.model;
0645         break;
0646 
0647     case POWER_SUPPLY_PROP_MANUFACTURER:
0648         val->strval = bat->bix.oem_info;
0649         break;
0650 
0651     case POWER_SUPPLY_PROP_SERIAL_NUMBER:
0652         val->strval = bat->bix.serial;
0653         break;
0654 
0655     default:
0656         status = -EINVAL;
0657         break;
0658     }
0659 
0660 out:
0661     mutex_unlock(&bat->lock);
0662     return status;
0663 }
0664 
0665 
0666 /* -- Alarm attribute. ------------------------------------------------------ */
0667 
0668 static ssize_t alarm_show(struct device *dev, struct device_attribute *attr, char *buf)
0669 {
0670     struct power_supply *psy = dev_get_drvdata(dev);
0671     struct spwr_battery_device *bat = power_supply_get_drvdata(psy);
0672     int status;
0673 
0674     mutex_lock(&bat->lock);
0675     status = sysfs_emit(buf, "%d\n", bat->alarm * 1000);
0676     mutex_unlock(&bat->lock);
0677 
0678     return status;
0679 }
0680 
0681 static ssize_t alarm_store(struct device *dev, struct device_attribute *attr, const char *buf,
0682                size_t count)
0683 {
0684     struct power_supply *psy = dev_get_drvdata(dev);
0685     struct spwr_battery_device *bat = power_supply_get_drvdata(psy);
0686     unsigned long value;
0687     int status;
0688 
0689     status = kstrtoul(buf, 0, &value);
0690     if (status)
0691         return status;
0692 
0693     mutex_lock(&bat->lock);
0694 
0695     if (!spwr_battery_present(bat)) {
0696         mutex_unlock(&bat->lock);
0697         return -ENODEV;
0698     }
0699 
0700     status = spwr_battery_set_alarm_unlocked(bat, value / 1000);
0701     if (status) {
0702         mutex_unlock(&bat->lock);
0703         return status;
0704     }
0705 
0706     mutex_unlock(&bat->lock);
0707     return count;
0708 }
0709 
0710 static DEVICE_ATTR_RW(alarm);
0711 
0712 static struct attribute *spwr_battery_attrs[] = {
0713     &dev_attr_alarm.attr,
0714     NULL,
0715 };
0716 ATTRIBUTE_GROUPS(spwr_battery);
0717 
0718 
0719 /* -- Device setup. --------------------------------------------------------- */
0720 
0721 static void spwr_battery_init(struct spwr_battery_device *bat, struct ssam_device *sdev,
0722                   struct ssam_event_registry registry, const char *name)
0723 {
0724     mutex_init(&bat->lock);
0725     strncpy(bat->name, name, ARRAY_SIZE(bat->name) - 1);
0726 
0727     bat->sdev = sdev;
0728 
0729     bat->notif.base.priority = 1;
0730     bat->notif.base.fn = spwr_notify_bat;
0731     bat->notif.event.reg = registry;
0732     bat->notif.event.id.target_category = sdev->uid.category;
0733     bat->notif.event.id.instance = 0;   /* need to register with instance 0 */
0734     bat->notif.event.mask = SSAM_EVENT_MASK_TARGET;
0735     bat->notif.event.flags = SSAM_EVENT_SEQUENCED;
0736 
0737     bat->psy_desc.name = bat->name;
0738     bat->psy_desc.type = POWER_SUPPLY_TYPE_BATTERY;
0739     bat->psy_desc.get_property = spwr_battery_get_property;
0740 
0741     INIT_DELAYED_WORK(&bat->update_work, spwr_battery_update_bst_workfn);
0742 }
0743 
0744 static int spwr_battery_register(struct spwr_battery_device *bat)
0745 {
0746     struct power_supply_config psy_cfg = {};
0747     __le32 sta;
0748     int status;
0749 
0750     /* Make sure the device is there and functioning properly. */
0751     status = ssam_retry(ssam_bat_get_sta, bat->sdev, &sta);
0752     if (status)
0753         return status;
0754 
0755     if ((le32_to_cpu(sta) & SAM_BATTERY_STA_OK) != SAM_BATTERY_STA_OK)
0756         return -ENODEV;
0757 
0758     /* Satisfy lockdep although we are in an exclusive context here. */
0759     mutex_lock(&bat->lock);
0760 
0761     status = spwr_battery_update_bix_unlocked(bat);
0762     if (status) {
0763         mutex_unlock(&bat->lock);
0764         return status;
0765     }
0766 
0767     if (spwr_battery_present(bat)) {
0768         u32 cap_warn = get_unaligned_le32(&bat->bix.design_cap_warn);
0769 
0770         status = spwr_battery_set_alarm_unlocked(bat, cap_warn);
0771         if (status) {
0772             mutex_unlock(&bat->lock);
0773             return status;
0774         }
0775     }
0776 
0777     mutex_unlock(&bat->lock);
0778 
0779     bat->psy_desc.external_power_changed = spwr_external_power_changed;
0780 
0781     switch (get_unaligned_le32(&bat->bix.power_unit)) {
0782     case SAM_BATTERY_POWER_UNIT_mW:
0783         bat->psy_desc.properties = spwr_battery_props_eng;
0784         bat->psy_desc.num_properties = ARRAY_SIZE(spwr_battery_props_eng);
0785         break;
0786 
0787     case SAM_BATTERY_POWER_UNIT_mA:
0788         bat->psy_desc.properties = spwr_battery_props_chg;
0789         bat->psy_desc.num_properties = ARRAY_SIZE(spwr_battery_props_chg);
0790         break;
0791 
0792     default:
0793         dev_err(&bat->sdev->dev, "unsupported battery power unit: %u\n",
0794             get_unaligned_le32(&bat->bix.power_unit));
0795         return -EINVAL;
0796     }
0797 
0798     psy_cfg.drv_data = bat;
0799     psy_cfg.attr_grp = spwr_battery_groups;
0800 
0801     bat->psy = devm_power_supply_register(&bat->sdev->dev, &bat->psy_desc, &psy_cfg);
0802     if (IS_ERR(bat->psy))
0803         return PTR_ERR(bat->psy);
0804 
0805     return ssam_device_notifier_register(bat->sdev, &bat->notif);
0806 }
0807 
0808 
0809 /* -- Driver setup. --------------------------------------------------------- */
0810 
0811 static int __maybe_unused surface_battery_resume(struct device *dev)
0812 {
0813     return spwr_battery_recheck_full(dev_get_drvdata(dev));
0814 }
0815 static SIMPLE_DEV_PM_OPS(surface_battery_pm_ops, NULL, surface_battery_resume);
0816 
0817 static int surface_battery_probe(struct ssam_device *sdev)
0818 {
0819     const struct spwr_psy_properties *p;
0820     struct spwr_battery_device *bat;
0821 
0822     p = ssam_device_get_match_data(sdev);
0823     if (!p)
0824         return -ENODEV;
0825 
0826     bat = devm_kzalloc(&sdev->dev, sizeof(*bat), GFP_KERNEL);
0827     if (!bat)
0828         return -ENOMEM;
0829 
0830     spwr_battery_init(bat, sdev, p->registry, p->name);
0831     ssam_device_set_drvdata(sdev, bat);
0832 
0833     return spwr_battery_register(bat);
0834 }
0835 
0836 static void surface_battery_remove(struct ssam_device *sdev)
0837 {
0838     struct spwr_battery_device *bat = ssam_device_get_drvdata(sdev);
0839 
0840     ssam_device_notifier_unregister(sdev, &bat->notif);
0841     cancel_delayed_work_sync(&bat->update_work);
0842 }
0843 
0844 static const struct spwr_psy_properties spwr_psy_props_bat1 = {
0845     .name = "BAT1",
0846     .registry = SSAM_EVENT_REGISTRY_SAM,
0847 };
0848 
0849 static const struct spwr_psy_properties spwr_psy_props_bat2_sb3 = {
0850     .name = "BAT2",
0851     .registry = SSAM_EVENT_REGISTRY_KIP,
0852 };
0853 
0854 static const struct ssam_device_id surface_battery_match[] = {
0855     { SSAM_SDEV(BAT, 0x01, 0x01, 0x00), (unsigned long)&spwr_psy_props_bat1     },
0856     { SSAM_SDEV(BAT, 0x02, 0x01, 0x00), (unsigned long)&spwr_psy_props_bat2_sb3 },
0857     { },
0858 };
0859 MODULE_DEVICE_TABLE(ssam, surface_battery_match);
0860 
0861 static struct ssam_device_driver surface_battery_driver = {
0862     .probe = surface_battery_probe,
0863     .remove = surface_battery_remove,
0864     .match_table = surface_battery_match,
0865     .driver = {
0866         .name = "surface_battery",
0867         .pm = &surface_battery_pm_ops,
0868         .probe_type = PROBE_PREFER_ASYNCHRONOUS,
0869     },
0870 };
0871 module_ssam_device_driver(surface_battery_driver);
0872 
0873 MODULE_AUTHOR("Maximilian Luz <luzmaximilian@gmail.com>");
0874 MODULE_DESCRIPTION("Battery driver for Surface System Aggregator Module");
0875 MODULE_LICENSE("GPL");