diff options
author | Jonghwa Lee <jonghwa3.lee@samsung.com> | 2013-12-18 01:42:34 -0500 |
---|---|---|
committer | Anton Vorontsov <anton@enomsg.org> | 2013-12-23 20:09:09 -0500 |
commit | 5c49a6256bed52f639ed70d252b1c91d1ab899d6 (patch) | |
tree | 8c4d8d6e4fcadc81de02dea26f1a643a2db59399 /drivers/power | |
parent | d36240d26025bec95f3499e2401a56db98d9f01c (diff) |
charger-manager: Modify the way of checking battery's temperature
Charger-manager driver used to check battery temperature through the
callback function passed by platform data. Unfortunatley, without that
pre-defined callback function, charger-manager can't get battery's
temperature at all. Also passing callback function through platform data
ruins DT support for charger-manager.
This patch mondifies charger-manager driver to get temperature of battery
without pre-defined callback function. Now, charger-manager can use either
of battery thermometer in fuel-gauge and ouside of battery. It uses
thermal framework interface for outer thermometer if thermal fw is
enabled. Otherwise, it tries to use fuel-gauge's through the power supply
interface.
Signed-off-by: Jonghwa Lee <jonghwa3.lee@samsung.com>
Signed-off-by: Myungjoo Ham <myungjoo.ham@samsung.com>
Signed-off-by: Anton Vorontsov <anton@enomsg.org>
Diffstat (limited to 'drivers/power')
-rw-r--r-- | drivers/power/charger-manager.c | 161 |
1 files changed, 120 insertions, 41 deletions
diff --git a/drivers/power/charger-manager.c b/drivers/power/charger-manager.c index 7287c0efd6bf..6b68d158e3c1 100644 --- a/drivers/power/charger-manager.c +++ b/drivers/power/charger-manager.c | |||
@@ -25,12 +25,22 @@ | |||
25 | #include <linux/power/charger-manager.h> | 25 | #include <linux/power/charger-manager.h> |
26 | #include <linux/regulator/consumer.h> | 26 | #include <linux/regulator/consumer.h> |
27 | #include <linux/sysfs.h> | 27 | #include <linux/sysfs.h> |
28 | #include <linux/thermal.h> | ||
29 | |||
30 | /* | ||
31 | * Default termperature threshold for charging. | ||
32 | * Every temperature units are in tenth of centigrade. | ||
33 | */ | ||
34 | #define CM_DEFAULT_RECHARGE_TEMP_DIFF 50 | ||
35 | #define CM_DEFAULT_CHARGE_TEMP_MAX 500 | ||
28 | 36 | ||
29 | static const char * const default_event_names[] = { | 37 | static const char * const default_event_names[] = { |
30 | [CM_EVENT_UNKNOWN] = "Unknown", | 38 | [CM_EVENT_UNKNOWN] = "Unknown", |
31 | [CM_EVENT_BATT_FULL] = "Battery Full", | 39 | [CM_EVENT_BATT_FULL] = "Battery Full", |
32 | [CM_EVENT_BATT_IN] = "Battery Inserted", | 40 | [CM_EVENT_BATT_IN] = "Battery Inserted", |
33 | [CM_EVENT_BATT_OUT] = "Battery Pulled Out", | 41 | [CM_EVENT_BATT_OUT] = "Battery Pulled Out", |
42 | [CM_EVENT_BATT_OVERHEAT] = "Battery Overheat", | ||
43 | [CM_EVENT_BATT_COLD] = "Battery Cold", | ||
34 | [CM_EVENT_EXT_PWR_IN_OUT] = "External Power Attach/Detach", | 44 | [CM_EVENT_EXT_PWR_IN_OUT] = "External Power Attach/Detach", |
35 | [CM_EVENT_CHG_START_STOP] = "Charging Start/Stop", | 45 | [CM_EVENT_CHG_START_STOP] = "Charging Start/Stop", |
36 | [CM_EVENT_OTHERS] = "Other battery events" | 46 | [CM_EVENT_OTHERS] = "Other battery events" |
@@ -540,6 +550,60 @@ static int check_charging_duration(struct charger_manager *cm) | |||
540 | return ret; | 550 | return ret; |
541 | } | 551 | } |
542 | 552 | ||
553 | static int cm_get_battery_temperature(struct charger_manager *cm, | ||
554 | int *temp) | ||
555 | { | ||
556 | int ret; | ||
557 | |||
558 | if (!cm->desc->measure_battery_temp) | ||
559 | return -ENODEV; | ||
560 | |||
561 | #ifdef CONFIG_THERMAL | ||
562 | ret = thermal_zone_get_temp(cm->tzd_batt, (unsigned long *)temp); | ||
563 | if (!ret) | ||
564 | /* Calibrate temperature unit */ | ||
565 | *temp /= 100; | ||
566 | #else | ||
567 | ret = cm->fuel_gauge->get_property(cm->fuel_gauge, | ||
568 | POWER_SUPPLY_PROP_TEMP, | ||
569 | (union power_supply_propval *)temp); | ||
570 | #endif | ||
571 | return ret; | ||
572 | } | ||
573 | |||
574 | static int cm_check_thermal_status(struct charger_manager *cm) | ||
575 | { | ||
576 | struct charger_desc *desc = cm->desc; | ||
577 | int temp, upper_limit, lower_limit; | ||
578 | int ret = 0; | ||
579 | |||
580 | ret = cm_get_battery_temperature(cm, &temp); | ||
581 | if (ret) { | ||
582 | /* FIXME: | ||
583 | * No information of battery temperature might | ||
584 | * occur hazadous result. We have to handle it | ||
585 | * depending on battery type. | ||
586 | */ | ||
587 | dev_err(cm->dev, "Failed to get battery temperature\n"); | ||
588 | return 0; | ||
589 | } | ||
590 | |||
591 | upper_limit = desc->temp_max; | ||
592 | lower_limit = desc->temp_min; | ||
593 | |||
594 | if (cm->emergency_stop) { | ||
595 | upper_limit -= desc->temp_diff; | ||
596 | lower_limit += desc->temp_diff; | ||
597 | } | ||
598 | |||
599 | if (temp > upper_limit) | ||
600 | ret = CM_EVENT_BATT_OVERHEAT; | ||
601 | else if (temp < lower_limit) | ||
602 | ret = CM_EVENT_BATT_COLD; | ||
603 | |||
604 | return ret; | ||
605 | } | ||
606 | |||
543 | /** | 607 | /** |
544 | * _cm_monitor - Monitor the temperature and return true for exceptions. | 608 | * _cm_monitor - Monitor the temperature and return true for exceptions. |
545 | * @cm: the Charger Manager representing the battery. | 609 | * @cm: the Charger Manager representing the battery. |
@@ -549,28 +613,22 @@ static int check_charging_duration(struct charger_manager *cm) | |||
549 | */ | 613 | */ |
550 | static bool _cm_monitor(struct charger_manager *cm) | 614 | static bool _cm_monitor(struct charger_manager *cm) |
551 | { | 615 | { |
552 | struct charger_desc *desc = cm->desc; | 616 | int temp_alrt; |
553 | int temp = desc->temperature_out_of_range(&cm->last_temp_mC); | ||
554 | 617 | ||
555 | dev_dbg(cm->dev, "monitoring (%2.2d.%3.3dC)\n", | 618 | temp_alrt = cm_check_thermal_status(cm); |
556 | cm->last_temp_mC / 1000, cm->last_temp_mC % 1000); | ||
557 | 619 | ||
558 | /* It has been stopped already */ | 620 | /* It has been stopped already */ |
559 | if (temp && cm->emergency_stop) | 621 | if (temp_alrt && cm->emergency_stop) |
560 | return false; | 622 | return false; |
561 | 623 | ||
562 | /* | 624 | /* |
563 | * Check temperature whether overheat or cold. | 625 | * Check temperature whether overheat or cold. |
564 | * If temperature is out of range normal state, stop charging. | 626 | * If temperature is out of range normal state, stop charging. |
565 | */ | 627 | */ |
566 | if (temp) { | 628 | if (temp_alrt) { |
567 | cm->emergency_stop = temp; | 629 | cm->emergency_stop = temp_alrt; |
568 | if (!try_charger_enable(cm, false)) { | 630 | if (!try_charger_enable(cm, false)) |
569 | if (temp > 0) | 631 | uevent_notify(cm, default_event_names[temp_alrt]); |
570 | uevent_notify(cm, "OVERHEAT"); | ||
571 | else | ||
572 | uevent_notify(cm, "COLD"); | ||
573 | } | ||
574 | 632 | ||
575 | /* | 633 | /* |
576 | * Check whole charging duration and discharing duration | 634 | * Check whole charging duration and discharing duration |
@@ -802,21 +860,8 @@ static int charger_get_property(struct power_supply *psy, | |||
802 | POWER_SUPPLY_PROP_CURRENT_NOW, val); | 860 | POWER_SUPPLY_PROP_CURRENT_NOW, val); |
803 | break; | 861 | break; |
804 | case POWER_SUPPLY_PROP_TEMP: | 862 | case POWER_SUPPLY_PROP_TEMP: |
805 | /* in thenth of centigrade */ | ||
806 | if (cm->last_temp_mC == INT_MIN) | ||
807 | desc->temperature_out_of_range(&cm->last_temp_mC); | ||
808 | val->intval = cm->last_temp_mC / 100; | ||
809 | if (!desc->measure_battery_temp) | ||
810 | ret = -ENODEV; | ||
811 | break; | ||
812 | case POWER_SUPPLY_PROP_TEMP_AMBIENT: | 863 | case POWER_SUPPLY_PROP_TEMP_AMBIENT: |
813 | /* in thenth of centigrade */ | 864 | return cm_get_battery_temperature(cm, &val->intval); |
814 | if (cm->last_temp_mC == INT_MIN) | ||
815 | desc->temperature_out_of_range(&cm->last_temp_mC); | ||
816 | val->intval = cm->last_temp_mC / 100; | ||
817 | if (desc->measure_battery_temp) | ||
818 | ret = -ENODEV; | ||
819 | break; | ||
820 | case POWER_SUPPLY_PROP_CAPACITY: | 865 | case POWER_SUPPLY_PROP_CAPACITY: |
821 | if (!cm->fuel_gauge) { | 866 | if (!cm->fuel_gauge) { |
822 | ret = -ENODEV; | 867 | ret = -ENODEV; |
@@ -1439,6 +1484,50 @@ err: | |||
1439 | return ret; | 1484 | return ret; |
1440 | } | 1485 | } |
1441 | 1486 | ||
1487 | static int cm_init_thermal_data(struct charger_manager *cm) | ||
1488 | { | ||
1489 | struct charger_desc *desc = cm->desc; | ||
1490 | union power_supply_propval val; | ||
1491 | int ret; | ||
1492 | |||
1493 | /* Verify whether fuel gauge provides battery temperature */ | ||
1494 | ret = cm->fuel_gauge->get_property(cm->fuel_gauge, | ||
1495 | POWER_SUPPLY_PROP_TEMP, &val); | ||
1496 | |||
1497 | if (!ret) { | ||
1498 | cm->charger_psy.properties[cm->charger_psy.num_properties] = | ||
1499 | POWER_SUPPLY_PROP_TEMP; | ||
1500 | cm->charger_psy.num_properties++; | ||
1501 | cm->desc->measure_battery_temp = true; | ||
1502 | } | ||
1503 | #ifdef CONFIG_THERMAL | ||
1504 | cm->tzd_batt = cm->fuel_gauge->tzd; | ||
1505 | |||
1506 | if (ret && desc->thermal_zone) { | ||
1507 | cm->tzd_batt = | ||
1508 | thermal_zone_get_zone_by_name(desc->thermal_zone); | ||
1509 | if (IS_ERR(cm->tzd_batt)) | ||
1510 | return PTR_ERR(cm->tzd_batt); | ||
1511 | |||
1512 | /* Use external thermometer */ | ||
1513 | cm->charger_psy.properties[cm->charger_psy.num_properties] = | ||
1514 | POWER_SUPPLY_PROP_TEMP_AMBIENT; | ||
1515 | cm->charger_psy.num_properties++; | ||
1516 | cm->desc->measure_battery_temp = true; | ||
1517 | ret = 0; | ||
1518 | } | ||
1519 | #endif | ||
1520 | if (cm->desc->measure_battery_temp) { | ||
1521 | /* NOTICE : Default allowable minimum charge temperature is 0 */ | ||
1522 | if (!desc->temp_max) | ||
1523 | desc->temp_max = CM_DEFAULT_CHARGE_TEMP_MAX; | ||
1524 | if (!desc->temp_diff) | ||
1525 | desc->temp_diff = CM_DEFAULT_RECHARGE_TEMP_DIFF; | ||
1526 | } | ||
1527 | |||
1528 | return ret; | ||
1529 | } | ||
1530 | |||
1442 | static int charger_manager_probe(struct platform_device *pdev) | 1531 | static int charger_manager_probe(struct platform_device *pdev) |
1443 | { | 1532 | { |
1444 | struct charger_desc *desc = dev_get_platdata(&pdev->dev); | 1533 | struct charger_desc *desc = dev_get_platdata(&pdev->dev); |
@@ -1470,7 +1559,6 @@ static int charger_manager_probe(struct platform_device *pdev) | |||
1470 | /* Basic Values. Unspecified are Null or 0 */ | 1559 | /* Basic Values. Unspecified are Null or 0 */ |
1471 | cm->dev = &pdev->dev; | 1560 | cm->dev = &pdev->dev; |
1472 | cm->desc = desc; | 1561 | cm->desc = desc; |
1473 | cm->last_temp_mC = INT_MIN; /* denotes "unmeasured, yet" */ | ||
1474 | 1562 | ||
1475 | /* | 1563 | /* |
1476 | * The following two do not need to be errors. | 1564 | * The following two do not need to be errors. |
@@ -1533,11 +1621,6 @@ static int charger_manager_probe(struct platform_device *pdev) | |||
1533 | return -EINVAL; | 1621 | return -EINVAL; |
1534 | } | 1622 | } |
1535 | 1623 | ||
1536 | if (!desc->temperature_out_of_range) { | ||
1537 | dev_err(&pdev->dev, "there is no temperature_out_of_range\n"); | ||
1538 | return -EINVAL; | ||
1539 | } | ||
1540 | |||
1541 | if (!desc->charging_max_duration_ms || | 1624 | if (!desc->charging_max_duration_ms || |
1542 | !desc->discharging_max_duration_ms) { | 1625 | !desc->discharging_max_duration_ms) { |
1543 | dev_info(&pdev->dev, "Cannot limit charging duration checking mechanism to prevent overcharge/overheat and control discharging duration\n"); | 1626 | dev_info(&pdev->dev, "Cannot limit charging duration checking mechanism to prevent overcharge/overheat and control discharging duration\n"); |
@@ -1583,14 +1666,10 @@ static int charger_manager_probe(struct platform_device *pdev) | |||
1583 | cm->charger_psy.num_properties++; | 1666 | cm->charger_psy.num_properties++; |
1584 | } | 1667 | } |
1585 | 1668 | ||
1586 | if (desc->measure_battery_temp) { | 1669 | ret = cm_init_thermal_data(cm); |
1587 | cm->charger_psy.properties[cm->charger_psy.num_properties] = | 1670 | if (ret) { |
1588 | POWER_SUPPLY_PROP_TEMP; | 1671 | dev_err(&pdev->dev, "Failed to initialize thermal data\n"); |
1589 | cm->charger_psy.num_properties++; | 1672 | cm->desc->measure_battery_temp = false; |
1590 | } else { | ||
1591 | cm->charger_psy.properties[cm->charger_psy.num_properties] = | ||
1592 | POWER_SUPPLY_PROP_TEMP_AMBIENT; | ||
1593 | cm->charger_psy.num_properties++; | ||
1594 | } | 1673 | } |
1595 | 1674 | ||
1596 | INIT_DELAYED_WORK(&cm->fullbatt_vchk_work, fullbatt_vchk); | 1675 | INIT_DELAYED_WORK(&cm->fullbatt_vchk_work, fullbatt_vchk); |