aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/power
diff options
context:
space:
mode:
authorRamakrishna Pallala <ramakrishna.pallala@intel.com>2012-09-18 12:28:07 -0400
committerAnton Vorontsov <anton.vorontsov@linaro.org>2012-09-20 17:44:45 -0400
commit1502cfe19bac2f8490e4167f2b7cb50b9759b273 (patch)
tree808e34627e5b4a68d703cceb2fed818f3195b141 /drivers/power
parentec60ea5cd6c9f4b249de1580b8ebfa430055008c (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.c97
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:
701static irqreturn_t smb347_interrupt(int irq, void *data) 707static 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
1017static 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
991static int smb347_battery_get_property(struct power_supply *psy, 1062static 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: