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 332dd0110bda..a9707c11fbed 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: |