aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/power/charger-manager.c161
-rw-r--r--include/linux/power/charger-manager.h8
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 */
233static 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
277out:
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