aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/power
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2011-01-14 12:25:59 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2011-01-14 12:25:59 -0500
commit5957e33d6aec266659a71cfabcf7cf2c593ad0d2 (patch)
tree6397dec8d71e4ed4f5982792c57d7c0ddb525d1e /drivers/power
parent0ad53eeefcbb2620b6a71ffdaad4add20b450b8b (diff)
parent359ab9f5b154cbd807a11e22792235f0f36b0cd5 (diff)
Merge git://git.infradead.org/battery-2.6
* git://git.infradead.org/battery-2.6: (21 commits) power_supply: Add MAX17042 Fuel Gauge Driver olpc_battery: Fix up XO-1.5 properties list olpc_battery: Add support for CURRENT_NOW and VOLTAGE_NOW olpc_battery: Add support for CHARGE_NOW olpc_battery: Add support for CHARGE_FULL_DESIGN olpc_battery: Ambient temperature is not available on XO-1.5 jz4740-battery: Should include linux/io.h s3c_adc_battery: Add gpio_inverted field to pdata power_supply: Don't use flush_scheduled_work() power_supply: Fix use after free and memory leak gpio-charger: Fix potential race between irq handler and probe/remove gpio-charger: Provide default name for the power_supply gpio-charger: Check result of kzalloc jz4740-battery: Check if platform_data is supplied isp1704_charger: Detect charger after probe isp1704_charger: Set isp->dev before anything needs it isp1704_charger: Detect HUB/Host chargers isp1704_charger: Correct length for storing model power_supply: Add gpio charger driver jz4740-battery: Protect against concurrent battery readings ...
Diffstat (limited to 'drivers/power')
-rw-r--r--drivers/power/Kconfig20
-rw-r--r--drivers/power/Makefile2
-rw-r--r--drivers/power/collie_battery.c13
-rw-r--r--drivers/power/ds2760_battery.c2
-rw-r--r--drivers/power/gpio-charger.c188
-rw-r--r--drivers/power/intel_mid_battery.c2
-rw-r--r--drivers/power/isp1704_charger.c201
-rw-r--r--drivers/power/jz4740-battery.c13
-rw-r--r--drivers/power/max17042_battery.c239
-rw-r--r--drivers/power/olpc_battery.c114
-rw-r--r--drivers/power/power_supply_core.c6
-rw-r--r--drivers/power/s3c_adc_battery.c12
-rw-r--r--drivers/power/tosa_battery.c13
-rw-r--r--drivers/power/wm97xx_battery.c4
-rw-r--r--drivers/power/z2_battery.c6
15 files changed, 766 insertions, 69 deletions
diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig
index 60d83d983a36..61bf5d724139 100644
--- a/drivers/power/Kconfig
+++ b/drivers/power/Kconfig
@@ -136,6 +136,16 @@ config BATTERY_MAX17040
136 in handheld and portable equipment. The MAX17040 is configured 136 in handheld and portable equipment. The MAX17040 is configured
137 to operate with a single lithium cell 137 to operate with a single lithium cell
138 138
139config BATTERY_MAX17042
140 tristate "Maxim MAX17042/8997/8966 Fuel Gauge"
141 depends on I2C
142 help
143 MAX17042 is fuel-gauge systems for lithium-ion (Li+) batteries
144 in handheld and portable equipment. The MAX17042 is configured
145 to operate with a single lithium cell. MAX8997 and MAX8966 are
146 multi-function devices that include fuel gauages that are compatible
147 with MAX17042.
148
139config BATTERY_Z2 149config BATTERY_Z2
140 tristate "Z2 battery driver" 150 tristate "Z2 battery driver"
141 depends on I2C && MACH_ZIPIT2 151 depends on I2C && MACH_ZIPIT2
@@ -185,4 +195,14 @@ config CHARGER_TWL4030
185 help 195 help
186 Say Y here to enable support for TWL4030 Battery Charge Interface. 196 Say Y here to enable support for TWL4030 Battery Charge Interface.
187 197
198config CHARGER_GPIO
199 tristate "GPIO charger"
200 depends on GPIOLIB
201 help
202 Say Y to include support for chargers which report their online status
203 through a GPIO pin.
204
205 This driver can be build as a module. If so, the module will be
206 called gpio-charger.
207
188endif # POWER_SUPPLY 208endif # POWER_SUPPLY
diff --git a/drivers/power/Makefile b/drivers/power/Makefile
index c75772eb157c..8385bfae8728 100644
--- a/drivers/power/Makefile
+++ b/drivers/power/Makefile
@@ -25,6 +25,7 @@ obj-$(CONFIG_BATTERY_BQ20Z75) += bq20z75.o
25obj-$(CONFIG_BATTERY_BQ27x00) += bq27x00_battery.o 25obj-$(CONFIG_BATTERY_BQ27x00) += bq27x00_battery.o
26obj-$(CONFIG_BATTERY_DA9030) += da9030_battery.o 26obj-$(CONFIG_BATTERY_DA9030) += da9030_battery.o
27obj-$(CONFIG_BATTERY_MAX17040) += max17040_battery.o 27obj-$(CONFIG_BATTERY_MAX17040) += max17040_battery.o
28obj-$(CONFIG_BATTERY_MAX17042) += max17042_battery.o
28obj-$(CONFIG_BATTERY_Z2) += z2_battery.o 29obj-$(CONFIG_BATTERY_Z2) += z2_battery.o
29obj-$(CONFIG_BATTERY_S3C_ADC) += s3c_adc_battery.o 30obj-$(CONFIG_BATTERY_S3C_ADC) += s3c_adc_battery.o
30obj-$(CONFIG_CHARGER_PCF50633) += pcf50633-charger.o 31obj-$(CONFIG_CHARGER_PCF50633) += pcf50633-charger.o
@@ -32,3 +33,4 @@ obj-$(CONFIG_BATTERY_JZ4740) += jz4740-battery.o
32obj-$(CONFIG_BATTERY_INTEL_MID) += intel_mid_battery.o 33obj-$(CONFIG_BATTERY_INTEL_MID) += intel_mid_battery.o
33obj-$(CONFIG_CHARGER_ISP1704) += isp1704_charger.o 34obj-$(CONFIG_CHARGER_ISP1704) += isp1704_charger.o
34obj-$(CONFIG_CHARGER_TWL4030) += twl4030_charger.o 35obj-$(CONFIG_CHARGER_TWL4030) += twl4030_charger.o
36obj-$(CONFIG_CHARGER_GPIO) += gpio-charger.o
diff --git a/drivers/power/collie_battery.c b/drivers/power/collie_battery.c
index 039f41ae217d..548d263b1ad0 100644
--- a/drivers/power/collie_battery.c
+++ b/drivers/power/collie_battery.c
@@ -295,7 +295,7 @@ static struct {
295static int collie_bat_suspend(struct ucb1x00_dev *dev, pm_message_t state) 295static int collie_bat_suspend(struct ucb1x00_dev *dev, pm_message_t state)
296{ 296{
297 /* flush all pending status updates */ 297 /* flush all pending status updates */
298 flush_scheduled_work(); 298 flush_work_sync(&bat_work);
299 return 0; 299 return 0;
300} 300}
301 301
@@ -362,7 +362,7 @@ err_psy_reg_bu:
362err_psy_reg_main: 362err_psy_reg_main:
363 363
364 /* see comment in collie_bat_remove */ 364 /* see comment in collie_bat_remove */
365 flush_scheduled_work(); 365 cancel_work_sync(&bat_work);
366 366
367 i--; 367 i--;
368err_gpio: 368err_gpio:
@@ -382,12 +382,11 @@ static void __devexit collie_bat_remove(struct ucb1x00_dev *dev)
382 power_supply_unregister(&collie_bat_main.psy); 382 power_supply_unregister(&collie_bat_main.psy);
383 383
384 /* 384 /*
385 * now flush all pending work. 385 * Now cancel the bat_work. We won't get any more schedules,
386 * we won't get any more schedules, since all 386 * since all sources (isr and external_power_changed) are
387 * sources (isr and external_power_changed) 387 * unregistered now.
388 * are unregistered now.
389 */ 388 */
390 flush_scheduled_work(); 389 cancel_work_sync(&bat_work);
391 390
392 for (i = ARRAY_SIZE(gpios) - 1; i >= 0; i--) 391 for (i = ARRAY_SIZE(gpios) - 1; i >= 0; i--)
393 gpio_free(gpios[i].gpio); 392 gpio_free(gpios[i].gpio);
diff --git a/drivers/power/ds2760_battery.c b/drivers/power/ds2760_battery.c
index e7f89785beef..e534290f3256 100644
--- a/drivers/power/ds2760_battery.c
+++ b/drivers/power/ds2760_battery.c
@@ -212,7 +212,7 @@ static int ds2760_battery_read_status(struct ds2760_device_info *di)
212 if (di->rem_capacity > 100) 212 if (di->rem_capacity > 100)
213 di->rem_capacity = 100; 213 di->rem_capacity = 100;
214 214
215 if (di->current_uA >= 100L) 215 if (di->current_uA < -100L)
216 di->life_sec = -((di->accum_current_uAh - di->empty_uAh) * 36L) 216 di->life_sec = -((di->accum_current_uAh - di->empty_uAh) * 36L)
217 / (di->current_uA / 100L); 217 / (di->current_uA / 100L);
218 else 218 else
diff --git a/drivers/power/gpio-charger.c b/drivers/power/gpio-charger.c
new file mode 100644
index 000000000000..25b88ac1d44c
--- /dev/null
+++ b/drivers/power/gpio-charger.c
@@ -0,0 +1,188 @@
1/*
2 * Copyright (C) 2010, Lars-Peter Clausen <lars@metafoo.de>
3 * Driver for chargers which report their online status through a GPIO pin
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version.
9 *
10 * You should have received a copy of the GNU General Public License along
11 * with this program; if not, write to the Free Software Foundation, Inc.,
12 * 675 Mass Ave, Cambridge, MA 02139, USA.
13 *
14 */
15
16#include <linux/device.h>
17#include <linux/gpio.h>
18#include <linux/init.h>
19#include <linux/interrupt.h>
20#include <linux/kernel.h>
21#include <linux/module.h>
22#include <linux/platform_device.h>
23#include <linux/power_supply.h>
24#include <linux/slab.h>
25
26#include <linux/power/gpio-charger.h>
27
28struct gpio_charger {
29 const struct gpio_charger_platform_data *pdata;
30 unsigned int irq;
31
32 struct power_supply charger;
33};
34
35static irqreturn_t gpio_charger_irq(int irq, void *devid)
36{
37 struct power_supply *charger = devid;
38
39 power_supply_changed(charger);
40
41 return IRQ_HANDLED;
42}
43
44static inline struct gpio_charger *psy_to_gpio_charger(struct power_supply *psy)
45{
46 return container_of(psy, struct gpio_charger, charger);
47}
48
49static int gpio_charger_get_property(struct power_supply *psy,
50 enum power_supply_property psp, union power_supply_propval *val)
51{
52 struct gpio_charger *gpio_charger = psy_to_gpio_charger(psy);
53 const struct gpio_charger_platform_data *pdata = gpio_charger->pdata;
54
55 switch (psp) {
56 case POWER_SUPPLY_PROP_ONLINE:
57 val->intval = gpio_get_value(pdata->gpio);
58 val->intval ^= pdata->gpio_active_low;
59 break;
60 default:
61 return -EINVAL;
62 }
63
64 return 0;
65}
66
67static enum power_supply_property gpio_charger_properties[] = {
68 POWER_SUPPLY_PROP_ONLINE,
69};
70
71static int __devinit gpio_charger_probe(struct platform_device *pdev)
72{
73 const struct gpio_charger_platform_data *pdata = pdev->dev.platform_data;
74 struct gpio_charger *gpio_charger;
75 struct power_supply *charger;
76 int ret;
77 int irq;
78
79 if (!pdata) {
80 dev_err(&pdev->dev, "No platform data\n");
81 return -EINVAL;
82 }
83
84 if (!gpio_is_valid(pdata->gpio)) {
85 dev_err(&pdev->dev, "Invalid gpio pin\n");
86 return -EINVAL;
87 }
88
89 gpio_charger = kzalloc(sizeof(*gpio_charger), GFP_KERNEL);
90 if (!gpio_charger) {
91 dev_err(&pdev->dev, "Failed to alloc driver structure\n");
92 return -ENOMEM;
93 }
94
95 charger = &gpio_charger->charger;
96
97 charger->name = pdata->name ? pdata->name : "gpio-charger";
98 charger->type = pdata->type;
99 charger->properties = gpio_charger_properties;
100 charger->num_properties = ARRAY_SIZE(gpio_charger_properties);
101 charger->get_property = gpio_charger_get_property;
102 charger->supplied_to = pdata->supplied_to;
103 charger->num_supplicants = pdata->num_supplicants;
104
105 ret = gpio_request(pdata->gpio, dev_name(&pdev->dev));
106 if (ret) {
107 dev_err(&pdev->dev, "Failed to request gpio pin: %d\n", ret);
108 goto err_free;
109 }
110 ret = gpio_direction_input(pdata->gpio);
111 if (ret) {
112 dev_err(&pdev->dev, "Failed to set gpio to input: %d\n", ret);
113 goto err_gpio_free;
114 }
115
116 gpio_charger->pdata = pdata;
117
118 ret = power_supply_register(&pdev->dev, charger);
119 if (ret < 0) {
120 dev_err(&pdev->dev, "Failed to register power supply: %d\n",
121 ret);
122 goto err_gpio_free;
123 }
124
125 irq = gpio_to_irq(pdata->gpio);
126 if (irq > 0) {
127 ret = request_any_context_irq(irq, gpio_charger_irq,
128 IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
129 dev_name(&pdev->dev), charger);
130 if (ret)
131 dev_warn(&pdev->dev, "Failed to request irq: %d\n", ret);
132 else
133 gpio_charger->irq = irq;
134 }
135
136 platform_set_drvdata(pdev, gpio_charger);
137
138 return 0;
139
140err_gpio_free:
141 gpio_free(pdata->gpio);
142err_free:
143 kfree(gpio_charger);
144 return ret;
145}
146
147static int __devexit gpio_charger_remove(struct platform_device *pdev)
148{
149 struct gpio_charger *gpio_charger = platform_get_drvdata(pdev);
150
151 if (gpio_charger->irq)
152 free_irq(gpio_charger->irq, &gpio_charger->charger);
153
154 power_supply_unregister(&gpio_charger->charger);
155
156 gpio_free(gpio_charger->pdata->gpio);
157
158 platform_set_drvdata(pdev, NULL);
159 kfree(gpio_charger);
160
161 return 0;
162}
163
164static struct platform_driver gpio_charger_driver = {
165 .probe = gpio_charger_probe,
166 .remove = __devexit_p(gpio_charger_remove),
167 .driver = {
168 .name = "gpio-charger",
169 .owner = THIS_MODULE,
170 },
171};
172
173static int __init gpio_charger_init(void)
174{
175 return platform_driver_register(&gpio_charger_driver);
176}
177module_init(gpio_charger_init);
178
179static void __exit gpio_charger_exit(void)
180{
181 platform_driver_unregister(&gpio_charger_driver);
182}
183module_exit(gpio_charger_exit);
184
185MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
186MODULE_DESCRIPTION("Driver for chargers which report their online status through a GPIO");
187MODULE_LICENSE("GPL");
188MODULE_ALIAS("platform:gpio-charger");
diff --git a/drivers/power/intel_mid_battery.c b/drivers/power/intel_mid_battery.c
index 36cf402c0677..bce3a01da2f0 100644
--- a/drivers/power/intel_mid_battery.c
+++ b/drivers/power/intel_mid_battery.c
@@ -765,7 +765,7 @@ static int __devexit platform_pmic_battery_remove(struct platform_device *pdev)
765 power_supply_unregister(&pbi->usb); 765 power_supply_unregister(&pbi->usb);
766 power_supply_unregister(&pbi->batt); 766 power_supply_unregister(&pbi->batt);
767 767
768 flush_scheduled_work(); 768 cancel_work_sync(&pbi->handler);
769 kfree(pbi); 769 kfree(pbi);
770 return 0; 770 return 0;
771} 771}
diff --git a/drivers/power/isp1704_charger.c b/drivers/power/isp1704_charger.c
index 72512185f3e2..2ad9b14a5ce3 100644
--- a/drivers/power/isp1704_charger.c
+++ b/drivers/power/isp1704_charger.c
@@ -59,11 +59,61 @@ struct isp1704_charger {
59 struct notifier_block nb; 59 struct notifier_block nb;
60 struct work_struct work; 60 struct work_struct work;
61 61
62 char model[7]; 62 /* properties */
63 char model[8];
63 unsigned present:1; 64 unsigned present:1;
65 unsigned online:1;
66 unsigned current_max;
67
68 /* temp storage variables */
69 unsigned long event;
70 unsigned max_power;
64}; 71};
65 72
66/* 73/*
74 * Determine is the charging port DCP (dedicated charger) or CDP (Host/HUB
75 * chargers).
76 *
77 * REVISIT: The method is defined in Battery Charging Specification and is
78 * applicable to any ULPI transceiver. Nothing isp170x specific here.
79 */
80static inline int isp1704_charger_type(struct isp1704_charger *isp)
81{
82 u8 reg;
83 u8 func_ctrl;
84 u8 otg_ctrl;
85 int type = POWER_SUPPLY_TYPE_USB_DCP;
86
87 func_ctrl = otg_io_read(isp->otg, ULPI_FUNC_CTRL);
88 otg_ctrl = otg_io_read(isp->otg, ULPI_OTG_CTRL);
89
90 /* disable pulldowns */
91 reg = ULPI_OTG_CTRL_DM_PULLDOWN | ULPI_OTG_CTRL_DP_PULLDOWN;
92 otg_io_write(isp->otg, ULPI_CLR(ULPI_OTG_CTRL), reg);
93
94 /* full speed */
95 otg_io_write(isp->otg, ULPI_CLR(ULPI_FUNC_CTRL),
96 ULPI_FUNC_CTRL_XCVRSEL_MASK);
97 otg_io_write(isp->otg, ULPI_SET(ULPI_FUNC_CTRL),
98 ULPI_FUNC_CTRL_FULL_SPEED);
99
100 /* Enable strong pull-up on DP (1.5K) and reset */
101 reg = ULPI_FUNC_CTRL_TERMSELECT | ULPI_FUNC_CTRL_RESET;
102 otg_io_write(isp->otg, ULPI_SET(ULPI_FUNC_CTRL), reg);
103 usleep_range(1000, 2000);
104
105 reg = otg_io_read(isp->otg, ULPI_DEBUG);
106 if ((reg & 3) != 3)
107 type = POWER_SUPPLY_TYPE_USB_CDP;
108
109 /* recover original state */
110 otg_io_write(isp->otg, ULPI_FUNC_CTRL, func_ctrl);
111 otg_io_write(isp->otg, ULPI_OTG_CTRL, otg_ctrl);
112
113 return type;
114}
115
116/*
67 * ISP1704 detects PS/2 adapters as charger. To make sure the detected charger 117 * ISP1704 detects PS/2 adapters as charger. To make sure the detected charger
68 * is actually a dedicated charger, the following steps need to be taken. 118 * is actually a dedicated charger, the following steps need to be taken.
69 */ 119 */
@@ -127,16 +177,19 @@ static inline int isp1704_charger_verify(struct isp1704_charger *isp)
127static inline int isp1704_charger_detect(struct isp1704_charger *isp) 177static inline int isp1704_charger_detect(struct isp1704_charger *isp)
128{ 178{
129 unsigned long timeout; 179 unsigned long timeout;
130 u8 r; 180 u8 pwr_ctrl;
131 int ret = 0; 181 int ret = 0;
132 182
183 pwr_ctrl = otg_io_read(isp->otg, ISP1704_PWR_CTRL);
184
133 /* set SW control bit in PWR_CTRL register */ 185 /* set SW control bit in PWR_CTRL register */
134 otg_io_write(isp->otg, ISP1704_PWR_CTRL, 186 otg_io_write(isp->otg, ISP1704_PWR_CTRL,
135 ISP1704_PWR_CTRL_SWCTRL); 187 ISP1704_PWR_CTRL_SWCTRL);
136 188
137 /* enable manual charger detection */ 189 /* enable manual charger detection */
138 r = (ISP1704_PWR_CTRL_SWCTRL | ISP1704_PWR_CTRL_DPVSRC_EN); 190 otg_io_write(isp->otg, ULPI_SET(ISP1704_PWR_CTRL),
139 otg_io_write(isp->otg, ULPI_SET(ISP1704_PWR_CTRL), r); 191 ISP1704_PWR_CTRL_SWCTRL
192 | ISP1704_PWR_CTRL_DPVSRC_EN);
140 usleep_range(1000, 2000); 193 usleep_range(1000, 2000);
141 194
142 timeout = jiffies + msecs_to_jiffies(300); 195 timeout = jiffies + msecs_to_jiffies(300);
@@ -147,7 +200,10 @@ static inline int isp1704_charger_detect(struct isp1704_charger *isp)
147 ret = isp1704_charger_verify(isp); 200 ret = isp1704_charger_verify(isp);
148 break; 201 break;
149 } 202 }
150 } while (!time_after(jiffies, timeout)); 203 } while (!time_after(jiffies, timeout) && isp->online);
204
205 /* recover original state */
206 otg_io_write(isp->otg, ISP1704_PWR_CTRL, pwr_ctrl);
151 207
152 return ret; 208 return ret;
153} 209}
@@ -155,52 +211,92 @@ static inline int isp1704_charger_detect(struct isp1704_charger *isp)
155static void isp1704_charger_work(struct work_struct *data) 211static void isp1704_charger_work(struct work_struct *data)
156{ 212{
157 int detect; 213 int detect;
214 unsigned long event;
215 unsigned power;
158 struct isp1704_charger *isp = 216 struct isp1704_charger *isp =
159 container_of(data, struct isp1704_charger, work); 217 container_of(data, struct isp1704_charger, work);
218 static DEFINE_MUTEX(lock);
160 219
161 /* 220 event = isp->event;
162 * FIXME Only supporting dedicated chargers even though isp1704 can 221 power = isp->max_power;
163 * detect HUB and HOST chargers. If the device has already been
164 * enumerated, the detection will break the connection.
165 */
166 if (isp->otg->state != OTG_STATE_B_IDLE)
167 return;
168 222
169 /* disable data pullups */ 223 mutex_lock(&lock);
170 if (isp->otg->gadget) 224
171 usb_gadget_disconnect(isp->otg->gadget); 225 switch (event) {
226 case USB_EVENT_VBUS:
227 isp->online = true;
228
229 /* detect charger */
230 detect = isp1704_charger_detect(isp);
231
232 if (detect) {
233 isp->present = detect;
234 isp->psy.type = isp1704_charger_type(isp);
235 }
172 236
173 /* detect charger */ 237 switch (isp->psy.type) {
174 detect = isp1704_charger_detect(isp); 238 case POWER_SUPPLY_TYPE_USB_DCP:
175 if (detect) { 239 isp->current_max = 1800;
176 isp->present = detect; 240 break;
177 power_supply_changed(&isp->psy); 241 case POWER_SUPPLY_TYPE_USB_CDP:
242 /*
243 * Only 500mA here or high speed chirp
244 * handshaking may break
245 */
246 isp->current_max = 500;
247 /* FALLTHROUGH */
248 case POWER_SUPPLY_TYPE_USB:
249 default:
250 /* enable data pullups */
251 if (isp->otg->gadget)
252 usb_gadget_connect(isp->otg->gadget);
253 }
254 break;
255 case USB_EVENT_NONE:
256 isp->online = false;
257 isp->current_max = 0;
258 isp->present = 0;
259 isp->current_max = 0;
260 isp->psy.type = POWER_SUPPLY_TYPE_USB;
261
262 /*
263 * Disable data pullups. We need to prevent the controller from
264 * enumerating.
265 *
266 * FIXME: This is here to allow charger detection with Host/HUB
267 * chargers. The pullups may be enabled elsewhere, so this can
268 * not be the final solution.
269 */
270 if (isp->otg->gadget)
271 usb_gadget_disconnect(isp->otg->gadget);
272 break;
273 case USB_EVENT_ENUMERATED:
274 if (isp->present)
275 isp->current_max = 1800;
276 else
277 isp->current_max = power;
278 break;
279 default:
280 goto out;
178 } 281 }
179 282
180 /* enable data pullups */ 283 power_supply_changed(&isp->psy);
181 if (isp->otg->gadget) 284out:
182 usb_gadget_connect(isp->otg->gadget); 285 mutex_unlock(&lock);
183} 286}
184 287
185static int isp1704_notifier_call(struct notifier_block *nb, 288static int isp1704_notifier_call(struct notifier_block *nb,
186 unsigned long event, void *unused) 289 unsigned long event, void *power)
187{ 290{
188 struct isp1704_charger *isp = 291 struct isp1704_charger *isp =
189 container_of(nb, struct isp1704_charger, nb); 292 container_of(nb, struct isp1704_charger, nb);
190 293
191 switch (event) { 294 isp->event = event;
192 case USB_EVENT_VBUS: 295
193 schedule_work(&isp->work); 296 if (power)
194 break; 297 isp->max_power = *((unsigned *)power);
195 case USB_EVENT_NONE: 298
196 if (isp->present) { 299 schedule_work(&isp->work);
197 isp->present = 0;
198 power_supply_changed(&isp->psy);
199 }
200 break;
201 default:
202 return NOTIFY_DONE;
203 }
204 300
205 return NOTIFY_OK; 301 return NOTIFY_OK;
206} 302}
@@ -216,6 +312,12 @@ static int isp1704_charger_get_property(struct power_supply *psy,
216 case POWER_SUPPLY_PROP_PRESENT: 312 case POWER_SUPPLY_PROP_PRESENT:
217 val->intval = isp->present; 313 val->intval = isp->present;
218 break; 314 break;
315 case POWER_SUPPLY_PROP_ONLINE:
316 val->intval = isp->online;
317 break;
318 case POWER_SUPPLY_PROP_CURRENT_MAX:
319 val->intval = isp->current_max;
320 break;
219 case POWER_SUPPLY_PROP_MODEL_NAME: 321 case POWER_SUPPLY_PROP_MODEL_NAME:
220 val->strval = isp->model; 322 val->strval = isp->model;
221 break; 323 break;
@@ -230,6 +332,8 @@ static int isp1704_charger_get_property(struct power_supply *psy,
230 332
231static enum power_supply_property power_props[] = { 333static enum power_supply_property power_props[] = {
232 POWER_SUPPLY_PROP_PRESENT, 334 POWER_SUPPLY_PROP_PRESENT,
335 POWER_SUPPLY_PROP_ONLINE,
336 POWER_SUPPLY_PROP_CURRENT_MAX,
233 POWER_SUPPLY_PROP_MODEL_NAME, 337 POWER_SUPPLY_PROP_MODEL_NAME,
234 POWER_SUPPLY_PROP_MANUFACTURER, 338 POWER_SUPPLY_PROP_MANUFACTURER,
235}; 339};
@@ -287,13 +391,13 @@ static int __devinit isp1704_charger_probe(struct platform_device *pdev)
287 if (!isp->otg) 391 if (!isp->otg)
288 goto fail0; 392 goto fail0;
289 393
394 isp->dev = &pdev->dev;
395 platform_set_drvdata(pdev, isp);
396
290 ret = isp1704_test_ulpi(isp); 397 ret = isp1704_test_ulpi(isp);
291 if (ret < 0) 398 if (ret < 0)
292 goto fail1; 399 goto fail1;
293 400
294 isp->dev = &pdev->dev;
295 platform_set_drvdata(pdev, isp);
296
297 isp->psy.name = "isp1704"; 401 isp->psy.name = "isp1704";
298 isp->psy.type = POWER_SUPPLY_TYPE_USB; 402 isp->psy.type = POWER_SUPPLY_TYPE_USB;
299 isp->psy.properties = power_props; 403 isp->psy.properties = power_props;
@@ -318,6 +422,23 @@ static int __devinit isp1704_charger_probe(struct platform_device *pdev)
318 422
319 dev_info(isp->dev, "registered with product id %s\n", isp->model); 423 dev_info(isp->dev, "registered with product id %s\n", isp->model);
320 424
425 /*
426 * Taking over the D+ pullup.
427 *
428 * FIXME: The device will be disconnected if it was already
429 * enumerated. The charger driver should be always loaded before any
430 * gadget is loaded.
431 */
432 if (isp->otg->gadget)
433 usb_gadget_disconnect(isp->otg->gadget);
434
435 /* Detect charger if VBUS is valid (the cable was already plugged). */
436 ret = otg_io_read(isp->otg, ULPI_USB_INT_STS);
437 if ((ret & ULPI_INT_VBUS_VALID) && !isp->otg->default_a) {
438 isp->event = USB_EVENT_VBUS;
439 schedule_work(&isp->work);
440 }
441
321 return 0; 442 return 0;
322fail2: 443fail2:
323 power_supply_unregister(&isp->psy); 444 power_supply_unregister(&isp->psy);
diff --git a/drivers/power/jz4740-battery.c b/drivers/power/jz4740-battery.c
index a8108a73593e..02414db6a94c 100644
--- a/drivers/power/jz4740-battery.c
+++ b/drivers/power/jz4740-battery.c
@@ -19,6 +19,7 @@
19#include <linux/module.h> 19#include <linux/module.h>
20#include <linux/platform_device.h> 20#include <linux/platform_device.h>
21#include <linux/slab.h> 21#include <linux/slab.h>
22#include <linux/io.h>
22 23
23#include <linux/delay.h> 24#include <linux/delay.h>
24#include <linux/gpio.h> 25#include <linux/gpio.h>
@@ -47,6 +48,8 @@ struct jz_battery {
47 48
48 struct power_supply battery; 49 struct power_supply battery;
49 struct delayed_work work; 50 struct delayed_work work;
51
52 struct mutex lock;
50}; 53};
51 54
52static inline struct jz_battery *psy_to_jz_battery(struct power_supply *psy) 55static inline struct jz_battery *psy_to_jz_battery(struct power_supply *psy)
@@ -68,6 +71,8 @@ static long jz_battery_read_voltage(struct jz_battery *battery)
68 unsigned long val; 71 unsigned long val;
69 long voltage; 72 long voltage;
70 73
74 mutex_lock(&battery->lock);
75
71 INIT_COMPLETION(battery->read_completion); 76 INIT_COMPLETION(battery->read_completion);
72 77
73 enable_irq(battery->irq); 78 enable_irq(battery->irq);
@@ -91,6 +96,8 @@ static long jz_battery_read_voltage(struct jz_battery *battery)
91 battery->cell->disable(battery->pdev); 96 battery->cell->disable(battery->pdev);
92 disable_irq(battery->irq); 97 disable_irq(battery->irq);
93 98
99 mutex_unlock(&battery->lock);
100
94 return voltage; 101 return voltage;
95} 102}
96 103
@@ -240,6 +247,11 @@ static int __devinit jz_battery_probe(struct platform_device *pdev)
240 struct jz_battery *jz_battery; 247 struct jz_battery *jz_battery;
241 struct power_supply *battery; 248 struct power_supply *battery;
242 249
250 if (!pdata) {
251 dev_err(&pdev->dev, "No platform_data supplied\n");
252 return -ENXIO;
253 }
254
243 jz_battery = kzalloc(sizeof(*jz_battery), GFP_KERNEL); 255 jz_battery = kzalloc(sizeof(*jz_battery), GFP_KERNEL);
244 if (!jz_battery) { 256 if (!jz_battery) {
245 dev_err(&pdev->dev, "Failed to allocate driver structure\n"); 257 dev_err(&pdev->dev, "Failed to allocate driver structure\n");
@@ -291,6 +303,7 @@ static int __devinit jz_battery_probe(struct platform_device *pdev)
291 jz_battery->pdev = pdev; 303 jz_battery->pdev = pdev;
292 304
293 init_completion(&jz_battery->read_completion); 305 init_completion(&jz_battery->read_completion);
306 mutex_init(&jz_battery->lock);
294 307
295 INIT_DELAYED_WORK(&jz_battery->work, jz_battery_work); 308 INIT_DELAYED_WORK(&jz_battery->work, jz_battery_work);
296 309
diff --git a/drivers/power/max17042_battery.c b/drivers/power/max17042_battery.c
new file mode 100644
index 000000000000..c5c8805156cb
--- /dev/null
+++ b/drivers/power/max17042_battery.c
@@ -0,0 +1,239 @@
1/*
2 * Fuel gauge driver for Maxim 17042 / 8966 / 8997
3 * Note that Maxim 8966 and 8997 are mfd and this is its subdevice.
4 *
5 * Copyright (C) 2011 Samsung Electronics
6 * MyungJoo Ham <myungjoo.ham@samsung.com>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 *
22 * This driver is based on max17040_battery.c
23 */
24
25#include <linux/init.h>
26#include <linux/slab.h>
27#include <linux/i2c.h>
28#include <linux/mod_devicetable.h>
29#include <linux/power_supply.h>
30#include <linux/power/max17042_battery.h>
31
32enum max17042_register {
33 MAX17042_STATUS = 0x00,
34 MAX17042_VALRT_Th = 0x01,
35 MAX17042_TALRT_Th = 0x02,
36 MAX17042_SALRT_Th = 0x03,
37 MAX17042_AtRate = 0x04,
38 MAX17042_RepCap = 0x05,
39 MAX17042_RepSOC = 0x06,
40 MAX17042_Age = 0x07,
41 MAX17042_TEMP = 0x08,
42 MAX17042_VCELL = 0x09,
43 MAX17042_Current = 0x0A,
44 MAX17042_AvgCurrent = 0x0B,
45 MAX17042_Qresidual = 0x0C,
46 MAX17042_SOC = 0x0D,
47 MAX17042_AvSOC = 0x0E,
48 MAX17042_RemCap = 0x0F,
49 MAX17402_FullCAP = 0x10,
50 MAX17042_TTE = 0x11,
51 MAX17042_V_empty = 0x12,
52
53 MAX17042_RSLOW = 0x14,
54
55 MAX17042_AvgTA = 0x16,
56 MAX17042_Cycles = 0x17,
57 MAX17042_DesignCap = 0x18,
58 MAX17042_AvgVCELL = 0x19,
59 MAX17042_MinMaxTemp = 0x1A,
60 MAX17042_MinMaxVolt = 0x1B,
61 MAX17042_MinMaxCurr = 0x1C,
62 MAX17042_CONFIG = 0x1D,
63 MAX17042_ICHGTerm = 0x1E,
64 MAX17042_AvCap = 0x1F,
65 MAX17042_ManName = 0x20,
66 MAX17042_DevName = 0x21,
67 MAX17042_DevChem = 0x22,
68
69 MAX17042_TempNom = 0x24,
70 MAX17042_TempCold = 0x25,
71 MAX17042_TempHot = 0x26,
72 MAX17042_AIN = 0x27,
73 MAX17042_LearnCFG = 0x28,
74 MAX17042_SHFTCFG = 0x29,
75 MAX17042_RelaxCFG = 0x2A,
76 MAX17042_MiscCFG = 0x2B,
77 MAX17042_TGAIN = 0x2C,
78 MAx17042_TOFF = 0x2D,
79 MAX17042_CGAIN = 0x2E,
80 MAX17042_COFF = 0x2F,
81
82 MAX17042_Q_empty = 0x33,
83 MAX17042_T_empty = 0x34,
84
85 MAX17042_RCOMP0 = 0x38,
86 MAX17042_TempCo = 0x39,
87 MAX17042_Rx = 0x3A,
88 MAX17042_T_empty0 = 0x3B,
89 MAX17042_TaskPeriod = 0x3C,
90 MAX17042_FSTAT = 0x3D,
91
92 MAX17042_SHDNTIMER = 0x3F,
93
94 MAX17042_VFRemCap = 0x4A,
95
96 MAX17042_QH = 0x4D,
97 MAX17042_QL = 0x4E,
98};
99
100struct max17042_chip {
101 struct i2c_client *client;
102 struct power_supply battery;
103 struct max17042_platform_data *pdata;
104};
105
106static int max17042_write_reg(struct i2c_client *client, u8 reg, u16 value)
107{
108 int ret = i2c_smbus_write_word_data(client, reg, value);
109
110 if (ret < 0)
111 dev_err(&client->dev, "%s: err %d\n", __func__, ret);
112
113 return ret;
114}
115
116static int max17042_read_reg(struct i2c_client *client, u8 reg)
117{
118 int ret = i2c_smbus_read_word_data(client, reg);
119
120 if (ret < 0)
121 dev_err(&client->dev, "%s: err %d\n", __func__, ret);
122
123 return ret;
124}
125
126static enum power_supply_property max17042_battery_props[] = {
127 POWER_SUPPLY_PROP_VOLTAGE_NOW,
128 POWER_SUPPLY_PROP_VOLTAGE_AVG,
129 POWER_SUPPLY_PROP_CAPACITY,
130};
131
132static int max17042_get_property(struct power_supply *psy,
133 enum power_supply_property psp,
134 union power_supply_propval *val)
135{
136 struct max17042_chip *chip = container_of(psy,
137 struct max17042_chip, battery);
138
139 switch (psp) {
140 case POWER_SUPPLY_PROP_VOLTAGE_NOW:
141 val->intval = max17042_read_reg(chip->client,
142 MAX17042_VCELL) * 83; /* 1000 / 12 = 83 */
143 break;
144 case POWER_SUPPLY_PROP_VOLTAGE_AVG:
145 val->intval = max17042_read_reg(chip->client,
146 MAX17042_AvgVCELL) * 83;
147 break;
148 case POWER_SUPPLY_PROP_CAPACITY:
149 val->intval = max17042_read_reg(chip->client,
150 MAX17042_SOC) / 256;
151 break;
152 default:
153 return -EINVAL;
154 }
155 return 0;
156}
157
158static int __devinit max17042_probe(struct i2c_client *client,
159 const struct i2c_device_id *id)
160{
161 struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
162 struct max17042_chip *chip;
163 int ret;
164
165 if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA))
166 return -EIO;
167
168 chip = kzalloc(sizeof(*chip), GFP_KERNEL);
169 if (!chip)
170 return -ENOMEM;
171
172 chip->client = client;
173 chip->pdata = client->dev.platform_data;
174
175 i2c_set_clientdata(client, chip);
176
177 chip->battery.name = "max17042_battery";
178 chip->battery.type = POWER_SUPPLY_TYPE_BATTERY;
179 chip->battery.get_property = max17042_get_property;
180 chip->battery.properties = max17042_battery_props;
181 chip->battery.num_properties = ARRAY_SIZE(max17042_battery_props);
182
183 ret = power_supply_register(&client->dev, &chip->battery);
184 if (ret) {
185 dev_err(&client->dev, "failed: power supply register\n");
186 i2c_set_clientdata(client, NULL);
187 kfree(chip);
188 return ret;
189 }
190
191 if (!chip->pdata->enable_current_sense) {
192 max17042_write_reg(client, MAX17042_CGAIN, 0x0000);
193 max17042_write_reg(client, MAX17042_MiscCFG, 0x0003);
194 max17042_write_reg(client, MAX17042_LearnCFG, 0x0007);
195 }
196
197 return 0;
198}
199
200static int __devexit max17042_remove(struct i2c_client *client)
201{
202 struct max17042_chip *chip = i2c_get_clientdata(client);
203
204 power_supply_unregister(&chip->battery);
205 i2c_set_clientdata(client, NULL);
206 kfree(chip);
207 return 0;
208}
209
210static const struct i2c_device_id max17042_id[] = {
211 { "max17042", 0 },
212 { }
213};
214MODULE_DEVICE_TABLE(i2c, max17042_id);
215
216static struct i2c_driver max17042_i2c_driver = {
217 .driver = {
218 .name = "max17042",
219 },
220 .probe = max17042_probe,
221 .remove = __devexit_p(max17042_remove),
222 .id_table = max17042_id,
223};
224
225static int __init max17042_init(void)
226{
227 return i2c_add_driver(&max17042_i2c_driver);
228}
229module_init(max17042_init);
230
231static void __exit max17042_exit(void)
232{
233 i2c_del_driver(&max17042_i2c_driver);
234}
235module_exit(max17042_exit);
236
237MODULE_AUTHOR("MyungJoo Ham <myungjoo.ham@samsung.com>");
238MODULE_DESCRIPTION("MAX17042 Fuel Gauge");
239MODULE_LICENSE("GPL");
diff --git a/drivers/power/olpc_battery.c b/drivers/power/olpc_battery.c
index 5bc1dcf7785e..0b0ff3a936a6 100644
--- a/drivers/power/olpc_battery.c
+++ b/drivers/power/olpc_battery.c
@@ -201,6 +201,72 @@ static int olpc_bat_get_tech(union power_supply_propval *val)
201 return ret; 201 return ret;
202} 202}
203 203
204static int olpc_bat_get_charge_full_design(union power_supply_propval *val)
205{
206 uint8_t ec_byte;
207 union power_supply_propval tech;
208 int ret, mfr;
209
210 ret = olpc_bat_get_tech(&tech);
211 if (ret)
212 return ret;
213
214 ec_byte = BAT_ADDR_MFR_TYPE;
215 ret = olpc_ec_cmd(EC_BAT_EEPROM, &ec_byte, 1, &ec_byte, 1);
216 if (ret)
217 return ret;
218
219 mfr = ec_byte >> 4;
220
221 switch (tech.intval) {
222 case POWER_SUPPLY_TECHNOLOGY_NiMH:
223 switch (mfr) {
224 case 1: /* Gold Peak */
225 val->intval = 3000000*.8;
226 break;
227 default:
228 return -EIO;
229 }
230 break;
231
232 case POWER_SUPPLY_TECHNOLOGY_LiFe:
233 switch (mfr) {
234 case 1: /* Gold Peak */
235 val->intval = 2800000;
236 break;
237 case 2: /* BYD */
238 val->intval = 3100000;
239 break;
240 default:
241 return -EIO;
242 }
243 break;
244
245 default:
246 return -EIO;
247 }
248
249 return ret;
250}
251
252static int olpc_bat_get_charge_now(union power_supply_propval *val)
253{
254 uint8_t soc;
255 union power_supply_propval full;
256 int ret;
257
258 ret = olpc_ec_cmd(EC_BAT_SOC, NULL, 0, &soc, 1);
259 if (ret)
260 return ret;
261
262 ret = olpc_bat_get_charge_full_design(&full);
263 if (ret)
264 return ret;
265
266 val->intval = soc * (full.intval / 100);
267 return 0;
268}
269
204/********************************************************************* 270/*********************************************************************
205 * Battery properties 271 * Battery properties
206 *********************************************************************/ 272 *********************************************************************/
@@ -267,6 +333,7 @@ static int olpc_bat_get_property(struct power_supply *psy,
267 return ret; 333 return ret;
268 break; 334 break;
269 case POWER_SUPPLY_PROP_VOLTAGE_AVG: 335 case POWER_SUPPLY_PROP_VOLTAGE_AVG:
336 case POWER_SUPPLY_PROP_VOLTAGE_NOW:
270 ret = olpc_ec_cmd(EC_BAT_VOLTAGE, NULL, 0, (void *)&ec_word, 2); 337 ret = olpc_ec_cmd(EC_BAT_VOLTAGE, NULL, 0, (void *)&ec_word, 2);
271 if (ret) 338 if (ret)
272 return ret; 339 return ret;
@@ -274,6 +341,7 @@ static int olpc_bat_get_property(struct power_supply *psy,
274 val->intval = (s16)be16_to_cpu(ec_word) * 9760L / 32; 341 val->intval = (s16)be16_to_cpu(ec_word) * 9760L / 32;
275 break; 342 break;
276 case POWER_SUPPLY_PROP_CURRENT_AVG: 343 case POWER_SUPPLY_PROP_CURRENT_AVG:
344 case POWER_SUPPLY_PROP_CURRENT_NOW:
277 ret = olpc_ec_cmd(EC_BAT_CURRENT, NULL, 0, (void *)&ec_word, 2); 345 ret = olpc_ec_cmd(EC_BAT_CURRENT, NULL, 0, (void *)&ec_word, 2);
278 if (ret) 346 if (ret)
279 return ret; 347 return ret;
@@ -294,6 +362,16 @@ static int olpc_bat_get_property(struct power_supply *psy,
294 else 362 else
295 val->intval = POWER_SUPPLY_CAPACITY_LEVEL_NORMAL; 363 val->intval = POWER_SUPPLY_CAPACITY_LEVEL_NORMAL;
296 break; 364 break;
365 case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN:
366 ret = olpc_bat_get_charge_full_design(val);
367 if (ret)
368 return ret;
369 break;
370 case POWER_SUPPLY_PROP_CHARGE_NOW:
371 ret = olpc_bat_get_charge_now(val);
372 if (ret)
373 return ret;
374 break;
297 case POWER_SUPPLY_PROP_TEMP: 375 case POWER_SUPPLY_PROP_TEMP:
298 ret = olpc_ec_cmd(EC_BAT_TEMP, NULL, 0, (void *)&ec_word, 2); 376 ret = olpc_ec_cmd(EC_BAT_TEMP, NULL, 0, (void *)&ec_word, 2);
299 if (ret) 377 if (ret)
@@ -331,16 +409,20 @@ static int olpc_bat_get_property(struct power_supply *psy,
331 return ret; 409 return ret;
332} 410}
333 411
334static enum power_supply_property olpc_bat_props[] = { 412static enum power_supply_property olpc_xo1_bat_props[] = {
335 POWER_SUPPLY_PROP_STATUS, 413 POWER_SUPPLY_PROP_STATUS,
336 POWER_SUPPLY_PROP_CHARGE_TYPE, 414 POWER_SUPPLY_PROP_CHARGE_TYPE,
337 POWER_SUPPLY_PROP_PRESENT, 415 POWER_SUPPLY_PROP_PRESENT,
338 POWER_SUPPLY_PROP_HEALTH, 416 POWER_SUPPLY_PROP_HEALTH,
339 POWER_SUPPLY_PROP_TECHNOLOGY, 417 POWER_SUPPLY_PROP_TECHNOLOGY,
340 POWER_SUPPLY_PROP_VOLTAGE_AVG, 418 POWER_SUPPLY_PROP_VOLTAGE_AVG,
419 POWER_SUPPLY_PROP_VOLTAGE_NOW,
341 POWER_SUPPLY_PROP_CURRENT_AVG, 420 POWER_SUPPLY_PROP_CURRENT_AVG,
421 POWER_SUPPLY_PROP_CURRENT_NOW,
342 POWER_SUPPLY_PROP_CAPACITY, 422 POWER_SUPPLY_PROP_CAPACITY,
343 POWER_SUPPLY_PROP_CAPACITY_LEVEL, 423 POWER_SUPPLY_PROP_CAPACITY_LEVEL,
424 POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
425 POWER_SUPPLY_PROP_CHARGE_NOW,
344 POWER_SUPPLY_PROP_TEMP, 426 POWER_SUPPLY_PROP_TEMP,
345 POWER_SUPPLY_PROP_TEMP_AMBIENT, 427 POWER_SUPPLY_PROP_TEMP_AMBIENT,
346 POWER_SUPPLY_PROP_MANUFACTURER, 428 POWER_SUPPLY_PROP_MANUFACTURER,
@@ -348,6 +430,27 @@ static enum power_supply_property olpc_bat_props[] = {
348 POWER_SUPPLY_PROP_CHARGE_COUNTER, 430 POWER_SUPPLY_PROP_CHARGE_COUNTER,
349}; 431};
350 432
433/* XO-1.5 does not have ambient temperature property */
434static enum power_supply_property olpc_xo15_bat_props[] = {
435 POWER_SUPPLY_PROP_STATUS,
436 POWER_SUPPLY_PROP_CHARGE_TYPE,
437 POWER_SUPPLY_PROP_PRESENT,
438 POWER_SUPPLY_PROP_HEALTH,
439 POWER_SUPPLY_PROP_TECHNOLOGY,
440 POWER_SUPPLY_PROP_VOLTAGE_AVG,
441 POWER_SUPPLY_PROP_VOLTAGE_NOW,
442 POWER_SUPPLY_PROP_CURRENT_AVG,
443 POWER_SUPPLY_PROP_CURRENT_NOW,
444 POWER_SUPPLY_PROP_CAPACITY,
445 POWER_SUPPLY_PROP_CAPACITY_LEVEL,
446 POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
447 POWER_SUPPLY_PROP_CHARGE_NOW,
448 POWER_SUPPLY_PROP_TEMP,
449 POWER_SUPPLY_PROP_MANUFACTURER,
450 POWER_SUPPLY_PROP_SERIAL_NUMBER,
451 POWER_SUPPLY_PROP_CHARGE_COUNTER,
452};
453
351/* EEPROM reading goes completely around the power_supply API, sadly */ 454/* EEPROM reading goes completely around the power_supply API, sadly */
352 455
353#define EEPROM_START 0x20 456#define EEPROM_START 0x20
@@ -419,8 +522,6 @@ static struct device_attribute olpc_bat_error = {
419static struct platform_device *bat_pdev; 522static struct platform_device *bat_pdev;
420 523
421static struct power_supply olpc_bat = { 524static struct power_supply olpc_bat = {
422 .properties = olpc_bat_props,
423 .num_properties = ARRAY_SIZE(olpc_bat_props),
424 .get_property = olpc_bat_get_property, 525 .get_property = olpc_bat_get_property,
425 .use_for_apm = 1, 526 .use_for_apm = 1,
426}; 527};
@@ -466,6 +567,13 @@ static int __init olpc_bat_init(void)
466 goto ac_failed; 567 goto ac_failed;
467 568
468 olpc_bat.name = bat_pdev->name; 569 olpc_bat.name = bat_pdev->name;
570 if (olpc_board_at_least(olpc_board_pre(0xd0))) { /* XO-1.5 */
571 olpc_bat.properties = olpc_xo15_bat_props;
572 olpc_bat.num_properties = ARRAY_SIZE(olpc_xo15_bat_props);
573 } else { /* XO-1 */
574 olpc_bat.properties = olpc_xo1_bat_props;
575 olpc_bat.num_properties = ARRAY_SIZE(olpc_xo1_bat_props);
576 }
469 577
470 ret = power_supply_register(&bat_pdev->dev, &olpc_bat); 578 ret = power_supply_register(&bat_pdev->dev, &olpc_bat);
471 if (ret) 579 if (ret)
diff --git a/drivers/power/power_supply_core.c b/drivers/power/power_supply_core.c
index 91606bb55318..970f7335d3a7 100644
--- a/drivers/power/power_supply_core.c
+++ b/drivers/power/power_supply_core.c
@@ -190,10 +190,10 @@ int power_supply_register(struct device *parent, struct power_supply *psy)
190 goto success; 190 goto success;
191 191
192create_triggers_failed: 192create_triggers_failed:
193 device_unregister(psy->dev); 193 device_del(dev);
194kobject_set_name_failed: 194kobject_set_name_failed:
195device_add_failed: 195device_add_failed:
196 kfree(dev); 196 put_device(dev);
197success: 197success:
198 return rc; 198 return rc;
199} 199}
@@ -201,7 +201,7 @@ EXPORT_SYMBOL_GPL(power_supply_register);
201 201
202void power_supply_unregister(struct power_supply *psy) 202void power_supply_unregister(struct power_supply *psy)
203{ 203{
204 flush_scheduled_work(); 204 cancel_work_sync(&psy->changed_work);
205 power_supply_remove_triggers(psy); 205 power_supply_remove_triggers(psy);
206 device_unregister(psy->dev); 206 device_unregister(psy->dev);
207} 207}
diff --git a/drivers/power/s3c_adc_battery.c b/drivers/power/s3c_adc_battery.c
index 4a8ae3935b3b..4255f2358b13 100644
--- a/drivers/power/s3c_adc_battery.c
+++ b/drivers/power/s3c_adc_battery.c
@@ -112,6 +112,13 @@ static int calc_full_volt(int volt_val, int cur_val, int impedance)
112 return volt_val + cur_val * impedance / 1000; 112 return volt_val + cur_val * impedance / 1000;
113} 113}
114 114
115static int charge_finished(struct s3c_adc_bat *bat)
116{
117 return bat->pdata->gpio_inverted ?
118 !gpio_get_value(bat->pdata->gpio_charge_finished) :
119 gpio_get_value(bat->pdata->gpio_charge_finished);
120}
121
115static int s3c_adc_bat_get_property(struct power_supply *psy, 122static int s3c_adc_bat_get_property(struct power_supply *psy,
116 enum power_supply_property psp, 123 enum power_supply_property psp,
117 union power_supply_propval *val) 124 union power_supply_propval *val)
@@ -140,7 +147,7 @@ static int s3c_adc_bat_get_property(struct power_supply *psy,
140 147
141 if (bat->cable_plugged && 148 if (bat->cable_plugged &&
142 ((bat->pdata->gpio_charge_finished < 0) || 149 ((bat->pdata->gpio_charge_finished < 0) ||
143 !gpio_get_value(bat->pdata->gpio_charge_finished))) { 150 !charge_finished(bat))) {
144 lut = bat->pdata->lut_acin; 151 lut = bat->pdata->lut_acin;
145 lut_size = bat->pdata->lut_acin_cnt; 152 lut_size = bat->pdata->lut_acin_cnt;
146 } 153 }
@@ -236,8 +243,7 @@ static void s3c_adc_bat_work(struct work_struct *work)
236 } 243 }
237 } else { 244 } else {
238 if ((bat->pdata->gpio_charge_finished >= 0) && is_plugged) { 245 if ((bat->pdata->gpio_charge_finished >= 0) && is_plugged) {
239 is_charged = gpio_get_value( 246 is_charged = charge_finished(&main_bat);
240 main_bat.pdata->gpio_charge_finished);
241 if (is_charged) { 247 if (is_charged) {
242 if (bat->pdata->disable_charger) 248 if (bat->pdata->disable_charger)
243 bat->pdata->disable_charger(); 249 bat->pdata->disable_charger();
diff --git a/drivers/power/tosa_battery.c b/drivers/power/tosa_battery.c
index ee04936b2db5..53f0d3524fcd 100644
--- a/drivers/power/tosa_battery.c
+++ b/drivers/power/tosa_battery.c
@@ -332,7 +332,7 @@ static struct {
332static int tosa_bat_suspend(struct platform_device *dev, pm_message_t state) 332static int tosa_bat_suspend(struct platform_device *dev, pm_message_t state)
333{ 333{
334 /* flush all pending status updates */ 334 /* flush all pending status updates */
335 flush_scheduled_work(); 335 flush_work_sync(&bat_work);
336 return 0; 336 return 0;
337} 337}
338 338
@@ -422,7 +422,7 @@ err_psy_reg_jacket:
422err_psy_reg_main: 422err_psy_reg_main:
423 423
424 /* see comment in tosa_bat_remove */ 424 /* see comment in tosa_bat_remove */
425 flush_scheduled_work(); 425 cancel_work_sync(&bat_work);
426 426
427 i--; 427 i--;
428err_gpio: 428err_gpio:
@@ -445,12 +445,11 @@ static int __devexit tosa_bat_remove(struct platform_device *dev)
445 power_supply_unregister(&tosa_bat_main.psy); 445 power_supply_unregister(&tosa_bat_main.psy);
446 446
447 /* 447 /*
448 * now flush all pending work. 448 * Now cancel the bat_work. We won't get any more schedules,
449 * we won't get any more schedules, since all 449 * since all sources (isr and external_power_changed) are
450 * sources (isr and external_power_changed) 450 * unregistered now.
451 * are unregistered now.
452 */ 451 */
453 flush_scheduled_work(); 452 cancel_work_sync(&bat_work);
454 453
455 for (i = ARRAY_SIZE(gpios) - 1; i >= 0; i--) 454 for (i = ARRAY_SIZE(gpios) - 1; i >= 0; i--)
456 gpio_free(gpios[i].gpio); 455 gpio_free(gpios[i].gpio);
diff --git a/drivers/power/wm97xx_battery.c b/drivers/power/wm97xx_battery.c
index 5071d85ec12d..156559e56fa5 100644
--- a/drivers/power/wm97xx_battery.c
+++ b/drivers/power/wm97xx_battery.c
@@ -147,7 +147,7 @@ static irqreturn_t wm97xx_chrg_irq(int irq, void *data)
147#ifdef CONFIG_PM 147#ifdef CONFIG_PM
148static int wm97xx_bat_suspend(struct device *dev) 148static int wm97xx_bat_suspend(struct device *dev)
149{ 149{
150 flush_scheduled_work(); 150 flush_work_sync(&bat_work);
151 return 0; 151 return 0;
152} 152}
153 153
@@ -273,7 +273,7 @@ static int __devexit wm97xx_bat_remove(struct platform_device *dev)
273 free_irq(gpio_to_irq(pdata->charge_gpio), dev); 273 free_irq(gpio_to_irq(pdata->charge_gpio), dev);
274 gpio_free(pdata->charge_gpio); 274 gpio_free(pdata->charge_gpio);
275 } 275 }
276 flush_scheduled_work(); 276 cancel_work_sync(&bat_work);
277 power_supply_unregister(&bat_ps); 277 power_supply_unregister(&bat_ps);
278 kfree(prop); 278 kfree(prop);
279 return 0; 279 return 0;
diff --git a/drivers/power/z2_battery.c b/drivers/power/z2_battery.c
index 85064a9f649e..e5ed52d71937 100644
--- a/drivers/power/z2_battery.c
+++ b/drivers/power/z2_battery.c
@@ -254,7 +254,7 @@ static int __devexit z2_batt_remove(struct i2c_client *client)
254 struct z2_charger *charger = i2c_get_clientdata(client); 254 struct z2_charger *charger = i2c_get_clientdata(client);
255 struct z2_battery_info *info = charger->info; 255 struct z2_battery_info *info = charger->info;
256 256
257 flush_scheduled_work(); 257 cancel_work_sync(&charger->bat_work);
258 power_supply_unregister(&charger->batt_ps); 258 power_supply_unregister(&charger->batt_ps);
259 259
260 kfree(charger->batt_ps.properties); 260 kfree(charger->batt_ps.properties);
@@ -271,7 +271,9 @@ static int __devexit z2_batt_remove(struct i2c_client *client)
271#ifdef CONFIG_PM 271#ifdef CONFIG_PM
272static int z2_batt_suspend(struct i2c_client *client, pm_message_t state) 272static int z2_batt_suspend(struct i2c_client *client, pm_message_t state)
273{ 273{
274 flush_scheduled_work(); 274 struct z2_charger *charger = i2c_get_clientdata(client);
275
276 flush_work_sync(&charger->bat_work);
275 return 0; 277 return 0;
276} 278}
277 279