diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-10-07 04:29:24 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-10-07 04:29:24 -0400 |
commit | e665faa424a4a782aa986274920c1fc5b76f5560 (patch) | |
tree | 2cf64abadecbbeadcffc02cb7671cb593fc45488 /drivers/power/charger-manager.c | |
parent | ca4da6948bc6a7010ecf916dad528c177dcb9a81 (diff) | |
parent | 18766f0936d444fd7ff2e0064bd6e69a89d5c6fc (diff) |
Merge tag 'for-v3.7' of git://git.infradead.org/battery-2.6
Pull battery updates from Anton Vorontsov:
"1. New drivers:
- Marvell 88pm860x charger and battery drivers;
- Texas Instruments LP8788 charger driver;
2. Two new power supply properties: whether a battery is authentic,
and chargers' maximal currents and voltages;
3. A lot of TI LP8727 Charger cleanups;
4. New features for Charger Manager, mainly now we can disable
specific regulators;
5. Random fixes and cleanups for other drivers."
Fix up trivial conflicts in <linux/mfd/88pm860x.h>
* tag 'for-v3.7' of git://git.infradead.org/battery-2.6: (52 commits)
pda_power: Remove ac_draw_failed goto and label
charger-manager: Add support sysfs entry for charger
charger-manager: Support limit of maximum possible
charger-manager: Check fully charged state of battery periodically
lp8727_charger: More pure cosmetic improvements
lp8727_charger: Fix checkpatch warning
lp8727_charger: Add description in the private data
lp8727_charger: Fix a typo - chg_parm to chg_param
lp8727_charger: Make some cosmetic changes in lp8727_delayed_func()
lp8727_charger: Clean up lp8727_charger_changed()
lp8727_charger: Return if the battery is discharging
lp8727_charger: Make lp8727_charger_get_propery() simpler
lp8727_charger: Make lp8727_ctrl_switch() inline
lp8727_charger: Make lp8727_init_device() shorter
lp8727_charger: Clean up lp8727_is_charger_attached()
lp8727_charger: Use specific definition
lp8727_charger: Clean up lp8727 definitions
lp8727_charger: Use the definition rather than enum
lp8727_charger: Fix code for getting battery temp
lp8727_charger: Clear interrrupts at inital time
...
Diffstat (limited to 'drivers/power/charger-manager.c')
-rw-r--r-- | drivers/power/charger-manager.c | 434 |
1 files changed, 385 insertions, 49 deletions
diff --git a/drivers/power/charger-manager.c b/drivers/power/charger-manager.c index 7ff83cf43c8c..8a0aca6364c7 100644 --- a/drivers/power/charger-manager.c +++ b/drivers/power/charger-manager.c | |||
@@ -22,6 +22,7 @@ | |||
22 | #include <linux/platform_device.h> | 22 | #include <linux/platform_device.h> |
23 | #include <linux/power/charger-manager.h> | 23 | #include <linux/power/charger-manager.h> |
24 | #include <linux/regulator/consumer.h> | 24 | #include <linux/regulator/consumer.h> |
25 | #include <linux/sysfs.h> | ||
25 | 26 | ||
26 | static const char * const default_event_names[] = { | 27 | static const char * const default_event_names[] = { |
27 | [CM_EVENT_UNKNOWN] = "Unknown", | 28 | [CM_EVENT_UNKNOWN] = "Unknown", |
@@ -227,6 +228,58 @@ static bool is_charging(struct charger_manager *cm) | |||
227 | } | 228 | } |
228 | 229 | ||
229 | /** | 230 | /** |
231 | * is_full_charged - Returns true if the battery is fully charged. | ||
232 | * @cm: the Charger Manager representing the battery. | ||
233 | */ | ||
234 | static bool is_full_charged(struct charger_manager *cm) | ||
235 | { | ||
236 | struct charger_desc *desc = cm->desc; | ||
237 | union power_supply_propval val; | ||
238 | int ret = 0; | ||
239 | int uV; | ||
240 | |||
241 | /* If there is no battery, it cannot be charged */ | ||
242 | if (!is_batt_present(cm)) { | ||
243 | val.intval = 0; | ||
244 | goto out; | ||
245 | } | ||
246 | |||
247 | if (cm->fuel_gauge && desc->fullbatt_full_capacity > 0) { | ||
248 | /* Not full if capacity of fuel gauge isn't full */ | ||
249 | ret = cm->fuel_gauge->get_property(cm->fuel_gauge, | ||
250 | POWER_SUPPLY_PROP_CHARGE_FULL, &val); | ||
251 | if (!ret && val.intval > desc->fullbatt_full_capacity) { | ||
252 | val.intval = 1; | ||
253 | goto out; | ||
254 | } | ||
255 | } | ||
256 | |||
257 | /* Full, if it's over the fullbatt voltage */ | ||
258 | if (desc->fullbatt_uV > 0) { | ||
259 | ret = get_batt_uV(cm, &uV); | ||
260 | if (!ret && uV >= desc->fullbatt_uV) { | ||
261 | val.intval = 1; | ||
262 | goto out; | ||
263 | } | ||
264 | } | ||
265 | |||
266 | /* Full, if the capacity is more than fullbatt_soc */ | ||
267 | if (cm->fuel_gauge && desc->fullbatt_soc > 0) { | ||
268 | ret = cm->fuel_gauge->get_property(cm->fuel_gauge, | ||
269 | POWER_SUPPLY_PROP_CAPACITY, &val); | ||
270 | if (!ret && val.intval >= desc->fullbatt_soc) { | ||
271 | val.intval = 1; | ||
272 | goto out; | ||
273 | } | ||
274 | } | ||
275 | |||
276 | val.intval = 0; | ||
277 | |||
278 | out: | ||
279 | return val.intval ? true : false; | ||
280 | } | ||
281 | |||
282 | /** | ||
230 | * is_polling_required - Return true if need to continue polling for this CM. | 283 | * is_polling_required - Return true if need to continue polling for this CM. |
231 | * @cm: the Charger Manager representing the battery. | 284 | * @cm: the Charger Manager representing the battery. |
232 | */ | 285 | */ |
@@ -271,10 +324,46 @@ static int try_charger_enable(struct charger_manager *cm, bool enable) | |||
271 | if (enable) { | 324 | if (enable) { |
272 | if (cm->emergency_stop) | 325 | if (cm->emergency_stop) |
273 | return -EAGAIN; | 326 | return -EAGAIN; |
274 | for (i = 0 ; i < desc->num_charger_regulators ; i++) | 327 | |
275 | regulator_enable(desc->charger_regulators[i].consumer); | 328 | /* |
329 | * Save start time of charging to limit | ||
330 | * maximum possible charging time. | ||
331 | */ | ||
332 | cm->charging_start_time = ktime_to_ms(ktime_get()); | ||
333 | cm->charging_end_time = 0; | ||
334 | |||
335 | for (i = 0 ; i < desc->num_charger_regulators ; i++) { | ||
336 | if (desc->charger_regulators[i].externally_control) | ||
337 | continue; | ||
338 | |||
339 | err = regulator_enable(desc->charger_regulators[i].consumer); | ||
340 | if (err < 0) { | ||
341 | dev_warn(cm->dev, | ||
342 | "Cannot enable %s regulator\n", | ||
343 | desc->charger_regulators[i].regulator_name); | ||
344 | } | ||
345 | } | ||
276 | } else { | 346 | } else { |
277 | /* | 347 | /* |
348 | * Save end time of charging to maintain fully charged state | ||
349 | * of battery after full-batt. | ||
350 | */ | ||
351 | cm->charging_start_time = 0; | ||
352 | cm->charging_end_time = ktime_to_ms(ktime_get()); | ||
353 | |||
354 | for (i = 0 ; i < desc->num_charger_regulators ; i++) { | ||
355 | if (desc->charger_regulators[i].externally_control) | ||
356 | continue; | ||
357 | |||
358 | err = regulator_disable(desc->charger_regulators[i].consumer); | ||
359 | if (err < 0) { | ||
360 | dev_warn(cm->dev, | ||
361 | "Cannot disable %s regulator\n", | ||
362 | desc->charger_regulators[i].regulator_name); | ||
363 | } | ||
364 | } | ||
365 | |||
366 | /* | ||
278 | * Abnormal battery state - Stop charging forcibly, | 367 | * Abnormal battery state - Stop charging forcibly, |
279 | * even if charger was enabled at the other places | 368 | * even if charger was enabled at the other places |
280 | */ | 369 | */ |
@@ -400,15 +489,62 @@ static void fullbatt_vchk(struct work_struct *work) | |||
400 | return; | 489 | return; |
401 | } | 490 | } |
402 | 491 | ||
403 | diff = cm->fullbatt_vchk_uV; | 492 | diff = desc->fullbatt_uV; |
404 | diff -= batt_uV; | 493 | diff -= batt_uV; |
405 | 494 | ||
406 | dev_dbg(cm->dev, "VBATT dropped %duV after full-batt.\n", diff); | 495 | dev_info(cm->dev, "VBATT dropped %duV after full-batt.\n", diff); |
407 | 496 | ||
408 | if (diff > desc->fullbatt_vchkdrop_uV) { | 497 | if (diff > desc->fullbatt_vchkdrop_uV) { |
409 | try_charger_restart(cm); | 498 | try_charger_restart(cm); |
410 | uevent_notify(cm, "Recharge"); | 499 | uevent_notify(cm, "Recharging"); |
500 | } | ||
501 | } | ||
502 | |||
503 | /** | ||
504 | * check_charging_duration - Monitor charging/discharging duration | ||
505 | * @cm: the Charger Manager representing the battery. | ||
506 | * | ||
507 | * If whole charging duration exceed 'charging_max_duration_ms', | ||
508 | * cm stop charging to prevent overcharge/overheat. If discharging | ||
509 | * duration exceed 'discharging _max_duration_ms', charger cable is | ||
510 | * attached, after full-batt, cm start charging to maintain fully | ||
511 | * charged state for battery. | ||
512 | */ | ||
513 | static int check_charging_duration(struct charger_manager *cm) | ||
514 | { | ||
515 | struct charger_desc *desc = cm->desc; | ||
516 | u64 curr = ktime_to_ms(ktime_get()); | ||
517 | u64 duration; | ||
518 | int ret = false; | ||
519 | |||
520 | if (!desc->charging_max_duration_ms && | ||
521 | !desc->discharging_max_duration_ms) | ||
522 | return ret; | ||
523 | |||
524 | if (cm->charger_enabled) { | ||
525 | duration = curr - cm->charging_start_time; | ||
526 | |||
527 | if (duration > desc->charging_max_duration_ms) { | ||
528 | dev_info(cm->dev, "Charging duration exceed %lldms", | ||
529 | desc->charging_max_duration_ms); | ||
530 | uevent_notify(cm, "Discharging"); | ||
531 | try_charger_enable(cm, false); | ||
532 | ret = true; | ||
533 | } | ||
534 | } else if (is_ext_pwr_online(cm) && !cm->charger_enabled) { | ||
535 | duration = curr - cm->charging_end_time; | ||
536 | |||
537 | if (duration > desc->charging_max_duration_ms && | ||
538 | is_ext_pwr_online(cm)) { | ||
539 | dev_info(cm->dev, "DisCharging duration exceed %lldms", | ||
540 | desc->discharging_max_duration_ms); | ||
541 | uevent_notify(cm, "Recharing"); | ||
542 | try_charger_enable(cm, true); | ||
543 | ret = true; | ||
544 | } | ||
411 | } | 545 | } |
546 | |||
547 | return ret; | ||
412 | } | 548 | } |
413 | 549 | ||
414 | /** | 550 | /** |
@@ -426,10 +562,14 @@ static bool _cm_monitor(struct charger_manager *cm) | |||
426 | dev_dbg(cm->dev, "monitoring (%2.2d.%3.3dC)\n", | 562 | dev_dbg(cm->dev, "monitoring (%2.2d.%3.3dC)\n", |
427 | cm->last_temp_mC / 1000, cm->last_temp_mC % 1000); | 563 | cm->last_temp_mC / 1000, cm->last_temp_mC % 1000); |
428 | 564 | ||
429 | /* It has been stopped or charging already */ | 565 | /* It has been stopped already */ |
430 | if (!!temp == !!cm->emergency_stop) | 566 | if (temp && cm->emergency_stop) |
431 | return false; | 567 | return false; |
432 | 568 | ||
569 | /* | ||
570 | * Check temperature whether overheat or cold. | ||
571 | * If temperature is out of range normal state, stop charging. | ||
572 | */ | ||
433 | if (temp) { | 573 | if (temp) { |
434 | cm->emergency_stop = temp; | 574 | cm->emergency_stop = temp; |
435 | if (!try_charger_enable(cm, false)) { | 575 | if (!try_charger_enable(cm, false)) { |
@@ -438,10 +578,41 @@ static bool _cm_monitor(struct charger_manager *cm) | |||
438 | else | 578 | else |
439 | uevent_notify(cm, "COLD"); | 579 | uevent_notify(cm, "COLD"); |
440 | } | 580 | } |
581 | |||
582 | /* | ||
583 | * Check whole charging duration and discharing duration | ||
584 | * after full-batt. | ||
585 | */ | ||
586 | } else if (!cm->emergency_stop && check_charging_duration(cm)) { | ||
587 | dev_dbg(cm->dev, | ||
588 | "Charging/Discharging duration is out of range"); | ||
589 | /* | ||
590 | * Check dropped voltage of battery. If battery voltage is more | ||
591 | * dropped than fullbatt_vchkdrop_uV after fully charged state, | ||
592 | * charger-manager have to recharge battery. | ||
593 | */ | ||
594 | } else if (!cm->emergency_stop && is_ext_pwr_online(cm) && | ||
595 | !cm->charger_enabled) { | ||
596 | fullbatt_vchk(&cm->fullbatt_vchk_work.work); | ||
597 | |||
598 | /* | ||
599 | * Check whether fully charged state to protect overcharge | ||
600 | * if charger-manager is charging for battery. | ||
601 | */ | ||
602 | } else if (!cm->emergency_stop && is_full_charged(cm) && | ||
603 | cm->charger_enabled) { | ||
604 | dev_info(cm->dev, "EVENT_HANDLE: Battery Fully Charged.\n"); | ||
605 | uevent_notify(cm, default_event_names[CM_EVENT_BATT_FULL]); | ||
606 | |||
607 | try_charger_enable(cm, false); | ||
608 | |||
609 | fullbatt_vchk(&cm->fullbatt_vchk_work.work); | ||
441 | } else { | 610 | } else { |
442 | cm->emergency_stop = 0; | 611 | cm->emergency_stop = 0; |
443 | if (!try_charger_enable(cm, true)) | 612 | if (is_ext_pwr_online(cm)) { |
444 | uevent_notify(cm, "CHARGING"); | 613 | if (!try_charger_enable(cm, true)) |
614 | uevent_notify(cm, "CHARGING"); | ||
615 | } | ||
445 | } | 616 | } |
446 | 617 | ||
447 | return true; | 618 | return true; |
@@ -701,47 +872,10 @@ static int charger_get_property(struct power_supply *psy, | |||
701 | val->intval = 0; | 872 | val->intval = 0; |
702 | break; | 873 | break; |
703 | case POWER_SUPPLY_PROP_CHARGE_FULL: | 874 | case POWER_SUPPLY_PROP_CHARGE_FULL: |
704 | if (cm->fuel_gauge) { | 875 | if (is_full_charged(cm)) |
705 | if (cm->fuel_gauge->get_property(cm->fuel_gauge, | ||
706 | POWER_SUPPLY_PROP_CHARGE_FULL, val) == 0) | ||
707 | break; | ||
708 | } | ||
709 | |||
710 | if (is_ext_pwr_online(cm)) { | ||
711 | /* Not full if it's charging. */ | ||
712 | if (is_charging(cm)) { | ||
713 | val->intval = 0; | ||
714 | break; | ||
715 | } | ||
716 | /* | ||
717 | * Full if it's powered but not charging andi | ||
718 | * not forced stop by emergency | ||
719 | */ | ||
720 | if (!cm->emergency_stop) { | ||
721 | val->intval = 1; | ||
722 | break; | ||
723 | } | ||
724 | } | ||
725 | |||
726 | /* Full if it's over the fullbatt voltage */ | ||
727 | ret = get_batt_uV(cm, &uV); | ||
728 | if (!ret && desc->fullbatt_uV > 0 && uV >= desc->fullbatt_uV && | ||
729 | !is_charging(cm)) { | ||
730 | val->intval = 1; | 876 | val->intval = 1; |
731 | break; | 877 | else |
732 | } | 878 | val->intval = 0; |
733 | |||
734 | /* Full if the cap is 100 */ | ||
735 | if (cm->fuel_gauge) { | ||
736 | ret = cm->fuel_gauge->get_property(cm->fuel_gauge, | ||
737 | POWER_SUPPLY_PROP_CAPACITY, val); | ||
738 | if (!ret && val->intval >= 100 && !is_charging(cm)) { | ||
739 | val->intval = 1; | ||
740 | break; | ||
741 | } | ||
742 | } | ||
743 | |||
744 | val->intval = 0; | ||
745 | ret = 0; | 879 | ret = 0; |
746 | break; | 880 | break; |
747 | case POWER_SUPPLY_PROP_CHARGE_NOW: | 881 | case POWER_SUPPLY_PROP_CHARGE_NOW: |
@@ -1031,7 +1165,26 @@ static int charger_extcon_notifier(struct notifier_block *self, | |||
1031 | struct charger_cable *cable = | 1165 | struct charger_cable *cable = |
1032 | container_of(self, struct charger_cable, nb); | 1166 | container_of(self, struct charger_cable, nb); |
1033 | 1167 | ||
1168 | /* | ||
1169 | * The newly state of charger cable. | ||
1170 | * If cable is attached, cable->attached is true. | ||
1171 | */ | ||
1034 | cable->attached = event; | 1172 | cable->attached = event; |
1173 | |||
1174 | /* | ||
1175 | * Setup monitoring to check battery state | ||
1176 | * when charger cable is attached. | ||
1177 | */ | ||
1178 | if (cable->attached && is_polling_required(cable->cm)) { | ||
1179 | if (work_pending(&setup_polling)) | ||
1180 | cancel_work_sync(&setup_polling); | ||
1181 | schedule_work(&setup_polling); | ||
1182 | } | ||
1183 | |||
1184 | /* | ||
1185 | * Setup work for controlling charger(regulator) | ||
1186 | * according to charger cable. | ||
1187 | */ | ||
1035 | schedule_work(&cable->wq); | 1188 | schedule_work(&cable->wq); |
1036 | 1189 | ||
1037 | return NOTIFY_DONE; | 1190 | return NOTIFY_DONE; |
@@ -1068,12 +1221,101 @@ static int charger_extcon_init(struct charger_manager *cm, | |||
1068 | return ret; | 1221 | return ret; |
1069 | } | 1222 | } |
1070 | 1223 | ||
1224 | /* help function of sysfs node to control charger(regulator) */ | ||
1225 | static ssize_t charger_name_show(struct device *dev, | ||
1226 | struct device_attribute *attr, char *buf) | ||
1227 | { | ||
1228 | struct charger_regulator *charger | ||
1229 | = container_of(attr, struct charger_regulator, attr_name); | ||
1230 | |||
1231 | return sprintf(buf, "%s\n", charger->regulator_name); | ||
1232 | } | ||
1233 | |||
1234 | static ssize_t charger_state_show(struct device *dev, | ||
1235 | struct device_attribute *attr, char *buf) | ||
1236 | { | ||
1237 | struct charger_regulator *charger | ||
1238 | = container_of(attr, struct charger_regulator, attr_state); | ||
1239 | int state = 0; | ||
1240 | |||
1241 | if (!charger->externally_control) | ||
1242 | state = regulator_is_enabled(charger->consumer); | ||
1243 | |||
1244 | return sprintf(buf, "%s\n", state ? "enabled" : "disabled"); | ||
1245 | } | ||
1246 | |||
1247 | static ssize_t charger_externally_control_show(struct device *dev, | ||
1248 | struct device_attribute *attr, char *buf) | ||
1249 | { | ||
1250 | struct charger_regulator *charger = container_of(attr, | ||
1251 | struct charger_regulator, attr_externally_control); | ||
1252 | |||
1253 | return sprintf(buf, "%d\n", charger->externally_control); | ||
1254 | } | ||
1255 | |||
1256 | static ssize_t charger_externally_control_store(struct device *dev, | ||
1257 | struct device_attribute *attr, const char *buf, | ||
1258 | size_t count) | ||
1259 | { | ||
1260 | struct charger_regulator *charger | ||
1261 | = container_of(attr, struct charger_regulator, | ||
1262 | attr_externally_control); | ||
1263 | struct charger_manager *cm = charger->cm; | ||
1264 | struct charger_desc *desc = cm->desc; | ||
1265 | int i; | ||
1266 | int ret; | ||
1267 | int externally_control; | ||
1268 | int chargers_externally_control = 1; | ||
1269 | |||
1270 | ret = sscanf(buf, "%d", &externally_control); | ||
1271 | if (ret == 0) { | ||
1272 | ret = -EINVAL; | ||
1273 | return ret; | ||
1274 | } | ||
1275 | |||
1276 | if (!externally_control) { | ||
1277 | charger->externally_control = 0; | ||
1278 | return count; | ||
1279 | } | ||
1280 | |||
1281 | for (i = 0; i < desc->num_charger_regulators; i++) { | ||
1282 | if (&desc->charger_regulators[i] != charger && | ||
1283 | !desc->charger_regulators[i].externally_control) { | ||
1284 | /* | ||
1285 | * At least, one charger is controlled by | ||
1286 | * charger-manager | ||
1287 | */ | ||
1288 | chargers_externally_control = 0; | ||
1289 | break; | ||
1290 | } | ||
1291 | } | ||
1292 | |||
1293 | if (!chargers_externally_control) { | ||
1294 | if (cm->charger_enabled) { | ||
1295 | try_charger_enable(charger->cm, false); | ||
1296 | charger->externally_control = externally_control; | ||
1297 | try_charger_enable(charger->cm, true); | ||
1298 | } else { | ||
1299 | charger->externally_control = externally_control; | ||
1300 | } | ||
1301 | } else { | ||
1302 | dev_warn(cm->dev, | ||
1303 | "'%s' regulator should be controlled " | ||
1304 | "in charger-manager because charger-manager " | ||
1305 | "must need at least one charger for charging\n", | ||
1306 | charger->regulator_name); | ||
1307 | } | ||
1308 | |||
1309 | return count; | ||
1310 | } | ||
1311 | |||
1071 | static int charger_manager_probe(struct platform_device *pdev) | 1312 | static int charger_manager_probe(struct platform_device *pdev) |
1072 | { | 1313 | { |
1073 | struct charger_desc *desc = dev_get_platdata(&pdev->dev); | 1314 | struct charger_desc *desc = dev_get_platdata(&pdev->dev); |
1074 | struct charger_manager *cm; | 1315 | struct charger_manager *cm; |
1075 | int ret = 0, i = 0; | 1316 | int ret = 0, i = 0; |
1076 | int j = 0; | 1317 | int j = 0; |
1318 | int chargers_externally_control = 1; | ||
1077 | union power_supply_propval val; | 1319 | union power_supply_propval val; |
1078 | 1320 | ||
1079 | if (g_desc && !rtc_dev && g_desc->rtc_name) { | 1321 | if (g_desc && !rtc_dev && g_desc->rtc_name) { |
@@ -1125,6 +1367,15 @@ static int charger_manager_probe(struct platform_device *pdev) | |||
1125 | desc->fullbatt_vchkdrop_ms = 0; | 1367 | desc->fullbatt_vchkdrop_ms = 0; |
1126 | desc->fullbatt_vchkdrop_uV = 0; | 1368 | desc->fullbatt_vchkdrop_uV = 0; |
1127 | } | 1369 | } |
1370 | if (desc->fullbatt_soc == 0) { | ||
1371 | dev_info(&pdev->dev, "Ignoring full-battery soc(state of" | ||
1372 | " charge) threshold as it is not" | ||
1373 | " supplied."); | ||
1374 | } | ||
1375 | if (desc->fullbatt_full_capacity == 0) { | ||
1376 | dev_info(&pdev->dev, "Ignoring full-battery full capacity" | ||
1377 | " threshold as it is not supplied."); | ||
1378 | } | ||
1128 | 1379 | ||
1129 | if (!desc->charger_regulators || desc->num_charger_regulators < 1) { | 1380 | if (!desc->charger_regulators || desc->num_charger_regulators < 1) { |
1130 | ret = -EINVAL; | 1381 | ret = -EINVAL; |
@@ -1182,6 +1433,15 @@ static int charger_manager_probe(struct platform_device *pdev) | |||
1182 | goto err_chg_stat; | 1433 | goto err_chg_stat; |
1183 | } | 1434 | } |
1184 | 1435 | ||
1436 | if (!desc->charging_max_duration_ms || | ||
1437 | !desc->discharging_max_duration_ms) { | ||
1438 | dev_info(&pdev->dev, "Cannot limit charging duration " | ||
1439 | "checking mechanism to prevent overcharge/overheat " | ||
1440 | "and control discharging duration"); | ||
1441 | desc->charging_max_duration_ms = 0; | ||
1442 | desc->discharging_max_duration_ms = 0; | ||
1443 | } | ||
1444 | |||
1185 | platform_set_drvdata(pdev, cm); | 1445 | platform_set_drvdata(pdev, cm); |
1186 | 1446 | ||
1187 | memcpy(&cm->charger_psy, &psy_default, sizeof(psy_default)); | 1447 | memcpy(&cm->charger_psy, &psy_default, sizeof(psy_default)); |
@@ -1245,6 +1505,8 @@ static int charger_manager_probe(struct platform_device *pdev) | |||
1245 | for (i = 0 ; i < desc->num_charger_regulators ; i++) { | 1505 | for (i = 0 ; i < desc->num_charger_regulators ; i++) { |
1246 | struct charger_regulator *charger | 1506 | struct charger_regulator *charger |
1247 | = &desc->charger_regulators[i]; | 1507 | = &desc->charger_regulators[i]; |
1508 | char buf[11]; | ||
1509 | char *str; | ||
1248 | 1510 | ||
1249 | charger->consumer = regulator_get(&pdev->dev, | 1511 | charger->consumer = regulator_get(&pdev->dev, |
1250 | charger->regulator_name); | 1512 | charger->regulator_name); |
@@ -1254,6 +1516,7 @@ static int charger_manager_probe(struct platform_device *pdev) | |||
1254 | ret = -EINVAL; | 1516 | ret = -EINVAL; |
1255 | goto err_chg_get; | 1517 | goto err_chg_get; |
1256 | } | 1518 | } |
1519 | charger->cm = cm; | ||
1257 | 1520 | ||
1258 | for (j = 0 ; j < charger->num_cables ; j++) { | 1521 | for (j = 0 ; j < charger->num_cables ; j++) { |
1259 | struct charger_cable *cable = &charger->cables[j]; | 1522 | struct charger_cable *cable = &charger->cables[j]; |
@@ -1267,6 +1530,71 @@ static int charger_manager_probe(struct platform_device *pdev) | |||
1267 | cable->charger = charger; | 1530 | cable->charger = charger; |
1268 | cable->cm = cm; | 1531 | cable->cm = cm; |
1269 | } | 1532 | } |
1533 | |||
1534 | /* Create sysfs entry to control charger(regulator) */ | ||
1535 | snprintf(buf, 10, "charger.%d", i); | ||
1536 | str = kzalloc(sizeof(char) * (strlen(buf) + 1), GFP_KERNEL); | ||
1537 | if (!str) { | ||
1538 | for (i--; i >= 0; i--) { | ||
1539 | charger = &desc->charger_regulators[i]; | ||
1540 | kfree(charger->attr_g.name); | ||
1541 | } | ||
1542 | ret = -ENOMEM; | ||
1543 | |||
1544 | goto err_extcon; | ||
1545 | } | ||
1546 | strcpy(str, buf); | ||
1547 | |||
1548 | charger->attrs[0] = &charger->attr_name.attr; | ||
1549 | charger->attrs[1] = &charger->attr_state.attr; | ||
1550 | charger->attrs[2] = &charger->attr_externally_control.attr; | ||
1551 | charger->attrs[3] = NULL; | ||
1552 | charger->attr_g.name = str; | ||
1553 | charger->attr_g.attrs = charger->attrs; | ||
1554 | |||
1555 | sysfs_attr_init(&charger->attr_name.attr); | ||
1556 | charger->attr_name.attr.name = "name"; | ||
1557 | charger->attr_name.attr.mode = 0444; | ||
1558 | charger->attr_name.show = charger_name_show; | ||
1559 | |||
1560 | sysfs_attr_init(&charger->attr_state.attr); | ||
1561 | charger->attr_state.attr.name = "state"; | ||
1562 | charger->attr_state.attr.mode = 0444; | ||
1563 | charger->attr_state.show = charger_state_show; | ||
1564 | |||
1565 | sysfs_attr_init(&charger->attr_externally_control.attr); | ||
1566 | charger->attr_externally_control.attr.name | ||
1567 | = "externally_control"; | ||
1568 | charger->attr_externally_control.attr.mode = 0644; | ||
1569 | charger->attr_externally_control.show | ||
1570 | = charger_externally_control_show; | ||
1571 | charger->attr_externally_control.store | ||
1572 | = charger_externally_control_store; | ||
1573 | |||
1574 | if (!desc->charger_regulators[i].externally_control || | ||
1575 | !chargers_externally_control) { | ||
1576 | chargers_externally_control = 0; | ||
1577 | } | ||
1578 | dev_info(&pdev->dev, "'%s' regulator's externally_control" | ||
1579 | "is %d\n", charger->regulator_name, | ||
1580 | charger->externally_control); | ||
1581 | |||
1582 | ret = sysfs_create_group(&cm->charger_psy.dev->kobj, | ||
1583 | &charger->attr_g); | ||
1584 | if (ret < 0) { | ||
1585 | dev_info(&pdev->dev, "Cannot create sysfs entry" | ||
1586 | "of %s regulator\n", | ||
1587 | charger->regulator_name); | ||
1588 | } | ||
1589 | } | ||
1590 | |||
1591 | if (chargers_externally_control) { | ||
1592 | dev_err(&pdev->dev, "Cannot register regulator because " | ||
1593 | "charger-manager must need at least " | ||
1594 | "one charger for charging battery\n"); | ||
1595 | |||
1596 | ret = -EINVAL; | ||
1597 | goto err_chg_enable; | ||
1270 | } | 1598 | } |
1271 | 1599 | ||
1272 | ret = try_charger_enable(cm, true); | 1600 | ret = try_charger_enable(cm, true); |
@@ -1292,6 +1620,14 @@ static int charger_manager_probe(struct platform_device *pdev) | |||
1292 | return 0; | 1620 | return 0; |
1293 | 1621 | ||
1294 | err_chg_enable: | 1622 | err_chg_enable: |
1623 | for (i = 0; i < desc->num_charger_regulators; i++) { | ||
1624 | struct charger_regulator *charger; | ||
1625 | |||
1626 | charger = &desc->charger_regulators[i]; | ||
1627 | sysfs_remove_group(&cm->charger_psy.dev->kobj, | ||
1628 | &charger->attr_g); | ||
1629 | kfree(charger->attr_g.name); | ||
1630 | } | ||
1295 | err_extcon: | 1631 | err_extcon: |
1296 | for (i = 0 ; i < desc->num_charger_regulators ; i++) { | 1632 | for (i = 0 ; i < desc->num_charger_regulators ; i++) { |
1297 | struct charger_regulator *charger | 1633 | struct charger_regulator *charger |