aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/power/ab8500_charger.c
diff options
context:
space:
mode:
authorLee Jones <lee.jones@linaro.org>2013-02-14 04:24:10 -0500
committerLee Jones <lee.jones@linaro.org>2013-03-06 23:35:38 -0500
commit4dcdf57773fd45b483fc7613b9e51b89a57d655c (patch)
treeb5ca9c4474c6e58a09ec3429e813a451f84962cb /drivers/power/ab8500_charger.c
parent72a90ddbc3d89a63b769ae1b8538c612cf01e675 (diff)
ab8500-bm: Quick re-attach charging behaviour
Due to a bug in some AB8500 ASICs charger removal cannot always be detected if the removal and reinsertion is done to close in time. This patch detects above described case and handles the situation so that charging will be kept turned on. Signed-off-by: Lee Jones <lee.jones@linaro.org>
Diffstat (limited to 'drivers/power/ab8500_charger.c')
-rw-r--r--drivers/power/ab8500_charger.c105
1 files changed, 103 insertions, 2 deletions
diff --git a/drivers/power/ab8500_charger.c b/drivers/power/ab8500_charger.c
index dcd3c6feca97..3eb23cf9ff47 100644
--- a/drivers/power/ab8500_charger.c
+++ b/drivers/power/ab8500_charger.c
@@ -52,6 +52,7 @@
52#define VBUS_DET_DBNC100 0x02 52#define VBUS_DET_DBNC100 0x02
53#define VBUS_DET_DBNC1 0x01 53#define VBUS_DET_DBNC1 0x01
54#define OTP_ENABLE_WD 0x01 54#define OTP_ENABLE_WD 0x01
55#define DROP_COUNT_RESET 0x01
55 56
56#define MAIN_CH_INPUT_CURR_SHIFT 4 57#define MAIN_CH_INPUT_CURR_SHIFT 4
57#define VBUS_IN_CURR_LIM_SHIFT 4 58#define VBUS_IN_CURR_LIM_SHIFT 4
@@ -1678,6 +1679,105 @@ static int ab8500_charger_usb_en(struct ux500_charger *charger,
1678} 1679}
1679 1680
1680/** 1681/**
1682 * ab8500_charger_usb_check_enable() - enable usb charging
1683 * @charger: pointer to the ux500_charger structure
1684 * @vset: charging voltage
1685 * @iset: charger output current
1686 *
1687 * Check if the VBUS charger has been disconnected and reconnected without
1688 * AB8500 rising an interrupt. Returns 0 on success.
1689 */
1690static int ab8500_charger_usb_check_enable(struct ux500_charger *charger,
1691 int vset, int iset)
1692{
1693 u8 usbch_ctrl1 = 0;
1694 int ret = 0;
1695
1696 struct ab8500_charger *di = to_ab8500_charger_usb_device_info(charger);
1697
1698 if (!di->usb.charger_connected)
1699 return ret;
1700
1701 ret = abx500_get_register_interruptible(di->dev, AB8500_CHARGER,
1702 AB8500_USBCH_CTRL1_REG, &usbch_ctrl1);
1703 if (ret < 0) {
1704 dev_err(di->dev, "ab8500 read failed %d\n", __LINE__);
1705 return ret;
1706 }
1707 dev_dbg(di->dev, "USB charger ctrl: 0x%02x\n", usbch_ctrl1);
1708
1709 if (!(usbch_ctrl1 & USB_CH_ENA)) {
1710 dev_info(di->dev, "Charging has been disabled abnormally and will be re-enabled\n");
1711
1712 ret = abx500_mask_and_set_register_interruptible(di->dev,
1713 AB8500_CHARGER, AB8500_CHARGER_CTRL,
1714 DROP_COUNT_RESET, DROP_COUNT_RESET);
1715 if (ret < 0) {
1716 dev_err(di->dev, "ab8500 write failed %d\n", __LINE__);
1717 return ret;
1718 }
1719
1720 ret = ab8500_charger_usb_en(&di->usb_chg, true, vset, iset);
1721 if (ret < 0) {
1722 dev_err(di->dev, "Failed to enable VBUS charger %d\n",
1723 __LINE__);
1724 return ret;
1725 }
1726 }
1727 return ret;
1728}
1729
1730/**
1731 * ab8500_charger_ac_check_enable() - enable usb charging
1732 * @charger: pointer to the ux500_charger structure
1733 * @vset: charging voltage
1734 * @iset: charger output current
1735 *
1736 * Check if the AC charger has been disconnected and reconnected without
1737 * AB8500 rising an interrupt. Returns 0 on success.
1738 */
1739static int ab8500_charger_ac_check_enable(struct ux500_charger *charger,
1740 int vset, int iset)
1741{
1742 u8 mainch_ctrl1 = 0;
1743 int ret = 0;
1744
1745 struct ab8500_charger *di = to_ab8500_charger_ac_device_info(charger);
1746
1747 if (!di->ac.charger_connected)
1748 return ret;
1749
1750 ret = abx500_get_register_interruptible(di->dev, AB8500_CHARGER,
1751 AB8500_MCH_CTRL1, &mainch_ctrl1);
1752 if (ret < 0) {
1753 dev_err(di->dev, "ab8500 read failed %d\n", __LINE__);
1754 return ret;
1755 }
1756 dev_dbg(di->dev, "AC charger ctrl: 0x%02x\n", mainch_ctrl1);
1757
1758 if (!(mainch_ctrl1 & MAIN_CH_ENA)) {
1759 dev_info(di->dev, "Charging has been disabled abnormally and will be re-enabled\n");
1760
1761 ret = abx500_mask_and_set_register_interruptible(di->dev,
1762 AB8500_CHARGER, AB8500_CHARGER_CTRL,
1763 DROP_COUNT_RESET, DROP_COUNT_RESET);
1764
1765 if (ret < 0) {
1766 dev_err(di->dev, "ab8500 write failed %d\n", __LINE__);
1767 return ret;
1768 }
1769
1770 ret = ab8500_charger_ac_en(&di->usb_chg, true, vset, iset);
1771 if (ret < 0) {
1772 dev_err(di->dev, "failed to enable AC charger %d\n",
1773 __LINE__);
1774 return ret;
1775 }
1776 }
1777 return ret;
1778}
1779
1780/**
1681 * ab8500_charger_watchdog_kick() - kick charger watchdog 1781 * ab8500_charger_watchdog_kick() - kick charger watchdog
1682 * @di: pointer to the ab8500_charger structure 1782 * @di: pointer to the ab8500_charger structure
1683 * 1783 *
@@ -1734,8 +1834,7 @@ static int ab8500_charger_update_charger_current(struct ux500_charger *charger,
1734 1834
1735 /* Reset the main and usb drop input current measurement counter */ 1835 /* Reset the main and usb drop input current measurement counter */
1736 ret = abx500_set_register_interruptible(di->dev, AB8500_CHARGER, 1836 ret = abx500_set_register_interruptible(di->dev, AB8500_CHARGER,
1737 AB8500_CHARGER_CTRL, 1837 AB8500_CHARGER_CTRL, DROP_COUNT_RESET);
1738 0x1);
1739 if (ret) { 1838 if (ret) {
1740 dev_err(di->dev, "%s write failed\n", __func__); 1839 dev_err(di->dev, "%s write failed\n", __func__);
1741 return ret; 1840 return ret;
@@ -3221,6 +3320,7 @@ static int ab8500_charger_probe(struct platform_device *pdev)
3221 di->ac_chg.psy.num_supplicants = ARRAY_SIZE(supply_interface), 3320 di->ac_chg.psy.num_supplicants = ARRAY_SIZE(supply_interface),
3222 /* ux500_charger sub-class */ 3321 /* ux500_charger sub-class */
3223 di->ac_chg.ops.enable = &ab8500_charger_ac_en; 3322 di->ac_chg.ops.enable = &ab8500_charger_ac_en;
3323 di->ac_chg.ops.check_enable = &ab8500_charger_ac_check_enable;
3224 di->ac_chg.ops.kick_wd = &ab8500_charger_watchdog_kick; 3324 di->ac_chg.ops.kick_wd = &ab8500_charger_watchdog_kick;
3225 di->ac_chg.ops.update_curr = &ab8500_charger_update_charger_current; 3325 di->ac_chg.ops.update_curr = &ab8500_charger_update_charger_current;
3226 di->ac_chg.max_out_volt = ab8500_charger_voltage_map[ 3326 di->ac_chg.max_out_volt = ab8500_charger_voltage_map[
@@ -3242,6 +3342,7 @@ static int ab8500_charger_probe(struct platform_device *pdev)
3242 di->usb_chg.psy.num_supplicants = ARRAY_SIZE(supply_interface), 3342 di->usb_chg.psy.num_supplicants = ARRAY_SIZE(supply_interface),
3243 /* ux500_charger sub-class */ 3343 /* ux500_charger sub-class */
3244 di->usb_chg.ops.enable = &ab8500_charger_usb_en; 3344 di->usb_chg.ops.enable = &ab8500_charger_usb_en;
3345 di->usb_chg.ops.check_enable = &ab8500_charger_usb_check_enable;
3245 di->usb_chg.ops.kick_wd = &ab8500_charger_watchdog_kick; 3346 di->usb_chg.ops.kick_wd = &ab8500_charger_watchdog_kick;
3246 di->usb_chg.ops.update_curr = &ab8500_charger_update_charger_current; 3347 di->usb_chg.ops.update_curr = &ab8500_charger_update_charger_current;
3247 di->usb_chg.max_out_volt = ab8500_charger_voltage_map[ 3348 di->usb_chg.max_out_volt = ab8500_charger_voltage_map[