0001
0002
0003
0004
0005
0006
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
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
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
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
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
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
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
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
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;
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
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
0148
0149
0150
0151
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
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
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
0318
0319
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
0350
0351
0352
0353
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
0373
0374
0375 status = 0;
0376 break;
0377
0378 case SAM_EVENT_CID_BAT_DPTF:
0379
0380
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
0415
0416
0417
0418
0419
0420
0421
0422 schedule_delayed_work(&bat->update_work, SPWR_AC_BAT_UPDATE_DELAY);
0423 }
0424
0425
0426
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
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
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
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;
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
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
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
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");