diff options
Diffstat (limited to 'drivers/power/pcf50633-charger.c')
-rw-r--r-- | drivers/power/pcf50633-charger.c | 88 |
1 files changed, 71 insertions, 17 deletions
diff --git a/drivers/power/pcf50633-charger.c b/drivers/power/pcf50633-charger.c index 41aec2acbb91..e8b278f71781 100644 --- a/drivers/power/pcf50633-charger.c +++ b/drivers/power/pcf50633-charger.c | |||
@@ -36,6 +36,8 @@ struct pcf50633_mbc { | |||
36 | 36 | ||
37 | struct power_supply usb; | 37 | struct power_supply usb; |
38 | struct power_supply adapter; | 38 | struct power_supply adapter; |
39 | |||
40 | struct delayed_work charging_restart_work; | ||
39 | }; | 41 | }; |
40 | 42 | ||
41 | int pcf50633_mbc_usb_curlim_set(struct pcf50633 *pcf, int ma) | 43 | int pcf50633_mbc_usb_curlim_set(struct pcf50633 *pcf, int ma) |
@@ -43,6 +45,8 @@ int pcf50633_mbc_usb_curlim_set(struct pcf50633 *pcf, int ma) | |||
43 | struct pcf50633_mbc *mbc = platform_get_drvdata(pcf->mbc_pdev); | 45 | struct pcf50633_mbc *mbc = platform_get_drvdata(pcf->mbc_pdev); |
44 | int ret = 0; | 46 | int ret = 0; |
45 | u8 bits; | 47 | u8 bits; |
48 | int charging_start = 1; | ||
49 | u8 mbcs2, chgmod; | ||
46 | 50 | ||
47 | if (ma >= 1000) | 51 | if (ma >= 1000) |
48 | bits = PCF50633_MBCC7_USB_1000mA; | 52 | bits = PCF50633_MBCC7_USB_1000mA; |
@@ -50,8 +54,10 @@ int pcf50633_mbc_usb_curlim_set(struct pcf50633 *pcf, int ma) | |||
50 | bits = PCF50633_MBCC7_USB_500mA; | 54 | bits = PCF50633_MBCC7_USB_500mA; |
51 | else if (ma >= 100) | 55 | else if (ma >= 100) |
52 | bits = PCF50633_MBCC7_USB_100mA; | 56 | bits = PCF50633_MBCC7_USB_100mA; |
53 | else | 57 | else { |
54 | bits = PCF50633_MBCC7_USB_SUSPEND; | 58 | bits = PCF50633_MBCC7_USB_SUSPEND; |
59 | charging_start = 0; | ||
60 | } | ||
55 | 61 | ||
56 | ret = pcf50633_reg_set_bit_mask(pcf, PCF50633_REG_MBCC7, | 62 | ret = pcf50633_reg_set_bit_mask(pcf, PCF50633_REG_MBCC7, |
57 | PCF50633_MBCC7_USB_MASK, bits); | 63 | PCF50633_MBCC7_USB_MASK, bits); |
@@ -60,6 +66,22 @@ int pcf50633_mbc_usb_curlim_set(struct pcf50633 *pcf, int ma) | |||
60 | else | 66 | else |
61 | dev_info(pcf->dev, "usb curlim to %d mA\n", ma); | 67 | dev_info(pcf->dev, "usb curlim to %d mA\n", ma); |
62 | 68 | ||
69 | /* Manual charging start */ | ||
70 | mbcs2 = pcf50633_reg_read(pcf, PCF50633_REG_MBCS2); | ||
71 | chgmod = (mbcs2 & PCF50633_MBCS2_MBC_MASK); | ||
72 | |||
73 | /* If chgmod == BATFULL, setting chgena has no effect. | ||
74 | * We need to set resume instead. | ||
75 | */ | ||
76 | if (chgmod != PCF50633_MBCS2_MBC_BAT_FULL) | ||
77 | pcf50633_reg_set_bit_mask(pcf, PCF50633_REG_MBCC1, | ||
78 | PCF50633_MBCC1_CHGENA, PCF50633_MBCC1_CHGENA); | ||
79 | else | ||
80 | pcf50633_reg_set_bit_mask(pcf, PCF50633_REG_MBCC1, | ||
81 | PCF50633_MBCC1_RESUME, PCF50633_MBCC1_RESUME); | ||
82 | |||
83 | mbc->usb_active = charging_start; | ||
84 | |||
63 | power_supply_changed(&mbc->usb); | 85 | power_supply_changed(&mbc->usb); |
64 | 86 | ||
65 | return ret; | 87 | return ret; |
@@ -84,21 +106,6 @@ int pcf50633_mbc_get_status(struct pcf50633 *pcf) | |||
84 | } | 106 | } |
85 | EXPORT_SYMBOL_GPL(pcf50633_mbc_get_status); | 107 | EXPORT_SYMBOL_GPL(pcf50633_mbc_get_status); |
86 | 108 | ||
87 | void pcf50633_mbc_set_status(struct pcf50633 *pcf, int what, int status) | ||
88 | { | ||
89 | struct pcf50633_mbc *mbc = platform_get_drvdata(pcf->mbc_pdev); | ||
90 | |||
91 | if (what & PCF50633_MBC_USB_ONLINE) | ||
92 | mbc->usb_online = !!status; | ||
93 | if (what & PCF50633_MBC_USB_ACTIVE) | ||
94 | mbc->usb_active = !!status; | ||
95 | if (what & PCF50633_MBC_ADAPTER_ONLINE) | ||
96 | mbc->adapter_online = !!status; | ||
97 | if (what & PCF50633_MBC_ADAPTER_ACTIVE) | ||
98 | mbc->adapter_active = !!status; | ||
99 | } | ||
100 | EXPORT_SYMBOL_GPL(pcf50633_mbc_set_status); | ||
101 | |||
102 | static ssize_t | 109 | static ssize_t |
103 | show_chgmode(struct device *dev, struct device_attribute *attr, char *buf) | 110 | show_chgmode(struct device *dev, struct device_attribute *attr, char *buf) |
104 | { | 111 | { |
@@ -160,10 +167,44 @@ static struct attribute_group mbc_attr_group = { | |||
160 | .attrs = pcf50633_mbc_sysfs_entries, | 167 | .attrs = pcf50633_mbc_sysfs_entries, |
161 | }; | 168 | }; |
162 | 169 | ||
170 | /* MBC state machine switches into charging mode when the battery voltage | ||
171 | * falls below 96% of a battery float voltage. But the voltage drop in Li-ion | ||
172 | * batteries is marginal(1~2 %) till about 80% of its capacity - which means, | ||
173 | * after a BATFULL, charging won't be restarted until 80%. | ||
174 | * | ||
175 | * This work_struct function restarts charging at regular intervals to make | ||
176 | * sure we don't discharge too much | ||
177 | */ | ||
178 | |||
179 | static void pcf50633_mbc_charging_restart(struct work_struct *work) | ||
180 | { | ||
181 | struct pcf50633_mbc *mbc; | ||
182 | u8 mbcs2, chgmod; | ||
183 | |||
184 | mbc = container_of(work, struct pcf50633_mbc, | ||
185 | charging_restart_work.work); | ||
186 | |||
187 | mbcs2 = pcf50633_reg_read(mbc->pcf, PCF50633_REG_MBCS2); | ||
188 | chgmod = (mbcs2 & PCF50633_MBCS2_MBC_MASK); | ||
189 | |||
190 | if (chgmod != PCF50633_MBCS2_MBC_BAT_FULL) | ||
191 | return; | ||
192 | |||
193 | /* Restart charging */ | ||
194 | pcf50633_reg_set_bit_mask(mbc->pcf, PCF50633_REG_MBCC1, | ||
195 | PCF50633_MBCC1_RESUME, PCF50633_MBCC1_RESUME); | ||
196 | mbc->usb_active = 1; | ||
197 | power_supply_changed(&mbc->usb); | ||
198 | |||
199 | dev_info(mbc->pcf->dev, "Charging restarted\n"); | ||
200 | } | ||
201 | |||
163 | static void | 202 | static void |
164 | pcf50633_mbc_irq_handler(int irq, void *data) | 203 | pcf50633_mbc_irq_handler(int irq, void *data) |
165 | { | 204 | { |
166 | struct pcf50633_mbc *mbc = data; | 205 | struct pcf50633_mbc *mbc = data; |
206 | int chg_restart_interval = | ||
207 | mbc->pcf->pdata->charging_restart_interval; | ||
167 | 208 | ||
168 | /* USB */ | 209 | /* USB */ |
169 | if (irq == PCF50633_IRQ_USBINS) { | 210 | if (irq == PCF50633_IRQ_USBINS) { |
@@ -172,6 +213,7 @@ pcf50633_mbc_irq_handler(int irq, void *data) | |||
172 | mbc->usb_online = 0; | 213 | mbc->usb_online = 0; |
173 | mbc->usb_active = 0; | 214 | mbc->usb_active = 0; |
174 | pcf50633_mbc_usb_curlim_set(mbc->pcf, 0); | 215 | pcf50633_mbc_usb_curlim_set(mbc->pcf, 0); |
216 | cancel_delayed_work_sync(&mbc->charging_restart_work); | ||
175 | } | 217 | } |
176 | 218 | ||
177 | /* Adapter */ | 219 | /* Adapter */ |
@@ -186,7 +228,14 @@ pcf50633_mbc_irq_handler(int irq, void *data) | |||
186 | if (irq == PCF50633_IRQ_BATFULL) { | 228 | if (irq == PCF50633_IRQ_BATFULL) { |
187 | mbc->usb_active = 0; | 229 | mbc->usb_active = 0; |
188 | mbc->adapter_active = 0; | 230 | mbc->adapter_active = 0; |
189 | } | 231 | |
232 | if (chg_restart_interval > 0) | ||
233 | schedule_delayed_work(&mbc->charging_restart_work, | ||
234 | chg_restart_interval); | ||
235 | } else if (irq == PCF50633_IRQ_USBLIMON) | ||
236 | mbc->usb_active = 0; | ||
237 | else if (irq == PCF50633_IRQ_USBLIMOFF) | ||
238 | mbc->usb_active = 1; | ||
190 | 239 | ||
191 | power_supply_changed(&mbc->usb); | 240 | power_supply_changed(&mbc->usb); |
192 | power_supply_changed(&mbc->adapter); | 241 | power_supply_changed(&mbc->adapter); |
@@ -303,6 +352,9 @@ static int __devinit pcf50633_mbc_probe(struct platform_device *pdev) | |||
303 | return ret; | 352 | return ret; |
304 | } | 353 | } |
305 | 354 | ||
355 | INIT_DELAYED_WORK(&mbc->charging_restart_work, | ||
356 | pcf50633_mbc_charging_restart); | ||
357 | |||
306 | ret = sysfs_create_group(&pdev->dev.kobj, &mbc_attr_group); | 358 | ret = sysfs_create_group(&pdev->dev.kobj, &mbc_attr_group); |
307 | if (ret) | 359 | if (ret) |
308 | dev_err(mbc->pcf->dev, "failed to create sysfs entries\n"); | 360 | dev_err(mbc->pcf->dev, "failed to create sysfs entries\n"); |
@@ -328,6 +380,8 @@ static int __devexit pcf50633_mbc_remove(struct platform_device *pdev) | |||
328 | power_supply_unregister(&mbc->usb); | 380 | power_supply_unregister(&mbc->usb); |
329 | power_supply_unregister(&mbc->adapter); | 381 | power_supply_unregister(&mbc->adapter); |
330 | 382 | ||
383 | cancel_delayed_work_sync(&mbc->charging_restart_work); | ||
384 | |||
331 | kfree(mbc); | 385 | kfree(mbc); |
332 | 386 | ||
333 | return 0; | 387 | return 0; |