diff options
author | Chanwoo Choi <cw00.choi@samsung.com> | 2012-09-21 00:20:05 -0400 |
---|---|---|
committer | Anton Vorontsov <anton.vorontsov@linaro.org> | 2012-09-21 01:08:00 -0400 |
commit | 8fcfe088e21aa0db9d62eaf565757def673efba6 (patch) | |
tree | 5394f0f8ac6ec50f1ab158927c858a621b074127 | |
parent | 2ed9e9b6530951b5b96185e6761119361a166d7a (diff) |
charger-manager: Support limit of maximum possible
This patch check maximum possible duration of charging/discharging.
If whole charging duration exceed 'desc->charging_max_duration_ms', cm
stop charging to prevent overcharge/overheat. And if discharging duration
exceed, charger cable is attached, after full-batt, cm start charging to
maintain fully charged state 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>
-rw-r--r-- | drivers/power/charger-manager.c | 80 | ||||
-rw-r--r-- | include/linux/power/charger-manager.h | 15 |
2 files changed, 94 insertions, 1 deletions
diff --git a/drivers/power/charger-manager.c b/drivers/power/charger-manager.c index c701f5e6f327..e92ec55ced91 100644 --- a/drivers/power/charger-manager.c +++ b/drivers/power/charger-manager.c | |||
@@ -323,6 +323,14 @@ static int try_charger_enable(struct charger_manager *cm, bool enable) | |||
323 | if (enable) { | 323 | if (enable) { |
324 | if (cm->emergency_stop) | 324 | if (cm->emergency_stop) |
325 | return -EAGAIN; | 325 | return -EAGAIN; |
326 | |||
327 | /* | ||
328 | * Save start time of charging to limit | ||
329 | * maximum possible charging time. | ||
330 | */ | ||
331 | cm->charging_start_time = ktime_to_ms(ktime_get()); | ||
332 | cm->charging_end_time = 0; | ||
333 | |||
326 | for (i = 0 ; i < desc->num_charger_regulators ; i++) { | 334 | for (i = 0 ; i < desc->num_charger_regulators ; i++) { |
327 | err = regulator_enable(desc->charger_regulators[i].consumer); | 335 | err = regulator_enable(desc->charger_regulators[i].consumer); |
328 | if (err < 0) { | 336 | if (err < 0) { |
@@ -332,6 +340,13 @@ static int try_charger_enable(struct charger_manager *cm, bool enable) | |||
332 | } | 340 | } |
333 | } | 341 | } |
334 | } else { | 342 | } else { |
343 | /* | ||
344 | * Save end time of charging to maintain fully charged state | ||
345 | * of battery after full-batt. | ||
346 | */ | ||
347 | cm->charging_start_time = 0; | ||
348 | cm->charging_end_time = ktime_to_ms(ktime_get()); | ||
349 | |||
335 | for (i = 0 ; i < desc->num_charger_regulators ; i++) { | 350 | for (i = 0 ; i < desc->num_charger_regulators ; i++) { |
336 | err = regulator_disable(desc->charger_regulators[i].consumer); | 351 | err = regulator_disable(desc->charger_regulators[i].consumer); |
337 | if (err < 0) { | 352 | if (err < 0) { |
@@ -474,8 +489,55 @@ static void fullbatt_vchk(struct work_struct *work) | |||
474 | 489 | ||
475 | if (diff > desc->fullbatt_vchkdrop_uV) { | 490 | if (diff > desc->fullbatt_vchkdrop_uV) { |
476 | try_charger_restart(cm); | 491 | try_charger_restart(cm); |
477 | uevent_notify(cm, "Recharge"); | 492 | uevent_notify(cm, "Recharging"); |
493 | } | ||
494 | } | ||
495 | |||
496 | /** | ||
497 | * check_charging_duration - Monitor charging/discharging duration | ||
498 | * @cm: the Charger Manager representing the battery. | ||
499 | * | ||
500 | * If whole charging duration exceed 'charging_max_duration_ms', | ||
501 | * cm stop charging to prevent overcharge/overheat. If discharging | ||
502 | * duration exceed 'discharging _max_duration_ms', charger cable is | ||
503 | * attached, after full-batt, cm start charging to maintain fully | ||
504 | * charged state for battery. | ||
505 | */ | ||
506 | static int check_charging_duration(struct charger_manager *cm) | ||
507 | { | ||
508 | struct charger_desc *desc = cm->desc; | ||
509 | u64 curr = ktime_to_ms(ktime_get()); | ||
510 | u64 duration; | ||
511 | int ret = false; | ||
512 | |||
513 | if (!desc->charging_max_duration_ms && | ||
514 | !desc->discharging_max_duration_ms) | ||
515 | return ret; | ||
516 | |||
517 | if (cm->charger_enabled) { | ||
518 | duration = curr - cm->charging_start_time; | ||
519 | |||
520 | if (duration > desc->charging_max_duration_ms) { | ||
521 | dev_info(cm->dev, "Charging duration exceed %lldms", | ||
522 | desc->charging_max_duration_ms); | ||
523 | uevent_notify(cm, "Discharging"); | ||
524 | try_charger_enable(cm, false); | ||
525 | ret = true; | ||
526 | } | ||
527 | } else if (is_ext_pwr_online(cm) && !cm->charger_enabled) { | ||
528 | duration = curr - cm->charging_end_time; | ||
529 | |||
530 | if (duration > desc->charging_max_duration_ms && | ||
531 | is_ext_pwr_online(cm)) { | ||
532 | dev_info(cm->dev, "DisCharging duration exceed %lldms", | ||
533 | desc->discharging_max_duration_ms); | ||
534 | uevent_notify(cm, "Recharing"); | ||
535 | try_charger_enable(cm, true); | ||
536 | ret = true; | ||
537 | } | ||
478 | } | 538 | } |
539 | |||
540 | return ret; | ||
479 | } | 541 | } |
480 | 542 | ||
481 | /** | 543 | /** |
@@ -511,6 +573,13 @@ static bool _cm_monitor(struct charger_manager *cm) | |||
511 | } | 573 | } |
512 | 574 | ||
513 | /* | 575 | /* |
576 | * Check whole charging duration and discharing duration | ||
577 | * after full-batt. | ||
578 | */ | ||
579 | } else if (!cm->emergency_stop && check_charging_duration(cm)) { | ||
580 | dev_dbg(cm->dev, | ||
581 | "Charging/Discharging duration is out of range"); | ||
582 | /* | ||
514 | * Check dropped voltage of battery. If battery voltage is more | 583 | * Check dropped voltage of battery. If battery voltage is more |
515 | * dropped than fullbatt_vchkdrop_uV after fully charged state, | 584 | * dropped than fullbatt_vchkdrop_uV after fully charged state, |
516 | * charger-manager have to recharge battery. | 585 | * charger-manager have to recharge battery. |
@@ -1271,6 +1340,15 @@ static int charger_manager_probe(struct platform_device *pdev) | |||
1271 | goto err_chg_stat; | 1340 | goto err_chg_stat; |
1272 | } | 1341 | } |
1273 | 1342 | ||
1343 | if (!desc->charging_max_duration_ms || | ||
1344 | !desc->discharging_max_duration_ms) { | ||
1345 | dev_info(&pdev->dev, "Cannot limit charging duration " | ||
1346 | "checking mechanism to prevent overcharge/overheat " | ||
1347 | "and control discharging duration"); | ||
1348 | desc->charging_max_duration_ms = 0; | ||
1349 | desc->discharging_max_duration_ms = 0; | ||
1350 | } | ||
1351 | |||
1274 | platform_set_drvdata(pdev, cm); | 1352 | platform_set_drvdata(pdev, cm); |
1275 | 1353 | ||
1276 | memcpy(&cm->charger_psy, &psy_default, sizeof(psy_default)); | 1354 | memcpy(&cm->charger_psy, &psy_default, sizeof(psy_default)); |
diff --git a/include/linux/power/charger-manager.h b/include/linux/power/charger-manager.h index 76b37ef3c071..a7b388ea1588 100644 --- a/include/linux/power/charger-manager.h +++ b/include/linux/power/charger-manager.h | |||
@@ -162,6 +162,13 @@ struct charger_regulator { | |||
162 | * @measure_battery_temp: | 162 | * @measure_battery_temp: |
163 | * true: measure battery temperature | 163 | * true: measure battery temperature |
164 | * false: measure ambient temperature | 164 | * false: measure ambient temperature |
165 | * @charging_max_duration_ms: Maximum possible duration for charging | ||
166 | * If whole charging duration exceed 'charging_max_duration_ms', | ||
167 | * cm stop charging. | ||
168 | * @discharging_max_duration_ms: | ||
169 | * Maximum possible duration for discharging with charger cable | ||
170 | * after full-batt. If discharging duration exceed 'discharging | ||
171 | * max_duration_ms', cm start charging. | ||
165 | */ | 172 | */ |
166 | struct charger_desc { | 173 | struct charger_desc { |
167 | char *psy_name; | 174 | char *psy_name; |
@@ -186,6 +193,9 @@ struct charger_desc { | |||
186 | 193 | ||
187 | int (*temperature_out_of_range)(int *mC); | 194 | int (*temperature_out_of_range)(int *mC); |
188 | bool measure_battery_temp; | 195 | bool measure_battery_temp; |
196 | |||
197 | u64 charging_max_duration_ms; | ||
198 | u64 discharging_max_duration_ms; | ||
189 | }; | 199 | }; |
190 | 200 | ||
191 | #define PSY_NAME_MAX 30 | 201 | #define PSY_NAME_MAX 30 |
@@ -210,6 +220,8 @@ struct charger_desc { | |||
210 | * saved status of external power before entering suspend-to-RAM | 220 | * saved status of external power before entering suspend-to-RAM |
211 | * @status_save_batt: | 221 | * @status_save_batt: |
212 | * saved status of battery before entering suspend-to-RAM | 222 | * saved status of battery before entering suspend-to-RAM |
223 | * @charging_start_time: saved start time of enabling charging | ||
224 | * @charging_end_time: saved end time of disabling charging | ||
213 | */ | 225 | */ |
214 | struct charger_manager { | 226 | struct charger_manager { |
215 | struct list_head entry; | 227 | struct list_head entry; |
@@ -232,6 +244,9 @@ struct charger_manager { | |||
232 | 244 | ||
233 | bool status_save_ext_pwr_inserted; | 245 | bool status_save_ext_pwr_inserted; |
234 | bool status_save_batt; | 246 | bool status_save_batt; |
247 | |||
248 | u64 charging_start_time; | ||
249 | u64 charging_end_time; | ||
235 | }; | 250 | }; |
236 | 251 | ||
237 | #ifdef CONFIG_CHARGER_MANAGER | 252 | #ifdef CONFIG_CHARGER_MANAGER |