aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/power/charger-manager.c
diff options
context:
space:
mode:
authorChanwoo Choi <cw00.choi@samsung.com>2012-08-21 04:06:52 -0400
committerAnton Vorontsov <anton.vorontsov@linaro.org>2012-09-21 01:07:49 -0400
commit2ed9e9b6530951b5b96185e6761119361a166d7a (patch)
treedd5e298b0102b3dcb611be6710a2bed536c2741b /drivers/power/charger-manager.c
parentb9633ef1a9cdf4317d8c4a8db977485e2a8e1cb8 (diff)
charger-manager: Check fully charged state of battery periodically
This patch check periodically fully charged state of battery to protect overcharge and overheat. If battery is fully charged, stop charging and check droped voltage with 'fullbatt_vchkdrop_ms' period. When voltage of battery is more droped than 'fullbatt_vchkdrop_uV' voltage, charger-manager will restart charging for battery. Signed-off-by: Chanwoo Choi <cw00.choi@samsung.com> Signed-off-by: Myungjoo Ham <myungjoo.ham@samsung.com> Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com> Signed-off-by: Anton Vorontsov <anton.vorontsov@linaro.org>
Diffstat (limited to 'drivers/power/charger-manager.c')
-rw-r--r--drivers/power/charger-manager.c161
1 files changed, 116 insertions, 45 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;