diff options
-rw-r--r-- | drivers/power/charger-manager.c | 161 | ||||
-rw-r--r-- | include/linux/power/charger-manager.h | 8 |
2 files changed, 123 insertions, 46 deletions
diff --git a/drivers/power/charger-manager.c b/drivers/power/charger-manager.c index cdf29d2eb7a5..c701f5e6f327 100644 --- a/drivers/power/charger-manager.c +++ b/drivers/power/charger-manager.c | |||
@@ -227,6 +227,58 @@ static bool is_charging(struct charger_manager *cm) | |||
227 | } | 227 | } |
228 | 228 | ||
229 | /** | 229 | /** |
230 | * is_full_charged - Returns true if the battery is fully charged. | ||
231 | * @cm: the Charger Manager representing the battery. | ||
232 | */ | ||
233 | static bool is_full_charged(struct charger_manager *cm) | ||
234 | { | ||
235 | struct charger_desc *desc = cm->desc; | ||
236 | union power_supply_propval val; | ||
237 | int ret = 0; | ||
238 | int uV; | ||
239 | |||
240 | /* If there is no battery, it cannot be charged */ | ||
241 | if (!is_batt_present(cm)) { | ||
242 | val.intval = 0; | ||
243 | goto out; | ||
244 | } | ||
245 | |||
246 | if (cm->fuel_gauge && desc->fullbatt_full_capacity > 0) { | ||
247 | /* Not full if capacity of fuel gauge isn't full */ | ||
248 | ret = cm->fuel_gauge->get_property(cm->fuel_gauge, | ||
249 | POWER_SUPPLY_PROP_CHARGE_FULL, &val); | ||
250 | if (!ret && val.intval > desc->fullbatt_full_capacity) { | ||
251 | val.intval = 1; | ||
252 | goto out; | ||
253 | } | ||
254 | } | ||
255 | |||
256 | /* Full, if it's over the fullbatt voltage */ | ||
257 | if (desc->fullbatt_uV > 0) { | ||
258 | ret = get_batt_uV(cm, &uV); | ||
259 | if (!ret && uV >= desc->fullbatt_uV) { | ||
260 | val.intval = 1; | ||
261 | goto out; | ||
262 | } | ||
263 | } | ||
264 | |||
265 | /* Full, if the capacity is more than fullbatt_soc */ | ||
266 | if (cm->fuel_gauge && desc->fullbatt_soc > 0) { | ||
267 | ret = cm->fuel_gauge->get_property(cm->fuel_gauge, | ||
268 | POWER_SUPPLY_PROP_CAPACITY, &val); | ||
269 | if (!ret && val.intval >= desc->fullbatt_soc) { | ||
270 | val.intval = 1; | ||
271 | goto out; | ||
272 | } | ||
273 | } | ||
274 | |||
275 | val.intval = 0; | ||
276 | |||
277 | out: | ||
278 | return val.intval ? true : false; | ||
279 | } | ||
280 | |||
281 | /** | ||
230 | * is_polling_required - Return true if need to continue polling for this CM. | 282 | * is_polling_required - Return true if need to continue polling for this CM. |
231 | * @cm: the Charger Manager representing the battery. | 283 | * @cm: the Charger Manager representing the battery. |
232 | */ | 284 | */ |
@@ -418,7 +470,7 @@ static void fullbatt_vchk(struct work_struct *work) | |||
418 | diff = desc->fullbatt_uV; | 470 | diff = desc->fullbatt_uV; |
419 | diff -= batt_uV; | 471 | diff -= batt_uV; |
420 | 472 | ||
421 | dev_dbg(cm->dev, "VBATT dropped %duV after full-batt.\n", diff); | 473 | dev_info(cm->dev, "VBATT dropped %duV after full-batt.\n", diff); |
422 | 474 | ||
423 | if (diff > desc->fullbatt_vchkdrop_uV) { | 475 | if (diff > desc->fullbatt_vchkdrop_uV) { |
424 | try_charger_restart(cm); | 476 | try_charger_restart(cm); |
@@ -441,10 +493,14 @@ static bool _cm_monitor(struct charger_manager *cm) | |||
441 | dev_dbg(cm->dev, "monitoring (%2.2d.%3.3dC)\n", | 493 | dev_dbg(cm->dev, "monitoring (%2.2d.%3.3dC)\n", |
442 | cm->last_temp_mC / 1000, cm->last_temp_mC % 1000); | 494 | cm->last_temp_mC / 1000, cm->last_temp_mC % 1000); |
443 | 495 | ||
444 | /* It has been stopped or charging already */ | 496 | /* It has been stopped already */ |
445 | if (!!temp == !!cm->emergency_stop) | 497 | if (temp && cm->emergency_stop) |
446 | return false; | 498 | return false; |
447 | 499 | ||
500 | /* | ||
501 | * Check temperature whether overheat or cold. | ||
502 | * If temperature is out of range normal state, stop charging. | ||
503 | */ | ||
448 | if (temp) { | 504 | if (temp) { |
449 | cm->emergency_stop = temp; | 505 | cm->emergency_stop = temp; |
450 | if (!try_charger_enable(cm, false)) { | 506 | if (!try_charger_enable(cm, false)) { |
@@ -453,10 +509,34 @@ static bool _cm_monitor(struct charger_manager *cm) | |||
453 | else | 509 | else |
454 | uevent_notify(cm, "COLD"); | 510 | uevent_notify(cm, "COLD"); |
455 | } | 511 | } |
512 | |||
513 | /* | ||
514 | * Check dropped voltage of battery. If battery voltage is more | ||
515 | * dropped than fullbatt_vchkdrop_uV after fully charged state, | ||
516 | * charger-manager have to recharge battery. | ||
517 | */ | ||
518 | } else if (!cm->emergency_stop && is_ext_pwr_online(cm) && | ||
519 | !cm->charger_enabled) { | ||
520 | fullbatt_vchk(&cm->fullbatt_vchk_work.work); | ||
521 | |||
522 | /* | ||
523 | * Check whether fully charged state to protect overcharge | ||
524 | * if charger-manager is charging for battery. | ||
525 | */ | ||
526 | } else if (!cm->emergency_stop && is_full_charged(cm) && | ||
527 | cm->charger_enabled) { | ||
528 | dev_info(cm->dev, "EVENT_HANDLE: Battery Fully Charged.\n"); | ||
529 | uevent_notify(cm, default_event_names[CM_EVENT_BATT_FULL]); | ||
530 | |||
531 | try_charger_enable(cm, false); | ||
532 | |||
533 | fullbatt_vchk(&cm->fullbatt_vchk_work.work); | ||
456 | } else { | 534 | } else { |
457 | cm->emergency_stop = 0; | 535 | cm->emergency_stop = 0; |
458 | if (!try_charger_enable(cm, true)) | 536 | if (is_ext_pwr_online(cm)) { |
459 | uevent_notify(cm, "CHARGING"); | 537 | if (!try_charger_enable(cm, true)) |
538 | uevent_notify(cm, "CHARGING"); | ||
539 | } | ||
460 | } | 540 | } |
461 | 541 | ||
462 | return true; | 542 | return true; |
@@ -719,47 +799,10 @@ static int charger_get_property(struct power_supply *psy, | |||
719 | val->intval = 0; | 799 | val->intval = 0; |
720 | break; | 800 | break; |
721 | case POWER_SUPPLY_PROP_CHARGE_FULL: | 801 | case POWER_SUPPLY_PROP_CHARGE_FULL: |
722 | if (cm->fuel_gauge) { | 802 | if (is_full_charged(cm)) |
723 | if (cm->fuel_gauge->get_property(cm->fuel_gauge, | ||
724 | POWER_SUPPLY_PROP_CHARGE_FULL, val) == 0) | ||
725 | break; | ||
726 | } | ||
727 | |||
728 | if (is_ext_pwr_online(cm)) { | ||
729 | /* Not full if it's charging. */ | ||
730 | if (is_charging(cm)) { | ||
731 | val->intval = 0; | ||
732 | break; | ||
733 | } | ||
734 | /* | ||
735 | * Full if it's powered but not charging andi | ||
736 | * not forced stop by emergency | ||
737 | */ | ||
738 | if (!cm->emergency_stop) { | ||
739 | val->intval = 1; | ||
740 | break; | ||
741 | } | ||
742 | } | ||
743 | |||
744 | /* Full if it's over the fullbatt voltage */ | ||
745 | ret = get_batt_uV(cm, &uV); | ||
746 | if (!ret && desc->fullbatt_uV > 0 && uV >= desc->fullbatt_uV && | ||
747 | !is_charging(cm)) { | ||
748 | val->intval = 1; | 803 | val->intval = 1; |
749 | break; | 804 | else |
750 | } | 805 | val->intval = 0; |
751 | |||
752 | /* Full if the cap is 100 */ | ||
753 | if (cm->fuel_gauge) { | ||
754 | ret = cm->fuel_gauge->get_property(cm->fuel_gauge, | ||
755 | POWER_SUPPLY_PROP_CAPACITY, val); | ||
756 | if (!ret && val->intval >= 100 && !is_charging(cm)) { | ||
757 | val->intval = 1; | ||
758 | break; | ||
759 | } | ||
760 | } | ||
761 | |||
762 | val->intval = 0; | ||
763 | ret = 0; | 806 | ret = 0; |
764 | break; | 807 | break; |
765 | case POWER_SUPPLY_PROP_CHARGE_NOW: | 808 | case POWER_SUPPLY_PROP_CHARGE_NOW: |
@@ -1049,7 +1092,26 @@ static int charger_extcon_notifier(struct notifier_block *self, | |||
1049 | struct charger_cable *cable = | 1092 | struct charger_cable *cable = |
1050 | container_of(self, struct charger_cable, nb); | 1093 | container_of(self, struct charger_cable, nb); |
1051 | 1094 | ||
1095 | /* | ||
1096 | * The newly state of charger cable. | ||
1097 | * If cable is attached, cable->attached is true. | ||
1098 | */ | ||
1052 | cable->attached = event; | 1099 | cable->attached = event; |
1100 | |||
1101 | /* | ||
1102 | * Setup monitoring to check battery state | ||
1103 | * when charger cable is attached. | ||
1104 | */ | ||
1105 | if (cable->attached && is_polling_required(cable->cm)) { | ||
1106 | if (work_pending(&setup_polling)) | ||
1107 | cancel_work_sync(&setup_polling); | ||
1108 | schedule_work(&setup_polling); | ||
1109 | } | ||
1110 | |||
1111 | /* | ||
1112 | * Setup work for controlling charger(regulator) | ||
1113 | * according to charger cable. | ||
1114 | */ | ||
1053 | schedule_work(&cable->wq); | 1115 | schedule_work(&cable->wq); |
1054 | 1116 | ||
1055 | return NOTIFY_DONE; | 1117 | return NOTIFY_DONE; |
@@ -1143,6 +1205,15 @@ static int charger_manager_probe(struct platform_device *pdev) | |||
1143 | desc->fullbatt_vchkdrop_ms = 0; | 1205 | desc->fullbatt_vchkdrop_ms = 0; |
1144 | desc->fullbatt_vchkdrop_uV = 0; | 1206 | desc->fullbatt_vchkdrop_uV = 0; |
1145 | } | 1207 | } |
1208 | if (desc->fullbatt_soc == 0) { | ||
1209 | dev_info(&pdev->dev, "Ignoring full-battery soc(state of" | ||
1210 | " charge) threshold as it is not" | ||
1211 | " supplied."); | ||
1212 | } | ||
1213 | if (desc->fullbatt_full_capacity == 0) { | ||
1214 | dev_info(&pdev->dev, "Ignoring full-battery full capacity" | ||
1215 | " threshold as it is not supplied."); | ||
1216 | } | ||
1146 | 1217 | ||
1147 | if (!desc->charger_regulators || desc->num_charger_regulators < 1) { | 1218 | if (!desc->charger_regulators || desc->num_charger_regulators < 1) { |
1148 | ret = -EINVAL; | 1219 | ret = -EINVAL; |
diff --git a/include/linux/power/charger-manager.h b/include/linux/power/charger-manager.h index b542270affc1..76b37ef3c071 100644 --- a/include/linux/power/charger-manager.h +++ b/include/linux/power/charger-manager.h | |||
@@ -140,7 +140,11 @@ struct charger_regulator { | |||
140 | * If it has dropped more than fullbatt_vchkdrop_uV after | 140 | * If it has dropped more than fullbatt_vchkdrop_uV after |
141 | * fullbatt_vchkdrop_ms, CM will restart charging. | 141 | * fullbatt_vchkdrop_ms, CM will restart charging. |
142 | * @fullbatt_uV: voltage in microvolt | 142 | * @fullbatt_uV: voltage in microvolt |
143 | * If it is not being charged and VBATT >= fullbatt_uV, | 143 | * If VBATT >= fullbatt_uV, it is assumed to be full. |
144 | * @fullbatt_soc: state of Charge in % | ||
145 | * If state of Charge >= fullbatt_soc, it is assumed to be full. | ||
146 | * @fullbatt_full_capacity: full capacity measure | ||
147 | * If full capacity of battery >= fullbatt_full_capacity, | ||
144 | * it is assumed to be full. | 148 | * it is assumed to be full. |
145 | * @polling_interval_ms: interval in millisecond at which | 149 | * @polling_interval_ms: interval in millisecond at which |
146 | * charger manager will monitor battery health | 150 | * charger manager will monitor battery health |
@@ -168,6 +172,8 @@ struct charger_desc { | |||
168 | unsigned int fullbatt_vchkdrop_ms; | 172 | unsigned int fullbatt_vchkdrop_ms; |
169 | unsigned int fullbatt_vchkdrop_uV; | 173 | unsigned int fullbatt_vchkdrop_uV; |
170 | unsigned int fullbatt_uV; | 174 | unsigned int fullbatt_uV; |
175 | unsigned int fullbatt_soc; | ||
176 | unsigned int fullbatt_full_capacity; | ||
171 | 177 | ||
172 | enum data_source battery_present; | 178 | enum data_source battery_present; |
173 | 179 | ||