diff options
author | Lee Jones <lee.jones@linaro.org> | 2013-01-11 08:12:51 -0500 |
---|---|---|
committer | Anton Vorontsov <anton@enomsg.org> | 2013-01-15 20:35:12 -0500 |
commit | b269fff4f9ad2cec9413ea9e10f26c5d8c9f5ddc (patch) | |
tree | 5a36453c476b251e0f6d363ed8e672dc2b6c9036 | |
parent | 3988a4df3499e604a3f2ae979372d27fc5664f77 (diff) |
ab8500_charger: Detect charger removal
Add two new work queues to provide USB and AC charger disconnect
detection.
Signed-off-by: Lee Jones <lee.jones@linaro.org>
Signed-off-by: Anton Vorontsov <anton@enomsg.org>
-rw-r--r-- | drivers/power/ab8500_charger.c | 142 |
1 files changed, 141 insertions, 1 deletions
diff --git a/drivers/power/ab8500_charger.c b/drivers/power/ab8500_charger.c index a941e6a66996..24c4ae58dab5 100644 --- a/drivers/power/ab8500_charger.c +++ b/drivers/power/ab8500_charger.c | |||
@@ -31,6 +31,7 @@ | |||
31 | #include <linux/mfd/abx500/ab8500-gpadc.h> | 31 | #include <linux/mfd/abx500/ab8500-gpadc.h> |
32 | #include <linux/mfd/abx500/ux500_chargalg.h> | 32 | #include <linux/mfd/abx500/ux500_chargalg.h> |
33 | #include <linux/usb/otg.h> | 33 | #include <linux/usb/otg.h> |
34 | #include <linux/mutex.h> | ||
34 | 35 | ||
35 | /* Charger constants */ | 36 | /* Charger constants */ |
36 | #define NO_PW_CONN 0 | 37 | #define NO_PW_CONN 0 |
@@ -68,6 +69,11 @@ | |||
68 | #define MAIN_CH_NOK 0x01 | 69 | #define MAIN_CH_NOK 0x01 |
69 | #define VBUS_DET 0x80 | 70 | #define VBUS_DET 0x80 |
70 | 71 | ||
72 | #define MAIN_CH_STATUS2_MAINCHGDROP 0x80 | ||
73 | #define MAIN_CH_STATUS2_MAINCHARGERDETDBNC 0x40 | ||
74 | #define USB_CH_VBUSDROP 0x40 | ||
75 | #define USB_CH_VBUSDETDBNC 0x01 | ||
76 | |||
71 | /* UsbLineStatus register bit masks */ | 77 | /* UsbLineStatus register bit masks */ |
72 | #define AB8500_USB_LINK_STATUS 0x78 | 78 | #define AB8500_USB_LINK_STATUS 0x78 |
73 | #define AB8500_STD_HOST_SUSP 0x18 | 79 | #define AB8500_STD_HOST_SUSP 0x18 |
@@ -82,6 +88,8 @@ | |||
82 | /* Step up/down delay in us */ | 88 | /* Step up/down delay in us */ |
83 | #define STEP_UDELAY 1000 | 89 | #define STEP_UDELAY 1000 |
84 | 90 | ||
91 | #define CHARGER_STATUS_POLL 10 /* in ms */ | ||
92 | |||
85 | /* UsbLineStatus register - usb types */ | 93 | /* UsbLineStatus register - usb types */ |
86 | enum ab8500_charger_link_status { | 94 | enum ab8500_charger_link_status { |
87 | USB_STAT_NOT_CONFIGURED, | 95 | USB_STAT_NOT_CONFIGURED, |
@@ -203,6 +211,10 @@ struct ab8500_charger_usb_state { | |||
203 | * @check_usbchgnotok_work: Work for checking USB charger not ok status | 211 | * @check_usbchgnotok_work: Work for checking USB charger not ok status |
204 | * @kick_wd_work: Work for kicking the charger watchdog in case | 212 | * @kick_wd_work: Work for kicking the charger watchdog in case |
205 | * of ABB rev 1.* due to the watchog logic bug | 213 | * of ABB rev 1.* due to the watchog logic bug |
214 | * @ac_charger_attached_work: Work for checking if AC charger is still | ||
215 | * connected | ||
216 | * @usb_charger_attached_work: Work for checking if USB charger is still | ||
217 | * connected | ||
206 | * @ac_work: Work for checking AC charger connection | 218 | * @ac_work: Work for checking AC charger connection |
207 | * @detect_usb_type_work: Work for detecting the USB type connected | 219 | * @detect_usb_type_work: Work for detecting the USB type connected |
208 | * @usb_link_status_work: Work for checking the new USB link status | 220 | * @usb_link_status_work: Work for checking the new USB link status |
@@ -211,6 +223,7 @@ struct ab8500_charger_usb_state { | |||
211 | * Work for checking Main thermal status | 223 | * Work for checking Main thermal status |
212 | * @check_usb_thermal_prot_work: | 224 | * @check_usb_thermal_prot_work: |
213 | * Work for checking USB thermal status | 225 | * Work for checking USB thermal status |
226 | * @charger_attached_mutex: For controlling the wakelock | ||
214 | */ | 227 | */ |
215 | struct ab8500_charger { | 228 | struct ab8500_charger { |
216 | struct device *dev; | 229 | struct device *dev; |
@@ -239,6 +252,8 @@ struct ab8500_charger { | |||
239 | struct delayed_work check_hw_failure_work; | 252 | struct delayed_work check_hw_failure_work; |
240 | struct delayed_work check_usbchgnotok_work; | 253 | struct delayed_work check_usbchgnotok_work; |
241 | struct delayed_work kick_wd_work; | 254 | struct delayed_work kick_wd_work; |
255 | struct delayed_work ac_charger_attached_work; | ||
256 | struct delayed_work usb_charger_attached_work; | ||
242 | struct work_struct ac_work; | 257 | struct work_struct ac_work; |
243 | struct work_struct detect_usb_type_work; | 258 | struct work_struct detect_usb_type_work; |
244 | struct work_struct usb_link_status_work; | 259 | struct work_struct usb_link_status_work; |
@@ -247,6 +262,7 @@ struct ab8500_charger { | |||
247 | struct work_struct check_usb_thermal_prot_work; | 262 | struct work_struct check_usb_thermal_prot_work; |
248 | struct usb_phy *usb_phy; | 263 | struct usb_phy *usb_phy; |
249 | struct notifier_block nb; | 264 | struct notifier_block nb; |
265 | struct mutex charger_attached_mutex; | ||
250 | }; | 266 | }; |
251 | 267 | ||
252 | /* AC properties */ | 268 | /* AC properties */ |
@@ -349,6 +365,19 @@ static void ab8500_charger_set_usb_connected(struct ab8500_charger *di, | |||
349 | dev_dbg(di->dev, "USB connected:%i\n", connected); | 365 | dev_dbg(di->dev, "USB connected:%i\n", connected); |
350 | di->usb.charger_connected = connected; | 366 | di->usb.charger_connected = connected; |
351 | sysfs_notify(&di->usb_chg.psy.dev->kobj, NULL, "present"); | 367 | sysfs_notify(&di->usb_chg.psy.dev->kobj, NULL, "present"); |
368 | |||
369 | if (connected) { | ||
370 | mutex_lock(&di->charger_attached_mutex); | ||
371 | mutex_unlock(&di->charger_attached_mutex); | ||
372 | |||
373 | queue_delayed_work(di->charger_wq, | ||
374 | &di->usb_charger_attached_work, | ||
375 | HZ); | ||
376 | } else { | ||
377 | cancel_delayed_work_sync(&di->usb_charger_attached_work); | ||
378 | mutex_lock(&di->charger_attached_mutex); | ||
379 | mutex_unlock(&di->charger_attached_mutex); | ||
380 | } | ||
352 | } | 381 | } |
353 | } | 382 | } |
354 | 383 | ||
@@ -1706,6 +1735,84 @@ static void ab8500_charger_ac_work(struct work_struct *work) | |||
1706 | sysfs_notify(&di->ac_chg.psy.dev->kobj, NULL, "present"); | 1735 | sysfs_notify(&di->ac_chg.psy.dev->kobj, NULL, "present"); |
1707 | } | 1736 | } |
1708 | 1737 | ||
1738 | static void ab8500_charger_usb_attached_work(struct work_struct *work) | ||
1739 | { | ||
1740 | struct ab8500_charger *di = container_of(work, | ||
1741 | struct ab8500_charger, | ||
1742 | usb_charger_attached_work.work); | ||
1743 | int usbch = (USB_CH_VBUSDROP | USB_CH_VBUSDETDBNC); | ||
1744 | int ret, i; | ||
1745 | u8 statval; | ||
1746 | |||
1747 | for (i = 0; i < 10; i++) { | ||
1748 | ret = abx500_get_register_interruptible(di->dev, | ||
1749 | AB8500_CHARGER, | ||
1750 | AB8500_CH_USBCH_STAT1_REG, | ||
1751 | &statval); | ||
1752 | if (ret < 0) { | ||
1753 | dev_err(di->dev, "ab8500 read failed %d\n", __LINE__); | ||
1754 | goto reschedule; | ||
1755 | } | ||
1756 | if ((statval & usbch) != usbch) | ||
1757 | goto reschedule; | ||
1758 | |||
1759 | msleep(CHARGER_STATUS_POLL); | ||
1760 | } | ||
1761 | |||
1762 | ab8500_charger_usb_en(&di->usb_chg, 0, 0, 0); | ||
1763 | |||
1764 | mutex_lock(&di->charger_attached_mutex); | ||
1765 | mutex_unlock(&di->charger_attached_mutex); | ||
1766 | |||
1767 | return; | ||
1768 | |||
1769 | reschedule: | ||
1770 | queue_delayed_work(di->charger_wq, | ||
1771 | &di->usb_charger_attached_work, | ||
1772 | HZ); | ||
1773 | } | ||
1774 | |||
1775 | static void ab8500_charger_ac_attached_work(struct work_struct *work) | ||
1776 | { | ||
1777 | |||
1778 | struct ab8500_charger *di = container_of(work, | ||
1779 | struct ab8500_charger, | ||
1780 | ac_charger_attached_work.work); | ||
1781 | int mainch = (MAIN_CH_STATUS2_MAINCHGDROP | | ||
1782 | MAIN_CH_STATUS2_MAINCHARGERDETDBNC); | ||
1783 | int ret, i; | ||
1784 | u8 statval; | ||
1785 | |||
1786 | for (i = 0; i < 10; i++) { | ||
1787 | ret = abx500_get_register_interruptible(di->dev, | ||
1788 | AB8500_CHARGER, | ||
1789 | AB8500_CH_STATUS2_REG, | ||
1790 | &statval); | ||
1791 | if (ret < 0) { | ||
1792 | dev_err(di->dev, "ab8500 read failed %d\n", __LINE__); | ||
1793 | goto reschedule; | ||
1794 | } | ||
1795 | |||
1796 | if ((statval & mainch) != mainch) | ||
1797 | goto reschedule; | ||
1798 | |||
1799 | msleep(CHARGER_STATUS_POLL); | ||
1800 | } | ||
1801 | |||
1802 | ab8500_charger_ac_en(&di->ac_chg, 0, 0, 0); | ||
1803 | queue_work(di->charger_wq, &di->ac_work); | ||
1804 | |||
1805 | mutex_lock(&di->charger_attached_mutex); | ||
1806 | mutex_unlock(&di->charger_attached_mutex); | ||
1807 | |||
1808 | return; | ||
1809 | |||
1810 | reschedule: | ||
1811 | queue_delayed_work(di->charger_wq, | ||
1812 | &di->ac_charger_attached_work, | ||
1813 | HZ); | ||
1814 | } | ||
1815 | |||
1709 | /** | 1816 | /** |
1710 | * ab8500_charger_detect_usb_type_work() - work to detect USB type | 1817 | * ab8500_charger_detect_usb_type_work() - work to detect USB type |
1711 | * @work: Pointer to the work_struct structure | 1818 | * @work: Pointer to the work_struct structure |
@@ -1986,6 +2093,10 @@ static irqreturn_t ab8500_charger_mainchunplugdet_handler(int irq, void *_di) | |||
1986 | dev_dbg(di->dev, "Main charger unplugged\n"); | 2093 | dev_dbg(di->dev, "Main charger unplugged\n"); |
1987 | queue_work(di->charger_wq, &di->ac_work); | 2094 | queue_work(di->charger_wq, &di->ac_work); |
1988 | 2095 | ||
2096 | cancel_delayed_work_sync(&di->ac_charger_attached_work); | ||
2097 | mutex_lock(&di->charger_attached_mutex); | ||
2098 | mutex_unlock(&di->charger_attached_mutex); | ||
2099 | |||
1989 | return IRQ_HANDLED; | 2100 | return IRQ_HANDLED; |
1990 | } | 2101 | } |
1991 | 2102 | ||
@@ -2003,6 +2114,11 @@ static irqreturn_t ab8500_charger_mainchplugdet_handler(int irq, void *_di) | |||
2003 | dev_dbg(di->dev, "Main charger plugged\n"); | 2114 | dev_dbg(di->dev, "Main charger plugged\n"); |
2004 | queue_work(di->charger_wq, &di->ac_work); | 2115 | queue_work(di->charger_wq, &di->ac_work); |
2005 | 2116 | ||
2117 | mutex_lock(&di->charger_attached_mutex); | ||
2118 | mutex_unlock(&di->charger_attached_mutex); | ||
2119 | queue_delayed_work(di->charger_wq, | ||
2120 | &di->ac_charger_attached_work, | ||
2121 | HZ); | ||
2006 | return IRQ_HANDLED; | 2122 | return IRQ_HANDLED; |
2007 | } | 2123 | } |
2008 | 2124 | ||
@@ -2634,7 +2750,7 @@ static int ab8500_charger_probe(struct platform_device *pdev) | |||
2634 | struct device_node *np = pdev->dev.of_node; | 2750 | struct device_node *np = pdev->dev.of_node; |
2635 | struct abx500_bm_data *plat = pdev->dev.platform_data; | 2751 | struct abx500_bm_data *plat = pdev->dev.platform_data; |
2636 | struct ab8500_charger *di; | 2752 | struct ab8500_charger *di; |
2637 | int irq, i, charger_status, ret = 0; | 2753 | int irq, i, charger_status, ret = 0, ch_stat; |
2638 | 2754 | ||
2639 | di = devm_kzalloc(&pdev->dev, sizeof(*di), GFP_KERNEL); | 2755 | di = devm_kzalloc(&pdev->dev, sizeof(*di), GFP_KERNEL); |
2640 | if (!di) { | 2756 | if (!di) { |
@@ -2713,12 +2829,19 @@ static int ab8500_charger_probe(struct platform_device *pdev) | |||
2713 | return -ENOMEM; | 2829 | return -ENOMEM; |
2714 | } | 2830 | } |
2715 | 2831 | ||
2832 | mutex_init(&di->charger_attached_mutex); | ||
2833 | |||
2716 | /* Init work for HW failure check */ | 2834 | /* Init work for HW failure check */ |
2717 | INIT_DEFERRABLE_WORK(&di->check_hw_failure_work, | 2835 | INIT_DEFERRABLE_WORK(&di->check_hw_failure_work, |
2718 | ab8500_charger_check_hw_failure_work); | 2836 | ab8500_charger_check_hw_failure_work); |
2719 | INIT_DEFERRABLE_WORK(&di->check_usbchgnotok_work, | 2837 | INIT_DEFERRABLE_WORK(&di->check_usbchgnotok_work, |
2720 | ab8500_charger_check_usbchargernotok_work); | 2838 | ab8500_charger_check_usbchargernotok_work); |
2721 | 2839 | ||
2840 | INIT_DELAYED_WORK(&di->ac_charger_attached_work, | ||
2841 | ab8500_charger_ac_attached_work); | ||
2842 | INIT_DELAYED_WORK(&di->usb_charger_attached_work, | ||
2843 | ab8500_charger_usb_attached_work); | ||
2844 | |||
2722 | /* | 2845 | /* |
2723 | * For ABB revision 1.0 and 1.1 there is a bug in the watchdog | 2846 | * For ABB revision 1.0 and 1.1 there is a bug in the watchdog |
2724 | * logic. That means we have to continously kick the charger | 2847 | * logic. That means we have to continously kick the charger |
@@ -2832,6 +2955,23 @@ static int ab8500_charger_probe(struct platform_device *pdev) | |||
2832 | 2955 | ||
2833 | platform_set_drvdata(pdev, di); | 2956 | platform_set_drvdata(pdev, di); |
2834 | 2957 | ||
2958 | mutex_lock(&di->charger_attached_mutex); | ||
2959 | |||
2960 | ch_stat = ab8500_charger_detect_chargers(di); | ||
2961 | |||
2962 | if ((ch_stat & AC_PW_CONN) == AC_PW_CONN) { | ||
2963 | queue_delayed_work(di->charger_wq, | ||
2964 | &di->ac_charger_attached_work, | ||
2965 | HZ); | ||
2966 | } | ||
2967 | if ((ch_stat & USB_PW_CONN) == USB_PW_CONN) { | ||
2968 | queue_delayed_work(di->charger_wq, | ||
2969 | &di->usb_charger_attached_work, | ||
2970 | HZ); | ||
2971 | } | ||
2972 | |||
2973 | mutex_unlock(&di->charger_attached_mutex); | ||
2974 | |||
2835 | return ret; | 2975 | return ret; |
2836 | 2976 | ||
2837 | free_irq: | 2977 | free_irq: |