diff options
| author | Ramakrishna Pallala <ramakrishna.pallala@intel.com> | 2012-09-18 12:28:07 -0400 |
|---|---|---|
| committer | Anton Vorontsov <anton.vorontsov@linaro.org> | 2012-09-20 17:44:45 -0400 |
| commit | 1502cfe19bac2f8490e4167f2b7cb50b9759b273 (patch) | |
| tree | 808e34627e5b4a68d703cceb2fed818f3195b141 /drivers/power | |
| parent | ec60ea5cd6c9f4b249de1580b8ebfa430055008c (diff) | |
smb347-charger: Fix battery status reporting logic for charger faults
This patch checks for charger status register for determining the
battery charging status and reports Discharing/Charging/Not Charging/Full
accordingly.
This patch also adds the interrupt support for Safety Timer Expiration.
This interrupt is helpful in debugging the cause for charger fault.
Signed-off-by: Ramakrishna Pallala <ramakrishna.pallala@intel.com>
Acked-by: Mika Westerberg <mika.westerberg@linux.intel.com>
Signed-off-by: Anton Vorontsov <anton.vorontsov@linaro.org>
Diffstat (limited to 'drivers/power')
| -rw-r--r-- | drivers/power/smb347-charger.c | 97 |
1 files changed, 82 insertions, 15 deletions
diff --git a/drivers/power/smb347-charger.c b/drivers/power/smb347-charger.c index 332dd0110bd..a9707c11fbe 100644 --- a/drivers/power/smb347-charger.c +++ b/drivers/power/smb347-charger.c | |||
| @@ -80,6 +80,7 @@ | |||
| 80 | #define CFG_FAULT_IRQ_DCIN_UV BIT(2) | 80 | #define CFG_FAULT_IRQ_DCIN_UV BIT(2) |
| 81 | #define CFG_STATUS_IRQ 0x0d | 81 | #define CFG_STATUS_IRQ 0x0d |
| 82 | #define CFG_STATUS_IRQ_TERMINATION_OR_TAPER BIT(4) | 82 | #define CFG_STATUS_IRQ_TERMINATION_OR_TAPER BIT(4) |
| 83 | #define CFG_STATUS_IRQ_CHARGE_TIMEOUT BIT(7) | ||
| 83 | #define CFG_ADDRESS 0x0e | 84 | #define CFG_ADDRESS 0x0e |
| 84 | 85 | ||
| 85 | /* Command registers */ | 86 | /* Command registers */ |
| @@ -96,6 +97,9 @@ | |||
| 96 | #define IRQSTAT_C_TERMINATION_STAT BIT(0) | 97 | #define IRQSTAT_C_TERMINATION_STAT BIT(0) |
| 97 | #define IRQSTAT_C_TERMINATION_IRQ BIT(1) | 98 | #define IRQSTAT_C_TERMINATION_IRQ BIT(1) |
| 98 | #define IRQSTAT_C_TAPER_IRQ BIT(3) | 99 | #define IRQSTAT_C_TAPER_IRQ BIT(3) |
| 100 | #define IRQSTAT_D 0x38 | ||
| 101 | #define IRQSTAT_D_CHARGE_TIMEOUT_STAT BIT(2) | ||
| 102 | #define IRQSTAT_D_CHARGE_TIMEOUT_IRQ BIT(3) | ||
| 99 | #define IRQSTAT_E 0x39 | 103 | #define IRQSTAT_E 0x39 |
| 100 | #define IRQSTAT_E_USBIN_UV_STAT BIT(0) | 104 | #define IRQSTAT_E_USBIN_UV_STAT BIT(0) |
| 101 | #define IRQSTAT_E_USBIN_UV_IRQ BIT(1) | 105 | #define IRQSTAT_E_USBIN_UV_IRQ BIT(1) |
| @@ -109,8 +113,10 @@ | |||
| 109 | #define STAT_B 0x3c | 113 | #define STAT_B 0x3c |
| 110 | #define STAT_C 0x3d | 114 | #define STAT_C 0x3d |
| 111 | #define STAT_C_CHG_ENABLED BIT(0) | 115 | #define STAT_C_CHG_ENABLED BIT(0) |
| 116 | #define STAT_C_HOLDOFF_STAT BIT(3) | ||
| 112 | #define STAT_C_CHG_MASK 0x06 | 117 | #define STAT_C_CHG_MASK 0x06 |
| 113 | #define STAT_C_CHG_SHIFT 1 | 118 | #define STAT_C_CHG_SHIFT 1 |
| 119 | #define STAT_C_CHG_TERM BIT(5) | ||
| 114 | #define STAT_C_CHARGER_ERROR BIT(6) | 120 | #define STAT_C_CHARGER_ERROR BIT(6) |
| 115 | #define STAT_E 0x3f | 121 | #define STAT_E 0x3f |
| 116 | 122 | ||
| @@ -701,7 +707,7 @@ fail: | |||
| 701 | static irqreturn_t smb347_interrupt(int irq, void *data) | 707 | static irqreturn_t smb347_interrupt(int irq, void *data) |
| 702 | { | 708 | { |
| 703 | struct smb347_charger *smb = data; | 709 | struct smb347_charger *smb = data; |
| 704 | unsigned int stat_c, irqstat_e, irqstat_c; | 710 | unsigned int stat_c, irqstat_c, irqstat_d, irqstat_e; |
| 705 | bool handled = false; | 711 | bool handled = false; |
| 706 | int ret; | 712 | int ret; |
| 707 | 713 | ||
| @@ -717,6 +723,12 @@ static irqreturn_t smb347_interrupt(int irq, void *data) | |||
| 717 | return IRQ_NONE; | 723 | return IRQ_NONE; |
| 718 | } | 724 | } |
| 719 | 725 | ||
| 726 | ret = regmap_read(smb->regmap, IRQSTAT_D, &irqstat_d); | ||
| 727 | if (ret < 0) { | ||
| 728 | dev_warn(smb->dev, "reading IRQSTAT_D failed\n"); | ||
| 729 | return IRQ_NONE; | ||
| 730 | } | ||
| 731 | |||
| 720 | ret = regmap_read(smb->regmap, IRQSTAT_E, &irqstat_e); | 732 | ret = regmap_read(smb->regmap, IRQSTAT_E, &irqstat_e); |
| 721 | if (ret < 0) { | 733 | if (ret < 0) { |
| 722 | dev_warn(smb->dev, "reading IRQSTAT_E failed\n"); | 734 | dev_warn(smb->dev, "reading IRQSTAT_E failed\n"); |
| @@ -724,13 +736,11 @@ static irqreturn_t smb347_interrupt(int irq, void *data) | |||
| 724 | } | 736 | } |
| 725 | 737 | ||
| 726 | /* | 738 | /* |
| 727 | * If we get charger error we report the error back to user and | 739 | * If we get charger error we report the error back to user. |
| 728 | * disable charging. | 740 | * If the error is recovered charging will resume again. |
| 729 | */ | 741 | */ |
| 730 | if (stat_c & STAT_C_CHARGER_ERROR) { | 742 | if (stat_c & STAT_C_CHARGER_ERROR) { |
| 731 | dev_err(smb->dev, "error in charger, disabling charging\n"); | 743 | dev_err(smb->dev, "charging stopped due to charger error\n"); |
| 732 | |||
| 733 | smb347_charging_disable(smb); | ||
| 734 | power_supply_changed(&smb->battery); | 744 | power_supply_changed(&smb->battery); |
| 735 | handled = true; | 745 | handled = true; |
| 736 | } | 746 | } |
| @@ -743,6 +753,20 @@ static irqreturn_t smb347_interrupt(int irq, void *data) | |||
| 743 | if (irqstat_c & (IRQSTAT_C_TERMINATION_IRQ | IRQSTAT_C_TAPER_IRQ)) { | 753 | if (irqstat_c & (IRQSTAT_C_TERMINATION_IRQ | IRQSTAT_C_TAPER_IRQ)) { |
| 744 | if (irqstat_c & IRQSTAT_C_TERMINATION_STAT) | 754 | if (irqstat_c & IRQSTAT_C_TERMINATION_STAT) |
| 745 | power_supply_changed(&smb->battery); | 755 | power_supply_changed(&smb->battery); |
| 756 | dev_dbg(smb->dev, "going to HW maintenance mode\n"); | ||
| 757 | handled = true; | ||
| 758 | } | ||
| 759 | |||
| 760 | /* | ||
| 761 | * If we got a charger timeout INT that means the charge | ||
| 762 | * full is not detected with in charge timeout value. | ||
| 763 | */ | ||
| 764 | if (irqstat_d & IRQSTAT_D_CHARGE_TIMEOUT_IRQ) { | ||
| 765 | dev_dbg(smb->dev, "total Charge Timeout INT received\n"); | ||
| 766 | |||
| 767 | if (irqstat_d & IRQSTAT_D_CHARGE_TIMEOUT_STAT) | ||
| 768 | dev_warn(smb->dev, "charging stopped due to timeout\n"); | ||
| 769 | power_supply_changed(&smb->battery); | ||
| 746 | handled = true; | 770 | handled = true; |
| 747 | } | 771 | } |
| 748 | 772 | ||
| @@ -776,6 +800,7 @@ static int smb347_irq_set(struct smb347_charger *smb, bool enable) | |||
| 776 | * Enable/disable interrupts for: | 800 | * Enable/disable interrupts for: |
| 777 | * - under voltage | 801 | * - under voltage |
| 778 | * - termination current reached | 802 | * - termination current reached |
| 803 | * - charger timeout | ||
| 779 | * - charger error | 804 | * - charger error |
| 780 | */ | 805 | */ |
| 781 | ret = regmap_update_bits(smb->regmap, CFG_FAULT_IRQ, 0xff, | 806 | ret = regmap_update_bits(smb->regmap, CFG_FAULT_IRQ, 0xff, |
| @@ -784,7 +809,8 @@ static int smb347_irq_set(struct smb347_charger *smb, bool enable) | |||
| 784 | goto fail; | 809 | goto fail; |
| 785 | 810 | ||
| 786 | ret = regmap_update_bits(smb->regmap, CFG_STATUS_IRQ, 0xff, | 811 | ret = regmap_update_bits(smb->regmap, CFG_STATUS_IRQ, 0xff, |
| 787 | enable ? CFG_STATUS_IRQ_TERMINATION_OR_TAPER : 0); | 812 | enable ? (CFG_STATUS_IRQ_TERMINATION_OR_TAPER | |
| 813 | CFG_STATUS_IRQ_CHARGE_TIMEOUT) : 0); | ||
| 788 | if (ret < 0) | 814 | if (ret < 0) |
| 789 | goto fail; | 815 | goto fail; |
| 790 | 816 | ||
| @@ -988,6 +1014,51 @@ static enum power_supply_property smb347_usb_properties[] = { | |||
| 988 | POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE, | 1014 | POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE, |
| 989 | }; | 1015 | }; |
| 990 | 1016 | ||
| 1017 | static int smb347_get_charging_status(struct smb347_charger *smb) | ||
| 1018 | { | ||
| 1019 | int ret, status; | ||
| 1020 | unsigned int val; | ||
| 1021 | |||
| 1022 | if (!smb347_is_ps_online(smb)) | ||
| 1023 | return POWER_SUPPLY_STATUS_DISCHARGING; | ||
| 1024 | |||
| 1025 | ret = regmap_read(smb->regmap, STAT_C, &val); | ||
| 1026 | if (ret < 0) | ||
| 1027 | return ret; | ||
| 1028 | |||
| 1029 | if ((val & STAT_C_CHARGER_ERROR) || | ||
| 1030 | (val & STAT_C_HOLDOFF_STAT)) { | ||
| 1031 | /* | ||
| 1032 | * set to NOT CHARGING upon charger error | ||
| 1033 | * or charging has stopped. | ||
| 1034 | */ | ||
| 1035 | status = POWER_SUPPLY_STATUS_NOT_CHARGING; | ||
| 1036 | } else { | ||
| 1037 | if ((val & STAT_C_CHG_MASK) >> STAT_C_CHG_SHIFT) { | ||
| 1038 | /* | ||
| 1039 | * set to charging if battery is in pre-charge, | ||
| 1040 | * fast charge or taper charging mode. | ||
| 1041 | */ | ||
| 1042 | status = POWER_SUPPLY_STATUS_CHARGING; | ||
| 1043 | } else if (val & STAT_C_CHG_TERM) { | ||
| 1044 | /* | ||
| 1045 | * set the status to FULL if battery is not in pre | ||
| 1046 | * charge, fast charge or taper charging mode AND | ||
| 1047 | * charging is terminated at least once. | ||
| 1048 | */ | ||
| 1049 | status = POWER_SUPPLY_STATUS_FULL; | ||
| 1050 | } else { | ||
| 1051 | /* | ||
| 1052 | * in this case no charger error or termination | ||
| 1053 | * occured but charging is not in progress!!! | ||
| 1054 | */ | ||
| 1055 | status = POWER_SUPPLY_STATUS_NOT_CHARGING; | ||
| 1056 | } | ||
| 1057 | } | ||
| 1058 | |||
| 1059 | return status; | ||
| 1060 | } | ||
| 1061 | |||
| 991 | static int smb347_battery_get_property(struct power_supply *psy, | 1062 | static int smb347_battery_get_property(struct power_supply *psy, |
| 992 | enum power_supply_property prop, | 1063 | enum power_supply_property prop, |
| 993 | union power_supply_propval *val) | 1064 | union power_supply_propval *val) |
| @@ -1003,14 +1074,10 @@ static int smb347_battery_get_property(struct power_supply *psy, | |||
| 1003 | 1074 | ||
| 1004 | switch (prop) { | 1075 | switch (prop) { |
| 1005 | case POWER_SUPPLY_PROP_STATUS: | 1076 | case POWER_SUPPLY_PROP_STATUS: |
| 1006 | if (!smb347_is_ps_online(smb)) { | 1077 | ret = smb347_get_charging_status(smb); |
| 1007 | val->intval = POWER_SUPPLY_STATUS_DISCHARGING; | 1078 | if (ret < 0) |
| 1008 | break; | 1079 | return ret; |
| 1009 | } | 1080 | val->intval = ret; |
| 1010 | if (smb347_charging_status(smb)) | ||
| 1011 | val->intval = POWER_SUPPLY_STATUS_CHARGING; | ||
| 1012 | else | ||
| 1013 | val->intval = POWER_SUPPLY_STATUS_FULL; | ||
| 1014 | break; | 1081 | break; |
| 1015 | 1082 | ||
| 1016 | case POWER_SUPPLY_PROP_CHARGE_TYPE: | 1083 | case POWER_SUPPLY_PROP_CHARGE_TYPE: |
