diff options
| -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 |
