diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-01-11 21:53:05 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-01-11 21:53:05 -0500 |
commit | b24ca57e7625bc304e77bc429693ad32a691eb16 (patch) | |
tree | 770aa389c6e763cf37776a35e85ff1e41958b1e9 /drivers/power | |
parent | 6296e5d3c067df41980a5fd09ad4cc6765f79bb9 (diff) | |
parent | 913272b3864d6da89c70d9fc2c30ccb57794b369 (diff) |
Merge git://git.infradead.org/battery-2.6
* git://git.infradead.org/battery-2.6: (68 commits)
power_supply: Mark da9052 driver as broken
power_supply: Drop usage of nowarn variant of sysfs_create_link()
s3c_adc_battery: Average over more than one adc sample
power_supply: Add DA9052 battery driver
isp1704_charger: Fix missing check
jz4740-battery: Fix signedness bug
power_supply: Assume mains power by default
sbs-battery: Fix devicetree match table
ARM: rx51: Add bq27200 i2c board info
sbs-battery: Change power supply name
devicetree-bindings: Propagate bq20z75->sbs rename to dt bindings
devicetree-bindings: Add vendor entry for Smart Battery Systems
sbs-battery: Rename internals to new name
bq20z75: Rename to sbs-battery
wm97xx_battery: Use DEFINE_MUTEX() for work_lock
max8997_charger: Remove duplicate module.h
lp8727_charger: Some minor fixes for the header
lp8727_charger: Add header file
power_supply: Convert drivers/power/* to use module_platform_driver()
power_supply: Add "unknown" in power supply type
...
Diffstat (limited to 'drivers/power')
32 files changed, 3034 insertions, 710 deletions
diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig index 9f88641e67f9..3a8daf858742 100644 --- a/drivers/power/Kconfig +++ b/drivers/power/Kconfig | |||
@@ -116,12 +116,12 @@ config BATTERY_WM97XX | |||
116 | help | 116 | help |
117 | Say Y to enable support for battery measured by WM97xx aux port. | 117 | Say Y to enable support for battery measured by WM97xx aux port. |
118 | 118 | ||
119 | config BATTERY_BQ20Z75 | 119 | config BATTERY_SBS |
120 | tristate "TI BQ20z75 gas gauge" | 120 | tristate "SBS Compliant gas gauge" |
121 | depends on I2C | 121 | depends on I2C |
122 | help | 122 | help |
123 | Say Y to include support for TI BQ20z75 SBS-compliant | 123 | Say Y to include support for SBS battery driver for SBS-compliant |
124 | gas gauge and protection IC. | 124 | gas gauges. |
125 | 125 | ||
126 | config BATTERY_BQ27x00 | 126 | config BATTERY_BQ27x00 |
127 | tristate "BQ27x00 battery driver" | 127 | tristate "BQ27x00 battery driver" |
@@ -150,6 +150,14 @@ config BATTERY_DA9030 | |||
150 | Say Y here to enable support for batteries charger integrated into | 150 | Say Y here to enable support for batteries charger integrated into |
151 | DA9030 PMIC. | 151 | DA9030 PMIC. |
152 | 152 | ||
153 | config BATTERY_DA9052 | ||
154 | tristate "Dialog DA9052 Battery" | ||
155 | depends on PMIC_DA9052 | ||
156 | depends on BROKEN | ||
157 | help | ||
158 | Say Y here to enable support for batteries charger integrated into | ||
159 | DA9052 PMIC. | ||
160 | |||
153 | config BATTERY_MAX17040 | 161 | config BATTERY_MAX17040 |
154 | tristate "Maxim MAX17040 Fuel Gauge" | 162 | tristate "Maxim MAX17040 Fuel Gauge" |
155 | depends on I2C | 163 | depends on I2C |
@@ -226,6 +234,12 @@ config CHARGER_TWL4030 | |||
226 | help | 234 | help |
227 | Say Y here to enable support for TWL4030 Battery Charge Interface. | 235 | Say Y here to enable support for TWL4030 Battery Charge Interface. |
228 | 236 | ||
237 | config CHARGER_LP8727 | ||
238 | tristate "National Semiconductor LP8727 charger driver" | ||
239 | depends on I2C | ||
240 | help | ||
241 | Say Y here to enable support for LP8727 Charger Driver. | ||
242 | |||
229 | config CHARGER_GPIO | 243 | config CHARGER_GPIO |
230 | tristate "GPIO charger" | 244 | tristate "GPIO charger" |
231 | depends on GPIOLIB | 245 | depends on GPIOLIB |
@@ -236,6 +250,16 @@ config CHARGER_GPIO | |||
236 | This driver can be build as a module. If so, the module will be | 250 | This driver can be build as a module. If so, the module will be |
237 | called gpio-charger. | 251 | called gpio-charger. |
238 | 252 | ||
253 | config CHARGER_MANAGER | ||
254 | bool "Battery charger manager for multiple chargers" | ||
255 | depends on REGULATOR && RTC_CLASS | ||
256 | help | ||
257 | Say Y to enable charger-manager support, which allows multiple | ||
258 | chargers attached to a battery and multiple batteries attached to a | ||
259 | system. The charger-manager also can monitor charging status in | ||
260 | runtime and in suspend-to-RAM by waking up the system periodically | ||
261 | with help of suspend_again support. | ||
262 | |||
239 | config CHARGER_MAX8997 | 263 | config CHARGER_MAX8997 |
240 | tristate "Maxim MAX8997/MAX8966 PMIC battery charger driver" | 264 | tristate "Maxim MAX8997/MAX8966 PMIC battery charger driver" |
241 | depends on MFD_MAX8997 && REGULATOR_MAX8997 | 265 | depends on MFD_MAX8997 && REGULATOR_MAX8997 |
diff --git a/drivers/power/Makefile b/drivers/power/Makefile index b4af13dd8b66..e429008eaf10 100644 --- a/drivers/power/Makefile +++ b/drivers/power/Makefile | |||
@@ -22,9 +22,10 @@ obj-$(CONFIG_BATTERY_OLPC) += olpc_battery.o | |||
22 | obj-$(CONFIG_BATTERY_TOSA) += tosa_battery.o | 22 | obj-$(CONFIG_BATTERY_TOSA) += tosa_battery.o |
23 | obj-$(CONFIG_BATTERY_COLLIE) += collie_battery.o | 23 | obj-$(CONFIG_BATTERY_COLLIE) += collie_battery.o |
24 | obj-$(CONFIG_BATTERY_WM97XX) += wm97xx_battery.o | 24 | obj-$(CONFIG_BATTERY_WM97XX) += wm97xx_battery.o |
25 | obj-$(CONFIG_BATTERY_BQ20Z75) += bq20z75.o | 25 | obj-$(CONFIG_BATTERY_SBS) += sbs-battery.o |
26 | obj-$(CONFIG_BATTERY_BQ27x00) += bq27x00_battery.o | 26 | obj-$(CONFIG_BATTERY_BQ27x00) += bq27x00_battery.o |
27 | obj-$(CONFIG_BATTERY_DA9030) += da9030_battery.o | 27 | obj-$(CONFIG_BATTERY_DA9030) += da9030_battery.o |
28 | obj-$(CONFIG_BATTERY_DA9052) += da9052-battery.o | ||
28 | obj-$(CONFIG_BATTERY_MAX17040) += max17040_battery.o | 29 | obj-$(CONFIG_BATTERY_MAX17040) += max17040_battery.o |
29 | obj-$(CONFIG_BATTERY_MAX17042) += max17042_battery.o | 30 | obj-$(CONFIG_BATTERY_MAX17042) += max17042_battery.o |
30 | obj-$(CONFIG_BATTERY_Z2) += z2_battery.o | 31 | obj-$(CONFIG_BATTERY_Z2) += z2_battery.o |
@@ -35,6 +36,8 @@ obj-$(CONFIG_BATTERY_INTEL_MID) += intel_mid_battery.o | |||
35 | obj-$(CONFIG_CHARGER_ISP1704) += isp1704_charger.o | 36 | obj-$(CONFIG_CHARGER_ISP1704) += isp1704_charger.o |
36 | obj-$(CONFIG_CHARGER_MAX8903) += max8903_charger.o | 37 | obj-$(CONFIG_CHARGER_MAX8903) += max8903_charger.o |
37 | obj-$(CONFIG_CHARGER_TWL4030) += twl4030_charger.o | 38 | obj-$(CONFIG_CHARGER_TWL4030) += twl4030_charger.o |
39 | obj-$(CONFIG_CHARGER_LP8727) += lp8727_charger.o | ||
38 | obj-$(CONFIG_CHARGER_GPIO) += gpio-charger.o | 40 | obj-$(CONFIG_CHARGER_GPIO) += gpio-charger.o |
41 | obj-$(CONFIG_CHARGER_MANAGER) += charger-manager.o | ||
39 | obj-$(CONFIG_CHARGER_MAX8997) += max8997_charger.o | 42 | obj-$(CONFIG_CHARGER_MAX8997) += max8997_charger.o |
40 | obj-$(CONFIG_CHARGER_MAX8998) += max8998_charger.o | 43 | obj-$(CONFIG_CHARGER_MAX8998) += max8998_charger.o |
diff --git a/drivers/power/bq27x00_battery.c b/drivers/power/bq27x00_battery.c index bb16f5b7e167..98bf5676318d 100644 --- a/drivers/power/bq27x00_battery.c +++ b/drivers/power/bq27x00_battery.c | |||
@@ -54,13 +54,19 @@ | |||
54 | 54 | ||
55 | #define BQ27000_REG_RSOC 0x0B /* Relative State-of-Charge */ | 55 | #define BQ27000_REG_RSOC 0x0B /* Relative State-of-Charge */ |
56 | #define BQ27000_REG_ILMD 0x76 /* Initial last measured discharge */ | 56 | #define BQ27000_REG_ILMD 0x76 /* Initial last measured discharge */ |
57 | #define BQ27000_FLAG_CHGS BIT(7) | 57 | #define BQ27000_FLAG_EDVF BIT(0) /* Final End-of-Discharge-Voltage flag */ |
58 | #define BQ27000_FLAG_EDV1 BIT(1) /* First End-of-Discharge-Voltage flag */ | ||
59 | #define BQ27000_FLAG_CI BIT(4) /* Capacity Inaccurate flag */ | ||
58 | #define BQ27000_FLAG_FC BIT(5) | 60 | #define BQ27000_FLAG_FC BIT(5) |
61 | #define BQ27000_FLAG_CHGS BIT(7) /* Charge state flag */ | ||
59 | 62 | ||
60 | #define BQ27500_REG_SOC 0x2C | 63 | #define BQ27500_REG_SOC 0x2C |
61 | #define BQ27500_REG_DCAP 0x3C /* Design capacity */ | 64 | #define BQ27500_REG_DCAP 0x3C /* Design capacity */ |
62 | #define BQ27500_FLAG_DSC BIT(0) | 65 | #define BQ27500_FLAG_DSG BIT(0) /* Discharging */ |
63 | #define BQ27500_FLAG_FC BIT(9) | 66 | #define BQ27500_FLAG_SOCF BIT(1) /* State-of-Charge threshold final */ |
67 | #define BQ27500_FLAG_SOC1 BIT(2) /* State-of-Charge threshold 1 */ | ||
68 | #define BQ27500_FLAG_CHG BIT(8) /* Charging */ | ||
69 | #define BQ27500_FLAG_FC BIT(9) /* Fully charged */ | ||
64 | 70 | ||
65 | #define BQ27000_RS 20 /* Resistor sense */ | 71 | #define BQ27000_RS 20 /* Resistor sense */ |
66 | 72 | ||
@@ -79,9 +85,8 @@ struct bq27x00_reg_cache { | |||
79 | int charge_full; | 85 | int charge_full; |
80 | int cycle_count; | 86 | int cycle_count; |
81 | int capacity; | 87 | int capacity; |
88 | int energy; | ||
82 | int flags; | 89 | int flags; |
83 | |||
84 | int current_now; | ||
85 | }; | 90 | }; |
86 | 91 | ||
87 | struct bq27x00_device_info { | 92 | struct bq27x00_device_info { |
@@ -108,6 +113,7 @@ static enum power_supply_property bq27x00_battery_props[] = { | |||
108 | POWER_SUPPLY_PROP_VOLTAGE_NOW, | 113 | POWER_SUPPLY_PROP_VOLTAGE_NOW, |
109 | POWER_SUPPLY_PROP_CURRENT_NOW, | 114 | POWER_SUPPLY_PROP_CURRENT_NOW, |
110 | POWER_SUPPLY_PROP_CAPACITY, | 115 | POWER_SUPPLY_PROP_CAPACITY, |
116 | POWER_SUPPLY_PROP_CAPACITY_LEVEL, | ||
111 | POWER_SUPPLY_PROP_TEMP, | 117 | POWER_SUPPLY_PROP_TEMP, |
112 | POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW, | 118 | POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW, |
113 | POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG, | 119 | POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG, |
@@ -149,7 +155,7 @@ static int bq27x00_battery_read_rsoc(struct bq27x00_device_info *di) | |||
149 | rsoc = bq27x00_read(di, BQ27000_REG_RSOC, true); | 155 | rsoc = bq27x00_read(di, BQ27000_REG_RSOC, true); |
150 | 156 | ||
151 | if (rsoc < 0) | 157 | if (rsoc < 0) |
152 | dev_err(di->dev, "error reading relative State-of-Charge\n"); | 158 | dev_dbg(di->dev, "error reading relative State-of-Charge\n"); |
153 | 159 | ||
154 | return rsoc; | 160 | return rsoc; |
155 | } | 161 | } |
@@ -164,7 +170,8 @@ static int bq27x00_battery_read_charge(struct bq27x00_device_info *di, u8 reg) | |||
164 | 170 | ||
165 | charge = bq27x00_read(di, reg, false); | 171 | charge = bq27x00_read(di, reg, false); |
166 | if (charge < 0) { | 172 | if (charge < 0) { |
167 | dev_err(di->dev, "error reading nominal available capacity\n"); | 173 | dev_dbg(di->dev, "error reading charge register %02x: %d\n", |
174 | reg, charge); | ||
168 | return charge; | 175 | return charge; |
169 | } | 176 | } |
170 | 177 | ||
@@ -208,7 +215,7 @@ static int bq27x00_battery_read_ilmd(struct bq27x00_device_info *di) | |||
208 | ilmd = bq27x00_read(di, BQ27000_REG_ILMD, true); | 215 | ilmd = bq27x00_read(di, BQ27000_REG_ILMD, true); |
209 | 216 | ||
210 | if (ilmd < 0) { | 217 | if (ilmd < 0) { |
211 | dev_err(di->dev, "error reading initial last measured discharge\n"); | 218 | dev_dbg(di->dev, "error reading initial last measured discharge\n"); |
212 | return ilmd; | 219 | return ilmd; |
213 | } | 220 | } |
214 | 221 | ||
@@ -221,6 +228,50 @@ static int bq27x00_battery_read_ilmd(struct bq27x00_device_info *di) | |||
221 | } | 228 | } |
222 | 229 | ||
223 | /* | 230 | /* |
231 | * Return the battery Available energy in µWh | ||
232 | * Or < 0 if something fails. | ||
233 | */ | ||
234 | static int bq27x00_battery_read_energy(struct bq27x00_device_info *di) | ||
235 | { | ||
236 | int ae; | ||
237 | |||
238 | ae = bq27x00_read(di, BQ27x00_REG_AE, false); | ||
239 | if (ae < 0) { | ||
240 | dev_dbg(di->dev, "error reading available energy\n"); | ||
241 | return ae; | ||
242 | } | ||
243 | |||
244 | if (di->chip == BQ27500) | ||
245 | ae *= 1000; | ||
246 | else | ||
247 | ae = ae * 29200 / BQ27000_RS; | ||
248 | |||
249 | return ae; | ||
250 | } | ||
251 | |||
252 | /* | ||
253 | * Return the battery temperature in tenths of degree Celsius | ||
254 | * Or < 0 if something fails. | ||
255 | */ | ||
256 | static int bq27x00_battery_read_temperature(struct bq27x00_device_info *di) | ||
257 | { | ||
258 | int temp; | ||
259 | |||
260 | temp = bq27x00_read(di, BQ27x00_REG_TEMP, false); | ||
261 | if (temp < 0) { | ||
262 | dev_err(di->dev, "error reading temperature\n"); | ||
263 | return temp; | ||
264 | } | ||
265 | |||
266 | if (di->chip == BQ27500) | ||
267 | temp -= 2731; | ||
268 | else | ||
269 | temp = ((temp * 5) - 5463) / 2; | ||
270 | |||
271 | return temp; | ||
272 | } | ||
273 | |||
274 | /* | ||
224 | * Return the battery Cycle count total | 275 | * Return the battery Cycle count total |
225 | * Or < 0 if something fails. | 276 | * Or < 0 if something fails. |
226 | */ | 277 | */ |
@@ -245,7 +296,8 @@ static int bq27x00_battery_read_time(struct bq27x00_device_info *di, u8 reg) | |||
245 | 296 | ||
246 | tval = bq27x00_read(di, reg, false); | 297 | tval = bq27x00_read(di, reg, false); |
247 | if (tval < 0) { | 298 | if (tval < 0) { |
248 | dev_err(di->dev, "error reading register %02x: %d\n", reg, tval); | 299 | dev_dbg(di->dev, "error reading time register %02x: %d\n", |
300 | reg, tval); | ||
249 | return tval; | 301 | return tval; |
250 | } | 302 | } |
251 | 303 | ||
@@ -262,25 +314,31 @@ static void bq27x00_update(struct bq27x00_device_info *di) | |||
262 | 314 | ||
263 | cache.flags = bq27x00_read(di, BQ27x00_REG_FLAGS, is_bq27500); | 315 | cache.flags = bq27x00_read(di, BQ27x00_REG_FLAGS, is_bq27500); |
264 | if (cache.flags >= 0) { | 316 | if (cache.flags >= 0) { |
265 | cache.capacity = bq27x00_battery_read_rsoc(di); | 317 | if (!is_bq27500 && (cache.flags & BQ27000_FLAG_CI)) { |
266 | cache.temperature = bq27x00_read(di, BQ27x00_REG_TEMP, false); | 318 | dev_info(di->dev, "battery is not calibrated! ignoring capacity values\n"); |
267 | cache.time_to_empty = bq27x00_battery_read_time(di, BQ27x00_REG_TTE); | 319 | cache.capacity = -ENODATA; |
268 | cache.time_to_empty_avg = bq27x00_battery_read_time(di, BQ27x00_REG_TTECP); | 320 | cache.energy = -ENODATA; |
269 | cache.time_to_full = bq27x00_battery_read_time(di, BQ27x00_REG_TTF); | 321 | cache.time_to_empty = -ENODATA; |
270 | cache.charge_full = bq27x00_battery_read_lmd(di); | 322 | cache.time_to_empty_avg = -ENODATA; |
323 | cache.time_to_full = -ENODATA; | ||
324 | cache.charge_full = -ENODATA; | ||
325 | } else { | ||
326 | cache.capacity = bq27x00_battery_read_rsoc(di); | ||
327 | cache.energy = bq27x00_battery_read_energy(di); | ||
328 | cache.time_to_empty = bq27x00_battery_read_time(di, BQ27x00_REG_TTE); | ||
329 | cache.time_to_empty_avg = bq27x00_battery_read_time(di, BQ27x00_REG_TTECP); | ||
330 | cache.time_to_full = bq27x00_battery_read_time(di, BQ27x00_REG_TTF); | ||
331 | cache.charge_full = bq27x00_battery_read_lmd(di); | ||
332 | } | ||
333 | cache.temperature = bq27x00_battery_read_temperature(di); | ||
271 | cache.cycle_count = bq27x00_battery_read_cyct(di); | 334 | cache.cycle_count = bq27x00_battery_read_cyct(di); |
272 | 335 | ||
273 | if (!is_bq27500) | ||
274 | cache.current_now = bq27x00_read(di, BQ27x00_REG_AI, false); | ||
275 | |||
276 | /* We only have to read charge design full once */ | 336 | /* We only have to read charge design full once */ |
277 | if (di->charge_design_full <= 0) | 337 | if (di->charge_design_full <= 0) |
278 | di->charge_design_full = bq27x00_battery_read_ilmd(di); | 338 | di->charge_design_full = bq27x00_battery_read_ilmd(di); |
279 | } | 339 | } |
280 | 340 | ||
281 | /* Ignore current_now which is a snapshot of the current battery state | 341 | if (memcmp(&di->cache, &cache, sizeof(cache)) != 0) { |
282 | * and is likely to be different even between two consecutive reads */ | ||
283 | if (memcmp(&di->cache, &cache, sizeof(cache) - sizeof(int)) != 0) { | ||
284 | di->cache = cache; | 342 | di->cache = cache; |
285 | power_supply_changed(&di->bat); | 343 | power_supply_changed(&di->bat); |
286 | } | 344 | } |
@@ -302,25 +360,6 @@ static void bq27x00_battery_poll(struct work_struct *work) | |||
302 | } | 360 | } |
303 | } | 361 | } |
304 | 362 | ||
305 | |||
306 | /* | ||
307 | * Return the battery temperature in tenths of degree Celsius | ||
308 | * Or < 0 if something fails. | ||
309 | */ | ||
310 | static int bq27x00_battery_temperature(struct bq27x00_device_info *di, | ||
311 | union power_supply_propval *val) | ||
312 | { | ||
313 | if (di->cache.temperature < 0) | ||
314 | return di->cache.temperature; | ||
315 | |||
316 | if (di->chip == BQ27500) | ||
317 | val->intval = di->cache.temperature - 2731; | ||
318 | else | ||
319 | val->intval = ((di->cache.temperature * 5) - 5463) / 2; | ||
320 | |||
321 | return 0; | ||
322 | } | ||
323 | |||
324 | /* | 363 | /* |
325 | * Return the battery average current in µA | 364 | * Return the battery average current in µA |
326 | * Note that current can be negative signed as well | 365 | * Note that current can be negative signed as well |
@@ -330,20 +369,20 @@ static int bq27x00_battery_current(struct bq27x00_device_info *di, | |||
330 | union power_supply_propval *val) | 369 | union power_supply_propval *val) |
331 | { | 370 | { |
332 | int curr; | 371 | int curr; |
372 | int flags; | ||
333 | 373 | ||
334 | if (di->chip == BQ27500) | 374 | curr = bq27x00_read(di, BQ27x00_REG_AI, false); |
335 | curr = bq27x00_read(di, BQ27x00_REG_AI, false); | 375 | if (curr < 0) { |
336 | else | 376 | dev_err(di->dev, "error reading current\n"); |
337 | curr = di->cache.current_now; | ||
338 | |||
339 | if (curr < 0) | ||
340 | return curr; | 377 | return curr; |
378 | } | ||
341 | 379 | ||
342 | if (di->chip == BQ27500) { | 380 | if (di->chip == BQ27500) { |
343 | /* bq27500 returns signed value */ | 381 | /* bq27500 returns signed value */ |
344 | val->intval = (int)((s16)curr) * 1000; | 382 | val->intval = (int)((s16)curr) * 1000; |
345 | } else { | 383 | } else { |
346 | if (di->cache.flags & BQ27000_FLAG_CHGS) { | 384 | flags = bq27x00_read(di, BQ27x00_REG_FLAGS, false); |
385 | if (flags & BQ27000_FLAG_CHGS) { | ||
347 | dev_dbg(di->dev, "negative current!\n"); | 386 | dev_dbg(di->dev, "negative current!\n"); |
348 | curr = -curr; | 387 | curr = -curr; |
349 | } | 388 | } |
@@ -362,10 +401,14 @@ static int bq27x00_battery_status(struct bq27x00_device_info *di, | |||
362 | if (di->chip == BQ27500) { | 401 | if (di->chip == BQ27500) { |
363 | if (di->cache.flags & BQ27500_FLAG_FC) | 402 | if (di->cache.flags & BQ27500_FLAG_FC) |
364 | status = POWER_SUPPLY_STATUS_FULL; | 403 | status = POWER_SUPPLY_STATUS_FULL; |
365 | else if (di->cache.flags & BQ27500_FLAG_DSC) | 404 | else if (di->cache.flags & BQ27500_FLAG_DSG) |
366 | status = POWER_SUPPLY_STATUS_DISCHARGING; | 405 | status = POWER_SUPPLY_STATUS_DISCHARGING; |
367 | else | 406 | else if (di->cache.flags & BQ27500_FLAG_CHG) |
368 | status = POWER_SUPPLY_STATUS_CHARGING; | 407 | status = POWER_SUPPLY_STATUS_CHARGING; |
408 | else if (power_supply_am_i_supplied(&di->bat)) | ||
409 | status = POWER_SUPPLY_STATUS_NOT_CHARGING; | ||
410 | else | ||
411 | status = POWER_SUPPLY_STATUS_UNKNOWN; | ||
369 | } else { | 412 | } else { |
370 | if (di->cache.flags & BQ27000_FLAG_FC) | 413 | if (di->cache.flags & BQ27000_FLAG_FC) |
371 | status = POWER_SUPPLY_STATUS_FULL; | 414 | status = POWER_SUPPLY_STATUS_FULL; |
@@ -382,50 +425,56 @@ static int bq27x00_battery_status(struct bq27x00_device_info *di, | |||
382 | return 0; | 425 | return 0; |
383 | } | 426 | } |
384 | 427 | ||
385 | /* | 428 | static int bq27x00_battery_capacity_level(struct bq27x00_device_info *di, |
386 | * Return the battery Voltage in milivolts | ||
387 | * Or < 0 if something fails. | ||
388 | */ | ||
389 | static int bq27x00_battery_voltage(struct bq27x00_device_info *di, | ||
390 | union power_supply_propval *val) | 429 | union power_supply_propval *val) |
391 | { | 430 | { |
392 | int volt; | 431 | int level; |
393 | 432 | ||
394 | volt = bq27x00_read(di, BQ27x00_REG_VOLT, false); | 433 | if (di->chip == BQ27500) { |
395 | if (volt < 0) | 434 | if (di->cache.flags & BQ27500_FLAG_FC) |
396 | return volt; | 435 | level = POWER_SUPPLY_CAPACITY_LEVEL_FULL; |
436 | else if (di->cache.flags & BQ27500_FLAG_SOC1) | ||
437 | level = POWER_SUPPLY_CAPACITY_LEVEL_LOW; | ||
438 | else if (di->cache.flags & BQ27500_FLAG_SOCF) | ||
439 | level = POWER_SUPPLY_CAPACITY_LEVEL_CRITICAL; | ||
440 | else | ||
441 | level = POWER_SUPPLY_CAPACITY_LEVEL_NORMAL; | ||
442 | } else { | ||
443 | if (di->cache.flags & BQ27000_FLAG_FC) | ||
444 | level = POWER_SUPPLY_CAPACITY_LEVEL_FULL; | ||
445 | else if (di->cache.flags & BQ27000_FLAG_EDV1) | ||
446 | level = POWER_SUPPLY_CAPACITY_LEVEL_LOW; | ||
447 | else if (di->cache.flags & BQ27000_FLAG_EDVF) | ||
448 | level = POWER_SUPPLY_CAPACITY_LEVEL_CRITICAL; | ||
449 | else | ||
450 | level = POWER_SUPPLY_CAPACITY_LEVEL_NORMAL; | ||
451 | } | ||
397 | 452 | ||
398 | val->intval = volt * 1000; | 453 | val->intval = level; |
399 | 454 | ||
400 | return 0; | 455 | return 0; |
401 | } | 456 | } |
402 | 457 | ||
403 | /* | 458 | /* |
404 | * Return the battery Available energy in µWh | 459 | * Return the battery Voltage in milivolts |
405 | * Or < 0 if something fails. | 460 | * Or < 0 if something fails. |
406 | */ | 461 | */ |
407 | static int bq27x00_battery_energy(struct bq27x00_device_info *di, | 462 | static int bq27x00_battery_voltage(struct bq27x00_device_info *di, |
408 | union power_supply_propval *val) | 463 | union power_supply_propval *val) |
409 | { | 464 | { |
410 | int ae; | 465 | int volt; |
411 | 466 | ||
412 | ae = bq27x00_read(di, BQ27x00_REG_AE, false); | 467 | volt = bq27x00_read(di, BQ27x00_REG_VOLT, false); |
413 | if (ae < 0) { | 468 | if (volt < 0) { |
414 | dev_err(di->dev, "error reading available energy\n"); | 469 | dev_err(di->dev, "error reading voltage\n"); |
415 | return ae; | 470 | return volt; |
416 | } | 471 | } |
417 | 472 | ||
418 | if (di->chip == BQ27500) | 473 | val->intval = volt * 1000; |
419 | ae *= 1000; | ||
420 | else | ||
421 | ae = ae * 29200 / BQ27000_RS; | ||
422 | |||
423 | val->intval = ae; | ||
424 | 474 | ||
425 | return 0; | 475 | return 0; |
426 | } | 476 | } |
427 | 477 | ||
428 | |||
429 | static int bq27x00_simple_value(int value, | 478 | static int bq27x00_simple_value(int value, |
430 | union power_supply_propval *val) | 479 | union power_supply_propval *val) |
431 | { | 480 | { |
@@ -473,8 +522,11 @@ static int bq27x00_battery_get_property(struct power_supply *psy, | |||
473 | case POWER_SUPPLY_PROP_CAPACITY: | 522 | case POWER_SUPPLY_PROP_CAPACITY: |
474 | ret = bq27x00_simple_value(di->cache.capacity, val); | 523 | ret = bq27x00_simple_value(di->cache.capacity, val); |
475 | break; | 524 | break; |
525 | case POWER_SUPPLY_PROP_CAPACITY_LEVEL: | ||
526 | ret = bq27x00_battery_capacity_level(di, val); | ||
527 | break; | ||
476 | case POWER_SUPPLY_PROP_TEMP: | 528 | case POWER_SUPPLY_PROP_TEMP: |
477 | ret = bq27x00_battery_temperature(di, val); | 529 | ret = bq27x00_simple_value(di->cache.temperature, val); |
478 | break; | 530 | break; |
479 | case POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW: | 531 | case POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW: |
480 | ret = bq27x00_simple_value(di->cache.time_to_empty, val); | 532 | ret = bq27x00_simple_value(di->cache.time_to_empty, val); |
@@ -501,7 +553,7 @@ static int bq27x00_battery_get_property(struct power_supply *psy, | |||
501 | ret = bq27x00_simple_value(di->cache.cycle_count, val); | 553 | ret = bq27x00_simple_value(di->cache.cycle_count, val); |
502 | break; | 554 | break; |
503 | case POWER_SUPPLY_PROP_ENERGY_NOW: | 555 | case POWER_SUPPLY_PROP_ENERGY_NOW: |
504 | ret = bq27x00_battery_energy(di, val); | 556 | ret = bq27x00_simple_value(di->cache.energy, val); |
505 | break; | 557 | break; |
506 | default: | 558 | default: |
507 | return -EINVAL; | 559 | return -EINVAL; |
@@ -546,6 +598,14 @@ static int bq27x00_powersupply_init(struct bq27x00_device_info *di) | |||
546 | 598 | ||
547 | static void bq27x00_powersupply_unregister(struct bq27x00_device_info *di) | 599 | static void bq27x00_powersupply_unregister(struct bq27x00_device_info *di) |
548 | { | 600 | { |
601 | /* | ||
602 | * power_supply_unregister call bq27x00_battery_get_property which | ||
603 | * call bq27x00_battery_poll. | ||
604 | * Make sure that bq27x00_battery_poll will not call | ||
605 | * schedule_delayed_work again after unregister (which cause OOPS). | ||
606 | */ | ||
607 | poll_interval = 0; | ||
608 | |||
549 | cancel_delayed_work_sync(&di->work); | 609 | cancel_delayed_work_sync(&di->work); |
550 | 610 | ||
551 | power_supply_unregister(&di->bat); | 611 | power_supply_unregister(&di->bat); |
diff --git a/drivers/power/charger-manager.c b/drivers/power/charger-manager.c new file mode 100644 index 000000000000..0378d019efae --- /dev/null +++ b/drivers/power/charger-manager.c | |||
@@ -0,0 +1,1072 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2011 Samsung Electronics Co., Ltd. | ||
3 | * MyungJoo Ham <myungjoo.ham@samsung.com> | ||
4 | * | ||
5 | * This driver enables to monitor battery health and control charger | ||
6 | * during suspend-to-mem. | ||
7 | * Charger manager depends on other devices. register this later than | ||
8 | * the depending devices. | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of the GNU General Public License version 2 as | ||
12 | * published by the Free Software Foundation. | ||
13 | **/ | ||
14 | |||
15 | #include <linux/io.h> | ||
16 | #include <linux/module.h> | ||
17 | #include <linux/irq.h> | ||
18 | #include <linux/interrupt.h> | ||
19 | #include <linux/rtc.h> | ||
20 | #include <linux/slab.h> | ||
21 | #include <linux/workqueue.h> | ||
22 | #include <linux/platform_device.h> | ||
23 | #include <linux/power/charger-manager.h> | ||
24 | #include <linux/regulator/consumer.h> | ||
25 | |||
26 | /* | ||
27 | * Regard CM_JIFFIES_SMALL jiffies is small enough to ignore for | ||
28 | * delayed works so that we can run delayed works with CM_JIFFIES_SMALL | ||
29 | * without any delays. | ||
30 | */ | ||
31 | #define CM_JIFFIES_SMALL (2) | ||
32 | |||
33 | /* If y is valid (> 0) and smaller than x, do x = y */ | ||
34 | #define CM_MIN_VALID(x, y) x = (((y > 0) && ((x) > (y))) ? (y) : (x)) | ||
35 | |||
36 | /* | ||
37 | * Regard CM_RTC_SMALL (sec) is small enough to ignore error in invoking | ||
38 | * rtc alarm. It should be 2 or larger | ||
39 | */ | ||
40 | #define CM_RTC_SMALL (2) | ||
41 | |||
42 | #define UEVENT_BUF_SIZE 32 | ||
43 | |||
44 | static LIST_HEAD(cm_list); | ||
45 | static DEFINE_MUTEX(cm_list_mtx); | ||
46 | |||
47 | /* About in-suspend (suspend-again) monitoring */ | ||
48 | static struct rtc_device *rtc_dev; | ||
49 | /* | ||
50 | * Backup RTC alarm | ||
51 | * Save the wakeup alarm before entering suspend-to-RAM | ||
52 | */ | ||
53 | static struct rtc_wkalrm rtc_wkalarm_save; | ||
54 | /* Backup RTC alarm time in terms of seconds since 01-01-1970 00:00:00 */ | ||
55 | static unsigned long rtc_wkalarm_save_time; | ||
56 | static bool cm_suspended; | ||
57 | static bool cm_rtc_set; | ||
58 | static unsigned long cm_suspend_duration_ms; | ||
59 | |||
60 | /* Global charger-manager description */ | ||
61 | static struct charger_global_desc *g_desc; /* init with setup_charger_manager */ | ||
62 | |||
63 | /** | ||
64 | * is_batt_present - See if the battery presents in place. | ||
65 | * @cm: the Charger Manager representing the battery. | ||
66 | */ | ||
67 | static bool is_batt_present(struct charger_manager *cm) | ||
68 | { | ||
69 | union power_supply_propval val; | ||
70 | bool present = false; | ||
71 | int i, ret; | ||
72 | |||
73 | switch (cm->desc->battery_present) { | ||
74 | case CM_FUEL_GAUGE: | ||
75 | ret = cm->fuel_gauge->get_property(cm->fuel_gauge, | ||
76 | POWER_SUPPLY_PROP_PRESENT, &val); | ||
77 | if (ret == 0 && val.intval) | ||
78 | present = true; | ||
79 | break; | ||
80 | case CM_CHARGER_STAT: | ||
81 | for (i = 0; cm->charger_stat[i]; i++) { | ||
82 | ret = cm->charger_stat[i]->get_property( | ||
83 | cm->charger_stat[i], | ||
84 | POWER_SUPPLY_PROP_PRESENT, &val); | ||
85 | if (ret == 0 && val.intval) { | ||
86 | present = true; | ||
87 | break; | ||
88 | } | ||
89 | } | ||
90 | break; | ||
91 | } | ||
92 | |||
93 | return present; | ||
94 | } | ||
95 | |||
96 | /** | ||
97 | * is_ext_pwr_online - See if an external power source is attached to charge | ||
98 | * @cm: the Charger Manager representing the battery. | ||
99 | * | ||
100 | * Returns true if at least one of the chargers of the battery has an external | ||
101 | * power source attached to charge the battery regardless of whether it is | ||
102 | * actually charging or not. | ||
103 | */ | ||
104 | static bool is_ext_pwr_online(struct charger_manager *cm) | ||
105 | { | ||
106 | union power_supply_propval val; | ||
107 | bool online = false; | ||
108 | int i, ret; | ||
109 | |||
110 | /* If at least one of them has one, it's yes. */ | ||
111 | for (i = 0; cm->charger_stat[i]; i++) { | ||
112 | ret = cm->charger_stat[i]->get_property( | ||
113 | cm->charger_stat[i], | ||
114 | POWER_SUPPLY_PROP_ONLINE, &val); | ||
115 | if (ret == 0 && val.intval) { | ||
116 | online = true; | ||
117 | break; | ||
118 | } | ||
119 | } | ||
120 | |||
121 | return online; | ||
122 | } | ||
123 | |||
124 | /** | ||
125 | * get_batt_uV - Get the voltage level of the battery | ||
126 | * @cm: the Charger Manager representing the battery. | ||
127 | * @uV: the voltage level returned. | ||
128 | * | ||
129 | * Returns 0 if there is no error. | ||
130 | * Returns a negative value on error. | ||
131 | */ | ||
132 | static int get_batt_uV(struct charger_manager *cm, int *uV) | ||
133 | { | ||
134 | union power_supply_propval val; | ||
135 | int ret; | ||
136 | |||
137 | if (cm->fuel_gauge) | ||
138 | ret = cm->fuel_gauge->get_property(cm->fuel_gauge, | ||
139 | POWER_SUPPLY_PROP_VOLTAGE_NOW, &val); | ||
140 | else | ||
141 | return -ENODEV; | ||
142 | |||
143 | if (ret) | ||
144 | return ret; | ||
145 | |||
146 | *uV = val.intval; | ||
147 | return 0; | ||
148 | } | ||
149 | |||
150 | /** | ||
151 | * is_charging - Returns true if the battery is being charged. | ||
152 | * @cm: the Charger Manager representing the battery. | ||
153 | */ | ||
154 | static bool is_charging(struct charger_manager *cm) | ||
155 | { | ||
156 | int i, ret; | ||
157 | bool charging = false; | ||
158 | union power_supply_propval val; | ||
159 | |||
160 | /* If there is no battery, it cannot be charged */ | ||
161 | if (!is_batt_present(cm)) | ||
162 | return false; | ||
163 | |||
164 | /* If at least one of the charger is charging, return yes */ | ||
165 | for (i = 0; cm->charger_stat[i]; i++) { | ||
166 | /* 1. The charger sholuld not be DISABLED */ | ||
167 | if (cm->emergency_stop) | ||
168 | continue; | ||
169 | if (!cm->charger_enabled) | ||
170 | continue; | ||
171 | |||
172 | /* 2. The charger should be online (ext-power) */ | ||
173 | ret = cm->charger_stat[i]->get_property( | ||
174 | cm->charger_stat[i], | ||
175 | POWER_SUPPLY_PROP_ONLINE, &val); | ||
176 | if (ret) { | ||
177 | dev_warn(cm->dev, "Cannot read ONLINE value from %s.\n", | ||
178 | cm->desc->psy_charger_stat[i]); | ||
179 | continue; | ||
180 | } | ||
181 | if (val.intval == 0) | ||
182 | continue; | ||
183 | |||
184 | /* | ||
185 | * 3. The charger should not be FULL, DISCHARGING, | ||
186 | * or NOT_CHARGING. | ||
187 | */ | ||
188 | ret = cm->charger_stat[i]->get_property( | ||
189 | cm->charger_stat[i], | ||
190 | POWER_SUPPLY_PROP_STATUS, &val); | ||
191 | if (ret) { | ||
192 | dev_warn(cm->dev, "Cannot read STATUS value from %s.\n", | ||
193 | cm->desc->psy_charger_stat[i]); | ||
194 | continue; | ||
195 | } | ||
196 | if (val.intval == POWER_SUPPLY_STATUS_FULL || | ||
197 | val.intval == POWER_SUPPLY_STATUS_DISCHARGING || | ||
198 | val.intval == POWER_SUPPLY_STATUS_NOT_CHARGING) | ||
199 | continue; | ||
200 | |||
201 | /* Then, this is charging. */ | ||
202 | charging = true; | ||
203 | break; | ||
204 | } | ||
205 | |||
206 | return charging; | ||
207 | } | ||
208 | |||
209 | /** | ||
210 | * is_polling_required - Return true if need to continue polling for this CM. | ||
211 | * @cm: the Charger Manager representing the battery. | ||
212 | */ | ||
213 | static bool is_polling_required(struct charger_manager *cm) | ||
214 | { | ||
215 | switch (cm->desc->polling_mode) { | ||
216 | case CM_POLL_DISABLE: | ||
217 | return false; | ||
218 | case CM_POLL_ALWAYS: | ||
219 | return true; | ||
220 | case CM_POLL_EXTERNAL_POWER_ONLY: | ||
221 | return is_ext_pwr_online(cm); | ||
222 | case CM_POLL_CHARGING_ONLY: | ||
223 | return is_charging(cm); | ||
224 | default: | ||
225 | dev_warn(cm->dev, "Incorrect polling_mode (%d)\n", | ||
226 | cm->desc->polling_mode); | ||
227 | } | ||
228 | |||
229 | return false; | ||
230 | } | ||
231 | |||
232 | /** | ||
233 | * try_charger_enable - Enable/Disable chargers altogether | ||
234 | * @cm: the Charger Manager representing the battery. | ||
235 | * @enable: true: enable / false: disable | ||
236 | * | ||
237 | * Note that Charger Manager keeps the charger enabled regardless whether | ||
238 | * the charger is charging or not (because battery is full or no external | ||
239 | * power source exists) except when CM needs to disable chargers forcibly | ||
240 | * bacause of emergency causes; when the battery is overheated or too cold. | ||
241 | */ | ||
242 | static int try_charger_enable(struct charger_manager *cm, bool enable) | ||
243 | { | ||
244 | int err = 0, i; | ||
245 | struct charger_desc *desc = cm->desc; | ||
246 | |||
247 | /* Ignore if it's redundent command */ | ||
248 | if (enable && cm->charger_enabled) | ||
249 | return 0; | ||
250 | if (!enable && !cm->charger_enabled) | ||
251 | return 0; | ||
252 | |||
253 | if (enable) { | ||
254 | if (cm->emergency_stop) | ||
255 | return -EAGAIN; | ||
256 | err = regulator_bulk_enable(desc->num_charger_regulators, | ||
257 | desc->charger_regulators); | ||
258 | } else { | ||
259 | /* | ||
260 | * Abnormal battery state - Stop charging forcibly, | ||
261 | * even if charger was enabled at the other places | ||
262 | */ | ||
263 | err = regulator_bulk_disable(desc->num_charger_regulators, | ||
264 | desc->charger_regulators); | ||
265 | |||
266 | for (i = 0; i < desc->num_charger_regulators; i++) { | ||
267 | if (regulator_is_enabled( | ||
268 | desc->charger_regulators[i].consumer)) { | ||
269 | regulator_force_disable( | ||
270 | desc->charger_regulators[i].consumer); | ||
271 | dev_warn(cm->dev, | ||
272 | "Disable regulator(%s) forcibly.\n", | ||
273 | desc->charger_regulators[i].supply); | ||
274 | } | ||
275 | } | ||
276 | } | ||
277 | |||
278 | if (!err) | ||
279 | cm->charger_enabled = enable; | ||
280 | |||
281 | return err; | ||
282 | } | ||
283 | |||
284 | /** | ||
285 | * uevent_notify - Let users know something has changed. | ||
286 | * @cm: the Charger Manager representing the battery. | ||
287 | * @event: the event string. | ||
288 | * | ||
289 | * If @event is null, it implies that uevent_notify is called | ||
290 | * by resume function. When called in the resume function, cm_suspended | ||
291 | * should be already reset to false in order to let uevent_notify | ||
292 | * notify the recent event during the suspend to users. While | ||
293 | * suspended, uevent_notify does not notify users, but tracks | ||
294 | * events so that uevent_notify can notify users later after resumed. | ||
295 | */ | ||
296 | static void uevent_notify(struct charger_manager *cm, const char *event) | ||
297 | { | ||
298 | static char env_str[UEVENT_BUF_SIZE + 1] = ""; | ||
299 | static char env_str_save[UEVENT_BUF_SIZE + 1] = ""; | ||
300 | |||
301 | if (cm_suspended) { | ||
302 | /* Nothing in suspended-event buffer */ | ||
303 | if (env_str_save[0] == 0) { | ||
304 | if (!strncmp(env_str, event, UEVENT_BUF_SIZE)) | ||
305 | return; /* status not changed */ | ||
306 | strncpy(env_str_save, event, UEVENT_BUF_SIZE); | ||
307 | return; | ||
308 | } | ||
309 | |||
310 | if (!strncmp(env_str_save, event, UEVENT_BUF_SIZE)) | ||
311 | return; /* Duplicated. */ | ||
312 | else | ||
313 | strncpy(env_str_save, event, UEVENT_BUF_SIZE); | ||
314 | |||
315 | return; | ||
316 | } | ||
317 | |||
318 | if (event == NULL) { | ||
319 | /* No messages pending */ | ||
320 | if (!env_str_save[0]) | ||
321 | return; | ||
322 | |||
323 | strncpy(env_str, env_str_save, UEVENT_BUF_SIZE); | ||
324 | kobject_uevent(&cm->dev->kobj, KOBJ_CHANGE); | ||
325 | env_str_save[0] = 0; | ||
326 | |||
327 | return; | ||
328 | } | ||
329 | |||
330 | /* status not changed */ | ||
331 | if (!strncmp(env_str, event, UEVENT_BUF_SIZE)) | ||
332 | return; | ||
333 | |||
334 | /* save the status and notify the update */ | ||
335 | strncpy(env_str, event, UEVENT_BUF_SIZE); | ||
336 | kobject_uevent(&cm->dev->kobj, KOBJ_CHANGE); | ||
337 | |||
338 | dev_info(cm->dev, event); | ||
339 | } | ||
340 | |||
341 | /** | ||
342 | * _cm_monitor - Monitor the temperature and return true for exceptions. | ||
343 | * @cm: the Charger Manager representing the battery. | ||
344 | * | ||
345 | * Returns true if there is an event to notify for the battery. | ||
346 | * (True if the status of "emergency_stop" changes) | ||
347 | */ | ||
348 | static bool _cm_monitor(struct charger_manager *cm) | ||
349 | { | ||
350 | struct charger_desc *desc = cm->desc; | ||
351 | int temp = desc->temperature_out_of_range(&cm->last_temp_mC); | ||
352 | |||
353 | dev_dbg(cm->dev, "monitoring (%2.2d.%3.3dC)\n", | ||
354 | cm->last_temp_mC / 1000, cm->last_temp_mC % 1000); | ||
355 | |||
356 | /* It has been stopped or charging already */ | ||
357 | if (!!temp == !!cm->emergency_stop) | ||
358 | return false; | ||
359 | |||
360 | if (temp) { | ||
361 | cm->emergency_stop = temp; | ||
362 | if (!try_charger_enable(cm, false)) { | ||
363 | if (temp > 0) | ||
364 | uevent_notify(cm, "OVERHEAT"); | ||
365 | else | ||
366 | uevent_notify(cm, "COLD"); | ||
367 | } | ||
368 | } else { | ||
369 | cm->emergency_stop = 0; | ||
370 | if (!try_charger_enable(cm, true)) | ||
371 | uevent_notify(cm, "CHARGING"); | ||
372 | } | ||
373 | |||
374 | return true; | ||
375 | } | ||
376 | |||
377 | /** | ||
378 | * cm_monitor - Monitor every battery. | ||
379 | * | ||
380 | * Returns true if there is an event to notify from any of the batteries. | ||
381 | * (True if the status of "emergency_stop" changes) | ||
382 | */ | ||
383 | static bool cm_monitor(void) | ||
384 | { | ||
385 | bool stop = false; | ||
386 | struct charger_manager *cm; | ||
387 | |||
388 | mutex_lock(&cm_list_mtx); | ||
389 | |||
390 | list_for_each_entry(cm, &cm_list, entry) | ||
391 | stop = stop || _cm_monitor(cm); | ||
392 | |||
393 | mutex_unlock(&cm_list_mtx); | ||
394 | |||
395 | return stop; | ||
396 | } | ||
397 | |||
398 | static int charger_get_property(struct power_supply *psy, | ||
399 | enum power_supply_property psp, | ||
400 | union power_supply_propval *val) | ||
401 | { | ||
402 | struct charger_manager *cm = container_of(psy, | ||
403 | struct charger_manager, charger_psy); | ||
404 | struct charger_desc *desc = cm->desc; | ||
405 | int i, ret = 0, uV; | ||
406 | |||
407 | switch (psp) { | ||
408 | case POWER_SUPPLY_PROP_STATUS: | ||
409 | if (is_charging(cm)) | ||
410 | val->intval = POWER_SUPPLY_STATUS_CHARGING; | ||
411 | else if (is_ext_pwr_online(cm)) | ||
412 | val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING; | ||
413 | else | ||
414 | val->intval = POWER_SUPPLY_STATUS_DISCHARGING; | ||
415 | break; | ||
416 | case POWER_SUPPLY_PROP_HEALTH: | ||
417 | if (cm->emergency_stop > 0) | ||
418 | val->intval = POWER_SUPPLY_HEALTH_OVERHEAT; | ||
419 | else if (cm->emergency_stop < 0) | ||
420 | val->intval = POWER_SUPPLY_HEALTH_COLD; | ||
421 | else | ||
422 | val->intval = POWER_SUPPLY_HEALTH_GOOD; | ||
423 | break; | ||
424 | case POWER_SUPPLY_PROP_PRESENT: | ||
425 | if (is_batt_present(cm)) | ||
426 | val->intval = 1; | ||
427 | else | ||
428 | val->intval = 0; | ||
429 | break; | ||
430 | case POWER_SUPPLY_PROP_VOLTAGE_NOW: | ||
431 | ret = get_batt_uV(cm, &i); | ||
432 | val->intval = i; | ||
433 | break; | ||
434 | case POWER_SUPPLY_PROP_CURRENT_NOW: | ||
435 | ret = cm->fuel_gauge->get_property(cm->fuel_gauge, | ||
436 | POWER_SUPPLY_PROP_CURRENT_NOW, val); | ||
437 | break; | ||
438 | case POWER_SUPPLY_PROP_TEMP: | ||
439 | /* in thenth of centigrade */ | ||
440 | if (cm->last_temp_mC == INT_MIN) | ||
441 | desc->temperature_out_of_range(&cm->last_temp_mC); | ||
442 | val->intval = cm->last_temp_mC / 100; | ||
443 | if (!desc->measure_battery_temp) | ||
444 | ret = -ENODEV; | ||
445 | break; | ||
446 | case POWER_SUPPLY_PROP_TEMP_AMBIENT: | ||
447 | /* in thenth of centigrade */ | ||
448 | if (cm->last_temp_mC == INT_MIN) | ||
449 | desc->temperature_out_of_range(&cm->last_temp_mC); | ||
450 | val->intval = cm->last_temp_mC / 100; | ||
451 | if (desc->measure_battery_temp) | ||
452 | ret = -ENODEV; | ||
453 | break; | ||
454 | case POWER_SUPPLY_PROP_CAPACITY: | ||
455 | if (!cm->fuel_gauge) { | ||
456 | ret = -ENODEV; | ||
457 | break; | ||
458 | } | ||
459 | |||
460 | if (!is_batt_present(cm)) { | ||
461 | /* There is no battery. Assume 100% */ | ||
462 | val->intval = 100; | ||
463 | break; | ||
464 | } | ||
465 | |||
466 | ret = cm->fuel_gauge->get_property(cm->fuel_gauge, | ||
467 | POWER_SUPPLY_PROP_CAPACITY, val); | ||
468 | if (ret) | ||
469 | break; | ||
470 | |||
471 | if (val->intval > 100) { | ||
472 | val->intval = 100; | ||
473 | break; | ||
474 | } | ||
475 | if (val->intval < 0) | ||
476 | val->intval = 0; | ||
477 | |||
478 | /* Do not adjust SOC when charging: voltage is overrated */ | ||
479 | if (is_charging(cm)) | ||
480 | break; | ||
481 | |||
482 | /* | ||
483 | * If the capacity value is inconsistent, calibrate it base on | ||
484 | * the battery voltage values and the thresholds given as desc | ||
485 | */ | ||
486 | ret = get_batt_uV(cm, &uV); | ||
487 | if (ret) { | ||
488 | /* Voltage information not available. No calibration */ | ||
489 | ret = 0; | ||
490 | break; | ||
491 | } | ||
492 | |||
493 | if (desc->fullbatt_uV > 0 && uV >= desc->fullbatt_uV && | ||
494 | !is_charging(cm)) { | ||
495 | val->intval = 100; | ||
496 | break; | ||
497 | } | ||
498 | |||
499 | break; | ||
500 | case POWER_SUPPLY_PROP_ONLINE: | ||
501 | if (is_ext_pwr_online(cm)) | ||
502 | val->intval = 1; | ||
503 | else | ||
504 | val->intval = 0; | ||
505 | break; | ||
506 | case POWER_SUPPLY_PROP_CHARGE_FULL: | ||
507 | if (cm->fuel_gauge) { | ||
508 | if (cm->fuel_gauge->get_property(cm->fuel_gauge, | ||
509 | POWER_SUPPLY_PROP_CHARGE_FULL, val) == 0) | ||
510 | break; | ||
511 | } | ||
512 | |||
513 | if (is_ext_pwr_online(cm)) { | ||
514 | /* Not full if it's charging. */ | ||
515 | if (is_charging(cm)) { | ||
516 | val->intval = 0; | ||
517 | break; | ||
518 | } | ||
519 | /* | ||
520 | * Full if it's powered but not charging andi | ||
521 | * not forced stop by emergency | ||
522 | */ | ||
523 | if (!cm->emergency_stop) { | ||
524 | val->intval = 1; | ||
525 | break; | ||
526 | } | ||
527 | } | ||
528 | |||
529 | /* Full if it's over the fullbatt voltage */ | ||
530 | ret = get_batt_uV(cm, &uV); | ||
531 | if (!ret && desc->fullbatt_uV > 0 && uV >= desc->fullbatt_uV && | ||
532 | !is_charging(cm)) { | ||
533 | val->intval = 1; | ||
534 | break; | ||
535 | } | ||
536 | |||
537 | /* Full if the cap is 100 */ | ||
538 | if (cm->fuel_gauge) { | ||
539 | ret = cm->fuel_gauge->get_property(cm->fuel_gauge, | ||
540 | POWER_SUPPLY_PROP_CAPACITY, val); | ||
541 | if (!ret && val->intval >= 100 && !is_charging(cm)) { | ||
542 | val->intval = 1; | ||
543 | break; | ||
544 | } | ||
545 | } | ||
546 | |||
547 | val->intval = 0; | ||
548 | ret = 0; | ||
549 | break; | ||
550 | case POWER_SUPPLY_PROP_CHARGE_NOW: | ||
551 | if (is_charging(cm)) { | ||
552 | ret = cm->fuel_gauge->get_property(cm->fuel_gauge, | ||
553 | POWER_SUPPLY_PROP_CHARGE_NOW, | ||
554 | val); | ||
555 | if (ret) { | ||
556 | val->intval = 1; | ||
557 | ret = 0; | ||
558 | } else { | ||
559 | /* If CHARGE_NOW is supplied, use it */ | ||
560 | val->intval = (val->intval > 0) ? | ||
561 | val->intval : 1; | ||
562 | } | ||
563 | } else { | ||
564 | val->intval = 0; | ||
565 | } | ||
566 | break; | ||
567 | default: | ||
568 | return -EINVAL; | ||
569 | } | ||
570 | return ret; | ||
571 | } | ||
572 | |||
573 | #define NUM_CHARGER_PSY_OPTIONAL (4) | ||
574 | static enum power_supply_property default_charger_props[] = { | ||
575 | /* Guaranteed to provide */ | ||
576 | POWER_SUPPLY_PROP_STATUS, | ||
577 | POWER_SUPPLY_PROP_HEALTH, | ||
578 | POWER_SUPPLY_PROP_PRESENT, | ||
579 | POWER_SUPPLY_PROP_VOLTAGE_NOW, | ||
580 | POWER_SUPPLY_PROP_CAPACITY, | ||
581 | POWER_SUPPLY_PROP_ONLINE, | ||
582 | POWER_SUPPLY_PROP_CHARGE_FULL, | ||
583 | /* | ||
584 | * Optional properties are: | ||
585 | * POWER_SUPPLY_PROP_CHARGE_NOW, | ||
586 | * POWER_SUPPLY_PROP_CURRENT_NOW, | ||
587 | * POWER_SUPPLY_PROP_TEMP, and | ||
588 | * POWER_SUPPLY_PROP_TEMP_AMBIENT, | ||
589 | */ | ||
590 | }; | ||
591 | |||
592 | static struct power_supply psy_default = { | ||
593 | .name = "battery", | ||
594 | .type = POWER_SUPPLY_TYPE_BATTERY, | ||
595 | .properties = default_charger_props, | ||
596 | .num_properties = ARRAY_SIZE(default_charger_props), | ||
597 | .get_property = charger_get_property, | ||
598 | }; | ||
599 | |||
600 | /** | ||
601 | * cm_setup_timer - For in-suspend monitoring setup wakeup alarm | ||
602 | * for suspend_again. | ||
603 | * | ||
604 | * Returns true if the alarm is set for Charger Manager to use. | ||
605 | * Returns false if | ||
606 | * cm_setup_timer fails to set an alarm, | ||
607 | * cm_setup_timer does not need to set an alarm for Charger Manager, | ||
608 | * or an alarm previously configured is to be used. | ||
609 | */ | ||
610 | static bool cm_setup_timer(void) | ||
611 | { | ||
612 | struct charger_manager *cm; | ||
613 | unsigned int wakeup_ms = UINT_MAX; | ||
614 | bool ret = false; | ||
615 | |||
616 | mutex_lock(&cm_list_mtx); | ||
617 | |||
618 | list_for_each_entry(cm, &cm_list, entry) { | ||
619 | /* Skip if polling is not required for this CM */ | ||
620 | if (!is_polling_required(cm) && !cm->emergency_stop) | ||
621 | continue; | ||
622 | if (cm->desc->polling_interval_ms == 0) | ||
623 | continue; | ||
624 | CM_MIN_VALID(wakeup_ms, cm->desc->polling_interval_ms); | ||
625 | } | ||
626 | |||
627 | mutex_unlock(&cm_list_mtx); | ||
628 | |||
629 | if (wakeup_ms < UINT_MAX && wakeup_ms > 0) { | ||
630 | pr_info("Charger Manager wakeup timer: %u ms.\n", wakeup_ms); | ||
631 | if (rtc_dev) { | ||
632 | struct rtc_wkalrm tmp; | ||
633 | unsigned long time, now; | ||
634 | unsigned long add = DIV_ROUND_UP(wakeup_ms, 1000); | ||
635 | |||
636 | /* | ||
637 | * Set alarm with the polling interval (wakeup_ms) | ||
638 | * except when rtc_wkalarm_save comes first. | ||
639 | * However, the alarm time should be NOW + | ||
640 | * CM_RTC_SMALL or later. | ||
641 | */ | ||
642 | tmp.enabled = 1; | ||
643 | rtc_read_time(rtc_dev, &tmp.time); | ||
644 | rtc_tm_to_time(&tmp.time, &now); | ||
645 | if (add < CM_RTC_SMALL) | ||
646 | add = CM_RTC_SMALL; | ||
647 | time = now + add; | ||
648 | |||
649 | ret = true; | ||
650 | |||
651 | if (rtc_wkalarm_save.enabled && | ||
652 | rtc_wkalarm_save_time && | ||
653 | rtc_wkalarm_save_time < time) { | ||
654 | if (rtc_wkalarm_save_time < now + CM_RTC_SMALL) | ||
655 | time = now + CM_RTC_SMALL; | ||
656 | else | ||
657 | time = rtc_wkalarm_save_time; | ||
658 | |||
659 | /* The timer is not appointed by CM */ | ||
660 | ret = false; | ||
661 | } | ||
662 | |||
663 | pr_info("Waking up after %lu secs.\n", | ||
664 | time - now); | ||
665 | |||
666 | rtc_time_to_tm(time, &tmp.time); | ||
667 | rtc_set_alarm(rtc_dev, &tmp); | ||
668 | cm_suspend_duration_ms += wakeup_ms; | ||
669 | return ret; | ||
670 | } | ||
671 | } | ||
672 | |||
673 | if (rtc_dev) | ||
674 | rtc_set_alarm(rtc_dev, &rtc_wkalarm_save); | ||
675 | return false; | ||
676 | } | ||
677 | |||
678 | /** | ||
679 | * cm_suspend_again - Determine whether suspend again or not | ||
680 | * | ||
681 | * Returns true if the system should be suspended again | ||
682 | * Returns false if the system should be woken up | ||
683 | */ | ||
684 | bool cm_suspend_again(void) | ||
685 | { | ||
686 | struct charger_manager *cm; | ||
687 | bool ret = false; | ||
688 | |||
689 | if (!g_desc || !g_desc->rtc_only_wakeup || !g_desc->rtc_only_wakeup() || | ||
690 | !cm_rtc_set) | ||
691 | return false; | ||
692 | |||
693 | if (cm_monitor()) | ||
694 | goto out; | ||
695 | |||
696 | ret = true; | ||
697 | mutex_lock(&cm_list_mtx); | ||
698 | list_for_each_entry(cm, &cm_list, entry) { | ||
699 | if (cm->status_save_ext_pwr_inserted != is_ext_pwr_online(cm) || | ||
700 | cm->status_save_batt != is_batt_present(cm)) | ||
701 | ret = false; | ||
702 | } | ||
703 | mutex_unlock(&cm_list_mtx); | ||
704 | |||
705 | cm_rtc_set = cm_setup_timer(); | ||
706 | out: | ||
707 | /* It's about the time when the non-CM appointed timer goes off */ | ||
708 | if (rtc_wkalarm_save.enabled) { | ||
709 | unsigned long now; | ||
710 | struct rtc_time tmp; | ||
711 | |||
712 | rtc_read_time(rtc_dev, &tmp); | ||
713 | rtc_tm_to_time(&tmp, &now); | ||
714 | |||
715 | if (rtc_wkalarm_save_time && | ||
716 | now + CM_RTC_SMALL >= rtc_wkalarm_save_time) | ||
717 | return false; | ||
718 | } | ||
719 | return ret; | ||
720 | } | ||
721 | EXPORT_SYMBOL_GPL(cm_suspend_again); | ||
722 | |||
723 | /** | ||
724 | * setup_charger_manager - initialize charger_global_desc data | ||
725 | * @gd: pointer to instance of charger_global_desc | ||
726 | */ | ||
727 | int setup_charger_manager(struct charger_global_desc *gd) | ||
728 | { | ||
729 | if (!gd) | ||
730 | return -EINVAL; | ||
731 | |||
732 | if (rtc_dev) | ||
733 | rtc_class_close(rtc_dev); | ||
734 | rtc_dev = NULL; | ||
735 | g_desc = NULL; | ||
736 | |||
737 | if (!gd->rtc_only_wakeup) { | ||
738 | pr_err("The callback rtc_only_wakeup is not given.\n"); | ||
739 | return -EINVAL; | ||
740 | } | ||
741 | |||
742 | if (gd->rtc_name) { | ||
743 | rtc_dev = rtc_class_open(gd->rtc_name); | ||
744 | if (IS_ERR_OR_NULL(rtc_dev)) { | ||
745 | rtc_dev = NULL; | ||
746 | /* Retry at probe. RTC may be not registered yet */ | ||
747 | } | ||
748 | } else { | ||
749 | pr_warn("No wakeup timer is given for charger manager." | ||
750 | "In-suspend monitoring won't work.\n"); | ||
751 | } | ||
752 | |||
753 | g_desc = gd; | ||
754 | return 0; | ||
755 | } | ||
756 | EXPORT_SYMBOL_GPL(setup_charger_manager); | ||
757 | |||
758 | static int charger_manager_probe(struct platform_device *pdev) | ||
759 | { | ||
760 | struct charger_desc *desc = dev_get_platdata(&pdev->dev); | ||
761 | struct charger_manager *cm; | ||
762 | int ret = 0, i = 0; | ||
763 | union power_supply_propval val; | ||
764 | |||
765 | if (g_desc && !rtc_dev && g_desc->rtc_name) { | ||
766 | rtc_dev = rtc_class_open(g_desc->rtc_name); | ||
767 | if (IS_ERR_OR_NULL(rtc_dev)) { | ||
768 | rtc_dev = NULL; | ||
769 | dev_err(&pdev->dev, "Cannot get RTC %s.\n", | ||
770 | g_desc->rtc_name); | ||
771 | ret = -ENODEV; | ||
772 | goto err_alloc; | ||
773 | } | ||
774 | } | ||
775 | |||
776 | if (!desc) { | ||
777 | dev_err(&pdev->dev, "No platform data (desc) found.\n"); | ||
778 | ret = -ENODEV; | ||
779 | goto err_alloc; | ||
780 | } | ||
781 | |||
782 | cm = kzalloc(sizeof(struct charger_manager), GFP_KERNEL); | ||
783 | if (!cm) { | ||
784 | dev_err(&pdev->dev, "Cannot allocate memory.\n"); | ||
785 | ret = -ENOMEM; | ||
786 | goto err_alloc; | ||
787 | } | ||
788 | |||
789 | /* Basic Values. Unspecified are Null or 0 */ | ||
790 | cm->dev = &pdev->dev; | ||
791 | cm->desc = kzalloc(sizeof(struct charger_desc), GFP_KERNEL); | ||
792 | if (!cm->desc) { | ||
793 | dev_err(&pdev->dev, "Cannot allocate memory.\n"); | ||
794 | ret = -ENOMEM; | ||
795 | goto err_alloc_desc; | ||
796 | } | ||
797 | memcpy(cm->desc, desc, sizeof(struct charger_desc)); | ||
798 | cm->last_temp_mC = INT_MIN; /* denotes "unmeasured, yet" */ | ||
799 | |||
800 | if (!desc->charger_regulators || desc->num_charger_regulators < 1) { | ||
801 | ret = -EINVAL; | ||
802 | dev_err(&pdev->dev, "charger_regulators undefined.\n"); | ||
803 | goto err_no_charger; | ||
804 | } | ||
805 | |||
806 | if (!desc->psy_charger_stat || !desc->psy_charger_stat[0]) { | ||
807 | dev_err(&pdev->dev, "No power supply defined.\n"); | ||
808 | ret = -EINVAL; | ||
809 | goto err_no_charger_stat; | ||
810 | } | ||
811 | |||
812 | /* Counting index only */ | ||
813 | while (desc->psy_charger_stat[i]) | ||
814 | i++; | ||
815 | |||
816 | cm->charger_stat = kzalloc(sizeof(struct power_supply *) * (i + 1), | ||
817 | GFP_KERNEL); | ||
818 | if (!cm->charger_stat) { | ||
819 | ret = -ENOMEM; | ||
820 | goto err_no_charger_stat; | ||
821 | } | ||
822 | |||
823 | for (i = 0; desc->psy_charger_stat[i]; i++) { | ||
824 | cm->charger_stat[i] = power_supply_get_by_name( | ||
825 | desc->psy_charger_stat[i]); | ||
826 | if (!cm->charger_stat[i]) { | ||
827 | dev_err(&pdev->dev, "Cannot find power supply " | ||
828 | "\"%s\"\n", | ||
829 | desc->psy_charger_stat[i]); | ||
830 | ret = -ENODEV; | ||
831 | goto err_chg_stat; | ||
832 | } | ||
833 | } | ||
834 | |||
835 | cm->fuel_gauge = power_supply_get_by_name(desc->psy_fuel_gauge); | ||
836 | if (!cm->fuel_gauge) { | ||
837 | dev_err(&pdev->dev, "Cannot find power supply \"%s\"\n", | ||
838 | desc->psy_fuel_gauge); | ||
839 | ret = -ENODEV; | ||
840 | goto err_chg_stat; | ||
841 | } | ||
842 | |||
843 | if (desc->polling_interval_ms == 0 || | ||
844 | msecs_to_jiffies(desc->polling_interval_ms) <= CM_JIFFIES_SMALL) { | ||
845 | dev_err(&pdev->dev, "polling_interval_ms is too small\n"); | ||
846 | ret = -EINVAL; | ||
847 | goto err_chg_stat; | ||
848 | } | ||
849 | |||
850 | if (!desc->temperature_out_of_range) { | ||
851 | dev_err(&pdev->dev, "there is no temperature_out_of_range\n"); | ||
852 | ret = -EINVAL; | ||
853 | goto err_chg_stat; | ||
854 | } | ||
855 | |||
856 | platform_set_drvdata(pdev, cm); | ||
857 | |||
858 | memcpy(&cm->charger_psy, &psy_default, | ||
859 | sizeof(psy_default)); | ||
860 | if (!desc->psy_name) { | ||
861 | strncpy(cm->psy_name_buf, psy_default.name, | ||
862 | PSY_NAME_MAX); | ||
863 | } else { | ||
864 | strncpy(cm->psy_name_buf, desc->psy_name, PSY_NAME_MAX); | ||
865 | } | ||
866 | cm->charger_psy.name = cm->psy_name_buf; | ||
867 | |||
868 | /* Allocate for psy properties because they may vary */ | ||
869 | cm->charger_psy.properties = kzalloc(sizeof(enum power_supply_property) | ||
870 | * (ARRAY_SIZE(default_charger_props) + | ||
871 | NUM_CHARGER_PSY_OPTIONAL), | ||
872 | GFP_KERNEL); | ||
873 | if (!cm->charger_psy.properties) { | ||
874 | dev_err(&pdev->dev, "Cannot allocate for psy properties.\n"); | ||
875 | ret = -ENOMEM; | ||
876 | goto err_chg_stat; | ||
877 | } | ||
878 | memcpy(cm->charger_psy.properties, default_charger_props, | ||
879 | sizeof(enum power_supply_property) * | ||
880 | ARRAY_SIZE(default_charger_props)); | ||
881 | cm->charger_psy.num_properties = psy_default.num_properties; | ||
882 | |||
883 | /* Find which optional psy-properties are available */ | ||
884 | if (!cm->fuel_gauge->get_property(cm->fuel_gauge, | ||
885 | POWER_SUPPLY_PROP_CHARGE_NOW, &val)) { | ||
886 | cm->charger_psy.properties[cm->charger_psy.num_properties] = | ||
887 | POWER_SUPPLY_PROP_CHARGE_NOW; | ||
888 | cm->charger_psy.num_properties++; | ||
889 | } | ||
890 | if (!cm->fuel_gauge->get_property(cm->fuel_gauge, | ||
891 | POWER_SUPPLY_PROP_CURRENT_NOW, | ||
892 | &val)) { | ||
893 | cm->charger_psy.properties[cm->charger_psy.num_properties] = | ||
894 | POWER_SUPPLY_PROP_CURRENT_NOW; | ||
895 | cm->charger_psy.num_properties++; | ||
896 | } | ||
897 | if (!desc->measure_battery_temp) { | ||
898 | cm->charger_psy.properties[cm->charger_psy.num_properties] = | ||
899 | POWER_SUPPLY_PROP_TEMP_AMBIENT; | ||
900 | cm->charger_psy.num_properties++; | ||
901 | } | ||
902 | if (desc->measure_battery_temp) { | ||
903 | cm->charger_psy.properties[cm->charger_psy.num_properties] = | ||
904 | POWER_SUPPLY_PROP_TEMP; | ||
905 | cm->charger_psy.num_properties++; | ||
906 | } | ||
907 | |||
908 | ret = power_supply_register(NULL, &cm->charger_psy); | ||
909 | if (ret) { | ||
910 | dev_err(&pdev->dev, "Cannot register charger-manager with" | ||
911 | " name \"%s\".\n", cm->charger_psy.name); | ||
912 | goto err_register; | ||
913 | } | ||
914 | |||
915 | ret = regulator_bulk_get(&pdev->dev, desc->num_charger_regulators, | ||
916 | desc->charger_regulators); | ||
917 | if (ret) { | ||
918 | dev_err(&pdev->dev, "Cannot get charger regulators.\n"); | ||
919 | goto err_bulk_get; | ||
920 | } | ||
921 | |||
922 | ret = try_charger_enable(cm, true); | ||
923 | if (ret) { | ||
924 | dev_err(&pdev->dev, "Cannot enable charger regulators\n"); | ||
925 | goto err_chg_enable; | ||
926 | } | ||
927 | |||
928 | /* Add to the list */ | ||
929 | mutex_lock(&cm_list_mtx); | ||
930 | list_add(&cm->entry, &cm_list); | ||
931 | mutex_unlock(&cm_list_mtx); | ||
932 | |||
933 | return 0; | ||
934 | |||
935 | err_chg_enable: | ||
936 | if (desc->charger_regulators) | ||
937 | regulator_bulk_free(desc->num_charger_regulators, | ||
938 | desc->charger_regulators); | ||
939 | err_bulk_get: | ||
940 | power_supply_unregister(&cm->charger_psy); | ||
941 | err_register: | ||
942 | kfree(cm->charger_psy.properties); | ||
943 | err_chg_stat: | ||
944 | kfree(cm->charger_stat); | ||
945 | err_no_charger_stat: | ||
946 | err_no_charger: | ||
947 | kfree(cm->desc); | ||
948 | err_alloc_desc: | ||
949 | kfree(cm); | ||
950 | err_alloc: | ||
951 | return ret; | ||
952 | } | ||
953 | |||
954 | static int __devexit charger_manager_remove(struct platform_device *pdev) | ||
955 | { | ||
956 | struct charger_manager *cm = platform_get_drvdata(pdev); | ||
957 | struct charger_desc *desc = cm->desc; | ||
958 | |||
959 | /* Remove from the list */ | ||
960 | mutex_lock(&cm_list_mtx); | ||
961 | list_del(&cm->entry); | ||
962 | mutex_unlock(&cm_list_mtx); | ||
963 | |||
964 | if (desc->charger_regulators) | ||
965 | regulator_bulk_free(desc->num_charger_regulators, | ||
966 | desc->charger_regulators); | ||
967 | |||
968 | power_supply_unregister(&cm->charger_psy); | ||
969 | kfree(cm->charger_psy.properties); | ||
970 | kfree(cm->charger_stat); | ||
971 | kfree(cm->desc); | ||
972 | kfree(cm); | ||
973 | |||
974 | return 0; | ||
975 | } | ||
976 | |||
977 | const struct platform_device_id charger_manager_id[] = { | ||
978 | { "charger-manager", 0 }, | ||
979 | { }, | ||
980 | }; | ||
981 | |||
982 | static int cm_suspend_prepare(struct device *dev) | ||
983 | { | ||
984 | struct platform_device *pdev = container_of(dev, struct platform_device, | ||
985 | dev); | ||
986 | struct charger_manager *cm = platform_get_drvdata(pdev); | ||
987 | |||
988 | if (!cm_suspended) { | ||
989 | if (rtc_dev) { | ||
990 | struct rtc_time tmp; | ||
991 | unsigned long now; | ||
992 | |||
993 | rtc_read_alarm(rtc_dev, &rtc_wkalarm_save); | ||
994 | rtc_read_time(rtc_dev, &tmp); | ||
995 | |||
996 | if (rtc_wkalarm_save.enabled) { | ||
997 | rtc_tm_to_time(&rtc_wkalarm_save.time, | ||
998 | &rtc_wkalarm_save_time); | ||
999 | rtc_tm_to_time(&tmp, &now); | ||
1000 | if (now > rtc_wkalarm_save_time) | ||
1001 | rtc_wkalarm_save_time = 0; | ||
1002 | } else { | ||
1003 | rtc_wkalarm_save_time = 0; | ||
1004 | } | ||
1005 | } | ||
1006 | cm_suspended = true; | ||
1007 | } | ||
1008 | |||
1009 | cm->status_save_ext_pwr_inserted = is_ext_pwr_online(cm); | ||
1010 | cm->status_save_batt = is_batt_present(cm); | ||
1011 | |||
1012 | if (!cm_rtc_set) { | ||
1013 | cm_suspend_duration_ms = 0; | ||
1014 | cm_rtc_set = cm_setup_timer(); | ||
1015 | } | ||
1016 | |||
1017 | return 0; | ||
1018 | } | ||
1019 | |||
1020 | static void cm_suspend_complete(struct device *dev) | ||
1021 | { | ||
1022 | struct platform_device *pdev = container_of(dev, struct platform_device, | ||
1023 | dev); | ||
1024 | struct charger_manager *cm = platform_get_drvdata(pdev); | ||
1025 | |||
1026 | if (cm_suspended) { | ||
1027 | if (rtc_dev) { | ||
1028 | struct rtc_wkalrm tmp; | ||
1029 | |||
1030 | rtc_read_alarm(rtc_dev, &tmp); | ||
1031 | rtc_wkalarm_save.pending = tmp.pending; | ||
1032 | rtc_set_alarm(rtc_dev, &rtc_wkalarm_save); | ||
1033 | } | ||
1034 | cm_suspended = false; | ||
1035 | cm_rtc_set = false; | ||
1036 | } | ||
1037 | |||
1038 | uevent_notify(cm, NULL); | ||
1039 | } | ||
1040 | |||
1041 | static const struct dev_pm_ops charger_manager_pm = { | ||
1042 | .prepare = cm_suspend_prepare, | ||
1043 | .complete = cm_suspend_complete, | ||
1044 | }; | ||
1045 | |||
1046 | static struct platform_driver charger_manager_driver = { | ||
1047 | .driver = { | ||
1048 | .name = "charger-manager", | ||
1049 | .owner = THIS_MODULE, | ||
1050 | .pm = &charger_manager_pm, | ||
1051 | }, | ||
1052 | .probe = charger_manager_probe, | ||
1053 | .remove = __devexit_p(charger_manager_remove), | ||
1054 | .id_table = charger_manager_id, | ||
1055 | }; | ||
1056 | |||
1057 | static int __init charger_manager_init(void) | ||
1058 | { | ||
1059 | return platform_driver_register(&charger_manager_driver); | ||
1060 | } | ||
1061 | late_initcall(charger_manager_init); | ||
1062 | |||
1063 | static void __exit charger_manager_cleanup(void) | ||
1064 | { | ||
1065 | platform_driver_unregister(&charger_manager_driver); | ||
1066 | } | ||
1067 | module_exit(charger_manager_cleanup); | ||
1068 | |||
1069 | MODULE_AUTHOR("MyungJoo Ham <myungjoo.ham@samsung.com>"); | ||
1070 | MODULE_DESCRIPTION("Charger Manager"); | ||
1071 | MODULE_LICENSE("GPL"); | ||
1072 | MODULE_ALIAS("charger-manager"); | ||
diff --git a/drivers/power/collie_battery.c b/drivers/power/collie_battery.c index 548d263b1ad0..74c6b23aeabf 100644 --- a/drivers/power/collie_battery.c +++ b/drivers/power/collie_battery.c | |||
@@ -146,7 +146,7 @@ static void collie_bat_external_power_changed(struct power_supply *psy) | |||
146 | 146 | ||
147 | static irqreturn_t collie_bat_gpio_isr(int irq, void *data) | 147 | static irqreturn_t collie_bat_gpio_isr(int irq, void *data) |
148 | { | 148 | { |
149 | pr_info("collie_bat_gpio irq: %d\n", gpio_get_value(irq_to_gpio(irq))); | 149 | pr_info("collie_bat_gpio irq\n"); |
150 | schedule_work(&bat_work); | 150 | schedule_work(&bat_work); |
151 | return IRQ_HANDLED; | 151 | return IRQ_HANDLED; |
152 | } | 152 | } |
@@ -277,18 +277,13 @@ static struct collie_bat collie_bat_bu = { | |||
277 | .adc_temp_divider = -1, | 277 | .adc_temp_divider = -1, |
278 | }; | 278 | }; |
279 | 279 | ||
280 | static struct { | 280 | static struct gpio collie_batt_gpios[] = { |
281 | int gpio; | 281 | { COLLIE_GPIO_CO, GPIOF_IN, "main battery full" }, |
282 | char *name; | 282 | { COLLIE_GPIO_MAIN_BAT_LOW, GPIOF_IN, "main battery low" }, |
283 | bool output; | 283 | { COLLIE_GPIO_CHARGE_ON, GPIOF_OUT_INIT_LOW, "main charge on" }, |
284 | int value; | 284 | { COLLIE_GPIO_MBAT_ON, GPIOF_OUT_INIT_LOW, "main battery" }, |
285 | } gpios[] = { | 285 | { COLLIE_GPIO_TMP_ON, GPIOF_OUT_INIT_LOW, "main battery temp" }, |
286 | { COLLIE_GPIO_CO, "main battery full", 0, 0 }, | 286 | { COLLIE_GPIO_BBAT_ON, GPIOF_OUT_INIT_LOW, "backup battery" }, |
287 | { COLLIE_GPIO_MAIN_BAT_LOW, "main battery low", 0, 0 }, | ||
288 | { COLLIE_GPIO_CHARGE_ON, "main charge on", 1, 0 }, | ||
289 | { COLLIE_GPIO_MBAT_ON, "main battery", 1, 0 }, | ||
290 | { COLLIE_GPIO_TMP_ON, "main battery temp", 1, 0 }, | ||
291 | { COLLIE_GPIO_BBAT_ON, "backup battery", 1, 0 }, | ||
292 | }; | 287 | }; |
293 | 288 | ||
294 | #ifdef CONFIG_PM | 289 | #ifdef CONFIG_PM |
@@ -313,29 +308,16 @@ static int collie_bat_resume(struct ucb1x00_dev *dev) | |||
313 | static int __devinit collie_bat_probe(struct ucb1x00_dev *dev) | 308 | static int __devinit collie_bat_probe(struct ucb1x00_dev *dev) |
314 | { | 309 | { |
315 | int ret; | 310 | int ret; |
316 | int i; | ||
317 | 311 | ||
318 | if (!machine_is_collie()) | 312 | if (!machine_is_collie()) |
319 | return -ENODEV; | 313 | return -ENODEV; |
320 | 314 | ||
321 | ucb = dev->ucb; | 315 | ucb = dev->ucb; |
322 | 316 | ||
323 | for (i = 0; i < ARRAY_SIZE(gpios); i++) { | 317 | ret = gpio_request_array(collie_batt_gpios, |
324 | ret = gpio_request(gpios[i].gpio, gpios[i].name); | 318 | ARRAY_SIZE(collie_batt_gpios)); |
325 | if (ret) { | 319 | if (ret) |
326 | i--; | 320 | return ret; |
327 | goto err_gpio; | ||
328 | } | ||
329 | |||
330 | if (gpios[i].output) | ||
331 | ret = gpio_direction_output(gpios[i].gpio, | ||
332 | gpios[i].value); | ||
333 | else | ||
334 | ret = gpio_direction_input(gpios[i].gpio); | ||
335 | |||
336 | if (ret) | ||
337 | goto err_gpio; | ||
338 | } | ||
339 | 321 | ||
340 | mutex_init(&collie_bat_main.work_lock); | 322 | mutex_init(&collie_bat_main.work_lock); |
341 | 323 | ||
@@ -363,19 +345,12 @@ err_psy_reg_main: | |||
363 | 345 | ||
364 | /* see comment in collie_bat_remove */ | 346 | /* see comment in collie_bat_remove */ |
365 | cancel_work_sync(&bat_work); | 347 | cancel_work_sync(&bat_work); |
366 | 348 | gpio_free_array(collie_batt_gpios, ARRAY_SIZE(collie_batt_gpios)); | |
367 | i--; | ||
368 | err_gpio: | ||
369 | for (; i >= 0; i--) | ||
370 | gpio_free(gpios[i].gpio); | ||
371 | |||
372 | return ret; | 349 | return ret; |
373 | } | 350 | } |
374 | 351 | ||
375 | static void __devexit collie_bat_remove(struct ucb1x00_dev *dev) | 352 | static void __devexit collie_bat_remove(struct ucb1x00_dev *dev) |
376 | { | 353 | { |
377 | int i; | ||
378 | |||
379 | free_irq(gpio_to_irq(COLLIE_GPIO_CO), &collie_bat_main); | 354 | free_irq(gpio_to_irq(COLLIE_GPIO_CO), &collie_bat_main); |
380 | 355 | ||
381 | power_supply_unregister(&collie_bat_bu.psy); | 356 | power_supply_unregister(&collie_bat_bu.psy); |
@@ -387,9 +362,7 @@ static void __devexit collie_bat_remove(struct ucb1x00_dev *dev) | |||
387 | * unregistered now. | 362 | * unregistered now. |
388 | */ | 363 | */ |
389 | cancel_work_sync(&bat_work); | 364 | cancel_work_sync(&bat_work); |
390 | 365 | gpio_free_array(collie_batt_gpios, ARRAY_SIZE(collie_batt_gpios)); | |
391 | for (i = ARRAY_SIZE(gpios) - 1; i >= 0; i--) | ||
392 | gpio_free(gpios[i].gpio); | ||
393 | } | 366 | } |
394 | 367 | ||
395 | static struct ucb1x00_driver collie_bat_driver = { | 368 | static struct ucb1x00_driver collie_bat_driver = { |
diff --git a/drivers/power/da9030_battery.c b/drivers/power/da9030_battery.c index d2c793cf6765..3fd3e95d2b85 100644 --- a/drivers/power/da9030_battery.c +++ b/drivers/power/da9030_battery.c | |||
@@ -588,18 +588,7 @@ static struct platform_driver da903x_battery_driver = { | |||
588 | .remove = da9030_battery_remove, | 588 | .remove = da9030_battery_remove, |
589 | }; | 589 | }; |
590 | 590 | ||
591 | static int da903x_battery_init(void) | 591 | module_platform_driver(da903x_battery_driver); |
592 | { | ||
593 | return platform_driver_register(&da903x_battery_driver); | ||
594 | } | ||
595 | |||
596 | static void da903x_battery_exit(void) | ||
597 | { | ||
598 | platform_driver_unregister(&da903x_battery_driver); | ||
599 | } | ||
600 | |||
601 | module_init(da903x_battery_init); | ||
602 | module_exit(da903x_battery_exit); | ||
603 | 592 | ||
604 | MODULE_DESCRIPTION("DA9030 battery charger driver"); | 593 | MODULE_DESCRIPTION("DA9030 battery charger driver"); |
605 | MODULE_AUTHOR("Mike Rapoport, CompuLab"); | 594 | MODULE_AUTHOR("Mike Rapoport, CompuLab"); |
diff --git a/drivers/power/da9052-battery.c b/drivers/power/da9052-battery.c new file mode 100644 index 000000000000..e8ea47a53dee --- /dev/null +++ b/drivers/power/da9052-battery.c | |||
@@ -0,0 +1,664 @@ | |||
1 | /* | ||
2 | * Batttery Driver for Dialog DA9052 PMICs | ||
3 | * | ||
4 | * Copyright(c) 2011 Dialog Semiconductor Ltd. | ||
5 | * | ||
6 | * Author: David Dajun Chen <dchen@diasemi.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify it | ||
9 | * under the terms of the GNU General Public License as published by the | ||
10 | * Free Software Foundation; either version 2 of the License, or (at your | ||
11 | * option) any later version. | ||
12 | */ | ||
13 | |||
14 | #include <linux/delay.h> | ||
15 | #include <linux/freezer.h> | ||
16 | #include <linux/fs.h> | ||
17 | #include <linux/jiffies.h> | ||
18 | #include <linux/module.h> | ||
19 | #include <linux/timer.h> | ||
20 | #include <linux/uaccess.h> | ||
21 | #include <linux/platform_device.h> | ||
22 | #include <linux/power_supply.h> | ||
23 | |||
24 | #include <linux/mfd/da9052/da9052.h> | ||
25 | #include <linux/mfd/da9052/pdata.h> | ||
26 | #include <linux/mfd/da9052/reg.h> | ||
27 | |||
28 | /* STATIC CONFIGURATION */ | ||
29 | #define DA9052_BAT_CUTOFF_VOLT 2800 | ||
30 | #define DA9052_BAT_TSH 62000 | ||
31 | #define DA9052_BAT_LOW_CAP 4 | ||
32 | #define DA9052_AVG_SZ 4 | ||
33 | #define DA9052_VC_TBL_SZ 68 | ||
34 | #define DA9052_VC_TBL_REF_SZ 3 | ||
35 | |||
36 | #define DA9052_ISET_USB_MASK 0x0F | ||
37 | #define DA9052_CHG_USB_ILIM_MASK 0x40 | ||
38 | #define DA9052_CHG_LIM_COLS 16 | ||
39 | |||
40 | #define DA9052_MEAN(x, y) ((x + y) / 2) | ||
41 | |||
42 | enum charger_type_enum { | ||
43 | DA9052_NOCHARGER = 1, | ||
44 | DA9052_CHARGER, | ||
45 | }; | ||
46 | |||
47 | static const u16 da9052_chg_current_lim[2][DA9052_CHG_LIM_COLS] = { | ||
48 | {70, 80, 90, 100, 110, 120, 400, 450, | ||
49 | 500, 550, 600, 650, 700, 900, 1100, 1300}, | ||
50 | {80, 90, 100, 110, 120, 400, 450, 500, | ||
51 | 550, 600, 800, 1000, 1200, 1400, 1600, 1800}, | ||
52 | }; | ||
53 | |||
54 | static const u16 vc_tbl_ref[3] = {10, 25, 40}; | ||
55 | /* Lookup table for voltage vs capacity */ | ||
56 | static u32 const vc_tbl[3][68][2] = { | ||
57 | /* For temperature 10 degree Celsius */ | ||
58 | { | ||
59 | {4082, 100}, {4036, 98}, | ||
60 | {4020, 96}, {4008, 95}, | ||
61 | {3997, 93}, {3983, 91}, | ||
62 | {3964, 90}, {3943, 88}, | ||
63 | {3926, 87}, {3912, 85}, | ||
64 | {3900, 84}, {3890, 82}, | ||
65 | {3881, 80}, {3873, 79}, | ||
66 | {3865, 77}, {3857, 76}, | ||
67 | {3848, 74}, {3839, 73}, | ||
68 | {3829, 71}, {3820, 70}, | ||
69 | {3811, 68}, {3802, 67}, | ||
70 | {3794, 65}, {3785, 64}, | ||
71 | {3778, 62}, {3770, 61}, | ||
72 | {3763, 59}, {3756, 58}, | ||
73 | {3750, 56}, {3744, 55}, | ||
74 | {3738, 53}, {3732, 52}, | ||
75 | {3727, 50}, {3722, 49}, | ||
76 | {3717, 47}, {3712, 46}, | ||
77 | {3708, 44}, {3703, 43}, | ||
78 | {3700, 41}, {3696, 40}, | ||
79 | {3693, 38}, {3691, 37}, | ||
80 | {3688, 35}, {3686, 34}, | ||
81 | {3683, 32}, {3681, 31}, | ||
82 | {3678, 29}, {3675, 28}, | ||
83 | {3672, 26}, {3669, 25}, | ||
84 | {3665, 23}, {3661, 22}, | ||
85 | {3656, 21}, {3651, 19}, | ||
86 | {3645, 18}, {3639, 16}, | ||
87 | {3631, 15}, {3622, 13}, | ||
88 | {3611, 12}, {3600, 10}, | ||
89 | {3587, 9}, {3572, 7}, | ||
90 | {3548, 6}, {3503, 5}, | ||
91 | {3420, 3}, {3268, 2}, | ||
92 | {2992, 1}, {2746, 0} | ||
93 | }, | ||
94 | /* For temperature 25 degree Celsius */ | ||
95 | { | ||
96 | {4102, 100}, {4065, 98}, | ||
97 | {4048, 96}, {4034, 95}, | ||
98 | {4021, 93}, {4011, 92}, | ||
99 | {4001, 90}, {3986, 88}, | ||
100 | {3968, 87}, {3952, 85}, | ||
101 | {3938, 84}, {3926, 82}, | ||
102 | {3916, 81}, {3908, 79}, | ||
103 | {3900, 77}, {3892, 76}, | ||
104 | {3883, 74}, {3874, 73}, | ||
105 | {3864, 71}, {3855, 70}, | ||
106 | {3846, 68}, {3836, 67}, | ||
107 | {3827, 65}, {3819, 64}, | ||
108 | {3810, 62}, {3801, 61}, | ||
109 | {3793, 59}, {3786, 58}, | ||
110 | {3778, 56}, {3772, 55}, | ||
111 | {3765, 53}, {3759, 52}, | ||
112 | {3754, 50}, {3748, 49}, | ||
113 | {3743, 47}, {3738, 46}, | ||
114 | {3733, 44}, {3728, 43}, | ||
115 | {3724, 41}, {3720, 40}, | ||
116 | {3716, 38}, {3712, 37}, | ||
117 | {3709, 35}, {3706, 34}, | ||
118 | {3703, 33}, {3701, 31}, | ||
119 | {3698, 30}, {3696, 28}, | ||
120 | {3693, 27}, {3690, 25}, | ||
121 | {3687, 24}, {3683, 22}, | ||
122 | {3680, 21}, {3675, 19}, | ||
123 | {3671, 18}, {3666, 17}, | ||
124 | {3660, 15}, {3654, 14}, | ||
125 | {3647, 12}, {3639, 11}, | ||
126 | {3630, 9}, {3621, 8}, | ||
127 | {3613, 6}, {3606, 5}, | ||
128 | {3597, 4}, {3582, 2}, | ||
129 | {3546, 1}, {2747, 0} | ||
130 | }, | ||
131 | /* For temperature 40 degree Celsius */ | ||
132 | { | ||
133 | {4114, 100}, {4081, 98}, | ||
134 | {4065, 96}, {4050, 95}, | ||
135 | {4036, 93}, {4024, 92}, | ||
136 | {4013, 90}, {4002, 88}, | ||
137 | {3990, 87}, {3976, 85}, | ||
138 | {3962, 84}, {3950, 82}, | ||
139 | {3939, 81}, {3930, 79}, | ||
140 | {3921, 77}, {3912, 76}, | ||
141 | {3902, 74}, {3893, 73}, | ||
142 | {3883, 71}, {3874, 70}, | ||
143 | {3865, 68}, {3856, 67}, | ||
144 | {3847, 65}, {3838, 64}, | ||
145 | {3829, 62}, {3820, 61}, | ||
146 | {3812, 59}, {3803, 58}, | ||
147 | {3795, 56}, {3787, 55}, | ||
148 | {3780, 53}, {3773, 52}, | ||
149 | {3767, 50}, {3761, 49}, | ||
150 | {3756, 47}, {3751, 46}, | ||
151 | {3746, 44}, {3741, 43}, | ||
152 | {3736, 41}, {3732, 40}, | ||
153 | {3728, 38}, {3724, 37}, | ||
154 | {3720, 35}, {3716, 34}, | ||
155 | {3713, 33}, {3710, 31}, | ||
156 | {3707, 30}, {3704, 28}, | ||
157 | {3701, 27}, {3698, 25}, | ||
158 | {3695, 24}, {3691, 22}, | ||
159 | {3686, 21}, {3681, 19}, | ||
160 | {3676, 18}, {3671, 17}, | ||
161 | {3666, 15}, {3661, 14}, | ||
162 | {3655, 12}, {3648, 11}, | ||
163 | {3640, 9}, {3632, 8}, | ||
164 | {3622, 6}, {3616, 5}, | ||
165 | {3611, 4}, {3604, 2}, | ||
166 | {3594, 1}, {2747, 0} | ||
167 | } | ||
168 | }; | ||
169 | |||
170 | struct da9052_battery { | ||
171 | struct da9052 *da9052; | ||
172 | struct power_supply psy; | ||
173 | struct notifier_block nb; | ||
174 | int charger_type; | ||
175 | int status; | ||
176 | int health; | ||
177 | }; | ||
178 | |||
179 | static inline int volt_reg_to_mV(int value) | ||
180 | { | ||
181 | return ((value * 1000) / 512) + 2500; | ||
182 | } | ||
183 | |||
184 | static inline int ichg_reg_to_mA(int value) | ||
185 | { | ||
186 | return (value * 3900) / 1000; | ||
187 | } | ||
188 | |||
189 | static int da9052_read_chgend_current(struct da9052_battery *bat, | ||
190 | int *current_mA) | ||
191 | { | ||
192 | int ret; | ||
193 | |||
194 | if (bat->status == POWER_SUPPLY_STATUS_DISCHARGING) | ||
195 | return -EINVAL; | ||
196 | |||
197 | ret = da9052_reg_read(bat->da9052, DA9052_ICHG_END_REG); | ||
198 | if (ret < 0) | ||
199 | return ret; | ||
200 | |||
201 | *current_mA = ichg_reg_to_mA(ret & DA9052_ICHGEND_ICHGEND); | ||
202 | |||
203 | return 0; | ||
204 | } | ||
205 | |||
206 | static int da9052_read_chg_current(struct da9052_battery *bat, int *current_mA) | ||
207 | { | ||
208 | int ret; | ||
209 | |||
210 | if (bat->status == POWER_SUPPLY_STATUS_DISCHARGING) | ||
211 | return -EINVAL; | ||
212 | |||
213 | ret = da9052_reg_read(bat->da9052, DA9052_ICHG_AV_REG); | ||
214 | if (ret < 0) | ||
215 | return ret; | ||
216 | |||
217 | *current_mA = ichg_reg_to_mA(ret & DA9052_ICHGAV_ICHGAV); | ||
218 | |||
219 | return 0; | ||
220 | } | ||
221 | |||
222 | static int da9052_bat_check_status(struct da9052_battery *bat, int *status) | ||
223 | { | ||
224 | u8 v[2] = {0, 0}; | ||
225 | u8 bat_status; | ||
226 | u8 chg_end; | ||
227 | int ret; | ||
228 | int chg_current; | ||
229 | int chg_end_current; | ||
230 | bool dcinsel; | ||
231 | bool dcindet; | ||
232 | bool vbussel; | ||
233 | bool vbusdet; | ||
234 | bool dc; | ||
235 | bool vbus; | ||
236 | |||
237 | ret = da9052_group_read(bat->da9052, DA9052_STATUS_A_REG, 2, v); | ||
238 | if (ret < 0) | ||
239 | return ret; | ||
240 | |||
241 | bat_status = v[0]; | ||
242 | chg_end = v[1]; | ||
243 | |||
244 | dcinsel = bat_status & DA9052_STATUSA_DCINSEL; | ||
245 | dcindet = bat_status & DA9052_STATUSA_DCINDET; | ||
246 | vbussel = bat_status & DA9052_STATUSA_VBUSSEL; | ||
247 | vbusdet = bat_status & DA9052_STATUSA_VBUSDET; | ||
248 | dc = dcinsel && dcindet; | ||
249 | vbus = vbussel && vbusdet; | ||
250 | |||
251 | /* Preference to WALL(DCIN) charger unit */ | ||
252 | if (dc || vbus) { | ||
253 | bat->charger_type = DA9052_CHARGER; | ||
254 | |||
255 | /* If charging end flag is set and Charging current is greater | ||
256 | * than charging end limit then battery is charging | ||
257 | */ | ||
258 | if ((chg_end & DA9052_STATUSB_CHGEND) != 0) { | ||
259 | ret = da9052_read_chg_current(bat, &chg_current); | ||
260 | if (ret < 0) | ||
261 | return ret; | ||
262 | ret = da9052_read_chgend_current(bat, &chg_end_current); | ||
263 | if (ret < 0) | ||
264 | return ret; | ||
265 | |||
266 | if (chg_current >= chg_end_current) | ||
267 | bat->status = POWER_SUPPLY_STATUS_CHARGING; | ||
268 | else | ||
269 | bat->status = POWER_SUPPLY_STATUS_NOT_CHARGING; | ||
270 | } else { | ||
271 | /* If Charging end flag is cleared then battery is | ||
272 | * charging | ||
273 | */ | ||
274 | bat->status = POWER_SUPPLY_STATUS_CHARGING; | ||
275 | } | ||
276 | } else if (dcindet || vbusdet) { | ||
277 | bat->charger_type = DA9052_CHARGER; | ||
278 | bat->status = POWER_SUPPLY_STATUS_NOT_CHARGING; | ||
279 | } else { | ||
280 | bat->charger_type = DA9052_NOCHARGER; | ||
281 | bat->status = POWER_SUPPLY_STATUS_DISCHARGING; | ||
282 | } | ||
283 | |||
284 | if (status != NULL) | ||
285 | *status = bat->status; | ||
286 | return 0; | ||
287 | } | ||
288 | |||
289 | static int da9052_bat_read_volt(struct da9052_battery *bat, int *volt_mV) | ||
290 | { | ||
291 | int volt; | ||
292 | |||
293 | volt = da9052_adc_manual_read(bat->da9052, DA9052_ADC_MAN_MUXSEL_VBAT); | ||
294 | if (volt < 0) | ||
295 | return volt; | ||
296 | |||
297 | *volt_mV = volt_reg_to_mV(volt); | ||
298 | |||
299 | return 0; | ||
300 | } | ||
301 | |||
302 | static int da9052_bat_check_presence(struct da9052_battery *bat, int *illegal) | ||
303 | { | ||
304 | int bat_temp; | ||
305 | |||
306 | bat_temp = da9052_adc_read_temp(bat->da9052); | ||
307 | if (bat_temp < 0) | ||
308 | return bat_temp; | ||
309 | |||
310 | if (bat_temp > DA9052_BAT_TSH) | ||
311 | *illegal = 1; | ||
312 | else | ||
313 | *illegal = 0; | ||
314 | |||
315 | return 0; | ||
316 | } | ||
317 | |||
318 | static int da9052_bat_interpolate(int vbat_lower, int vbat_upper, | ||
319 | int level_lower, int level_upper, | ||
320 | int bat_voltage) | ||
321 | { | ||
322 | int tmp; | ||
323 | |||
324 | tmp = ((level_upper - level_lower) * 1000) / (vbat_upper - vbat_lower); | ||
325 | tmp = level_lower + (((bat_voltage - vbat_lower) * tmp) / 1000); | ||
326 | |||
327 | return tmp; | ||
328 | } | ||
329 | |||
330 | unsigned char da9052_determine_vc_tbl_index(unsigned char adc_temp) | ||
331 | { | ||
332 | int i; | ||
333 | |||
334 | if (adc_temp <= vc_tbl_ref[0]) | ||
335 | return 0; | ||
336 | |||
337 | if (adc_temp > vc_tbl_ref[DA9052_VC_TBL_REF_SZ - 1]) | ||
338 | return DA9052_VC_TBL_REF_SZ - 1; | ||
339 | |||
340 | for (i = 0; i < DA9052_VC_TBL_REF_SZ; i++) { | ||
341 | if ((adc_temp > vc_tbl_ref[i]) && | ||
342 | (adc_temp <= DA9052_MEAN(vc_tbl_ref[i], vc_tbl_ref[i + 1]))) | ||
343 | return i; | ||
344 | if ((adc_temp > DA9052_MEAN(vc_tbl_ref[i], vc_tbl_ref[i + 1])) | ||
345 | && (adc_temp <= vc_tbl_ref[i])) | ||
346 | return i + 1; | ||
347 | } | ||
348 | } | ||
349 | |||
350 | static int da9052_bat_read_capacity(struct da9052_battery *bat, int *capacity) | ||
351 | { | ||
352 | int adc_temp; | ||
353 | int bat_voltage; | ||
354 | int vbat_lower; | ||
355 | int vbat_upper; | ||
356 | int level_upper; | ||
357 | int level_lower; | ||
358 | int ret; | ||
359 | int flag; | ||
360 | int i = 0; | ||
361 | int j; | ||
362 | |||
363 | ret = da9052_bat_read_volt(bat, &bat_voltage); | ||
364 | if (ret < 0) | ||
365 | return ret; | ||
366 | |||
367 | adc_temp = da9052_adc_read_temp(bat->da9052); | ||
368 | if (adc_temp < 0) | ||
369 | return adc_temp; | ||
370 | |||
371 | i = da9052_determine_vc_tbl_index(adc_temp); | ||
372 | |||
373 | if (bat_voltage >= vc_tbl[i][0][0]) { | ||
374 | *capacity = 100; | ||
375 | return 0; | ||
376 | } | ||
377 | if (bat_voltage <= vc_tbl[i][DA9052_VC_TBL_SZ - 1][0]) { | ||
378 | *capacity = 0; | ||
379 | return 0; | ||
380 | } | ||
381 | flag = 0; | ||
382 | |||
383 | for (j = 0; j < (DA9052_VC_TBL_SZ-1); j++) { | ||
384 | if ((bat_voltage <= vc_tbl[i][j][0]) && | ||
385 | (bat_voltage >= vc_tbl[i][j + 1][0])) { | ||
386 | vbat_upper = vc_tbl[i][j][0]; | ||
387 | vbat_lower = vc_tbl[i][j + 1][0]; | ||
388 | level_upper = vc_tbl[i][j][1]; | ||
389 | level_lower = vc_tbl[i][j + 1][1]; | ||
390 | flag = 1; | ||
391 | break; | ||
392 | } | ||
393 | } | ||
394 | if (!flag) | ||
395 | return -EIO; | ||
396 | |||
397 | *capacity = da9052_bat_interpolate(vbat_lower, vbat_upper, level_lower, | ||
398 | level_upper, bat_voltage); | ||
399 | |||
400 | return 0; | ||
401 | } | ||
402 | |||
403 | static int da9052_bat_check_health(struct da9052_battery *bat, int *health) | ||
404 | { | ||
405 | int ret; | ||
406 | int bat_illegal; | ||
407 | int capacity; | ||
408 | |||
409 | ret = da9052_bat_check_presence(bat, &bat_illegal); | ||
410 | if (ret < 0) | ||
411 | return ret; | ||
412 | |||
413 | if (bat_illegal) { | ||
414 | bat->health = POWER_SUPPLY_HEALTH_UNKNOWN; | ||
415 | return 0; | ||
416 | } | ||
417 | |||
418 | if (bat->health != POWER_SUPPLY_HEALTH_OVERHEAT) { | ||
419 | ret = da9052_bat_read_capacity(bat, &capacity); | ||
420 | if (ret < 0) | ||
421 | return ret; | ||
422 | if (capacity < DA9052_BAT_LOW_CAP) | ||
423 | bat->health = POWER_SUPPLY_HEALTH_DEAD; | ||
424 | else | ||
425 | bat->health = POWER_SUPPLY_HEALTH_GOOD; | ||
426 | } | ||
427 | |||
428 | *health = bat->health; | ||
429 | |||
430 | return 0; | ||
431 | } | ||
432 | |||
433 | static irqreturn_t da9052_bat_irq(int irq, void *data) | ||
434 | { | ||
435 | struct da9052_battery *bat = data; | ||
436 | |||
437 | irq -= bat->da9052->irq_base; | ||
438 | |||
439 | if (irq == DA9052_IRQ_CHGEND) | ||
440 | bat->status = POWER_SUPPLY_STATUS_FULL; | ||
441 | else | ||
442 | da9052_bat_check_status(bat, NULL); | ||
443 | |||
444 | if (irq == DA9052_IRQ_CHGEND || irq == DA9052_IRQ_DCIN || | ||
445 | irq == DA9052_IRQ_VBUS || irq == DA9052_IRQ_TBAT) { | ||
446 | power_supply_changed(&bat->psy); | ||
447 | } | ||
448 | |||
449 | return IRQ_HANDLED; | ||
450 | } | ||
451 | |||
452 | static int da9052_USB_current_notifier(struct notifier_block *nb, | ||
453 | unsigned long events, void *data) | ||
454 | { | ||
455 | u8 row; | ||
456 | u8 col; | ||
457 | int *current_mA = data; | ||
458 | int ret; | ||
459 | struct da9052_battery *bat = container_of(nb, struct da9052_battery, | ||
460 | nb); | ||
461 | |||
462 | if (bat->status == POWER_SUPPLY_STATUS_DISCHARGING) | ||
463 | return -EPERM; | ||
464 | |||
465 | ret = da9052_reg_read(bat->da9052, DA9052_CHGBUCK_REG); | ||
466 | if (ret & DA9052_CHG_USB_ILIM_MASK) | ||
467 | return -EPERM; | ||
468 | |||
469 | if (bat->da9052->chip_id == DA9052) | ||
470 | row = 0; | ||
471 | else | ||
472 | row = 1; | ||
473 | |||
474 | if (*current_mA < da9052_chg_current_lim[row][0] || | ||
475 | *current_mA > da9052_chg_current_lim[row][DA9052_CHG_LIM_COLS - 1]) | ||
476 | return -EINVAL; | ||
477 | |||
478 | for (col = 0; col <= DA9052_CHG_LIM_COLS - 1 ; col++) { | ||
479 | if (*current_mA <= da9052_chg_current_lim[row][col]) | ||
480 | break; | ||
481 | } | ||
482 | |||
483 | return da9052_reg_update(bat->da9052, DA9052_ISET_REG, | ||
484 | DA9052_ISET_USB_MASK, col); | ||
485 | } | ||
486 | |||
487 | static int da9052_bat_get_property(struct power_supply *psy, | ||
488 | enum power_supply_property psp, | ||
489 | union power_supply_propval *val) | ||
490 | { | ||
491 | int ret; | ||
492 | int illegal; | ||
493 | struct da9052_battery *bat = container_of(psy, struct da9052_battery, | ||
494 | psy); | ||
495 | |||
496 | ret = da9052_bat_check_presence(bat, &illegal); | ||
497 | if (ret < 0) | ||
498 | return ret; | ||
499 | |||
500 | if (illegal && psp != POWER_SUPPLY_PROP_PRESENT) | ||
501 | return -ENODEV; | ||
502 | |||
503 | switch (psp) { | ||
504 | case POWER_SUPPLY_PROP_STATUS: | ||
505 | ret = da9052_bat_check_status(bat, &val->intval); | ||
506 | break; | ||
507 | case POWER_SUPPLY_PROP_ONLINE: | ||
508 | val->intval = | ||
509 | (bat->charger_type == DA9052_NOCHARGER) ? 0 : 1; | ||
510 | break; | ||
511 | case POWER_SUPPLY_PROP_PRESENT: | ||
512 | ret = da9052_bat_check_presence(bat, &val->intval); | ||
513 | break; | ||
514 | case POWER_SUPPLY_PROP_HEALTH: | ||
515 | ret = da9052_bat_check_health(bat, &val->intval); | ||
516 | break; | ||
517 | case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN: | ||
518 | val->intval = DA9052_BAT_CUTOFF_VOLT * 1000; | ||
519 | break; | ||
520 | case POWER_SUPPLY_PROP_VOLTAGE_AVG: | ||
521 | ret = da9052_bat_read_volt(bat, &val->intval); | ||
522 | break; | ||
523 | case POWER_SUPPLY_PROP_CURRENT_AVG: | ||
524 | ret = da9052_read_chg_current(bat, &val->intval); | ||
525 | break; | ||
526 | case POWER_SUPPLY_PROP_CAPACITY: | ||
527 | ret = da9052_bat_read_capacity(bat, &val->intval); | ||
528 | break; | ||
529 | case POWER_SUPPLY_PROP_TEMP: | ||
530 | val->intval = da9052_adc_read_temp(bat->da9052); | ||
531 | ret = val->intval; | ||
532 | break; | ||
533 | case POWER_SUPPLY_PROP_TECHNOLOGY: | ||
534 | val->intval = POWER_SUPPLY_TECHNOLOGY_LION; | ||
535 | break; | ||
536 | default: | ||
537 | return -EINVAL; | ||
538 | } | ||
539 | return ret; | ||
540 | } | ||
541 | |||
542 | static enum power_supply_property da9052_bat_props[] = { | ||
543 | POWER_SUPPLY_PROP_STATUS, | ||
544 | POWER_SUPPLY_PROP_ONLINE, | ||
545 | POWER_SUPPLY_PROP_PRESENT, | ||
546 | POWER_SUPPLY_PROP_HEALTH, | ||
547 | POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN, | ||
548 | POWER_SUPPLY_PROP_VOLTAGE_AVG, | ||
549 | POWER_SUPPLY_PROP_CURRENT_AVG, | ||
550 | POWER_SUPPLY_PROP_CAPACITY, | ||
551 | POWER_SUPPLY_PROP_TEMP, | ||
552 | POWER_SUPPLY_PROP_TECHNOLOGY, | ||
553 | }; | ||
554 | |||
555 | static struct power_supply template_battery = { | ||
556 | .name = "da9052-bat", | ||
557 | .type = POWER_SUPPLY_TYPE_BATTERY, | ||
558 | .properties = da9052_bat_props, | ||
559 | .num_properties = ARRAY_SIZE(da9052_bat_props), | ||
560 | .get_property = da9052_bat_get_property, | ||
561 | }; | ||
562 | |||
563 | static const char *const da9052_bat_irqs[] = { | ||
564 | "BATT TEMP", | ||
565 | "DCIN DET", | ||
566 | "DCIN REM", | ||
567 | "VBUS DET", | ||
568 | "VBUS REM", | ||
569 | "CHG END", | ||
570 | }; | ||
571 | |||
572 | static s32 __devinit da9052_bat_probe(struct platform_device *pdev) | ||
573 | { | ||
574 | struct da9052_pdata *pdata; | ||
575 | struct da9052_battery *bat; | ||
576 | int ret; | ||
577 | int irq; | ||
578 | int i; | ||
579 | |||
580 | bat = kzalloc(sizeof(struct da9052_battery), GFP_KERNEL); | ||
581 | if (!bat) | ||
582 | return -ENOMEM; | ||
583 | |||
584 | bat->da9052 = dev_get_drvdata(pdev->dev.parent); | ||
585 | bat->psy = template_battery; | ||
586 | bat->charger_type = DA9052_NOCHARGER; | ||
587 | bat->status = POWER_SUPPLY_STATUS_UNKNOWN; | ||
588 | bat->health = POWER_SUPPLY_HEALTH_UNKNOWN; | ||
589 | bat->nb.notifier_call = da9052_USB_current_notifier; | ||
590 | |||
591 | pdata = bat->da9052->dev->platform_data; | ||
592 | if (pdata != NULL && pdata->use_for_apm) | ||
593 | bat->psy.use_for_apm = pdata->use_for_apm; | ||
594 | else | ||
595 | bat->psy.use_for_apm = 1; | ||
596 | |||
597 | for (i = 0; i < ARRAY_SIZE(da9052_bat_irqs); i++) { | ||
598 | irq = platform_get_irq_byname(pdev, da9052_bat_irqs[i]); | ||
599 | ret = request_threaded_irq(bat->da9052->irq_base + irq, | ||
600 | NULL, da9052_bat_irq, | ||
601 | IRQF_TRIGGER_LOW | IRQF_ONESHOT, | ||
602 | da9052_bat_irqs[i], bat); | ||
603 | if (ret != 0) { | ||
604 | dev_err(bat->da9052->dev, | ||
605 | "DA9052 failed to request %s IRQ %d: %d\n", | ||
606 | da9052_bat_irqs[i], irq, ret); | ||
607 | goto err; | ||
608 | } | ||
609 | } | ||
610 | |||
611 | ret = power_supply_register(&pdev->dev, &bat->psy); | ||
612 | if (ret) | ||
613 | goto err; | ||
614 | |||
615 | return 0; | ||
616 | |||
617 | err: | ||
618 | for (; i >= 0; i--) { | ||
619 | irq = platform_get_irq_byname(pdev, da9052_bat_irqs[i]); | ||
620 | free_irq(bat->da9052->irq_base + irq, bat); | ||
621 | } | ||
622 | kfree(bat); | ||
623 | return ret; | ||
624 | } | ||
625 | static int __devexit da9052_bat_remove(struct platform_device *pdev) | ||
626 | { | ||
627 | int i; | ||
628 | int irq; | ||
629 | struct da9052_battery *bat = platform_get_drvdata(pdev); | ||
630 | |||
631 | for (i = 0; i < ARRAY_SIZE(da9052_bat_irqs); i++) { | ||
632 | irq = platform_get_irq_byname(pdev, da9052_bat_irqs[i]); | ||
633 | free_irq(bat->da9052->irq_base + irq, bat); | ||
634 | } | ||
635 | power_supply_unregister(&bat->psy); | ||
636 | |||
637 | return 0; | ||
638 | } | ||
639 | |||
640 | static struct platform_driver da9052_bat_driver = { | ||
641 | .probe = da9052_bat_probe, | ||
642 | .remove = __devexit_p(da9052_bat_remove), | ||
643 | .driver = { | ||
644 | .name = "da9052-bat", | ||
645 | .owner = THIS_MODULE, | ||
646 | }, | ||
647 | }; | ||
648 | |||
649 | static int __init da9052_bat_init(void) | ||
650 | { | ||
651 | return platform_driver_register(&da9052_bat_driver); | ||
652 | } | ||
653 | module_init(da9052_bat_init); | ||
654 | |||
655 | static void __exit da9052_bat_exit(void) | ||
656 | { | ||
657 | platform_driver_unregister(&da9052_bat_driver); | ||
658 | } | ||
659 | module_exit(da9052_bat_exit); | ||
660 | |||
661 | MODULE_DESCRIPTION("DA9052 BAT Device Driver"); | ||
662 | MODULE_AUTHOR("David Dajun Chen <dchen@diasemi.com>"); | ||
663 | MODULE_LICENSE("GPL"); | ||
664 | MODULE_ALIAS("platform:da9052-bat"); | ||
diff --git a/drivers/power/ds2760_battery.c b/drivers/power/ds2760_battery.c index f2c9cc33c0f9..545874b1df9e 100644 --- a/drivers/power/ds2760_battery.c +++ b/drivers/power/ds2760_battery.c | |||
@@ -95,7 +95,11 @@ static int rated_capacities[] = { | |||
95 | 2880, /* Samsung */ | 95 | 2880, /* Samsung */ |
96 | 2880, /* BYD */ | 96 | 2880, /* BYD */ |
97 | 2880, /* Lishen */ | 97 | 2880, /* Lishen */ |
98 | 2880 /* NEC */ | 98 | 2880, /* NEC */ |
99 | #ifdef CONFIG_MACH_H4700 | ||
100 | 0, | ||
101 | 3600, /* HP iPAQ hx4700 3.7V 3600mAh (359114-001) */ | ||
102 | #endif | ||
99 | }; | 103 | }; |
100 | 104 | ||
101 | /* array is level at temps 0°C, 10°C, 20°C, 30°C, 40°C | 105 | /* array is level at temps 0°C, 10°C, 20°C, 30°C, 40°C |
@@ -637,18 +641,7 @@ static struct platform_driver ds2760_battery_driver = { | |||
637 | .resume = ds2760_battery_resume, | 641 | .resume = ds2760_battery_resume, |
638 | }; | 642 | }; |
639 | 643 | ||
640 | static int __init ds2760_battery_init(void) | 644 | module_platform_driver(ds2760_battery_driver); |
641 | { | ||
642 | return platform_driver_register(&ds2760_battery_driver); | ||
643 | } | ||
644 | |||
645 | static void __exit ds2760_battery_exit(void) | ||
646 | { | ||
647 | platform_driver_unregister(&ds2760_battery_driver); | ||
648 | } | ||
649 | |||
650 | module_init(ds2760_battery_init); | ||
651 | module_exit(ds2760_battery_exit); | ||
652 | 645 | ||
653 | MODULE_LICENSE("GPL"); | 646 | MODULE_LICENSE("GPL"); |
654 | MODULE_AUTHOR("Szabolcs Gyurko <szabolcs.gyurko@tlt.hu>, " | 647 | MODULE_AUTHOR("Szabolcs Gyurko <szabolcs.gyurko@tlt.hu>, " |
diff --git a/drivers/power/ds2780_battery.c b/drivers/power/ds2780_battery.c index 91a783d72360..de31cae1ba53 100644 --- a/drivers/power/ds2780_battery.c +++ b/drivers/power/ds2780_battery.c | |||
@@ -841,29 +841,17 @@ static int __devexit ds2780_battery_remove(struct platform_device *pdev) | |||
841 | return 0; | 841 | return 0; |
842 | } | 842 | } |
843 | 843 | ||
844 | MODULE_ALIAS("platform:ds2780-battery"); | ||
845 | |||
846 | static struct platform_driver ds2780_battery_driver = { | 844 | static struct platform_driver ds2780_battery_driver = { |
847 | .driver = { | 845 | .driver = { |
848 | .name = "ds2780-battery", | 846 | .name = "ds2780-battery", |
849 | }, | 847 | }, |
850 | .probe = ds2780_battery_probe, | 848 | .probe = ds2780_battery_probe, |
851 | .remove = ds2780_battery_remove, | 849 | .remove = __devexit_p(ds2780_battery_remove), |
852 | }; | 850 | }; |
853 | 851 | ||
854 | static int __init ds2780_battery_init(void) | 852 | module_platform_driver(ds2780_battery_driver); |
855 | { | ||
856 | return platform_driver_register(&ds2780_battery_driver); | ||
857 | } | ||
858 | |||
859 | static void __exit ds2780_battery_exit(void) | ||
860 | { | ||
861 | platform_driver_unregister(&ds2780_battery_driver); | ||
862 | } | ||
863 | |||
864 | module_init(ds2780_battery_init); | ||
865 | module_exit(ds2780_battery_exit); | ||
866 | 853 | ||
867 | MODULE_LICENSE("GPL"); | 854 | MODULE_LICENSE("GPL"); |
868 | MODULE_AUTHOR("Clifton Barnes <cabarnes@indesign-llc.com>"); | 855 | MODULE_AUTHOR("Clifton Barnes <cabarnes@indesign-llc.com>"); |
869 | MODULE_DESCRIPTION("Maxim/Dallas DS2780 Stand-Alone Fuel Gauage IC driver"); | 856 | MODULE_DESCRIPTION("Maxim/Dallas DS2780 Stand-Alone Fuel Gauage IC driver"); |
857 | MODULE_ALIAS("platform:ds2780-battery"); | ||
diff --git a/drivers/power/gpio-charger.c b/drivers/power/gpio-charger.c index a64b8854cfd5..8672c9177dd7 100644 --- a/drivers/power/gpio-charger.c +++ b/drivers/power/gpio-charger.c | |||
@@ -185,17 +185,7 @@ static struct platform_driver gpio_charger_driver = { | |||
185 | }, | 185 | }, |
186 | }; | 186 | }; |
187 | 187 | ||
188 | static int __init gpio_charger_init(void) | 188 | module_platform_driver(gpio_charger_driver); |
189 | { | ||
190 | return platform_driver_register(&gpio_charger_driver); | ||
191 | } | ||
192 | module_init(gpio_charger_init); | ||
193 | |||
194 | static void __exit gpio_charger_exit(void) | ||
195 | { | ||
196 | platform_driver_unregister(&gpio_charger_driver); | ||
197 | } | ||
198 | module_exit(gpio_charger_exit); | ||
199 | 189 | ||
200 | MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>"); | 190 | MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>"); |
201 | MODULE_DESCRIPTION("Driver for chargers which report their online status through a GPIO"); | 191 | MODULE_DESCRIPTION("Driver for chargers which report their online status through a GPIO"); |
diff --git a/drivers/power/intel_mid_battery.c b/drivers/power/intel_mid_battery.c index 01fa671ec97f..d09649706bd3 100644 --- a/drivers/power/intel_mid_battery.c +++ b/drivers/power/intel_mid_battery.c | |||
@@ -779,18 +779,7 @@ static struct platform_driver platform_pmic_battery_driver = { | |||
779 | .remove = __devexit_p(platform_pmic_battery_remove), | 779 | .remove = __devexit_p(platform_pmic_battery_remove), |
780 | }; | 780 | }; |
781 | 781 | ||
782 | static int __init platform_pmic_battery_module_init(void) | 782 | module_platform_driver(platform_pmic_battery_driver); |
783 | { | ||
784 | return platform_driver_register(&platform_pmic_battery_driver); | ||
785 | } | ||
786 | |||
787 | static void __exit platform_pmic_battery_module_exit(void) | ||
788 | { | ||
789 | platform_driver_unregister(&platform_pmic_battery_driver); | ||
790 | } | ||
791 | |||
792 | module_init(platform_pmic_battery_module_init); | ||
793 | module_exit(platform_pmic_battery_module_exit); | ||
794 | 783 | ||
795 | MODULE_AUTHOR("Nithish Mahalingam <nithish.mahalingam@intel.com>"); | 784 | MODULE_AUTHOR("Nithish Mahalingam <nithish.mahalingam@intel.com>"); |
796 | MODULE_DESCRIPTION("Intel Moorestown PMIC Battery Driver"); | 785 | MODULE_DESCRIPTION("Intel Moorestown PMIC Battery Driver"); |
diff --git a/drivers/power/isp1704_charger.c b/drivers/power/isp1704_charger.c index f6d72b402a8e..b806667b59ae 100644 --- a/drivers/power/isp1704_charger.c +++ b/drivers/power/isp1704_charger.c | |||
@@ -79,7 +79,7 @@ static void isp1704_charger_set_power(struct isp1704_charger *isp, bool on) | |||
79 | { | 79 | { |
80 | struct isp1704_charger_data *board = isp->dev->platform_data; | 80 | struct isp1704_charger_data *board = isp->dev->platform_data; |
81 | 81 | ||
82 | if (board->set_power) | 82 | if (board && board->set_power) |
83 | board->set_power(on); | 83 | board->set_power(on); |
84 | } | 84 | } |
85 | 85 | ||
@@ -494,17 +494,7 @@ static struct platform_driver isp1704_charger_driver = { | |||
494 | .remove = __devexit_p(isp1704_charger_remove), | 494 | .remove = __devexit_p(isp1704_charger_remove), |
495 | }; | 495 | }; |
496 | 496 | ||
497 | static int __init isp1704_charger_init(void) | 497 | module_platform_driver(isp1704_charger_driver); |
498 | { | ||
499 | return platform_driver_register(&isp1704_charger_driver); | ||
500 | } | ||
501 | module_init(isp1704_charger_init); | ||
502 | |||
503 | static void __exit isp1704_charger_exit(void) | ||
504 | { | ||
505 | platform_driver_unregister(&isp1704_charger_driver); | ||
506 | } | ||
507 | module_exit(isp1704_charger_exit); | ||
508 | 498 | ||
509 | MODULE_ALIAS("platform:isp1704_charger"); | 499 | MODULE_ALIAS("platform:isp1704_charger"); |
510 | MODULE_AUTHOR("Nokia Corporation"); | 500 | MODULE_AUTHOR("Nokia Corporation"); |
diff --git a/drivers/power/jz4740-battery.c b/drivers/power/jz4740-battery.c index 763f894ed188..8dbc7bfaab14 100644 --- a/drivers/power/jz4740-battery.c +++ b/drivers/power/jz4740-battery.c | |||
@@ -67,7 +67,7 @@ static irqreturn_t jz_battery_irq_handler(int irq, void *devid) | |||
67 | 67 | ||
68 | static long jz_battery_read_voltage(struct jz_battery *battery) | 68 | static long jz_battery_read_voltage(struct jz_battery *battery) |
69 | { | 69 | { |
70 | unsigned long t; | 70 | long t; |
71 | unsigned long val; | 71 | unsigned long val; |
72 | long voltage; | 72 | long voltage; |
73 | 73 | ||
@@ -441,17 +441,7 @@ static struct platform_driver jz_battery_driver = { | |||
441 | }, | 441 | }, |
442 | }; | 442 | }; |
443 | 443 | ||
444 | static int __init jz_battery_init(void) | 444 | module_platform_driver(jz_battery_driver); |
445 | { | ||
446 | return platform_driver_register(&jz_battery_driver); | ||
447 | } | ||
448 | module_init(jz_battery_init); | ||
449 | |||
450 | static void __exit jz_battery_exit(void) | ||
451 | { | ||
452 | platform_driver_unregister(&jz_battery_driver); | ||
453 | } | ||
454 | module_exit(jz_battery_exit); | ||
455 | 445 | ||
456 | MODULE_ALIAS("platform:jz4740-battery"); | 446 | MODULE_ALIAS("platform:jz4740-battery"); |
457 | MODULE_LICENSE("GPL"); | 447 | MODULE_LICENSE("GPL"); |
diff --git a/drivers/power/lp8727_charger.c b/drivers/power/lp8727_charger.c new file mode 100644 index 000000000000..b15b575c070c --- /dev/null +++ b/drivers/power/lp8727_charger.c | |||
@@ -0,0 +1,494 @@ | |||
1 | /* | ||
2 | * Driver for LP8727 Micro/Mini USB IC with intergrated charger | ||
3 | * | ||
4 | * Copyright (C) 2011 National Semiconductor | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License version 2 as | ||
8 | * published by the Free Software Foundation. | ||
9 | * | ||
10 | */ | ||
11 | |||
12 | #include <linux/module.h> | ||
13 | #include <linux/slab.h> | ||
14 | #include <linux/interrupt.h> | ||
15 | #include <linux/i2c.h> | ||
16 | #include <linux/power_supply.h> | ||
17 | #include <linux/lp8727.h> | ||
18 | |||
19 | #define DEBOUNCE_MSEC 270 | ||
20 | |||
21 | /* Registers */ | ||
22 | #define CTRL1 0x1 | ||
23 | #define CTRL2 0x2 | ||
24 | #define SWCTRL 0x3 | ||
25 | #define INT1 0x4 | ||
26 | #define INT2 0x5 | ||
27 | #define STATUS1 0x6 | ||
28 | #define STATUS2 0x7 | ||
29 | #define CHGCTRL2 0x9 | ||
30 | |||
31 | /* CTRL1 register */ | ||
32 | #define CP_EN (1 << 0) | ||
33 | #define ADC_EN (1 << 1) | ||
34 | #define ID200_EN (1 << 4) | ||
35 | |||
36 | /* CTRL2 register */ | ||
37 | #define CHGDET_EN (1 << 1) | ||
38 | #define INT_EN (1 << 6) | ||
39 | |||
40 | /* SWCTRL register */ | ||
41 | #define SW_DM1_DM (0x0 << 0) | ||
42 | #define SW_DM1_U1 (0x1 << 0) | ||
43 | #define SW_DM1_HiZ (0x7 << 0) | ||
44 | #define SW_DP2_DP (0x0 << 3) | ||
45 | #define SW_DP2_U2 (0x1 << 3) | ||
46 | #define SW_DP2_HiZ (0x7 << 3) | ||
47 | |||
48 | /* INT1 register */ | ||
49 | #define IDNO (0xF << 0) | ||
50 | #define VBUS (1 << 4) | ||
51 | |||
52 | /* STATUS1 register */ | ||
53 | #define CHGSTAT (3 << 4) | ||
54 | #define CHPORT (1 << 6) | ||
55 | #define DCPORT (1 << 7) | ||
56 | |||
57 | /* STATUS2 register */ | ||
58 | #define TEMP_STAT (3 << 5) | ||
59 | |||
60 | enum lp8727_dev_id { | ||
61 | ID_NONE, | ||
62 | ID_TA, | ||
63 | ID_DEDICATED_CHG, | ||
64 | ID_USB_CHG, | ||
65 | ID_USB_DS, | ||
66 | ID_MAX, | ||
67 | }; | ||
68 | |||
69 | enum lp8727_chg_stat { | ||
70 | PRECHG, | ||
71 | CC, | ||
72 | CV, | ||
73 | EOC, | ||
74 | }; | ||
75 | |||
76 | struct lp8727_psy { | ||
77 | struct power_supply ac; | ||
78 | struct power_supply usb; | ||
79 | struct power_supply batt; | ||
80 | }; | ||
81 | |||
82 | struct lp8727_chg { | ||
83 | struct device *dev; | ||
84 | struct i2c_client *client; | ||
85 | struct mutex xfer_lock; | ||
86 | struct delayed_work work; | ||
87 | struct workqueue_struct *irqthread; | ||
88 | struct lp8727_platform_data *pdata; | ||
89 | struct lp8727_psy *psy; | ||
90 | struct lp8727_chg_param *chg_parm; | ||
91 | enum lp8727_dev_id devid; | ||
92 | }; | ||
93 | |||
94 | static int lp8727_i2c_read(struct lp8727_chg *pchg, u8 reg, u8 *data, u8 len) | ||
95 | { | ||
96 | s32 ret; | ||
97 | |||
98 | mutex_lock(&pchg->xfer_lock); | ||
99 | ret = i2c_smbus_read_i2c_block_data(pchg->client, reg, len, data); | ||
100 | mutex_unlock(&pchg->xfer_lock); | ||
101 | |||
102 | return (ret != len) ? -EIO : 0; | ||
103 | } | ||
104 | |||
105 | static int lp8727_i2c_write(struct lp8727_chg *pchg, u8 reg, u8 *data, u8 len) | ||
106 | { | ||
107 | s32 ret; | ||
108 | |||
109 | mutex_lock(&pchg->xfer_lock); | ||
110 | ret = i2c_smbus_write_i2c_block_data(pchg->client, reg, len, data); | ||
111 | mutex_unlock(&pchg->xfer_lock); | ||
112 | |||
113 | return ret; | ||
114 | } | ||
115 | |||
116 | static inline int lp8727_i2c_read_byte(struct lp8727_chg *pchg, u8 reg, | ||
117 | u8 *data) | ||
118 | { | ||
119 | return lp8727_i2c_read(pchg, reg, data, 1); | ||
120 | } | ||
121 | |||
122 | static inline int lp8727_i2c_write_byte(struct lp8727_chg *pchg, u8 reg, | ||
123 | u8 *data) | ||
124 | { | ||
125 | return lp8727_i2c_write(pchg, reg, data, 1); | ||
126 | } | ||
127 | |||
128 | static int lp8727_is_charger_attached(const char *name, int id) | ||
129 | { | ||
130 | if (name) { | ||
131 | if (!strcmp(name, "ac")) | ||
132 | return (id == ID_TA || id == ID_DEDICATED_CHG) ? 1 : 0; | ||
133 | else if (!strcmp(name, "usb")) | ||
134 | return (id == ID_USB_CHG) ? 1 : 0; | ||
135 | } | ||
136 | |||
137 | return (id >= ID_TA && id <= ID_USB_CHG) ? 1 : 0; | ||
138 | } | ||
139 | |||
140 | static void lp8727_init_device(struct lp8727_chg *pchg) | ||
141 | { | ||
142 | u8 val; | ||
143 | |||
144 | val = ID200_EN | ADC_EN | CP_EN; | ||
145 | if (lp8727_i2c_write_byte(pchg, CTRL1, &val)) | ||
146 | dev_err(pchg->dev, "i2c write err : addr=0x%.2x\n", CTRL1); | ||
147 | |||
148 | val = INT_EN | CHGDET_EN; | ||
149 | if (lp8727_i2c_write_byte(pchg, CTRL2, &val)) | ||
150 | dev_err(pchg->dev, "i2c write err : addr=0x%.2x\n", CTRL2); | ||
151 | } | ||
152 | |||
153 | static int lp8727_is_dedicated_charger(struct lp8727_chg *pchg) | ||
154 | { | ||
155 | u8 val; | ||
156 | lp8727_i2c_read_byte(pchg, STATUS1, &val); | ||
157 | return (val & DCPORT); | ||
158 | } | ||
159 | |||
160 | static int lp8727_is_usb_charger(struct lp8727_chg *pchg) | ||
161 | { | ||
162 | u8 val; | ||
163 | lp8727_i2c_read_byte(pchg, STATUS1, &val); | ||
164 | return (val & CHPORT); | ||
165 | } | ||
166 | |||
167 | static void lp8727_ctrl_switch(struct lp8727_chg *pchg, u8 sw) | ||
168 | { | ||
169 | u8 val = sw; | ||
170 | lp8727_i2c_write_byte(pchg, SWCTRL, &val); | ||
171 | } | ||
172 | |||
173 | static void lp8727_id_detection(struct lp8727_chg *pchg, u8 id, int vbusin) | ||
174 | { | ||
175 | u8 devid = ID_NONE; | ||
176 | u8 swctrl = SW_DM1_HiZ | SW_DP2_HiZ; | ||
177 | |||
178 | switch (id) { | ||
179 | case 0x5: | ||
180 | devid = ID_TA; | ||
181 | pchg->chg_parm = &pchg->pdata->ac; | ||
182 | break; | ||
183 | case 0xB: | ||
184 | if (lp8727_is_dedicated_charger(pchg)) { | ||
185 | pchg->chg_parm = &pchg->pdata->ac; | ||
186 | devid = ID_DEDICATED_CHG; | ||
187 | } else if (lp8727_is_usb_charger(pchg)) { | ||
188 | pchg->chg_parm = &pchg->pdata->usb; | ||
189 | devid = ID_USB_CHG; | ||
190 | swctrl = SW_DM1_DM | SW_DP2_DP; | ||
191 | } else if (vbusin) { | ||
192 | devid = ID_USB_DS; | ||
193 | swctrl = SW_DM1_DM | SW_DP2_DP; | ||
194 | } | ||
195 | break; | ||
196 | default: | ||
197 | devid = ID_NONE; | ||
198 | pchg->chg_parm = NULL; | ||
199 | break; | ||
200 | } | ||
201 | |||
202 | pchg->devid = devid; | ||
203 | lp8727_ctrl_switch(pchg, swctrl); | ||
204 | } | ||
205 | |||
206 | static void lp8727_enable_chgdet(struct lp8727_chg *pchg) | ||
207 | { | ||
208 | u8 val; | ||
209 | |||
210 | lp8727_i2c_read_byte(pchg, CTRL2, &val); | ||
211 | val |= CHGDET_EN; | ||
212 | lp8727_i2c_write_byte(pchg, CTRL2, &val); | ||
213 | } | ||
214 | |||
215 | static void lp8727_delayed_func(struct work_struct *_work) | ||
216 | { | ||
217 | u8 intstat[2], idno, vbus; | ||
218 | struct lp8727_chg *pchg = | ||
219 | container_of(_work, struct lp8727_chg, work.work); | ||
220 | |||
221 | if (lp8727_i2c_read(pchg, INT1, intstat, 2)) { | ||
222 | dev_err(pchg->dev, "can not read INT registers\n"); | ||
223 | return; | ||
224 | } | ||
225 | |||
226 | idno = intstat[0] & IDNO; | ||
227 | vbus = intstat[0] & VBUS; | ||
228 | |||
229 | lp8727_id_detection(pchg, idno, vbus); | ||
230 | lp8727_enable_chgdet(pchg); | ||
231 | |||
232 | power_supply_changed(&pchg->psy->ac); | ||
233 | power_supply_changed(&pchg->psy->usb); | ||
234 | power_supply_changed(&pchg->psy->batt); | ||
235 | } | ||
236 | |||
237 | static irqreturn_t lp8727_isr_func(int irq, void *ptr) | ||
238 | { | ||
239 | struct lp8727_chg *pchg = ptr; | ||
240 | unsigned long delay = msecs_to_jiffies(DEBOUNCE_MSEC); | ||
241 | |||
242 | queue_delayed_work(pchg->irqthread, &pchg->work, delay); | ||
243 | |||
244 | return IRQ_HANDLED; | ||
245 | } | ||
246 | |||
247 | static void lp8727_intr_config(struct lp8727_chg *pchg) | ||
248 | { | ||
249 | INIT_DELAYED_WORK(&pchg->work, lp8727_delayed_func); | ||
250 | |||
251 | pchg->irqthread = create_singlethread_workqueue("lp8727-irqthd"); | ||
252 | if (!pchg->irqthread) | ||
253 | dev_err(pchg->dev, "can not create thread for lp8727\n"); | ||
254 | |||
255 | if (request_threaded_irq(pchg->client->irq, | ||
256 | NULL, | ||
257 | lp8727_isr_func, | ||
258 | IRQF_TRIGGER_FALLING, "lp8727_irq", pchg)) { | ||
259 | dev_err(pchg->dev, "lp8727 irq can not be registered\n"); | ||
260 | } | ||
261 | } | ||
262 | |||
263 | static enum power_supply_property lp8727_charger_prop[] = { | ||
264 | POWER_SUPPLY_PROP_ONLINE, | ||
265 | }; | ||
266 | |||
267 | static enum power_supply_property lp8727_battery_prop[] = { | ||
268 | POWER_SUPPLY_PROP_STATUS, | ||
269 | POWER_SUPPLY_PROP_HEALTH, | ||
270 | POWER_SUPPLY_PROP_PRESENT, | ||
271 | POWER_SUPPLY_PROP_VOLTAGE_NOW, | ||
272 | POWER_SUPPLY_PROP_CAPACITY, | ||
273 | POWER_SUPPLY_PROP_TEMP, | ||
274 | }; | ||
275 | |||
276 | static char *battery_supplied_to[] = { | ||
277 | "main_batt", | ||
278 | }; | ||
279 | |||
280 | static int lp8727_charger_get_property(struct power_supply *psy, | ||
281 | enum power_supply_property psp, | ||
282 | union power_supply_propval *val) | ||
283 | { | ||
284 | struct lp8727_chg *pchg = dev_get_drvdata(psy->dev->parent); | ||
285 | |||
286 | if (psp == POWER_SUPPLY_PROP_ONLINE) | ||
287 | val->intval = lp8727_is_charger_attached(psy->name, | ||
288 | pchg->devid); | ||
289 | |||
290 | return 0; | ||
291 | } | ||
292 | |||
293 | static int lp8727_battery_get_property(struct power_supply *psy, | ||
294 | enum power_supply_property psp, | ||
295 | union power_supply_propval *val) | ||
296 | { | ||
297 | struct lp8727_chg *pchg = dev_get_drvdata(psy->dev->parent); | ||
298 | u8 read; | ||
299 | |||
300 | switch (psp) { | ||
301 | case POWER_SUPPLY_PROP_STATUS: | ||
302 | if (lp8727_is_charger_attached(psy->name, pchg->devid)) { | ||
303 | lp8727_i2c_read_byte(pchg, STATUS1, &read); | ||
304 | if (((read & CHGSTAT) >> 4) == EOC) | ||
305 | val->intval = POWER_SUPPLY_STATUS_FULL; | ||
306 | else | ||
307 | val->intval = POWER_SUPPLY_STATUS_CHARGING; | ||
308 | } else { | ||
309 | val->intval = POWER_SUPPLY_STATUS_DISCHARGING; | ||
310 | } | ||
311 | break; | ||
312 | case POWER_SUPPLY_PROP_HEALTH: | ||
313 | lp8727_i2c_read_byte(pchg, STATUS2, &read); | ||
314 | read = (read & TEMP_STAT) >> 5; | ||
315 | if (read >= 0x1 && read <= 0x3) | ||
316 | val->intval = POWER_SUPPLY_HEALTH_OVERHEAT; | ||
317 | else | ||
318 | val->intval = POWER_SUPPLY_HEALTH_GOOD; | ||
319 | break; | ||
320 | case POWER_SUPPLY_PROP_PRESENT: | ||
321 | if (pchg->pdata->get_batt_present) | ||
322 | val->intval = pchg->pdata->get_batt_present(); | ||
323 | break; | ||
324 | case POWER_SUPPLY_PROP_VOLTAGE_NOW: | ||
325 | if (pchg->pdata->get_batt_level) | ||
326 | val->intval = pchg->pdata->get_batt_level(); | ||
327 | break; | ||
328 | case POWER_SUPPLY_PROP_CAPACITY: | ||
329 | if (pchg->pdata->get_batt_capacity) | ||
330 | val->intval = pchg->pdata->get_batt_capacity(); | ||
331 | break; | ||
332 | case POWER_SUPPLY_PROP_TEMP: | ||
333 | if (pchg->pdata->get_batt_temp) | ||
334 | val->intval = pchg->pdata->get_batt_temp(); | ||
335 | break; | ||
336 | default: | ||
337 | break; | ||
338 | } | ||
339 | |||
340 | return 0; | ||
341 | } | ||
342 | |||
343 | static void lp8727_charger_changed(struct power_supply *psy) | ||
344 | { | ||
345 | struct lp8727_chg *pchg = dev_get_drvdata(psy->dev->parent); | ||
346 | u8 val; | ||
347 | u8 eoc_level, ichg; | ||
348 | |||
349 | if (lp8727_is_charger_attached(psy->name, pchg->devid)) { | ||
350 | if (pchg->chg_parm) { | ||
351 | eoc_level = pchg->chg_parm->eoc_level; | ||
352 | ichg = pchg->chg_parm->ichg; | ||
353 | val = (ichg << 4) | eoc_level; | ||
354 | lp8727_i2c_write_byte(pchg, CHGCTRL2, &val); | ||
355 | } | ||
356 | } | ||
357 | } | ||
358 | |||
359 | static int lp8727_register_psy(struct lp8727_chg *pchg) | ||
360 | { | ||
361 | struct lp8727_psy *psy; | ||
362 | |||
363 | psy = kzalloc(sizeof(*psy), GFP_KERNEL); | ||
364 | if (!psy) | ||
365 | goto err_mem; | ||
366 | |||
367 | pchg->psy = psy; | ||
368 | |||
369 | psy->ac.name = "ac"; | ||
370 | psy->ac.type = POWER_SUPPLY_TYPE_MAINS; | ||
371 | psy->ac.properties = lp8727_charger_prop; | ||
372 | psy->ac.num_properties = ARRAY_SIZE(lp8727_charger_prop); | ||
373 | psy->ac.get_property = lp8727_charger_get_property; | ||
374 | psy->ac.supplied_to = battery_supplied_to; | ||
375 | psy->ac.num_supplicants = ARRAY_SIZE(battery_supplied_to); | ||
376 | |||
377 | if (power_supply_register(pchg->dev, &psy->ac)) | ||
378 | goto err_psy; | ||
379 | |||
380 | psy->usb.name = "usb"; | ||
381 | psy->usb.type = POWER_SUPPLY_TYPE_USB; | ||
382 | psy->usb.properties = lp8727_charger_prop; | ||
383 | psy->usb.num_properties = ARRAY_SIZE(lp8727_charger_prop); | ||
384 | psy->usb.get_property = lp8727_charger_get_property; | ||
385 | psy->usb.supplied_to = battery_supplied_to; | ||
386 | psy->usb.num_supplicants = ARRAY_SIZE(battery_supplied_to); | ||
387 | |||
388 | if (power_supply_register(pchg->dev, &psy->usb)) | ||
389 | goto err_psy; | ||
390 | |||
391 | psy->batt.name = "main_batt"; | ||
392 | psy->batt.type = POWER_SUPPLY_TYPE_BATTERY; | ||
393 | psy->batt.properties = lp8727_battery_prop; | ||
394 | psy->batt.num_properties = ARRAY_SIZE(lp8727_battery_prop); | ||
395 | psy->batt.get_property = lp8727_battery_get_property; | ||
396 | psy->batt.external_power_changed = lp8727_charger_changed; | ||
397 | |||
398 | if (power_supply_register(pchg->dev, &psy->batt)) | ||
399 | goto err_psy; | ||
400 | |||
401 | return 0; | ||
402 | |||
403 | err_mem: | ||
404 | return -ENOMEM; | ||
405 | err_psy: | ||
406 | kfree(psy); | ||
407 | return -EPERM; | ||
408 | } | ||
409 | |||
410 | static void lp8727_unregister_psy(struct lp8727_chg *pchg) | ||
411 | { | ||
412 | struct lp8727_psy *psy = pchg->psy; | ||
413 | |||
414 | if (!psy) | ||
415 | return; | ||
416 | |||
417 | power_supply_unregister(&psy->ac); | ||
418 | power_supply_unregister(&psy->usb); | ||
419 | power_supply_unregister(&psy->batt); | ||
420 | kfree(psy); | ||
421 | } | ||
422 | |||
423 | static int lp8727_probe(struct i2c_client *cl, const struct i2c_device_id *id) | ||
424 | { | ||
425 | struct lp8727_chg *pchg; | ||
426 | int ret; | ||
427 | |||
428 | if (!i2c_check_functionality(cl->adapter, I2C_FUNC_SMBUS_I2C_BLOCK)) | ||
429 | return -EIO; | ||
430 | |||
431 | pchg = kzalloc(sizeof(*pchg), GFP_KERNEL); | ||
432 | if (!pchg) | ||
433 | return -ENOMEM; | ||
434 | |||
435 | pchg->client = cl; | ||
436 | pchg->dev = &cl->dev; | ||
437 | pchg->pdata = cl->dev.platform_data; | ||
438 | i2c_set_clientdata(cl, pchg); | ||
439 | |||
440 | mutex_init(&pchg->xfer_lock); | ||
441 | |||
442 | lp8727_init_device(pchg); | ||
443 | lp8727_intr_config(pchg); | ||
444 | |||
445 | ret = lp8727_register_psy(pchg); | ||
446 | if (ret) | ||
447 | dev_err(pchg->dev, | ||
448 | "can not register power supplies. err=%d", ret); | ||
449 | |||
450 | return 0; | ||
451 | } | ||
452 | |||
453 | static int __devexit lp8727_remove(struct i2c_client *cl) | ||
454 | { | ||
455 | struct lp8727_chg *pchg = i2c_get_clientdata(cl); | ||
456 | |||
457 | lp8727_unregister_psy(pchg); | ||
458 | free_irq(pchg->client->irq, pchg); | ||
459 | flush_workqueue(pchg->irqthread); | ||
460 | destroy_workqueue(pchg->irqthread); | ||
461 | kfree(pchg); | ||
462 | return 0; | ||
463 | } | ||
464 | |||
465 | static const struct i2c_device_id lp8727_ids[] = { | ||
466 | {"lp8727", 0}, | ||
467 | }; | ||
468 | |||
469 | static struct i2c_driver lp8727_driver = { | ||
470 | .driver = { | ||
471 | .name = "lp8727", | ||
472 | }, | ||
473 | .probe = lp8727_probe, | ||
474 | .remove = __devexit_p(lp8727_remove), | ||
475 | .id_table = lp8727_ids, | ||
476 | }; | ||
477 | |||
478 | static int __init lp8727_init(void) | ||
479 | { | ||
480 | return i2c_add_driver(&lp8727_driver); | ||
481 | } | ||
482 | |||
483 | static void __exit lp8727_exit(void) | ||
484 | { | ||
485 | i2c_del_driver(&lp8727_driver); | ||
486 | } | ||
487 | |||
488 | module_init(lp8727_init); | ||
489 | module_exit(lp8727_exit); | ||
490 | |||
491 | MODULE_DESCRIPTION("National Semiconductor LP8727 charger driver"); | ||
492 | MODULE_AUTHOR | ||
493 | ("Woogyom Kim <milo.kim@ti.com>, Daniel Jeong <daniel.jeong@ti.com>"); | ||
494 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/power/max17042_battery.c b/drivers/power/max17042_battery.c index 9f0183c73076..86acee2f9889 100644 --- a/drivers/power/max17042_battery.c +++ b/drivers/power/max17042_battery.c | |||
@@ -85,55 +85,79 @@ static int max17042_get_property(struct power_supply *psy, | |||
85 | { | 85 | { |
86 | struct max17042_chip *chip = container_of(psy, | 86 | struct max17042_chip *chip = container_of(psy, |
87 | struct max17042_chip, battery); | 87 | struct max17042_chip, battery); |
88 | int ret; | ||
88 | 89 | ||
89 | switch (psp) { | 90 | switch (psp) { |
90 | case POWER_SUPPLY_PROP_PRESENT: | 91 | case POWER_SUPPLY_PROP_PRESENT: |
91 | val->intval = max17042_read_reg(chip->client, | 92 | ret = max17042_read_reg(chip->client, MAX17042_STATUS); |
92 | MAX17042_STATUS); | 93 | if (ret < 0) |
93 | if (val->intval & MAX17042_STATUS_BattAbsent) | 94 | return ret; |
95 | |||
96 | if (ret & MAX17042_STATUS_BattAbsent) | ||
94 | val->intval = 0; | 97 | val->intval = 0; |
95 | else | 98 | else |
96 | val->intval = 1; | 99 | val->intval = 1; |
97 | break; | 100 | break; |
98 | case POWER_SUPPLY_PROP_CYCLE_COUNT: | 101 | case POWER_SUPPLY_PROP_CYCLE_COUNT: |
99 | val->intval = max17042_read_reg(chip->client, | 102 | ret = max17042_read_reg(chip->client, MAX17042_Cycles); |
100 | MAX17042_Cycles); | 103 | if (ret < 0) |
104 | return ret; | ||
105 | |||
106 | val->intval = ret; | ||
101 | break; | 107 | break; |
102 | case POWER_SUPPLY_PROP_VOLTAGE_MAX: | 108 | case POWER_SUPPLY_PROP_VOLTAGE_MAX: |
103 | val->intval = max17042_read_reg(chip->client, | 109 | ret = max17042_read_reg(chip->client, MAX17042_MinMaxVolt); |
104 | MAX17042_MinMaxVolt); | 110 | if (ret < 0) |
105 | val->intval >>= 8; | 111 | return ret; |
112 | |||
113 | val->intval = ret >> 8; | ||
106 | val->intval *= 20000; /* Units of LSB = 20mV */ | 114 | val->intval *= 20000; /* Units of LSB = 20mV */ |
107 | break; | 115 | break; |
108 | case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN: | 116 | case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN: |
109 | val->intval = max17042_read_reg(chip->client, | 117 | ret = max17042_read_reg(chip->client, MAX17042_V_empty); |
110 | MAX17042_V_empty); | 118 | if (ret < 0) |
111 | val->intval >>= 7; | 119 | return ret; |
120 | |||
121 | val->intval = ret >> 7; | ||
112 | val->intval *= 10000; /* Units of LSB = 10mV */ | 122 | val->intval *= 10000; /* Units of LSB = 10mV */ |
113 | break; | 123 | break; |
114 | case POWER_SUPPLY_PROP_VOLTAGE_NOW: | 124 | case POWER_SUPPLY_PROP_VOLTAGE_NOW: |
115 | val->intval = max17042_read_reg(chip->client, | 125 | ret = max17042_read_reg(chip->client, MAX17042_VCELL); |
116 | MAX17042_VCELL) * 83; /* 1000 / 12 = 83 */ | 126 | if (ret < 0) |
127 | return ret; | ||
128 | |||
129 | val->intval = ret * 625 / 8; | ||
117 | break; | 130 | break; |
118 | case POWER_SUPPLY_PROP_VOLTAGE_AVG: | 131 | case POWER_SUPPLY_PROP_VOLTAGE_AVG: |
119 | val->intval = max17042_read_reg(chip->client, | 132 | ret = max17042_read_reg(chip->client, MAX17042_AvgVCELL); |
120 | MAX17042_AvgVCELL) * 83; | 133 | if (ret < 0) |
134 | return ret; | ||
135 | |||
136 | val->intval = ret * 625 / 8; | ||
121 | break; | 137 | break; |
122 | case POWER_SUPPLY_PROP_CAPACITY: | 138 | case POWER_SUPPLY_PROP_CAPACITY: |
123 | val->intval = max17042_read_reg(chip->client, | 139 | ret = max17042_read_reg(chip->client, MAX17042_SOC); |
124 | MAX17042_SOC) / 256; | 140 | if (ret < 0) |
141 | return ret; | ||
142 | |||
143 | val->intval = ret >> 8; | ||
125 | break; | 144 | break; |
126 | case POWER_SUPPLY_PROP_CHARGE_FULL: | 145 | case POWER_SUPPLY_PROP_CHARGE_FULL: |
127 | val->intval = max17042_read_reg(chip->client, | 146 | ret = max17042_read_reg(chip->client, MAX17042_RepSOC); |
128 | MAX17042_RepSOC); | 147 | if (ret < 0) |
129 | if ((val->intval / 256) >= MAX17042_BATTERY_FULL) | 148 | return ret; |
149 | |||
150 | if ((ret >> 8) >= MAX17042_BATTERY_FULL) | ||
130 | val->intval = 1; | 151 | val->intval = 1; |
131 | else if (val->intval >= 0) | 152 | else if (ret >= 0) |
132 | val->intval = 0; | 153 | val->intval = 0; |
133 | break; | 154 | break; |
134 | case POWER_SUPPLY_PROP_TEMP: | 155 | case POWER_SUPPLY_PROP_TEMP: |
135 | val->intval = max17042_read_reg(chip->client, | 156 | ret = max17042_read_reg(chip->client, MAX17042_TEMP); |
136 | MAX17042_TEMP); | 157 | if (ret < 0) |
158 | return ret; | ||
159 | |||
160 | val->intval = ret; | ||
137 | /* The value is signed. */ | 161 | /* The value is signed. */ |
138 | if (val->intval & 0x8000) { | 162 | if (val->intval & 0x8000) { |
139 | val->intval = (0x7fff & ~val->intval) + 1; | 163 | val->intval = (0x7fff & ~val->intval) + 1; |
@@ -145,24 +169,30 @@ static int max17042_get_property(struct power_supply *psy, | |||
145 | break; | 169 | break; |
146 | case POWER_SUPPLY_PROP_CURRENT_NOW: | 170 | case POWER_SUPPLY_PROP_CURRENT_NOW: |
147 | if (chip->pdata->enable_current_sense) { | 171 | if (chip->pdata->enable_current_sense) { |
148 | val->intval = max17042_read_reg(chip->client, | 172 | ret = max17042_read_reg(chip->client, MAX17042_Current); |
149 | MAX17042_Current); | 173 | if (ret < 0) |
174 | return ret; | ||
175 | |||
176 | val->intval = ret; | ||
150 | if (val->intval & 0x8000) { | 177 | if (val->intval & 0x8000) { |
151 | /* Negative */ | 178 | /* Negative */ |
152 | val->intval = ~val->intval & 0x7fff; | 179 | val->intval = ~val->intval & 0x7fff; |
153 | val->intval++; | 180 | val->intval++; |
154 | val->intval *= -1; | 181 | val->intval *= -1; |
155 | } | 182 | } |
156 | val->intval >>= 4; | 183 | val->intval *= 1562500 / chip->pdata->r_sns; |
157 | val->intval *= 1000000 * 25 / chip->pdata->r_sns; | ||
158 | } else { | 184 | } else { |
159 | return -EINVAL; | 185 | return -EINVAL; |
160 | } | 186 | } |
161 | break; | 187 | break; |
162 | case POWER_SUPPLY_PROP_CURRENT_AVG: | 188 | case POWER_SUPPLY_PROP_CURRENT_AVG: |
163 | if (chip->pdata->enable_current_sense) { | 189 | if (chip->pdata->enable_current_sense) { |
164 | val->intval = max17042_read_reg(chip->client, | 190 | ret = max17042_read_reg(chip->client, |
165 | MAX17042_AvgCurrent); | 191 | MAX17042_AvgCurrent); |
192 | if (ret < 0) | ||
193 | return ret; | ||
194 | |||
195 | val->intval = ret; | ||
166 | if (val->intval & 0x8000) { | 196 | if (val->intval & 0x8000) { |
167 | /* Negative */ | 197 | /* Negative */ |
168 | val->intval = ~val->intval & 0x7fff; | 198 | val->intval = ~val->intval & 0x7fff; |
@@ -210,6 +240,9 @@ static int __devinit max17042_probe(struct i2c_client *client, | |||
210 | if (!chip->pdata->enable_current_sense) | 240 | if (!chip->pdata->enable_current_sense) |
211 | chip->battery.num_properties -= 2; | 241 | chip->battery.num_properties -= 2; |
212 | 242 | ||
243 | if (chip->pdata->r_sns == 0) | ||
244 | chip->pdata->r_sns = MAX17042_DEFAULT_SNS_RESISTOR; | ||
245 | |||
213 | ret = power_supply_register(&client->dev, &chip->battery); | 246 | ret = power_supply_register(&client->dev, &chip->battery); |
214 | if (ret) { | 247 | if (ret) { |
215 | dev_err(&client->dev, "failed: power supply register\n"); | 248 | dev_err(&client->dev, "failed: power supply register\n"); |
@@ -226,9 +259,6 @@ static int __devinit max17042_probe(struct i2c_client *client, | |||
226 | max17042_write_reg(client, MAX17042_CGAIN, 0x0000); | 259 | max17042_write_reg(client, MAX17042_CGAIN, 0x0000); |
227 | max17042_write_reg(client, MAX17042_MiscCFG, 0x0003); | 260 | max17042_write_reg(client, MAX17042_MiscCFG, 0x0003); |
228 | max17042_write_reg(client, MAX17042_LearnCFG, 0x0007); | 261 | max17042_write_reg(client, MAX17042_LearnCFG, 0x0007); |
229 | } else { | ||
230 | if (chip->pdata->r_sns == 0) | ||
231 | chip->pdata->r_sns = MAX17042_DEFAULT_SNS_RESISTOR; | ||
232 | } | 262 | } |
233 | 263 | ||
234 | return 0; | 264 | return 0; |
diff --git a/drivers/power/max8903_charger.c b/drivers/power/max8903_charger.c index 2595145f3bff..3e23f43e98af 100644 --- a/drivers/power/max8903_charger.c +++ b/drivers/power/max8903_charger.c | |||
@@ -374,19 +374,9 @@ static struct platform_driver max8903_driver = { | |||
374 | }, | 374 | }, |
375 | }; | 375 | }; |
376 | 376 | ||
377 | static int __init max8903_init(void) | 377 | module_platform_driver(max8903_driver); |
378 | { | ||
379 | return platform_driver_register(&max8903_driver); | ||
380 | } | ||
381 | module_init(max8903_init); | ||
382 | |||
383 | static void __exit max8903_exit(void) | ||
384 | { | ||
385 | platform_driver_unregister(&max8903_driver); | ||
386 | } | ||
387 | module_exit(max8903_exit); | ||
388 | 378 | ||
389 | MODULE_LICENSE("GPL"); | 379 | MODULE_LICENSE("GPL"); |
390 | MODULE_DESCRIPTION("MAX8903 Charger Driver"); | 380 | MODULE_DESCRIPTION("MAX8903 Charger Driver"); |
391 | MODULE_AUTHOR("MyungJoo Ham <myungjoo.ham@samsung.com>"); | 381 | MODULE_AUTHOR("MyungJoo Ham <myungjoo.ham@samsung.com>"); |
392 | MODULE_ALIAS("max8903-charger"); | 382 | MODULE_ALIAS("platform:max8903-charger"); |
diff --git a/drivers/power/max8925_power.c b/drivers/power/max8925_power.c index a70e16d3a3dc..daa333bd7ebb 100644 --- a/drivers/power/max8925_power.c +++ b/drivers/power/max8925_power.c | |||
@@ -78,6 +78,8 @@ struct max8925_power_info { | |||
78 | unsigned batt_detect:1; /* detecing MB by ID pin */ | 78 | unsigned batt_detect:1; /* detecing MB by ID pin */ |
79 | unsigned topoff_threshold:2; | 79 | unsigned topoff_threshold:2; |
80 | unsigned fast_charge:3; | 80 | unsigned fast_charge:3; |
81 | unsigned no_temp_support:1; | ||
82 | unsigned no_insert_detect:1; | ||
81 | 83 | ||
82 | int (*set_charger) (int); | 84 | int (*set_charger) (int); |
83 | }; | 85 | }; |
@@ -116,17 +118,7 @@ static irqreturn_t max8925_charger_handler(int irq, void *data) | |||
116 | case MAX8925_IRQ_VCHG_DC_F: | 118 | case MAX8925_IRQ_VCHG_DC_F: |
117 | info->ac_online = 0; | 119 | info->ac_online = 0; |
118 | __set_charger(info, 0); | 120 | __set_charger(info, 0); |
119 | dev_dbg(chip->dev, "Adapter is removal\n"); | 121 | dev_dbg(chip->dev, "Adapter removed\n"); |
120 | break; | ||
121 | case MAX8925_IRQ_VCHG_USB_R: | ||
122 | info->usb_online = 1; | ||
123 | __set_charger(info, 1); | ||
124 | dev_dbg(chip->dev, "USB inserted\n"); | ||
125 | break; | ||
126 | case MAX8925_IRQ_VCHG_USB_F: | ||
127 | info->usb_online = 0; | ||
128 | __set_charger(info, 0); | ||
129 | dev_dbg(chip->dev, "USB is removal\n"); | ||
130 | break; | 122 | break; |
131 | case MAX8925_IRQ_VCHG_THM_OK_F: | 123 | case MAX8925_IRQ_VCHG_THM_OK_F: |
132 | /* Battery is not ready yet */ | 124 | /* Battery is not ready yet */ |
@@ -168,27 +160,33 @@ static irqreturn_t max8925_charger_handler(int irq, void *data) | |||
168 | static int start_measure(struct max8925_power_info *info, int type) | 160 | static int start_measure(struct max8925_power_info *info, int type) |
169 | { | 161 | { |
170 | unsigned char buf[2] = {0, 0}; | 162 | unsigned char buf[2] = {0, 0}; |
163 | int meas_cmd; | ||
171 | int meas_reg = 0, ret; | 164 | int meas_reg = 0, ret; |
172 | 165 | ||
173 | switch (type) { | 166 | switch (type) { |
174 | case MEASURE_VCHG: | 167 | case MEASURE_VCHG: |
168 | meas_cmd = MAX8925_CMD_VCHG; | ||
175 | meas_reg = MAX8925_ADC_VCHG; | 169 | meas_reg = MAX8925_ADC_VCHG; |
176 | break; | 170 | break; |
177 | case MEASURE_VBBATT: | 171 | case MEASURE_VBBATT: |
172 | meas_cmd = MAX8925_CMD_VBBATT; | ||
178 | meas_reg = MAX8925_ADC_VBBATT; | 173 | meas_reg = MAX8925_ADC_VBBATT; |
179 | break; | 174 | break; |
180 | case MEASURE_VMBATT: | 175 | case MEASURE_VMBATT: |
176 | meas_cmd = MAX8925_CMD_VMBATT; | ||
181 | meas_reg = MAX8925_ADC_VMBATT; | 177 | meas_reg = MAX8925_ADC_VMBATT; |
182 | break; | 178 | break; |
183 | case MEASURE_ISNS: | 179 | case MEASURE_ISNS: |
180 | meas_cmd = MAX8925_CMD_ISNS; | ||
184 | meas_reg = MAX8925_ADC_ISNS; | 181 | meas_reg = MAX8925_ADC_ISNS; |
185 | break; | 182 | break; |
186 | default: | 183 | default: |
187 | return -EINVAL; | 184 | return -EINVAL; |
188 | } | 185 | } |
189 | 186 | ||
187 | max8925_reg_write(info->adc, meas_cmd, 0); | ||
190 | max8925_bulk_read(info->adc, meas_reg, 2, buf); | 188 | max8925_bulk_read(info->adc, meas_reg, 2, buf); |
191 | ret = (buf[0] << 4) | (buf[1] >> 4); | 189 | ret = ((buf[0]<<8) | buf[1]) >> 4; |
192 | 190 | ||
193 | return ret; | 191 | return ret; |
194 | } | 192 | } |
@@ -208,7 +206,7 @@ static int max8925_ac_get_prop(struct power_supply *psy, | |||
208 | if (info->ac_online) { | 206 | if (info->ac_online) { |
209 | ret = start_measure(info, MEASURE_VCHG); | 207 | ret = start_measure(info, MEASURE_VCHG); |
210 | if (ret >= 0) { | 208 | if (ret >= 0) { |
211 | val->intval = ret << 1; /* unit is mV */ | 209 | val->intval = ret * 2000; /* unit is uV */ |
212 | goto out; | 210 | goto out; |
213 | } | 211 | } |
214 | } | 212 | } |
@@ -242,7 +240,7 @@ static int max8925_usb_get_prop(struct power_supply *psy, | |||
242 | if (info->usb_online) { | 240 | if (info->usb_online) { |
243 | ret = start_measure(info, MEASURE_VCHG); | 241 | ret = start_measure(info, MEASURE_VCHG); |
244 | if (ret >= 0) { | 242 | if (ret >= 0) { |
245 | val->intval = ret << 1; /* unit is mV */ | 243 | val->intval = ret * 2000; /* unit is uV */ |
246 | goto out; | 244 | goto out; |
247 | } | 245 | } |
248 | } | 246 | } |
@@ -266,7 +264,6 @@ static int max8925_bat_get_prop(struct power_supply *psy, | |||
266 | union power_supply_propval *val) | 264 | union power_supply_propval *val) |
267 | { | 265 | { |
268 | struct max8925_power_info *info = dev_get_drvdata(psy->dev->parent); | 266 | struct max8925_power_info *info = dev_get_drvdata(psy->dev->parent); |
269 | long long int tmp = 0; | ||
270 | int ret = 0; | 267 | int ret = 0; |
271 | 268 | ||
272 | switch (psp) { | 269 | switch (psp) { |
@@ -277,7 +274,7 @@ static int max8925_bat_get_prop(struct power_supply *psy, | |||
277 | if (info->bat_online) { | 274 | if (info->bat_online) { |
278 | ret = start_measure(info, MEASURE_VMBATT); | 275 | ret = start_measure(info, MEASURE_VMBATT); |
279 | if (ret >= 0) { | 276 | if (ret >= 0) { |
280 | val->intval = ret << 1; /* unit is mV */ | 277 | val->intval = ret * 2000; /* unit is uV */ |
281 | ret = 0; | 278 | ret = 0; |
282 | break; | 279 | break; |
283 | } | 280 | } |
@@ -288,8 +285,8 @@ static int max8925_bat_get_prop(struct power_supply *psy, | |||
288 | if (info->bat_online) { | 285 | if (info->bat_online) { |
289 | ret = start_measure(info, MEASURE_ISNS); | 286 | ret = start_measure(info, MEASURE_ISNS); |
290 | if (ret >= 0) { | 287 | if (ret >= 0) { |
291 | tmp = (long long int)ret * 6250 / 4096 - 3125; | 288 | /* assume r_sns is 0.02 */ |
292 | ret = (int)tmp; | 289 | ret = ((ret * 6250) - 3125) /* uA */; |
293 | val->intval = 0; | 290 | val->intval = 0; |
294 | if (ret > 0) | 291 | if (ret > 0) |
295 | val->intval = ret; /* unit is mA */ | 292 | val->intval = ret; /* unit is mA */ |
@@ -365,13 +362,14 @@ static __devinit int max8925_init_charger(struct max8925_chip *chip, | |||
365 | int ret; | 362 | int ret; |
366 | 363 | ||
367 | REQUEST_IRQ(MAX8925_IRQ_VCHG_DC_OVP, "ac-ovp"); | 364 | REQUEST_IRQ(MAX8925_IRQ_VCHG_DC_OVP, "ac-ovp"); |
368 | REQUEST_IRQ(MAX8925_IRQ_VCHG_DC_F, "ac-remove"); | 365 | if (!info->no_insert_detect) { |
369 | REQUEST_IRQ(MAX8925_IRQ_VCHG_DC_R, "ac-insert"); | 366 | REQUEST_IRQ(MAX8925_IRQ_VCHG_DC_F, "ac-remove"); |
370 | REQUEST_IRQ(MAX8925_IRQ_VCHG_USB_OVP, "usb-ovp"); | 367 | REQUEST_IRQ(MAX8925_IRQ_VCHG_DC_R, "ac-insert"); |
371 | REQUEST_IRQ(MAX8925_IRQ_VCHG_USB_F, "usb-remove"); | 368 | } |
372 | REQUEST_IRQ(MAX8925_IRQ_VCHG_USB_R, "usb-insert"); | 369 | if (!info->no_temp_support) { |
373 | REQUEST_IRQ(MAX8925_IRQ_VCHG_THM_OK_R, "batt-temp-in-range"); | 370 | REQUEST_IRQ(MAX8925_IRQ_VCHG_THM_OK_R, "batt-temp-in-range"); |
374 | REQUEST_IRQ(MAX8925_IRQ_VCHG_THM_OK_F, "batt-temp-out-range"); | 371 | REQUEST_IRQ(MAX8925_IRQ_VCHG_THM_OK_F, "batt-temp-out-range"); |
372 | } | ||
375 | REQUEST_IRQ(MAX8925_IRQ_VCHG_SYSLOW_F, "vsys-high"); | 373 | REQUEST_IRQ(MAX8925_IRQ_VCHG_SYSLOW_F, "vsys-high"); |
376 | REQUEST_IRQ(MAX8925_IRQ_VCHG_SYSLOW_R, "vsys-low"); | 374 | REQUEST_IRQ(MAX8925_IRQ_VCHG_SYSLOW_R, "vsys-low"); |
377 | REQUEST_IRQ(MAX8925_IRQ_VCHG_RST, "charger-reset"); | 375 | REQUEST_IRQ(MAX8925_IRQ_VCHG_RST, "charger-reset"); |
@@ -379,9 +377,15 @@ static __devinit int max8925_init_charger(struct max8925_chip *chip, | |||
379 | REQUEST_IRQ(MAX8925_IRQ_VCHG_TOPOFF, "charger-topoff"); | 377 | REQUEST_IRQ(MAX8925_IRQ_VCHG_TOPOFF, "charger-topoff"); |
380 | REQUEST_IRQ(MAX8925_IRQ_VCHG_TMR_FAULT, "charger-timer-expire"); | 378 | REQUEST_IRQ(MAX8925_IRQ_VCHG_TMR_FAULT, "charger-timer-expire"); |
381 | 379 | ||
382 | info->ac_online = 0; | ||
383 | info->usb_online = 0; | 380 | info->usb_online = 0; |
384 | info->bat_online = 0; | 381 | info->bat_online = 0; |
382 | |||
383 | /* check for power - can miss interrupt at boot time */ | ||
384 | if (start_measure(info, MEASURE_VCHG) * 2000 > 500000) | ||
385 | info->ac_online = 1; | ||
386 | else | ||
387 | info->ac_online = 0; | ||
388 | |||
385 | ret = max8925_reg_read(info->gpm, MAX8925_CHG_STATUS); | 389 | ret = max8925_reg_read(info->gpm, MAX8925_CHG_STATUS); |
386 | if (ret >= 0) { | 390 | if (ret >= 0) { |
387 | /* | 391 | /* |
@@ -449,6 +453,8 @@ static __devinit int max8925_power_probe(struct platform_device *pdev) | |||
449 | info->ac.properties = max8925_ac_props; | 453 | info->ac.properties = max8925_ac_props; |
450 | info->ac.num_properties = ARRAY_SIZE(max8925_ac_props); | 454 | info->ac.num_properties = ARRAY_SIZE(max8925_ac_props); |
451 | info->ac.get_property = max8925_ac_get_prop; | 455 | info->ac.get_property = max8925_ac_get_prop; |
456 | info->ac.supplied_to = pdata->supplied_to; | ||
457 | info->ac.num_supplicants = pdata->num_supplicants; | ||
452 | ret = power_supply_register(&pdev->dev, &info->ac); | 458 | ret = power_supply_register(&pdev->dev, &info->ac); |
453 | if (ret) | 459 | if (ret) |
454 | goto out; | 460 | goto out; |
@@ -459,6 +465,9 @@ static __devinit int max8925_power_probe(struct platform_device *pdev) | |||
459 | info->usb.properties = max8925_usb_props; | 465 | info->usb.properties = max8925_usb_props; |
460 | info->usb.num_properties = ARRAY_SIZE(max8925_usb_props); | 466 | info->usb.num_properties = ARRAY_SIZE(max8925_usb_props); |
461 | info->usb.get_property = max8925_usb_get_prop; | 467 | info->usb.get_property = max8925_usb_get_prop; |
468 | info->usb.supplied_to = pdata->supplied_to; | ||
469 | info->usb.num_supplicants = pdata->num_supplicants; | ||
470 | |||
462 | ret = power_supply_register(&pdev->dev, &info->usb); | 471 | ret = power_supply_register(&pdev->dev, &info->usb); |
463 | if (ret) | 472 | if (ret) |
464 | goto out_usb; | 473 | goto out_usb; |
@@ -478,6 +487,8 @@ static __devinit int max8925_power_probe(struct platform_device *pdev) | |||
478 | info->topoff_threshold = pdata->topoff_threshold; | 487 | info->topoff_threshold = pdata->topoff_threshold; |
479 | info->fast_charge = pdata->fast_charge; | 488 | info->fast_charge = pdata->fast_charge; |
480 | info->set_charger = pdata->set_charger; | 489 | info->set_charger = pdata->set_charger; |
490 | info->no_temp_support = pdata->no_temp_support; | ||
491 | info->no_insert_detect = pdata->no_insert_detect; | ||
481 | 492 | ||
482 | max8925_init_charger(chip, info); | 493 | max8925_init_charger(chip, info); |
483 | return 0; | 494 | return 0; |
@@ -512,17 +523,7 @@ static struct platform_driver max8925_power_driver = { | |||
512 | }, | 523 | }, |
513 | }; | 524 | }; |
514 | 525 | ||
515 | static int __init max8925_power_init(void) | 526 | module_platform_driver(max8925_power_driver); |
516 | { | ||
517 | return platform_driver_register(&max8925_power_driver); | ||
518 | } | ||
519 | module_init(max8925_power_init); | ||
520 | |||
521 | static void __exit max8925_power_exit(void) | ||
522 | { | ||
523 | platform_driver_unregister(&max8925_power_driver); | ||
524 | } | ||
525 | module_exit(max8925_power_exit); | ||
526 | 527 | ||
527 | MODULE_LICENSE("GPL"); | 528 | MODULE_LICENSE("GPL"); |
528 | MODULE_DESCRIPTION("Power supply driver for MAX8925"); | 529 | MODULE_DESCRIPTION("Power supply driver for MAX8925"); |
diff --git a/drivers/power/max8997_charger.c b/drivers/power/max8997_charger.c index a23317d75c5a..6e88c5d026b9 100644 --- a/drivers/power/max8997_charger.c +++ b/drivers/power/max8997_charger.c | |||
@@ -19,7 +19,6 @@ | |||
19 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 19 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
20 | */ | 20 | */ |
21 | 21 | ||
22 | #include <linux/module.h> | ||
23 | #include <linux/err.h> | 22 | #include <linux/err.h> |
24 | #include <linux/module.h> | 23 | #include <linux/module.h> |
25 | #include <linux/slab.h> | 24 | #include <linux/slab.h> |
@@ -98,7 +97,7 @@ static __devinit int max8997_battery_probe(struct platform_device *pdev) | |||
98 | return -EINVAL; | 97 | return -EINVAL; |
99 | 98 | ||
100 | if (pdata->eoc_mA) { | 99 | if (pdata->eoc_mA) { |
101 | u8 val = (pdata->eoc_mA - 50) / 10; | 100 | int val = (pdata->eoc_mA - 50) / 10; |
102 | if (val < 0) | 101 | if (val < 0) |
103 | val = 0; | 102 | val = 0; |
104 | if (val > 0xf) | 103 | if (val > 0xf) |
@@ -179,6 +178,7 @@ static int __devexit max8997_battery_remove(struct platform_device *pdev) | |||
179 | 178 | ||
180 | static const struct platform_device_id max8997_battery_id[] = { | 179 | static const struct platform_device_id max8997_battery_id[] = { |
181 | { "max8997-battery", 0 }, | 180 | { "max8997-battery", 0 }, |
181 | { } | ||
182 | }; | 182 | }; |
183 | 183 | ||
184 | static struct platform_driver max8997_battery_driver = { | 184 | static struct platform_driver max8997_battery_driver = { |
diff --git a/drivers/power/max8998_charger.c b/drivers/power/max8998_charger.c index 93e3bb47a3a8..9b3f2bf56e70 100644 --- a/drivers/power/max8998_charger.c +++ b/drivers/power/max8998_charger.c | |||
@@ -154,6 +154,7 @@ static __devinit int max8998_battery_probe(struct platform_device *pdev) | |||
154 | case 0: | 154 | case 0: |
155 | dev_dbg(max8998->dev, | 155 | dev_dbg(max8998->dev, |
156 | "Full Timeout not set: leave it unchanged.\n"); | 156 | "Full Timeout not set: leave it unchanged.\n"); |
157 | break; | ||
157 | default: | 158 | default: |
158 | dev_err(max8998->dev, "Invalid Full Timeout value\n"); | 159 | dev_err(max8998->dev, "Invalid Full Timeout value\n"); |
159 | ret = -EINVAL; | 160 | ret = -EINVAL; |
@@ -190,6 +191,7 @@ static int __devexit max8998_battery_remove(struct platform_device *pdev) | |||
190 | 191 | ||
191 | static const struct platform_device_id max8998_battery_id[] = { | 192 | static const struct platform_device_id max8998_battery_id[] = { |
192 | { "max8998-battery", TYPE_MAX8998 }, | 193 | { "max8998-battery", TYPE_MAX8998 }, |
194 | { } | ||
193 | }; | 195 | }; |
194 | 196 | ||
195 | static struct platform_driver max8998_battery_driver = { | 197 | static struct platform_driver max8998_battery_driver = { |
@@ -202,17 +204,7 @@ static struct platform_driver max8998_battery_driver = { | |||
202 | .id_table = max8998_battery_id, | 204 | .id_table = max8998_battery_id, |
203 | }; | 205 | }; |
204 | 206 | ||
205 | static int __init max8998_battery_init(void) | 207 | module_platform_driver(max8998_battery_driver); |
206 | { | ||
207 | return platform_driver_register(&max8998_battery_driver); | ||
208 | } | ||
209 | module_init(max8998_battery_init); | ||
210 | |||
211 | static void __exit max8998_battery_cleanup(void) | ||
212 | { | ||
213 | platform_driver_unregister(&max8998_battery_driver); | ||
214 | } | ||
215 | module_exit(max8998_battery_cleanup); | ||
216 | 208 | ||
217 | MODULE_DESCRIPTION("MAXIM 8998 battery control driver"); | 209 | MODULE_DESCRIPTION("MAXIM 8998 battery control driver"); |
218 | MODULE_AUTHOR("MyungJoo Ham <myungjoo.ham@samsung.com>"); | 210 | MODULE_AUTHOR("MyungJoo Ham <myungjoo.ham@samsung.com>"); |
diff --git a/drivers/power/olpc_battery.c b/drivers/power/olpc_battery.c index 0b0ff3a936a6..7385092f9bc8 100644 --- a/drivers/power/olpc_battery.c +++ b/drivers/power/olpc_battery.c | |||
@@ -519,29 +519,35 @@ static struct device_attribute olpc_bat_error = { | |||
519 | * Initialisation | 519 | * Initialisation |
520 | *********************************************************************/ | 520 | *********************************************************************/ |
521 | 521 | ||
522 | static struct platform_device *bat_pdev; | ||
523 | |||
524 | static struct power_supply olpc_bat = { | 522 | static struct power_supply olpc_bat = { |
523 | .name = "olpc-battery", | ||
525 | .get_property = olpc_bat_get_property, | 524 | .get_property = olpc_bat_get_property, |
526 | .use_for_apm = 1, | 525 | .use_for_apm = 1, |
527 | }; | 526 | }; |
528 | 527 | ||
529 | void olpc_battery_trigger_uevent(unsigned long cause) | 528 | static int olpc_battery_suspend(struct platform_device *pdev, |
529 | pm_message_t state) | ||
530 | { | 530 | { |
531 | if (cause & EC_SCI_SRC_ACPWR) | 531 | if (device_may_wakeup(olpc_ac.dev)) |
532 | kobject_uevent(&olpc_ac.dev->kobj, KOBJ_CHANGE); | 532 | olpc_ec_wakeup_set(EC_SCI_SRC_ACPWR); |
533 | if (cause & (EC_SCI_SRC_BATERR|EC_SCI_SRC_BATSOC|EC_SCI_SRC_BATTERY)) | 533 | else |
534 | kobject_uevent(&olpc_bat.dev->kobj, KOBJ_CHANGE); | 534 | olpc_ec_wakeup_clear(EC_SCI_SRC_ACPWR); |
535 | |||
536 | if (device_may_wakeup(olpc_bat.dev)) | ||
537 | olpc_ec_wakeup_set(EC_SCI_SRC_BATTERY | EC_SCI_SRC_BATSOC | ||
538 | | EC_SCI_SRC_BATERR); | ||
539 | else | ||
540 | olpc_ec_wakeup_clear(EC_SCI_SRC_BATTERY | EC_SCI_SRC_BATSOC | ||
541 | | EC_SCI_SRC_BATERR); | ||
542 | |||
543 | return 0; | ||
535 | } | 544 | } |
536 | 545 | ||
537 | static int __init olpc_bat_init(void) | 546 | static int __devinit olpc_battery_probe(struct platform_device *pdev) |
538 | { | 547 | { |
539 | int ret = 0; | 548 | int ret; |
540 | uint8_t status; | 549 | uint8_t status; |
541 | 550 | ||
542 | if (!olpc_platform_info.ecver) | ||
543 | return -ENXIO; | ||
544 | |||
545 | /* | 551 | /* |
546 | * We've seen a number of EC protocol changes; this driver requires | 552 | * We've seen a number of EC protocol changes; this driver requires |
547 | * the latest EC protocol, supported by 0x44 and above. | 553 | * the latest EC protocol, supported by 0x44 and above. |
@@ -558,15 +564,10 @@ static int __init olpc_bat_init(void) | |||
558 | 564 | ||
559 | /* Ignore the status. It doesn't actually matter */ | 565 | /* Ignore the status. It doesn't actually matter */ |
560 | 566 | ||
561 | bat_pdev = platform_device_register_simple("olpc-battery", 0, NULL, 0); | 567 | ret = power_supply_register(&pdev->dev, &olpc_ac); |
562 | if (IS_ERR(bat_pdev)) | ||
563 | return PTR_ERR(bat_pdev); | ||
564 | |||
565 | ret = power_supply_register(&bat_pdev->dev, &olpc_ac); | ||
566 | if (ret) | 568 | if (ret) |
567 | goto ac_failed; | 569 | return ret; |
568 | 570 | ||
569 | olpc_bat.name = bat_pdev->name; | ||
570 | if (olpc_board_at_least(olpc_board_pre(0xd0))) { /* XO-1.5 */ | 571 | if (olpc_board_at_least(olpc_board_pre(0xd0))) { /* XO-1.5 */ |
571 | olpc_bat.properties = olpc_xo15_bat_props; | 572 | olpc_bat.properties = olpc_xo15_bat_props; |
572 | olpc_bat.num_properties = ARRAY_SIZE(olpc_xo15_bat_props); | 573 | olpc_bat.num_properties = ARRAY_SIZE(olpc_xo15_bat_props); |
@@ -575,7 +576,7 @@ static int __init olpc_bat_init(void) | |||
575 | olpc_bat.num_properties = ARRAY_SIZE(olpc_xo1_bat_props); | 576 | olpc_bat.num_properties = ARRAY_SIZE(olpc_xo1_bat_props); |
576 | } | 577 | } |
577 | 578 | ||
578 | ret = power_supply_register(&bat_pdev->dev, &olpc_bat); | 579 | ret = power_supply_register(&pdev->dev, &olpc_bat); |
579 | if (ret) | 580 | if (ret) |
580 | goto battery_failed; | 581 | goto battery_failed; |
581 | 582 | ||
@@ -587,7 +588,12 @@ static int __init olpc_bat_init(void) | |||
587 | if (ret) | 588 | if (ret) |
588 | goto error_failed; | 589 | goto error_failed; |
589 | 590 | ||
590 | goto success; | 591 | if (olpc_ec_wakeup_available()) { |
592 | device_set_wakeup_capable(olpc_ac.dev, true); | ||
593 | device_set_wakeup_capable(olpc_bat.dev, true); | ||
594 | } | ||
595 | |||
596 | return 0; | ||
591 | 597 | ||
592 | error_failed: | 598 | error_failed: |
593 | device_remove_bin_file(olpc_bat.dev, &olpc_bat_eeprom); | 599 | device_remove_bin_file(olpc_bat.dev, &olpc_bat_eeprom); |
@@ -595,23 +601,36 @@ eeprom_failed: | |||
595 | power_supply_unregister(&olpc_bat); | 601 | power_supply_unregister(&olpc_bat); |
596 | battery_failed: | 602 | battery_failed: |
597 | power_supply_unregister(&olpc_ac); | 603 | power_supply_unregister(&olpc_ac); |
598 | ac_failed: | ||
599 | platform_device_unregister(bat_pdev); | ||
600 | success: | ||
601 | return ret; | 604 | return ret; |
602 | } | 605 | } |
603 | 606 | ||
604 | static void __exit olpc_bat_exit(void) | 607 | static int __devexit olpc_battery_remove(struct platform_device *pdev) |
605 | { | 608 | { |
606 | device_remove_file(olpc_bat.dev, &olpc_bat_error); | 609 | device_remove_file(olpc_bat.dev, &olpc_bat_error); |
607 | device_remove_bin_file(olpc_bat.dev, &olpc_bat_eeprom); | 610 | device_remove_bin_file(olpc_bat.dev, &olpc_bat_eeprom); |
608 | power_supply_unregister(&olpc_bat); | 611 | power_supply_unregister(&olpc_bat); |
609 | power_supply_unregister(&olpc_ac); | 612 | power_supply_unregister(&olpc_ac); |
610 | platform_device_unregister(bat_pdev); | 613 | return 0; |
611 | } | 614 | } |
612 | 615 | ||
613 | module_init(olpc_bat_init); | 616 | static const struct of_device_id olpc_battery_ids[] __devinitconst = { |
614 | module_exit(olpc_bat_exit); | 617 | { .compatible = "olpc,xo1-battery" }, |
618 | {} | ||
619 | }; | ||
620 | MODULE_DEVICE_TABLE(of, olpc_battery_ids); | ||
621 | |||
622 | static struct platform_driver olpc_battery_driver = { | ||
623 | .driver = { | ||
624 | .name = "olpc-battery", | ||
625 | .owner = THIS_MODULE, | ||
626 | .of_match_table = olpc_battery_ids, | ||
627 | }, | ||
628 | .probe = olpc_battery_probe, | ||
629 | .remove = __devexit_p(olpc_battery_remove), | ||
630 | .suspend = olpc_battery_suspend, | ||
631 | }; | ||
632 | |||
633 | module_platform_driver(olpc_battery_driver); | ||
615 | 634 | ||
616 | MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>"); | 635 | MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>"); |
617 | MODULE_LICENSE("GPL"); | 636 | MODULE_LICENSE("GPL"); |
diff --git a/drivers/power/pcf50633-charger.c b/drivers/power/pcf50633-charger.c index 4fa52e1781a2..3d1e9efb6f53 100644 --- a/drivers/power/pcf50633-charger.c +++ b/drivers/power/pcf50633-charger.c | |||
@@ -474,17 +474,7 @@ static struct platform_driver pcf50633_mbc_driver = { | |||
474 | .remove = __devexit_p(pcf50633_mbc_remove), | 474 | .remove = __devexit_p(pcf50633_mbc_remove), |
475 | }; | 475 | }; |
476 | 476 | ||
477 | static int __init pcf50633_mbc_init(void) | 477 | module_platform_driver(pcf50633_mbc_driver); |
478 | { | ||
479 | return platform_driver_register(&pcf50633_mbc_driver); | ||
480 | } | ||
481 | module_init(pcf50633_mbc_init); | ||
482 | |||
483 | static void __exit pcf50633_mbc_exit(void) | ||
484 | { | ||
485 | platform_driver_unregister(&pcf50633_mbc_driver); | ||
486 | } | ||
487 | module_exit(pcf50633_mbc_exit); | ||
488 | 478 | ||
489 | MODULE_AUTHOR("Balaji Rao <balajirrao@openmoko.org>"); | 479 | MODULE_AUTHOR("Balaji Rao <balajirrao@openmoko.org>"); |
490 | MODULE_DESCRIPTION("PCF50633 mbc driver"); | 480 | MODULE_DESCRIPTION("PCF50633 mbc driver"); |
diff --git a/drivers/power/pda_power.c b/drivers/power/pda_power.c index 69f8aa3a6a4b..fd49689738af 100644 --- a/drivers/power/pda_power.c +++ b/drivers/power/pda_power.c | |||
@@ -14,6 +14,7 @@ | |||
14 | #include <linux/platform_device.h> | 14 | #include <linux/platform_device.h> |
15 | #include <linux/err.h> | 15 | #include <linux/err.h> |
16 | #include <linux/interrupt.h> | 16 | #include <linux/interrupt.h> |
17 | #include <linux/notifier.h> | ||
17 | #include <linux/power_supply.h> | 18 | #include <linux/power_supply.h> |
18 | #include <linux/pda_power.h> | 19 | #include <linux/pda_power.h> |
19 | #include <linux/regulator/consumer.h> | 20 | #include <linux/regulator/consumer.h> |
@@ -40,7 +41,9 @@ static int polling; | |||
40 | 41 | ||
41 | #ifdef CONFIG_USB_OTG_UTILS | 42 | #ifdef CONFIG_USB_OTG_UTILS |
42 | static struct otg_transceiver *transceiver; | 43 | static struct otg_transceiver *transceiver; |
44 | static struct notifier_block otg_nb; | ||
43 | #endif | 45 | #endif |
46 | |||
44 | static struct regulator *ac_draw; | 47 | static struct regulator *ac_draw; |
45 | 48 | ||
46 | enum { | 49 | enum { |
@@ -222,7 +225,42 @@ static void polling_timer_func(unsigned long unused) | |||
222 | #ifdef CONFIG_USB_OTG_UTILS | 225 | #ifdef CONFIG_USB_OTG_UTILS |
223 | static int otg_is_usb_online(void) | 226 | static int otg_is_usb_online(void) |
224 | { | 227 | { |
225 | return (transceiver->state == OTG_STATE_B_PERIPHERAL); | 228 | return (transceiver->last_event == USB_EVENT_VBUS || |
229 | transceiver->last_event == USB_EVENT_ENUMERATED); | ||
230 | } | ||
231 | |||
232 | static int otg_is_ac_online(void) | ||
233 | { | ||
234 | return (transceiver->last_event == USB_EVENT_CHARGER); | ||
235 | } | ||
236 | |||
237 | static int otg_handle_notification(struct notifier_block *nb, | ||
238 | unsigned long event, void *unused) | ||
239 | { | ||
240 | switch (event) { | ||
241 | case USB_EVENT_CHARGER: | ||
242 | ac_status = PDA_PSY_TO_CHANGE; | ||
243 | break; | ||
244 | case USB_EVENT_VBUS: | ||
245 | case USB_EVENT_ENUMERATED: | ||
246 | usb_status = PDA_PSY_TO_CHANGE; | ||
247 | break; | ||
248 | case USB_EVENT_NONE: | ||
249 | ac_status = PDA_PSY_TO_CHANGE; | ||
250 | usb_status = PDA_PSY_TO_CHANGE; | ||
251 | break; | ||
252 | default: | ||
253 | return NOTIFY_OK; | ||
254 | } | ||
255 | |||
256 | /* | ||
257 | * Wait a bit before reading ac/usb line status and setting charger, | ||
258 | * because ac/usb status readings may lag from irq. | ||
259 | */ | ||
260 | mod_timer(&charger_timer, | ||
261 | jiffies + msecs_to_jiffies(pdata->wait_for_status)); | ||
262 | |||
263 | return NOTIFY_OK; | ||
226 | } | 264 | } |
227 | #endif | 265 | #endif |
228 | 266 | ||
@@ -282,6 +320,16 @@ static int pda_power_probe(struct platform_device *pdev) | |||
282 | ret = PTR_ERR(ac_draw); | 320 | ret = PTR_ERR(ac_draw); |
283 | } | 321 | } |
284 | 322 | ||
323 | #ifdef CONFIG_USB_OTG_UTILS | ||
324 | transceiver = otg_get_transceiver(); | ||
325 | if (transceiver && !pdata->is_usb_online) { | ||
326 | pdata->is_usb_online = otg_is_usb_online; | ||
327 | } | ||
328 | if (transceiver && !pdata->is_ac_online) { | ||
329 | pdata->is_ac_online = otg_is_ac_online; | ||
330 | } | ||
331 | #endif | ||
332 | |||
285 | if (pdata->is_ac_online) { | 333 | if (pdata->is_ac_online) { |
286 | ret = power_supply_register(&pdev->dev, &pda_psy_ac); | 334 | ret = power_supply_register(&pdev->dev, &pda_psy_ac); |
287 | if (ret) { | 335 | if (ret) { |
@@ -303,13 +351,6 @@ static int pda_power_probe(struct platform_device *pdev) | |||
303 | } | 351 | } |
304 | } | 352 | } |
305 | 353 | ||
306 | #ifdef CONFIG_USB_OTG_UTILS | ||
307 | transceiver = otg_get_transceiver(); | ||
308 | if (transceiver && !pdata->is_usb_online) { | ||
309 | pdata->is_usb_online = otg_is_usb_online; | ||
310 | } | ||
311 | #endif | ||
312 | |||
313 | if (pdata->is_usb_online) { | 354 | if (pdata->is_usb_online) { |
314 | ret = power_supply_register(&pdev->dev, &pda_psy_usb); | 355 | ret = power_supply_register(&pdev->dev, &pda_psy_usb); |
315 | if (ret) { | 356 | if (ret) { |
@@ -331,6 +372,18 @@ static int pda_power_probe(struct platform_device *pdev) | |||
331 | } | 372 | } |
332 | } | 373 | } |
333 | 374 | ||
375 | #ifdef CONFIG_USB_OTG_UTILS | ||
376 | if (transceiver && pdata->use_otg_notifier) { | ||
377 | otg_nb.notifier_call = otg_handle_notification; | ||
378 | ret = otg_register_notifier(transceiver, &otg_nb); | ||
379 | if (ret) { | ||
380 | dev_err(dev, "failure to register otg notifier\n"); | ||
381 | goto otg_reg_notifier_failed; | ||
382 | } | ||
383 | polling = 0; | ||
384 | } | ||
385 | #endif | ||
386 | |||
334 | if (polling) { | 387 | if (polling) { |
335 | dev_dbg(dev, "will poll for status\n"); | 388 | dev_dbg(dev, "will poll for status\n"); |
336 | setup_timer(&polling_timer, polling_timer_func, 0); | 389 | setup_timer(&polling_timer, polling_timer_func, 0); |
@@ -343,6 +396,11 @@ static int pda_power_probe(struct platform_device *pdev) | |||
343 | 396 | ||
344 | return 0; | 397 | return 0; |
345 | 398 | ||
399 | #ifdef CONFIG_USB_OTG_UTILS | ||
400 | otg_reg_notifier_failed: | ||
401 | if (pdata->is_usb_online && usb_irq) | ||
402 | free_irq(usb_irq->start, &pda_psy_usb); | ||
403 | #endif | ||
346 | usb_irq_failed: | 404 | usb_irq_failed: |
347 | if (pdata->is_usb_online) | 405 | if (pdata->is_usb_online) |
348 | power_supply_unregister(&pda_psy_usb); | 406 | power_supply_unregister(&pda_psy_usb); |
@@ -440,8 +498,6 @@ static int pda_power_resume(struct platform_device *pdev) | |||
440 | #define pda_power_resume NULL | 498 | #define pda_power_resume NULL |
441 | #endif /* CONFIG_PM */ | 499 | #endif /* CONFIG_PM */ |
442 | 500 | ||
443 | MODULE_ALIAS("platform:pda-power"); | ||
444 | |||
445 | static struct platform_driver pda_power_pdrv = { | 501 | static struct platform_driver pda_power_pdrv = { |
446 | .driver = { | 502 | .driver = { |
447 | .name = "pda-power", | 503 | .name = "pda-power", |
@@ -452,17 +508,8 @@ static struct platform_driver pda_power_pdrv = { | |||
452 | .resume = pda_power_resume, | 508 | .resume = pda_power_resume, |
453 | }; | 509 | }; |
454 | 510 | ||
455 | static int __init pda_power_init(void) | 511 | module_platform_driver(pda_power_pdrv); |
456 | { | ||
457 | return platform_driver_register(&pda_power_pdrv); | ||
458 | } | ||
459 | 512 | ||
460 | static void __exit pda_power_exit(void) | ||
461 | { | ||
462 | platform_driver_unregister(&pda_power_pdrv); | ||
463 | } | ||
464 | |||
465 | module_init(pda_power_init); | ||
466 | module_exit(pda_power_exit); | ||
467 | MODULE_LICENSE("GPL"); | 513 | MODULE_LICENSE("GPL"); |
468 | MODULE_AUTHOR("Anton Vorontsov <cbou@mail.ru>"); | 514 | MODULE_AUTHOR("Anton Vorontsov <cbou@mail.ru>"); |
515 | MODULE_ALIAS("platform:pda-power"); | ||
diff --git a/drivers/power/power_supply_core.c b/drivers/power/power_supply_core.c index 329b46b2327d..6ad612726785 100644 --- a/drivers/power/power_supply_core.c +++ b/drivers/power/power_supply_core.c | |||
@@ -98,7 +98,9 @@ static int __power_supply_is_system_supplied(struct device *dev, void *data) | |||
98 | { | 98 | { |
99 | union power_supply_propval ret = {0,}; | 99 | union power_supply_propval ret = {0,}; |
100 | struct power_supply *psy = dev_get_drvdata(dev); | 100 | struct power_supply *psy = dev_get_drvdata(dev); |
101 | unsigned int *count = data; | ||
101 | 102 | ||
103 | (*count)++; | ||
102 | if (psy->type != POWER_SUPPLY_TYPE_BATTERY) { | 104 | if (psy->type != POWER_SUPPLY_TYPE_BATTERY) { |
103 | if (psy->get_property(psy, POWER_SUPPLY_PROP_ONLINE, &ret)) | 105 | if (psy->get_property(psy, POWER_SUPPLY_PROP_ONLINE, &ret)) |
104 | return 0; | 106 | return 0; |
@@ -111,10 +113,18 @@ static int __power_supply_is_system_supplied(struct device *dev, void *data) | |||
111 | int power_supply_is_system_supplied(void) | 113 | int power_supply_is_system_supplied(void) |
112 | { | 114 | { |
113 | int error; | 115 | int error; |
116 | unsigned int count = 0; | ||
114 | 117 | ||
115 | error = class_for_each_device(power_supply_class, NULL, NULL, | 118 | error = class_for_each_device(power_supply_class, NULL, &count, |
116 | __power_supply_is_system_supplied); | 119 | __power_supply_is_system_supplied); |
117 | 120 | ||
121 | /* | ||
122 | * If no power class device was found at all, most probably we are | ||
123 | * running on a desktop system, so assume we are on mains power. | ||
124 | */ | ||
125 | if (count == 0) | ||
126 | return 1; | ||
127 | |||
118 | return error; | 128 | return error; |
119 | } | 129 | } |
120 | EXPORT_SYMBOL_GPL(power_supply_is_system_supplied); | 130 | EXPORT_SYMBOL_GPL(power_supply_is_system_supplied); |
@@ -147,6 +157,12 @@ struct power_supply *power_supply_get_by_name(char *name) | |||
147 | } | 157 | } |
148 | EXPORT_SYMBOL_GPL(power_supply_get_by_name); | 158 | EXPORT_SYMBOL_GPL(power_supply_get_by_name); |
149 | 159 | ||
160 | int power_supply_powers(struct power_supply *psy, struct device *dev) | ||
161 | { | ||
162 | return sysfs_create_link(&psy->dev->kobj, &dev->kobj, "powers"); | ||
163 | } | ||
164 | EXPORT_SYMBOL_GPL(power_supply_powers); | ||
165 | |||
150 | static void power_supply_dev_release(struct device *dev) | 166 | static void power_supply_dev_release(struct device *dev) |
151 | { | 167 | { |
152 | pr_debug("device: '%s': %s\n", dev_name(dev), __func__); | 168 | pr_debug("device: '%s': %s\n", dev_name(dev), __func__); |
@@ -202,6 +218,7 @@ EXPORT_SYMBOL_GPL(power_supply_register); | |||
202 | void power_supply_unregister(struct power_supply *psy) | 218 | void power_supply_unregister(struct power_supply *psy) |
203 | { | 219 | { |
204 | cancel_work_sync(&psy->changed_work); | 220 | cancel_work_sync(&psy->changed_work); |
221 | sysfs_remove_link(&psy->dev->kobj, "powers"); | ||
205 | power_supply_remove_triggers(psy); | 222 | power_supply_remove_triggers(psy); |
206 | device_unregister(psy->dev); | 223 | device_unregister(psy->dev); |
207 | } | 224 | } |
diff --git a/drivers/power/power_supply_sysfs.c b/drivers/power/power_supply_sysfs.c index e95cd657dac2..b52b57ca3084 100644 --- a/drivers/power/power_supply_sysfs.c +++ b/drivers/power/power_supply_sysfs.c | |||
@@ -43,7 +43,7 @@ static ssize_t power_supply_show_property(struct device *dev, | |||
43 | struct device_attribute *attr, | 43 | struct device_attribute *attr, |
44 | char *buf) { | 44 | char *buf) { |
45 | static char *type_text[] = { | 45 | static char *type_text[] = { |
46 | "Battery", "UPS", "Mains", "USB", | 46 | "Unknown", "Battery", "UPS", "Mains", "USB", |
47 | "USB_DCP", "USB_CDP", "USB_ACA" | 47 | "USB_DCP", "USB_CDP", "USB_ACA" |
48 | }; | 48 | }; |
49 | static char *status_text[] = { | 49 | static char *status_text[] = { |
@@ -63,6 +63,9 @@ static ssize_t power_supply_show_property(struct device *dev, | |||
63 | static char *capacity_level_text[] = { | 63 | static char *capacity_level_text[] = { |
64 | "Unknown", "Critical", "Low", "Normal", "High", "Full" | 64 | "Unknown", "Critical", "Low", "Normal", "High", "Full" |
65 | }; | 65 | }; |
66 | static char *scope_text[] = { | ||
67 | "Unknown", "System", "Device" | ||
68 | }; | ||
66 | ssize_t ret = 0; | 69 | ssize_t ret = 0; |
67 | struct power_supply *psy = dev_get_drvdata(dev); | 70 | struct power_supply *psy = dev_get_drvdata(dev); |
68 | const ptrdiff_t off = attr - power_supply_attrs; | 71 | const ptrdiff_t off = attr - power_supply_attrs; |
@@ -78,8 +81,8 @@ static ssize_t power_supply_show_property(struct device *dev, | |||
78 | dev_dbg(dev, "driver has no data for `%s' property\n", | 81 | dev_dbg(dev, "driver has no data for `%s' property\n", |
79 | attr->attr.name); | 82 | attr->attr.name); |
80 | else if (ret != -ENODEV) | 83 | else if (ret != -ENODEV) |
81 | dev_err(dev, "driver failed to report `%s' property\n", | 84 | dev_err(dev, "driver failed to report `%s' property: %zd\n", |
82 | attr->attr.name); | 85 | attr->attr.name, ret); |
83 | return ret; | 86 | return ret; |
84 | } | 87 | } |
85 | 88 | ||
@@ -95,6 +98,8 @@ static ssize_t power_supply_show_property(struct device *dev, | |||
95 | return sprintf(buf, "%s\n", capacity_level_text[value.intval]); | 98 | return sprintf(buf, "%s\n", capacity_level_text[value.intval]); |
96 | else if (off == POWER_SUPPLY_PROP_TYPE) | 99 | else if (off == POWER_SUPPLY_PROP_TYPE) |
97 | return sprintf(buf, "%s\n", type_text[value.intval]); | 100 | return sprintf(buf, "%s\n", type_text[value.intval]); |
101 | else if (off == POWER_SUPPLY_PROP_SCOPE) | ||
102 | return sprintf(buf, "%s\n", scope_text[value.intval]); | ||
98 | else if (off >= POWER_SUPPLY_PROP_MODEL_NAME) | 103 | else if (off >= POWER_SUPPLY_PROP_MODEL_NAME) |
99 | return sprintf(buf, "%s\n", value.strval); | 104 | return sprintf(buf, "%s\n", value.strval); |
100 | 105 | ||
@@ -167,6 +172,7 @@ static struct device_attribute power_supply_attrs[] = { | |||
167 | POWER_SUPPLY_ATTR(time_to_full_now), | 172 | POWER_SUPPLY_ATTR(time_to_full_now), |
168 | POWER_SUPPLY_ATTR(time_to_full_avg), | 173 | POWER_SUPPLY_ATTR(time_to_full_avg), |
169 | POWER_SUPPLY_ATTR(type), | 174 | POWER_SUPPLY_ATTR(type), |
175 | POWER_SUPPLY_ATTR(scope), | ||
170 | /* Properties of type `const char *' */ | 176 | /* Properties of type `const char *' */ |
171 | POWER_SUPPLY_ATTR(model_name), | 177 | POWER_SUPPLY_ATTR(model_name), |
172 | POWER_SUPPLY_ATTR(manufacturer), | 178 | POWER_SUPPLY_ATTR(manufacturer), |
diff --git a/drivers/power/s3c_adc_battery.c b/drivers/power/s3c_adc_battery.c index d32d0d70f9ba..8b804a566756 100644 --- a/drivers/power/s3c_adc_battery.c +++ b/drivers/power/s3c_adc_battery.c | |||
@@ -47,6 +47,22 @@ static void s3c_adc_bat_ext_power_changed(struct power_supply *psy) | |||
47 | msecs_to_jiffies(JITTER_DELAY)); | 47 | msecs_to_jiffies(JITTER_DELAY)); |
48 | } | 48 | } |
49 | 49 | ||
50 | static int gather_samples(struct s3c_adc_client *client, int num, int channel) | ||
51 | { | ||
52 | int value, i; | ||
53 | |||
54 | /* default to 1 if nothing is set */ | ||
55 | if (num < 1) | ||
56 | num = 1; | ||
57 | |||
58 | value = 0; | ||
59 | for (i = 0; i < num; i++) | ||
60 | value += s3c_adc_read(client, channel); | ||
61 | value /= num; | ||
62 | |||
63 | return value; | ||
64 | } | ||
65 | |||
50 | static enum power_supply_property s3c_adc_backup_bat_props[] = { | 66 | static enum power_supply_property s3c_adc_backup_bat_props[] = { |
51 | POWER_SUPPLY_PROP_VOLTAGE_NOW, | 67 | POWER_SUPPLY_PROP_VOLTAGE_NOW, |
52 | POWER_SUPPLY_PROP_VOLTAGE_MIN, | 68 | POWER_SUPPLY_PROP_VOLTAGE_MIN, |
@@ -67,7 +83,8 @@ static int s3c_adc_backup_bat_get_property(struct power_supply *psy, | |||
67 | if (bat->volt_value < 0 || | 83 | if (bat->volt_value < 0 || |
68 | jiffies_to_msecs(jiffies - bat->timestamp) > | 84 | jiffies_to_msecs(jiffies - bat->timestamp) > |
69 | BAT_POLL_INTERVAL) { | 85 | BAT_POLL_INTERVAL) { |
70 | bat->volt_value = s3c_adc_read(bat->client, | 86 | bat->volt_value = gather_samples(bat->client, |
87 | bat->pdata->backup_volt_samples, | ||
71 | bat->pdata->backup_volt_channel); | 88 | bat->pdata->backup_volt_channel); |
72 | bat->volt_value *= bat->pdata->backup_volt_mult; | 89 | bat->volt_value *= bat->pdata->backup_volt_mult; |
73 | bat->timestamp = jiffies; | 90 | bat->timestamp = jiffies; |
@@ -139,9 +156,11 @@ static int s3c_adc_bat_get_property(struct power_supply *psy, | |||
139 | if (bat->volt_value < 0 || bat->cur_value < 0 || | 156 | if (bat->volt_value < 0 || bat->cur_value < 0 || |
140 | jiffies_to_msecs(jiffies - bat->timestamp) > | 157 | jiffies_to_msecs(jiffies - bat->timestamp) > |
141 | BAT_POLL_INTERVAL) { | 158 | BAT_POLL_INTERVAL) { |
142 | bat->volt_value = s3c_adc_read(bat->client, | 159 | bat->volt_value = gather_samples(bat->client, |
160 | bat->pdata->volt_samples, | ||
143 | bat->pdata->volt_channel) * bat->pdata->volt_mult; | 161 | bat->pdata->volt_channel) * bat->pdata->volt_mult; |
144 | bat->cur_value = s3c_adc_read(bat->client, | 162 | bat->cur_value = gather_samples(bat->client, |
163 | bat->pdata->current_samples, | ||
145 | bat->pdata->current_channel) * bat->pdata->current_mult; | 164 | bat->pdata->current_channel) * bat->pdata->current_mult; |
146 | bat->timestamp = jiffies; | 165 | bat->timestamp = jiffies; |
147 | } | 166 | } |
@@ -421,17 +440,7 @@ static struct platform_driver s3c_adc_bat_driver = { | |||
421 | .resume = s3c_adc_bat_resume, | 440 | .resume = s3c_adc_bat_resume, |
422 | }; | 441 | }; |
423 | 442 | ||
424 | static int __init s3c_adc_bat_init(void) | 443 | module_platform_driver(s3c_adc_bat_driver); |
425 | { | ||
426 | return platform_driver_register(&s3c_adc_bat_driver); | ||
427 | } | ||
428 | module_init(s3c_adc_bat_init); | ||
429 | |||
430 | static void __exit s3c_adc_bat_exit(void) | ||
431 | { | ||
432 | platform_driver_unregister(&s3c_adc_bat_driver); | ||
433 | } | ||
434 | module_exit(s3c_adc_bat_exit); | ||
435 | 444 | ||
436 | MODULE_AUTHOR("Vasily Khoruzhick <anarsoul@gmail.com>"); | 445 | MODULE_AUTHOR("Vasily Khoruzhick <anarsoul@gmail.com>"); |
437 | MODULE_DESCRIPTION("iPAQ H1930/H1940/RX1950 battery controller driver"); | 446 | MODULE_DESCRIPTION("iPAQ H1930/H1940/RX1950 battery controller driver"); |
diff --git a/drivers/power/bq20z75.c b/drivers/power/sbs-battery.c index 9c5e5beda3a8..9ff8af069da6 100644 --- a/drivers/power/bq20z75.c +++ b/drivers/power/sbs-battery.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Gas Gauge driver for TI's BQ20Z75 | 2 | * Gas Gauge driver for SBS Compliant Batteries |
3 | * | 3 | * |
4 | * Copyright (c) 2010, NVIDIA Corporation. | 4 | * Copyright (c) 2010, NVIDIA Corporation. |
5 | * | 5 | * |
@@ -28,7 +28,7 @@ | |||
28 | #include <linux/interrupt.h> | 28 | #include <linux/interrupt.h> |
29 | #include <linux/gpio.h> | 29 | #include <linux/gpio.h> |
30 | 30 | ||
31 | #include <linux/power/bq20z75.h> | 31 | #include <linux/power/sbs-battery.h> |
32 | 32 | ||
33 | enum { | 33 | enum { |
34 | REG_MANUFACTURER_DATA, | 34 | REG_MANUFACTURER_DATA, |
@@ -53,7 +53,7 @@ enum { | |||
53 | /* Battery Mode defines */ | 53 | /* Battery Mode defines */ |
54 | #define BATTERY_MODE_OFFSET 0x03 | 54 | #define BATTERY_MODE_OFFSET 0x03 |
55 | #define BATTERY_MODE_MASK 0x8000 | 55 | #define BATTERY_MODE_MASK 0x8000 |
56 | enum bq20z75_battery_mode { | 56 | enum sbs_battery_mode { |
57 | BATTERY_MODE_AMPS, | 57 | BATTERY_MODE_AMPS, |
58 | BATTERY_MODE_WATTS | 58 | BATTERY_MODE_WATTS |
59 | }; | 59 | }; |
@@ -67,62 +67,56 @@ enum bq20z75_battery_mode { | |||
67 | #define BATTERY_FULL_CHARGED 0x20 | 67 | #define BATTERY_FULL_CHARGED 0x20 |
68 | #define BATTERY_FULL_DISCHARGED 0x10 | 68 | #define BATTERY_FULL_DISCHARGED 0x10 |
69 | 69 | ||
70 | #define BQ20Z75_DATA(_psp, _addr, _min_value, _max_value) { \ | 70 | #define SBS_DATA(_psp, _addr, _min_value, _max_value) { \ |
71 | .psp = _psp, \ | 71 | .psp = _psp, \ |
72 | .addr = _addr, \ | 72 | .addr = _addr, \ |
73 | .min_value = _min_value, \ | 73 | .min_value = _min_value, \ |
74 | .max_value = _max_value, \ | 74 | .max_value = _max_value, \ |
75 | } | 75 | } |
76 | 76 | ||
77 | static const struct bq20z75_device_data { | 77 | static const struct chip_data { |
78 | enum power_supply_property psp; | 78 | enum power_supply_property psp; |
79 | u8 addr; | 79 | u8 addr; |
80 | int min_value; | 80 | int min_value; |
81 | int max_value; | 81 | int max_value; |
82 | } bq20z75_data[] = { | 82 | } sbs_data[] = { |
83 | [REG_MANUFACTURER_DATA] = | 83 | [REG_MANUFACTURER_DATA] = |
84 | BQ20Z75_DATA(POWER_SUPPLY_PROP_PRESENT, 0x00, 0, 65535), | 84 | SBS_DATA(POWER_SUPPLY_PROP_PRESENT, 0x00, 0, 65535), |
85 | [REG_TEMPERATURE] = | 85 | [REG_TEMPERATURE] = |
86 | BQ20Z75_DATA(POWER_SUPPLY_PROP_TEMP, 0x08, 0, 65535), | 86 | SBS_DATA(POWER_SUPPLY_PROP_TEMP, 0x08, 0, 65535), |
87 | [REG_VOLTAGE] = | 87 | [REG_VOLTAGE] = |
88 | BQ20Z75_DATA(POWER_SUPPLY_PROP_VOLTAGE_NOW, 0x09, 0, 20000), | 88 | SBS_DATA(POWER_SUPPLY_PROP_VOLTAGE_NOW, 0x09, 0, 20000), |
89 | [REG_CURRENT] = | 89 | [REG_CURRENT] = |
90 | BQ20Z75_DATA(POWER_SUPPLY_PROP_CURRENT_NOW, 0x0A, -32768, | 90 | SBS_DATA(POWER_SUPPLY_PROP_CURRENT_NOW, 0x0A, -32768, 32767), |
91 | 32767), | ||
92 | [REG_CAPACITY] = | 91 | [REG_CAPACITY] = |
93 | BQ20Z75_DATA(POWER_SUPPLY_PROP_CAPACITY, 0x0E, 0, 100), | 92 | SBS_DATA(POWER_SUPPLY_PROP_CAPACITY, 0x0E, 0, 100), |
94 | [REG_REMAINING_CAPACITY] = | 93 | [REG_REMAINING_CAPACITY] = |
95 | BQ20Z75_DATA(POWER_SUPPLY_PROP_ENERGY_NOW, 0x0F, 0, 65535), | 94 | SBS_DATA(POWER_SUPPLY_PROP_ENERGY_NOW, 0x0F, 0, 65535), |
96 | [REG_REMAINING_CAPACITY_CHARGE] = | 95 | [REG_REMAINING_CAPACITY_CHARGE] = |
97 | BQ20Z75_DATA(POWER_SUPPLY_PROP_CHARGE_NOW, 0x0F, 0, 65535), | 96 | SBS_DATA(POWER_SUPPLY_PROP_CHARGE_NOW, 0x0F, 0, 65535), |
98 | [REG_FULL_CHARGE_CAPACITY] = | 97 | [REG_FULL_CHARGE_CAPACITY] = |
99 | BQ20Z75_DATA(POWER_SUPPLY_PROP_ENERGY_FULL, 0x10, 0, 65535), | 98 | SBS_DATA(POWER_SUPPLY_PROP_ENERGY_FULL, 0x10, 0, 65535), |
100 | [REG_FULL_CHARGE_CAPACITY_CHARGE] = | 99 | [REG_FULL_CHARGE_CAPACITY_CHARGE] = |
101 | BQ20Z75_DATA(POWER_SUPPLY_PROP_CHARGE_FULL, 0x10, 0, 65535), | 100 | SBS_DATA(POWER_SUPPLY_PROP_CHARGE_FULL, 0x10, 0, 65535), |
102 | [REG_TIME_TO_EMPTY] = | 101 | [REG_TIME_TO_EMPTY] = |
103 | BQ20Z75_DATA(POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG, 0x12, 0, | 102 | SBS_DATA(POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG, 0x12, 0, 65535), |
104 | 65535), | ||
105 | [REG_TIME_TO_FULL] = | 103 | [REG_TIME_TO_FULL] = |
106 | BQ20Z75_DATA(POWER_SUPPLY_PROP_TIME_TO_FULL_AVG, 0x13, 0, | 104 | SBS_DATA(POWER_SUPPLY_PROP_TIME_TO_FULL_AVG, 0x13, 0, 65535), |
107 | 65535), | ||
108 | [REG_STATUS] = | 105 | [REG_STATUS] = |
109 | BQ20Z75_DATA(POWER_SUPPLY_PROP_STATUS, 0x16, 0, 65535), | 106 | SBS_DATA(POWER_SUPPLY_PROP_STATUS, 0x16, 0, 65535), |
110 | [REG_CYCLE_COUNT] = | 107 | [REG_CYCLE_COUNT] = |
111 | BQ20Z75_DATA(POWER_SUPPLY_PROP_CYCLE_COUNT, 0x17, 0, 65535), | 108 | SBS_DATA(POWER_SUPPLY_PROP_CYCLE_COUNT, 0x17, 0, 65535), |
112 | [REG_DESIGN_CAPACITY] = | 109 | [REG_DESIGN_CAPACITY] = |
113 | BQ20Z75_DATA(POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN, 0x18, 0, | 110 | SBS_DATA(POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN, 0x18, 0, 65535), |
114 | 65535), | ||
115 | [REG_DESIGN_CAPACITY_CHARGE] = | 111 | [REG_DESIGN_CAPACITY_CHARGE] = |
116 | BQ20Z75_DATA(POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, 0x18, 0, | 112 | SBS_DATA(POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, 0x18, 0, 65535), |
117 | 65535), | ||
118 | [REG_DESIGN_VOLTAGE] = | 113 | [REG_DESIGN_VOLTAGE] = |
119 | BQ20Z75_DATA(POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN, 0x19, 0, | 114 | SBS_DATA(POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN, 0x19, 0, 65535), |
120 | 65535), | ||
121 | [REG_SERIAL_NUMBER] = | 115 | [REG_SERIAL_NUMBER] = |
122 | BQ20Z75_DATA(POWER_SUPPLY_PROP_SERIAL_NUMBER, 0x1C, 0, 65535), | 116 | SBS_DATA(POWER_SUPPLY_PROP_SERIAL_NUMBER, 0x1C, 0, 65535), |
123 | }; | 117 | }; |
124 | 118 | ||
125 | static enum power_supply_property bq20z75_properties[] = { | 119 | static enum power_supply_property sbs_properties[] = { |
126 | POWER_SUPPLY_PROP_STATUS, | 120 | POWER_SUPPLY_PROP_STATUS, |
127 | POWER_SUPPLY_PROP_HEALTH, | 121 | POWER_SUPPLY_PROP_HEALTH, |
128 | POWER_SUPPLY_PROP_PRESENT, | 122 | POWER_SUPPLY_PROP_PRESENT, |
@@ -144,10 +138,10 @@ static enum power_supply_property bq20z75_properties[] = { | |||
144 | POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, | 138 | POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, |
145 | }; | 139 | }; |
146 | 140 | ||
147 | struct bq20z75_info { | 141 | struct sbs_info { |
148 | struct i2c_client *client; | 142 | struct i2c_client *client; |
149 | struct power_supply power_supply; | 143 | struct power_supply power_supply; |
150 | struct bq20z75_platform_data *pdata; | 144 | struct sbs_platform_data *pdata; |
151 | bool is_present; | 145 | bool is_present; |
152 | bool gpio_detect; | 146 | bool gpio_detect; |
153 | bool enable_detection; | 147 | bool enable_detection; |
@@ -158,14 +152,14 @@ struct bq20z75_info { | |||
158 | int ignore_changes; | 152 | int ignore_changes; |
159 | }; | 153 | }; |
160 | 154 | ||
161 | static int bq20z75_read_word_data(struct i2c_client *client, u8 address) | 155 | static int sbs_read_word_data(struct i2c_client *client, u8 address) |
162 | { | 156 | { |
163 | struct bq20z75_info *bq20z75_device = i2c_get_clientdata(client); | 157 | struct sbs_info *chip = i2c_get_clientdata(client); |
164 | s32 ret = 0; | 158 | s32 ret = 0; |
165 | int retries = 1; | 159 | int retries = 1; |
166 | 160 | ||
167 | if (bq20z75_device->pdata) | 161 | if (chip->pdata) |
168 | retries = max(bq20z75_device->pdata->i2c_retry_count + 1, 1); | 162 | retries = max(chip->pdata->i2c_retry_count + 1, 1); |
169 | 163 | ||
170 | while (retries > 0) { | 164 | while (retries > 0) { |
171 | ret = i2c_smbus_read_word_data(client, address); | 165 | ret = i2c_smbus_read_word_data(client, address); |
@@ -184,15 +178,15 @@ static int bq20z75_read_word_data(struct i2c_client *client, u8 address) | |||
184 | return le16_to_cpu(ret); | 178 | return le16_to_cpu(ret); |
185 | } | 179 | } |
186 | 180 | ||
187 | static int bq20z75_write_word_data(struct i2c_client *client, u8 address, | 181 | static int sbs_write_word_data(struct i2c_client *client, u8 address, |
188 | u16 value) | 182 | u16 value) |
189 | { | 183 | { |
190 | struct bq20z75_info *bq20z75_device = i2c_get_clientdata(client); | 184 | struct sbs_info *chip = i2c_get_clientdata(client); |
191 | s32 ret = 0; | 185 | s32 ret = 0; |
192 | int retries = 1; | 186 | int retries = 1; |
193 | 187 | ||
194 | if (bq20z75_device->pdata) | 188 | if (chip->pdata) |
195 | retries = max(bq20z75_device->pdata->i2c_retry_count + 1, 1); | 189 | retries = max(chip->pdata->i2c_retry_count + 1, 1); |
196 | 190 | ||
197 | while (retries > 0) { | 191 | while (retries > 0) { |
198 | ret = i2c_smbus_write_word_data(client, address, | 192 | ret = i2c_smbus_write_word_data(client, address, |
@@ -212,44 +206,41 @@ static int bq20z75_write_word_data(struct i2c_client *client, u8 address, | |||
212 | return 0; | 206 | return 0; |
213 | } | 207 | } |
214 | 208 | ||
215 | static int bq20z75_get_battery_presence_and_health( | 209 | static int sbs_get_battery_presence_and_health( |
216 | struct i2c_client *client, enum power_supply_property psp, | 210 | struct i2c_client *client, enum power_supply_property psp, |
217 | union power_supply_propval *val) | 211 | union power_supply_propval *val) |
218 | { | 212 | { |
219 | s32 ret; | 213 | s32 ret; |
220 | struct bq20z75_info *bq20z75_device = i2c_get_clientdata(client); | 214 | struct sbs_info *chip = i2c_get_clientdata(client); |
221 | 215 | ||
222 | if (psp == POWER_SUPPLY_PROP_PRESENT && | 216 | if (psp == POWER_SUPPLY_PROP_PRESENT && |
223 | bq20z75_device->gpio_detect) { | 217 | chip->gpio_detect) { |
224 | ret = gpio_get_value( | 218 | ret = gpio_get_value(chip->pdata->battery_detect); |
225 | bq20z75_device->pdata->battery_detect); | 219 | if (ret == chip->pdata->battery_detect_present) |
226 | if (ret == bq20z75_device->pdata->battery_detect_present) | ||
227 | val->intval = 1; | 220 | val->intval = 1; |
228 | else | 221 | else |
229 | val->intval = 0; | 222 | val->intval = 0; |
230 | bq20z75_device->is_present = val->intval; | 223 | chip->is_present = val->intval; |
231 | return ret; | 224 | return ret; |
232 | } | 225 | } |
233 | 226 | ||
234 | /* Write to ManufacturerAccess with | 227 | /* Write to ManufacturerAccess with |
235 | * ManufacturerAccess command and then | 228 | * ManufacturerAccess command and then |
236 | * read the status */ | 229 | * read the status */ |
237 | ret = bq20z75_write_word_data(client, | 230 | ret = sbs_write_word_data(client, sbs_data[REG_MANUFACTURER_DATA].addr, |
238 | bq20z75_data[REG_MANUFACTURER_DATA].addr, | 231 | MANUFACTURER_ACCESS_STATUS); |
239 | MANUFACTURER_ACCESS_STATUS); | ||
240 | if (ret < 0) { | 232 | if (ret < 0) { |
241 | if (psp == POWER_SUPPLY_PROP_PRESENT) | 233 | if (psp == POWER_SUPPLY_PROP_PRESENT) |
242 | val->intval = 0; /* battery removed */ | 234 | val->intval = 0; /* battery removed */ |
243 | return ret; | 235 | return ret; |
244 | } | 236 | } |
245 | 237 | ||
246 | ret = bq20z75_read_word_data(client, | 238 | ret = sbs_read_word_data(client, sbs_data[REG_MANUFACTURER_DATA].addr); |
247 | bq20z75_data[REG_MANUFACTURER_DATA].addr); | ||
248 | if (ret < 0) | 239 | if (ret < 0) |
249 | return ret; | 240 | return ret; |
250 | 241 | ||
251 | if (ret < bq20z75_data[REG_MANUFACTURER_DATA].min_value || | 242 | if (ret < sbs_data[REG_MANUFACTURER_DATA].min_value || |
252 | ret > bq20z75_data[REG_MANUFACTURER_DATA].max_value) { | 243 | ret > sbs_data[REG_MANUFACTURER_DATA].max_value) { |
253 | val->intval = 0; | 244 | val->intval = 0; |
254 | return 0; | 245 | return 0; |
255 | } | 246 | } |
@@ -279,24 +270,23 @@ static int bq20z75_get_battery_presence_and_health( | |||
279 | return 0; | 270 | return 0; |
280 | } | 271 | } |
281 | 272 | ||
282 | static int bq20z75_get_battery_property(struct i2c_client *client, | 273 | static int sbs_get_battery_property(struct i2c_client *client, |
283 | int reg_offset, enum power_supply_property psp, | 274 | int reg_offset, enum power_supply_property psp, |
284 | union power_supply_propval *val) | 275 | union power_supply_propval *val) |
285 | { | 276 | { |
286 | struct bq20z75_info *bq20z75_device = i2c_get_clientdata(client); | 277 | struct sbs_info *chip = i2c_get_clientdata(client); |
287 | s32 ret; | 278 | s32 ret; |
288 | 279 | ||
289 | ret = bq20z75_read_word_data(client, | 280 | ret = sbs_read_word_data(client, sbs_data[reg_offset].addr); |
290 | bq20z75_data[reg_offset].addr); | ||
291 | if (ret < 0) | 281 | if (ret < 0) |
292 | return ret; | 282 | return ret; |
293 | 283 | ||
294 | /* returned values are 16 bit */ | 284 | /* returned values are 16 bit */ |
295 | if (bq20z75_data[reg_offset].min_value < 0) | 285 | if (sbs_data[reg_offset].min_value < 0) |
296 | ret = (s16)ret; | 286 | ret = (s16)ret; |
297 | 287 | ||
298 | if (ret >= bq20z75_data[reg_offset].min_value && | 288 | if (ret >= sbs_data[reg_offset].min_value && |
299 | ret <= bq20z75_data[reg_offset].max_value) { | 289 | ret <= sbs_data[reg_offset].max_value) { |
300 | val->intval = ret; | 290 | val->intval = ret; |
301 | if (psp != POWER_SUPPLY_PROP_STATUS) | 291 | if (psp != POWER_SUPPLY_PROP_STATUS) |
302 | return 0; | 292 | return 0; |
@@ -310,12 +300,12 @@ static int bq20z75_get_battery_property(struct i2c_client *client, | |||
310 | else | 300 | else |
311 | val->intval = POWER_SUPPLY_STATUS_CHARGING; | 301 | val->intval = POWER_SUPPLY_STATUS_CHARGING; |
312 | 302 | ||
313 | if (bq20z75_device->poll_time == 0) | 303 | if (chip->poll_time == 0) |
314 | bq20z75_device->last_state = val->intval; | 304 | chip->last_state = val->intval; |
315 | else if (bq20z75_device->last_state != val->intval) { | 305 | else if (chip->last_state != val->intval) { |
316 | cancel_delayed_work_sync(&bq20z75_device->work); | 306 | cancel_delayed_work_sync(&chip->work); |
317 | power_supply_changed(&bq20z75_device->power_supply); | 307 | power_supply_changed(&chip->power_supply); |
318 | bq20z75_device->poll_time = 0; | 308 | chip->poll_time = 0; |
319 | } | 309 | } |
320 | } else { | 310 | } else { |
321 | if (psp == POWER_SUPPLY_PROP_STATUS) | 311 | if (psp == POWER_SUPPLY_PROP_STATUS) |
@@ -327,7 +317,7 @@ static int bq20z75_get_battery_property(struct i2c_client *client, | |||
327 | return 0; | 317 | return 0; |
328 | } | 318 | } |
329 | 319 | ||
330 | static void bq20z75_unit_adjustment(struct i2c_client *client, | 320 | static void sbs_unit_adjustment(struct i2c_client *client, |
331 | enum power_supply_property psp, union power_supply_propval *val) | 321 | enum power_supply_property psp, union power_supply_propval *val) |
332 | { | 322 | { |
333 | #define BASE_UNIT_CONVERSION 1000 | 323 | #define BASE_UNIT_CONVERSION 1000 |
@@ -338,7 +328,7 @@ static void bq20z75_unit_adjustment(struct i2c_client *client, | |||
338 | case POWER_SUPPLY_PROP_ENERGY_NOW: | 328 | case POWER_SUPPLY_PROP_ENERGY_NOW: |
339 | case POWER_SUPPLY_PROP_ENERGY_FULL: | 329 | case POWER_SUPPLY_PROP_ENERGY_FULL: |
340 | case POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN: | 330 | case POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN: |
341 | /* bq20z75 provides energy in units of 10mWh. | 331 | /* sbs provides energy in units of 10mWh. |
342 | * Convert to µWh | 332 | * Convert to µWh |
343 | */ | 333 | */ |
344 | val->intval *= BATTERY_MODE_CAP_MULT_WATT; | 334 | val->intval *= BATTERY_MODE_CAP_MULT_WATT; |
@@ -354,7 +344,7 @@ static void bq20z75_unit_adjustment(struct i2c_client *client, | |||
354 | break; | 344 | break; |
355 | 345 | ||
356 | case POWER_SUPPLY_PROP_TEMP: | 346 | case POWER_SUPPLY_PROP_TEMP: |
357 | /* bq20z75 provides battery temperature in 0.1K | 347 | /* sbs provides battery temperature in 0.1K |
358 | * so convert it to 0.1°C | 348 | * so convert it to 0.1°C |
359 | */ | 349 | */ |
360 | val->intval -= TEMP_KELVIN_TO_CELSIUS; | 350 | val->intval -= TEMP_KELVIN_TO_CELSIUS; |
@@ -362,7 +352,7 @@ static void bq20z75_unit_adjustment(struct i2c_client *client, | |||
362 | 352 | ||
363 | case POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG: | 353 | case POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG: |
364 | case POWER_SUPPLY_PROP_TIME_TO_FULL_AVG: | 354 | case POWER_SUPPLY_PROP_TIME_TO_FULL_AVG: |
365 | /* bq20z75 provides time to empty and time to full in minutes. | 355 | /* sbs provides time to empty and time to full in minutes. |
366 | * Convert to seconds | 356 | * Convert to seconds |
367 | */ | 357 | */ |
368 | val->intval *= TIME_UNIT_CONVERSION; | 358 | val->intval *= TIME_UNIT_CONVERSION; |
@@ -374,13 +364,12 @@ static void bq20z75_unit_adjustment(struct i2c_client *client, | |||
374 | } | 364 | } |
375 | } | 365 | } |
376 | 366 | ||
377 | static enum bq20z75_battery_mode | 367 | static enum sbs_battery_mode sbs_set_battery_mode(struct i2c_client *client, |
378 | bq20z75_set_battery_mode(struct i2c_client *client, | 368 | enum sbs_battery_mode mode) |
379 | enum bq20z75_battery_mode mode) | ||
380 | { | 369 | { |
381 | int ret, original_val; | 370 | int ret, original_val; |
382 | 371 | ||
383 | original_val = bq20z75_read_word_data(client, BATTERY_MODE_OFFSET); | 372 | original_val = sbs_read_word_data(client, BATTERY_MODE_OFFSET); |
384 | if (original_val < 0) | 373 | if (original_val < 0) |
385 | return original_val; | 374 | return original_val; |
386 | 375 | ||
@@ -392,68 +381,67 @@ bq20z75_set_battery_mode(struct i2c_client *client, | |||
392 | else | 381 | else |
393 | ret = original_val | BATTERY_MODE_MASK; | 382 | ret = original_val | BATTERY_MODE_MASK; |
394 | 383 | ||
395 | ret = bq20z75_write_word_data(client, BATTERY_MODE_OFFSET, ret); | 384 | ret = sbs_write_word_data(client, BATTERY_MODE_OFFSET, ret); |
396 | if (ret < 0) | 385 | if (ret < 0) |
397 | return ret; | 386 | return ret; |
398 | 387 | ||
399 | return original_val & BATTERY_MODE_MASK; | 388 | return original_val & BATTERY_MODE_MASK; |
400 | } | 389 | } |
401 | 390 | ||
402 | static int bq20z75_get_battery_capacity(struct i2c_client *client, | 391 | static int sbs_get_battery_capacity(struct i2c_client *client, |
403 | int reg_offset, enum power_supply_property psp, | 392 | int reg_offset, enum power_supply_property psp, |
404 | union power_supply_propval *val) | 393 | union power_supply_propval *val) |
405 | { | 394 | { |
406 | s32 ret; | 395 | s32 ret; |
407 | enum bq20z75_battery_mode mode = BATTERY_MODE_WATTS; | 396 | enum sbs_battery_mode mode = BATTERY_MODE_WATTS; |
408 | 397 | ||
409 | if (power_supply_is_amp_property(psp)) | 398 | if (power_supply_is_amp_property(psp)) |
410 | mode = BATTERY_MODE_AMPS; | 399 | mode = BATTERY_MODE_AMPS; |
411 | 400 | ||
412 | mode = bq20z75_set_battery_mode(client, mode); | 401 | mode = sbs_set_battery_mode(client, mode); |
413 | if (mode < 0) | 402 | if (mode < 0) |
414 | return mode; | 403 | return mode; |
415 | 404 | ||
416 | ret = bq20z75_read_word_data(client, bq20z75_data[reg_offset].addr); | 405 | ret = sbs_read_word_data(client, sbs_data[reg_offset].addr); |
417 | if (ret < 0) | 406 | if (ret < 0) |
418 | return ret; | 407 | return ret; |
419 | 408 | ||
420 | if (psp == POWER_SUPPLY_PROP_CAPACITY) { | 409 | if (psp == POWER_SUPPLY_PROP_CAPACITY) { |
421 | /* bq20z75 spec says that this can be >100 % | 410 | /* sbs spec says that this can be >100 % |
422 | * even if max value is 100 % */ | 411 | * even if max value is 100 % */ |
423 | val->intval = min(ret, 100); | 412 | val->intval = min(ret, 100); |
424 | } else | 413 | } else |
425 | val->intval = ret; | 414 | val->intval = ret; |
426 | 415 | ||
427 | ret = bq20z75_set_battery_mode(client, mode); | 416 | ret = sbs_set_battery_mode(client, mode); |
428 | if (ret < 0) | 417 | if (ret < 0) |
429 | return ret; | 418 | return ret; |
430 | 419 | ||
431 | return 0; | 420 | return 0; |
432 | } | 421 | } |
433 | 422 | ||
434 | static char bq20z75_serial[5]; | 423 | static char sbs_serial[5]; |
435 | static int bq20z75_get_battery_serial_number(struct i2c_client *client, | 424 | static int sbs_get_battery_serial_number(struct i2c_client *client, |
436 | union power_supply_propval *val) | 425 | union power_supply_propval *val) |
437 | { | 426 | { |
438 | int ret; | 427 | int ret; |
439 | 428 | ||
440 | ret = bq20z75_read_word_data(client, | 429 | ret = sbs_read_word_data(client, sbs_data[REG_SERIAL_NUMBER].addr); |
441 | bq20z75_data[REG_SERIAL_NUMBER].addr); | ||
442 | if (ret < 0) | 430 | if (ret < 0) |
443 | return ret; | 431 | return ret; |
444 | 432 | ||
445 | ret = sprintf(bq20z75_serial, "%04x", ret); | 433 | ret = sprintf(sbs_serial, "%04x", ret); |
446 | val->strval = bq20z75_serial; | 434 | val->strval = sbs_serial; |
447 | 435 | ||
448 | return 0; | 436 | return 0; |
449 | } | 437 | } |
450 | 438 | ||
451 | static int bq20z75_get_property_index(struct i2c_client *client, | 439 | static int sbs_get_property_index(struct i2c_client *client, |
452 | enum power_supply_property psp) | 440 | enum power_supply_property psp) |
453 | { | 441 | { |
454 | int count; | 442 | int count; |
455 | for (count = 0; count < ARRAY_SIZE(bq20z75_data); count++) | 443 | for (count = 0; count < ARRAY_SIZE(sbs_data); count++) |
456 | if (psp == bq20z75_data[count].psp) | 444 | if (psp == sbs_data[count].psp) |
457 | return count; | 445 | return count; |
458 | 446 | ||
459 | dev_warn(&client->dev, | 447 | dev_warn(&client->dev, |
@@ -462,19 +450,19 @@ static int bq20z75_get_property_index(struct i2c_client *client, | |||
462 | return -EINVAL; | 450 | return -EINVAL; |
463 | } | 451 | } |
464 | 452 | ||
465 | static int bq20z75_get_property(struct power_supply *psy, | 453 | static int sbs_get_property(struct power_supply *psy, |
466 | enum power_supply_property psp, | 454 | enum power_supply_property psp, |
467 | union power_supply_propval *val) | 455 | union power_supply_propval *val) |
468 | { | 456 | { |
469 | int ret = 0; | 457 | int ret = 0; |
470 | struct bq20z75_info *bq20z75_device = container_of(psy, | 458 | struct sbs_info *chip = container_of(psy, |
471 | struct bq20z75_info, power_supply); | 459 | struct sbs_info, power_supply); |
472 | struct i2c_client *client = bq20z75_device->client; | 460 | struct i2c_client *client = chip->client; |
473 | 461 | ||
474 | switch (psp) { | 462 | switch (psp) { |
475 | case POWER_SUPPLY_PROP_PRESENT: | 463 | case POWER_SUPPLY_PROP_PRESENT: |
476 | case POWER_SUPPLY_PROP_HEALTH: | 464 | case POWER_SUPPLY_PROP_HEALTH: |
477 | ret = bq20z75_get_battery_presence_and_health(client, psp, val); | 465 | ret = sbs_get_battery_presence_and_health(client, psp, val); |
478 | if (psp == POWER_SUPPLY_PROP_PRESENT) | 466 | if (psp == POWER_SUPPLY_PROP_PRESENT) |
479 | return 0; | 467 | return 0; |
480 | break; | 468 | break; |
@@ -490,15 +478,15 @@ static int bq20z75_get_property(struct power_supply *psy, | |||
490 | case POWER_SUPPLY_PROP_CHARGE_FULL: | 478 | case POWER_SUPPLY_PROP_CHARGE_FULL: |
491 | case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN: | 479 | case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN: |
492 | case POWER_SUPPLY_PROP_CAPACITY: | 480 | case POWER_SUPPLY_PROP_CAPACITY: |
493 | ret = bq20z75_get_property_index(client, psp); | 481 | ret = sbs_get_property_index(client, psp); |
494 | if (ret < 0) | 482 | if (ret < 0) |
495 | break; | 483 | break; |
496 | 484 | ||
497 | ret = bq20z75_get_battery_capacity(client, ret, psp, val); | 485 | ret = sbs_get_battery_capacity(client, ret, psp, val); |
498 | break; | 486 | break; |
499 | 487 | ||
500 | case POWER_SUPPLY_PROP_SERIAL_NUMBER: | 488 | case POWER_SUPPLY_PROP_SERIAL_NUMBER: |
501 | ret = bq20z75_get_battery_serial_number(client, val); | 489 | ret = sbs_get_battery_serial_number(client, val); |
502 | break; | 490 | break; |
503 | 491 | ||
504 | case POWER_SUPPLY_PROP_STATUS: | 492 | case POWER_SUPPLY_PROP_STATUS: |
@@ -509,11 +497,11 @@ static int bq20z75_get_property(struct power_supply *psy, | |||
509 | case POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG: | 497 | case POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG: |
510 | case POWER_SUPPLY_PROP_TIME_TO_FULL_AVG: | 498 | case POWER_SUPPLY_PROP_TIME_TO_FULL_AVG: |
511 | case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN: | 499 | case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN: |
512 | ret = bq20z75_get_property_index(client, psp); | 500 | ret = sbs_get_property_index(client, psp); |
513 | if (ret < 0) | 501 | if (ret < 0) |
514 | break; | 502 | break; |
515 | 503 | ||
516 | ret = bq20z75_get_battery_property(client, ret, psp, val); | 504 | ret = sbs_get_battery_property(client, ret, psp, val); |
517 | break; | 505 | break; |
518 | 506 | ||
519 | default: | 507 | default: |
@@ -522,25 +510,25 @@ static int bq20z75_get_property(struct power_supply *psy, | |||
522 | return -EINVAL; | 510 | return -EINVAL; |
523 | } | 511 | } |
524 | 512 | ||
525 | if (!bq20z75_device->enable_detection) | 513 | if (!chip->enable_detection) |
526 | goto done; | 514 | goto done; |
527 | 515 | ||
528 | if (!bq20z75_device->gpio_detect && | 516 | if (!chip->gpio_detect && |
529 | bq20z75_device->is_present != (ret >= 0)) { | 517 | chip->is_present != (ret >= 0)) { |
530 | bq20z75_device->is_present = (ret >= 0); | 518 | chip->is_present = (ret >= 0); |
531 | power_supply_changed(&bq20z75_device->power_supply); | 519 | power_supply_changed(&chip->power_supply); |
532 | } | 520 | } |
533 | 521 | ||
534 | done: | 522 | done: |
535 | if (!ret) { | 523 | if (!ret) { |
536 | /* Convert units to match requirements for power supply class */ | 524 | /* Convert units to match requirements for power supply class */ |
537 | bq20z75_unit_adjustment(client, psp, val); | 525 | sbs_unit_adjustment(client, psp, val); |
538 | } | 526 | } |
539 | 527 | ||
540 | dev_dbg(&client->dev, | 528 | dev_dbg(&client->dev, |
541 | "%s: property = %d, value = %x\n", __func__, psp, val->intval); | 529 | "%s: property = %d, value = %x\n", __func__, psp, val->intval); |
542 | 530 | ||
543 | if (ret && bq20z75_device->is_present) | 531 | if (ret && chip->is_present) |
544 | return ret; | 532 | return ret; |
545 | 533 | ||
546 | /* battery not present, so return NODATA for properties */ | 534 | /* battery not present, so return NODATA for properties */ |
@@ -550,7 +538,7 @@ done: | |||
550 | return 0; | 538 | return 0; |
551 | } | 539 | } |
552 | 540 | ||
553 | static irqreturn_t bq20z75_irq(int irq, void *devid) | 541 | static irqreturn_t sbs_irq(int irq, void *devid) |
554 | { | 542 | { |
555 | struct power_supply *battery = devid; | 543 | struct power_supply *battery = devid; |
556 | 544 | ||
@@ -559,36 +547,35 @@ static irqreturn_t bq20z75_irq(int irq, void *devid) | |||
559 | return IRQ_HANDLED; | 547 | return IRQ_HANDLED; |
560 | } | 548 | } |
561 | 549 | ||
562 | static void bq20z75_external_power_changed(struct power_supply *psy) | 550 | static void sbs_external_power_changed(struct power_supply *psy) |
563 | { | 551 | { |
564 | struct bq20z75_info *bq20z75_device; | 552 | struct sbs_info *chip; |
565 | 553 | ||
566 | bq20z75_device = container_of(psy, struct bq20z75_info, power_supply); | 554 | chip = container_of(psy, struct sbs_info, power_supply); |
567 | 555 | ||
568 | if (bq20z75_device->ignore_changes > 0) { | 556 | if (chip->ignore_changes > 0) { |
569 | bq20z75_device->ignore_changes--; | 557 | chip->ignore_changes--; |
570 | return; | 558 | return; |
571 | } | 559 | } |
572 | 560 | ||
573 | /* cancel outstanding work */ | 561 | /* cancel outstanding work */ |
574 | cancel_delayed_work_sync(&bq20z75_device->work); | 562 | cancel_delayed_work_sync(&chip->work); |
575 | 563 | ||
576 | schedule_delayed_work(&bq20z75_device->work, HZ); | 564 | schedule_delayed_work(&chip->work, HZ); |
577 | bq20z75_device->poll_time = bq20z75_device->pdata->poll_retry_count; | 565 | chip->poll_time = chip->pdata->poll_retry_count; |
578 | } | 566 | } |
579 | 567 | ||
580 | static void bq20z75_delayed_work(struct work_struct *work) | 568 | static void sbs_delayed_work(struct work_struct *work) |
581 | { | 569 | { |
582 | struct bq20z75_info *bq20z75_device; | 570 | struct sbs_info *chip; |
583 | s32 ret; | 571 | s32 ret; |
584 | 572 | ||
585 | bq20z75_device = container_of(work, struct bq20z75_info, work.work); | 573 | chip = container_of(work, struct sbs_info, work.work); |
586 | 574 | ||
587 | ret = bq20z75_read_word_data(bq20z75_device->client, | 575 | ret = sbs_read_word_data(chip->client, sbs_data[REG_STATUS].addr); |
588 | bq20z75_data[REG_STATUS].addr); | ||
589 | /* if the read failed, give up on this work */ | 576 | /* if the read failed, give up on this work */ |
590 | if (ret < 0) { | 577 | if (ret < 0) { |
591 | bq20z75_device->poll_time = 0; | 578 | chip->poll_time = 0; |
592 | return; | 579 | return; |
593 | } | 580 | } |
594 | 581 | ||
@@ -601,62 +588,145 @@ static void bq20z75_delayed_work(struct work_struct *work) | |||
601 | else | 588 | else |
602 | ret = POWER_SUPPLY_STATUS_CHARGING; | 589 | ret = POWER_SUPPLY_STATUS_CHARGING; |
603 | 590 | ||
604 | if (bq20z75_device->last_state != ret) { | 591 | if (chip->last_state != ret) { |
605 | bq20z75_device->poll_time = 0; | 592 | chip->poll_time = 0; |
606 | power_supply_changed(&bq20z75_device->power_supply); | 593 | power_supply_changed(&chip->power_supply); |
607 | return; | 594 | return; |
608 | } | 595 | } |
609 | if (bq20z75_device->poll_time > 0) { | 596 | if (chip->poll_time > 0) { |
610 | schedule_delayed_work(&bq20z75_device->work, HZ); | 597 | schedule_delayed_work(&chip->work, HZ); |
611 | bq20z75_device->poll_time--; | 598 | chip->poll_time--; |
612 | return; | 599 | return; |
613 | } | 600 | } |
614 | } | 601 | } |
615 | 602 | ||
616 | static int __devinit bq20z75_probe(struct i2c_client *client, | 603 | #if defined(CONFIG_OF) |
604 | |||
605 | #include <linux/of_device.h> | ||
606 | #include <linux/of_gpio.h> | ||
607 | |||
608 | static const struct of_device_id sbs_dt_ids[] = { | ||
609 | { .compatible = "sbs,sbs-battery" }, | ||
610 | { .compatible = "ti,bq20z75" }, | ||
611 | { } | ||
612 | }; | ||
613 | MODULE_DEVICE_TABLE(of, sbs_dt_ids); | ||
614 | |||
615 | static struct sbs_platform_data *sbs_of_populate_pdata( | ||
616 | struct i2c_client *client) | ||
617 | { | ||
618 | struct device_node *of_node = client->dev.of_node; | ||
619 | struct sbs_platform_data *pdata = client->dev.platform_data; | ||
620 | enum of_gpio_flags gpio_flags; | ||
621 | int rc; | ||
622 | u32 prop; | ||
623 | |||
624 | /* verify this driver matches this device */ | ||
625 | if (!of_node) | ||
626 | return NULL; | ||
627 | |||
628 | /* if platform data is set, honor it */ | ||
629 | if (pdata) | ||
630 | return pdata; | ||
631 | |||
632 | /* first make sure at least one property is set, otherwise | ||
633 | * it won't change behavior from running without pdata. | ||
634 | */ | ||
635 | if (!of_get_property(of_node, "sbs,i2c-retry-count", NULL) && | ||
636 | !of_get_property(of_node, "sbs,poll-retry-count", NULL) && | ||
637 | !of_get_property(of_node, "sbs,battery-detect-gpios", NULL)) | ||
638 | goto of_out; | ||
639 | |||
640 | pdata = devm_kzalloc(&client->dev, sizeof(struct sbs_platform_data), | ||
641 | GFP_KERNEL); | ||
642 | if (!pdata) | ||
643 | goto of_out; | ||
644 | |||
645 | rc = of_property_read_u32(of_node, "sbs,i2c-retry-count", &prop); | ||
646 | if (!rc) | ||
647 | pdata->i2c_retry_count = prop; | ||
648 | |||
649 | rc = of_property_read_u32(of_node, "sbs,poll-retry-count", &prop); | ||
650 | if (!rc) | ||
651 | pdata->poll_retry_count = prop; | ||
652 | |||
653 | if (!of_get_property(of_node, "sbs,battery-detect-gpios", NULL)) { | ||
654 | pdata->battery_detect = -1; | ||
655 | goto of_out; | ||
656 | } | ||
657 | |||
658 | pdata->battery_detect = of_get_named_gpio_flags(of_node, | ||
659 | "sbs,battery-detect-gpios", 0, &gpio_flags); | ||
660 | |||
661 | if (gpio_flags & OF_GPIO_ACTIVE_LOW) | ||
662 | pdata->battery_detect_present = 0; | ||
663 | else | ||
664 | pdata->battery_detect_present = 1; | ||
665 | |||
666 | of_out: | ||
667 | return pdata; | ||
668 | } | ||
669 | #else | ||
670 | #define sbs_dt_ids NULL | ||
671 | static struct sbs_platform_data *sbs_of_populate_pdata( | ||
672 | struct i2c_client *client) | ||
673 | { | ||
674 | return client->dev.platform_data; | ||
675 | } | ||
676 | #endif | ||
677 | |||
678 | static int __devinit sbs_probe(struct i2c_client *client, | ||
617 | const struct i2c_device_id *id) | 679 | const struct i2c_device_id *id) |
618 | { | 680 | { |
619 | struct bq20z75_info *bq20z75_device; | 681 | struct sbs_info *chip; |
620 | struct bq20z75_platform_data *pdata = client->dev.platform_data; | 682 | struct sbs_platform_data *pdata = client->dev.platform_data; |
621 | int rc; | 683 | int rc; |
622 | int irq; | 684 | int irq; |
685 | char *name; | ||
623 | 686 | ||
624 | bq20z75_device = kzalloc(sizeof(struct bq20z75_info), GFP_KERNEL); | 687 | name = kasprintf(GFP_KERNEL, "sbs-%s", dev_name(&client->dev)); |
625 | if (!bq20z75_device) | 688 | if (!name) { |
689 | dev_err(&client->dev, "Failed to allocate device name\n"); | ||
626 | return -ENOMEM; | 690 | return -ENOMEM; |
691 | } | ||
692 | |||
693 | chip = kzalloc(sizeof(struct sbs_info), GFP_KERNEL); | ||
694 | if (!chip) { | ||
695 | rc = -ENOMEM; | ||
696 | goto exit_free_name; | ||
697 | } | ||
627 | 698 | ||
628 | bq20z75_device->client = client; | 699 | chip->client = client; |
629 | bq20z75_device->enable_detection = false; | 700 | chip->enable_detection = false; |
630 | bq20z75_device->gpio_detect = false; | 701 | chip->gpio_detect = false; |
631 | bq20z75_device->power_supply.name = "battery"; | 702 | chip->power_supply.name = name; |
632 | bq20z75_device->power_supply.type = POWER_SUPPLY_TYPE_BATTERY; | 703 | chip->power_supply.type = POWER_SUPPLY_TYPE_BATTERY; |
633 | bq20z75_device->power_supply.properties = bq20z75_properties; | 704 | chip->power_supply.properties = sbs_properties; |
634 | bq20z75_device->power_supply.num_properties = | 705 | chip->power_supply.num_properties = ARRAY_SIZE(sbs_properties); |
635 | ARRAY_SIZE(bq20z75_properties); | 706 | chip->power_supply.get_property = sbs_get_property; |
636 | bq20z75_device->power_supply.get_property = bq20z75_get_property; | ||
637 | /* ignore first notification of external change, it is generated | 707 | /* ignore first notification of external change, it is generated |
638 | * from the power_supply_register call back | 708 | * from the power_supply_register call back |
639 | */ | 709 | */ |
640 | bq20z75_device->ignore_changes = 1; | 710 | chip->ignore_changes = 1; |
641 | bq20z75_device->last_state = POWER_SUPPLY_STATUS_UNKNOWN; | 711 | chip->last_state = POWER_SUPPLY_STATUS_UNKNOWN; |
642 | bq20z75_device->power_supply.external_power_changed = | 712 | chip->power_supply.external_power_changed = sbs_external_power_changed; |
643 | bq20z75_external_power_changed; | 713 | |
714 | pdata = sbs_of_populate_pdata(client); | ||
644 | 715 | ||
645 | if (pdata) { | 716 | if (pdata) { |
646 | bq20z75_device->gpio_detect = | 717 | chip->gpio_detect = gpio_is_valid(pdata->battery_detect); |
647 | gpio_is_valid(pdata->battery_detect); | 718 | chip->pdata = pdata; |
648 | bq20z75_device->pdata = pdata; | ||
649 | } | 719 | } |
650 | 720 | ||
651 | i2c_set_clientdata(client, bq20z75_device); | 721 | i2c_set_clientdata(client, chip); |
652 | 722 | ||
653 | if (!bq20z75_device->gpio_detect) | 723 | if (!chip->gpio_detect) |
654 | goto skip_gpio; | 724 | goto skip_gpio; |
655 | 725 | ||
656 | rc = gpio_request(pdata->battery_detect, dev_name(&client->dev)); | 726 | rc = gpio_request(pdata->battery_detect, dev_name(&client->dev)); |
657 | if (rc) { | 727 | if (rc) { |
658 | dev_warn(&client->dev, "Failed to request gpio: %d\n", rc); | 728 | dev_warn(&client->dev, "Failed to request gpio: %d\n", rc); |
659 | bq20z75_device->gpio_detect = false; | 729 | chip->gpio_detect = false; |
660 | goto skip_gpio; | 730 | goto skip_gpio; |
661 | } | 731 | } |
662 | 732 | ||
@@ -664,7 +734,7 @@ static int __devinit bq20z75_probe(struct i2c_client *client, | |||
664 | if (rc) { | 734 | if (rc) { |
665 | dev_warn(&client->dev, "Failed to get gpio as input: %d\n", rc); | 735 | dev_warn(&client->dev, "Failed to get gpio as input: %d\n", rc); |
666 | gpio_free(pdata->battery_detect); | 736 | gpio_free(pdata->battery_detect); |
667 | bq20z75_device->gpio_detect = false; | 737 | chip->gpio_detect = false; |
668 | goto skip_gpio; | 738 | goto skip_gpio; |
669 | } | 739 | } |
670 | 740 | ||
@@ -672,25 +742,25 @@ static int __devinit bq20z75_probe(struct i2c_client *client, | |||
672 | if (irq <= 0) { | 742 | if (irq <= 0) { |
673 | dev_warn(&client->dev, "Failed to get gpio as irq: %d\n", irq); | 743 | dev_warn(&client->dev, "Failed to get gpio as irq: %d\n", irq); |
674 | gpio_free(pdata->battery_detect); | 744 | gpio_free(pdata->battery_detect); |
675 | bq20z75_device->gpio_detect = false; | 745 | chip->gpio_detect = false; |
676 | goto skip_gpio; | 746 | goto skip_gpio; |
677 | } | 747 | } |
678 | 748 | ||
679 | rc = request_irq(irq, bq20z75_irq, | 749 | rc = request_irq(irq, sbs_irq, |
680 | IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, | 750 | IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, |
681 | dev_name(&client->dev), &bq20z75_device->power_supply); | 751 | dev_name(&client->dev), &chip->power_supply); |
682 | if (rc) { | 752 | if (rc) { |
683 | dev_warn(&client->dev, "Failed to request irq: %d\n", rc); | 753 | dev_warn(&client->dev, "Failed to request irq: %d\n", rc); |
684 | gpio_free(pdata->battery_detect); | 754 | gpio_free(pdata->battery_detect); |
685 | bq20z75_device->gpio_detect = false; | 755 | chip->gpio_detect = false; |
686 | goto skip_gpio; | 756 | goto skip_gpio; |
687 | } | 757 | } |
688 | 758 | ||
689 | bq20z75_device->irq = irq; | 759 | chip->irq = irq; |
690 | 760 | ||
691 | skip_gpio: | 761 | skip_gpio: |
692 | 762 | ||
693 | rc = power_supply_register(&client->dev, &bq20z75_device->power_supply); | 763 | rc = power_supply_register(&client->dev, &chip->power_supply); |
694 | if (rc) { | 764 | if (rc) { |
695 | dev_err(&client->dev, | 765 | dev_err(&client->dev, |
696 | "%s: Failed to register power supply\n", __func__); | 766 | "%s: Failed to register power supply\n", __func__); |
@@ -700,95 +770,100 @@ skip_gpio: | |||
700 | dev_info(&client->dev, | 770 | dev_info(&client->dev, |
701 | "%s: battery gas gauge device registered\n", client->name); | 771 | "%s: battery gas gauge device registered\n", client->name); |
702 | 772 | ||
703 | INIT_DELAYED_WORK(&bq20z75_device->work, bq20z75_delayed_work); | 773 | INIT_DELAYED_WORK(&chip->work, sbs_delayed_work); |
704 | 774 | ||
705 | bq20z75_device->enable_detection = true; | 775 | chip->enable_detection = true; |
706 | 776 | ||
707 | return 0; | 777 | return 0; |
708 | 778 | ||
709 | exit_psupply: | 779 | exit_psupply: |
710 | if (bq20z75_device->irq) | 780 | if (chip->irq) |
711 | free_irq(bq20z75_device->irq, &bq20z75_device->power_supply); | 781 | free_irq(chip->irq, &chip->power_supply); |
712 | if (bq20z75_device->gpio_detect) | 782 | if (chip->gpio_detect) |
713 | gpio_free(pdata->battery_detect); | 783 | gpio_free(pdata->battery_detect); |
714 | 784 | ||
715 | kfree(bq20z75_device); | 785 | kfree(chip); |
786 | |||
787 | exit_free_name: | ||
788 | kfree(name); | ||
716 | 789 | ||
717 | return rc; | 790 | return rc; |
718 | } | 791 | } |
719 | 792 | ||
720 | static int __devexit bq20z75_remove(struct i2c_client *client) | 793 | static int __devexit sbs_remove(struct i2c_client *client) |
721 | { | 794 | { |
722 | struct bq20z75_info *bq20z75_device = i2c_get_clientdata(client); | 795 | struct sbs_info *chip = i2c_get_clientdata(client); |
723 | 796 | ||
724 | if (bq20z75_device->irq) | 797 | if (chip->irq) |
725 | free_irq(bq20z75_device->irq, &bq20z75_device->power_supply); | 798 | free_irq(chip->irq, &chip->power_supply); |
726 | if (bq20z75_device->gpio_detect) | 799 | if (chip->gpio_detect) |
727 | gpio_free(bq20z75_device->pdata->battery_detect); | 800 | gpio_free(chip->pdata->battery_detect); |
728 | 801 | ||
729 | power_supply_unregister(&bq20z75_device->power_supply); | 802 | power_supply_unregister(&chip->power_supply); |
730 | 803 | ||
731 | cancel_delayed_work_sync(&bq20z75_device->work); | 804 | cancel_delayed_work_sync(&chip->work); |
732 | 805 | ||
733 | kfree(bq20z75_device); | 806 | kfree(chip->power_supply.name); |
734 | bq20z75_device = NULL; | 807 | kfree(chip); |
808 | chip = NULL; | ||
735 | 809 | ||
736 | return 0; | 810 | return 0; |
737 | } | 811 | } |
738 | 812 | ||
739 | #if defined CONFIG_PM | 813 | #if defined CONFIG_PM |
740 | static int bq20z75_suspend(struct i2c_client *client, | 814 | static int sbs_suspend(struct i2c_client *client, |
741 | pm_message_t state) | 815 | pm_message_t state) |
742 | { | 816 | { |
743 | struct bq20z75_info *bq20z75_device = i2c_get_clientdata(client); | 817 | struct sbs_info *chip = i2c_get_clientdata(client); |
744 | s32 ret; | 818 | s32 ret; |
745 | 819 | ||
746 | if (bq20z75_device->poll_time > 0) | 820 | if (chip->poll_time > 0) |
747 | cancel_delayed_work_sync(&bq20z75_device->work); | 821 | cancel_delayed_work_sync(&chip->work); |
748 | 822 | ||
749 | /* write to manufacturer access with sleep command */ | 823 | /* write to manufacturer access with sleep command */ |
750 | ret = bq20z75_write_word_data(client, | 824 | ret = sbs_write_word_data(client, sbs_data[REG_MANUFACTURER_DATA].addr, |
751 | bq20z75_data[REG_MANUFACTURER_DATA].addr, | ||
752 | MANUFACTURER_ACCESS_SLEEP); | 825 | MANUFACTURER_ACCESS_SLEEP); |
753 | if (bq20z75_device->is_present && ret < 0) | 826 | if (chip->is_present && ret < 0) |
754 | return ret; | 827 | return ret; |
755 | 828 | ||
756 | return 0; | 829 | return 0; |
757 | } | 830 | } |
758 | #else | 831 | #else |
759 | #define bq20z75_suspend NULL | 832 | #define sbs_suspend NULL |
760 | #endif | 833 | #endif |
761 | /* any smbus transaction will wake up bq20z75 */ | 834 | /* any smbus transaction will wake up sbs */ |
762 | #define bq20z75_resume NULL | 835 | #define sbs_resume NULL |
763 | 836 | ||
764 | static const struct i2c_device_id bq20z75_id[] = { | 837 | static const struct i2c_device_id sbs_id[] = { |
765 | { "bq20z75", 0 }, | 838 | { "bq20z75", 0 }, |
839 | { "sbs-battery", 1 }, | ||
766 | {} | 840 | {} |
767 | }; | 841 | }; |
768 | MODULE_DEVICE_TABLE(i2c, bq20z75_id); | 842 | MODULE_DEVICE_TABLE(i2c, sbs_id); |
769 | 843 | ||
770 | static struct i2c_driver bq20z75_battery_driver = { | 844 | static struct i2c_driver sbs_battery_driver = { |
771 | .probe = bq20z75_probe, | 845 | .probe = sbs_probe, |
772 | .remove = __devexit_p(bq20z75_remove), | 846 | .remove = __devexit_p(sbs_remove), |
773 | .suspend = bq20z75_suspend, | 847 | .suspend = sbs_suspend, |
774 | .resume = bq20z75_resume, | 848 | .resume = sbs_resume, |
775 | .id_table = bq20z75_id, | 849 | .id_table = sbs_id, |
776 | .driver = { | 850 | .driver = { |
777 | .name = "bq20z75-battery", | 851 | .name = "sbs-battery", |
852 | .of_match_table = sbs_dt_ids, | ||
778 | }, | 853 | }, |
779 | }; | 854 | }; |
780 | 855 | ||
781 | static int __init bq20z75_battery_init(void) | 856 | static int __init sbs_battery_init(void) |
782 | { | 857 | { |
783 | return i2c_add_driver(&bq20z75_battery_driver); | 858 | return i2c_add_driver(&sbs_battery_driver); |
784 | } | 859 | } |
785 | module_init(bq20z75_battery_init); | 860 | module_init(sbs_battery_init); |
786 | 861 | ||
787 | static void __exit bq20z75_battery_exit(void) | 862 | static void __exit sbs_battery_exit(void) |
788 | { | 863 | { |
789 | i2c_del_driver(&bq20z75_battery_driver); | 864 | i2c_del_driver(&sbs_battery_driver); |
790 | } | 865 | } |
791 | module_exit(bq20z75_battery_exit); | 866 | module_exit(sbs_battery_exit); |
792 | 867 | ||
793 | MODULE_DESCRIPTION("BQ20z75 battery monitor driver"); | 868 | MODULE_DESCRIPTION("SBS battery monitor driver"); |
794 | MODULE_LICENSE("GPL"); | 869 | MODULE_LICENSE("GPL"); |
diff --git a/drivers/power/tosa_battery.c b/drivers/power/tosa_battery.c index 53f0d3524fcd..28bbe7e094e3 100644 --- a/drivers/power/tosa_battery.c +++ b/drivers/power/tosa_battery.c | |||
@@ -307,25 +307,20 @@ static struct tosa_bat tosa_bat_bu = { | |||
307 | .adc_temp_divider = -1, | 307 | .adc_temp_divider = -1, |
308 | }; | 308 | }; |
309 | 309 | ||
310 | static struct { | 310 | static struct gpio tosa_bat_gpios[] = { |
311 | int gpio; | 311 | { TOSA_GPIO_CHARGE_OFF, GPIOF_OUT_INIT_HIGH, "main charge off" }, |
312 | char *name; | 312 | { TOSA_GPIO_CHARGE_OFF_JC, GPIOF_OUT_INIT_HIGH, "jacket charge off" }, |
313 | bool output; | 313 | { TOSA_GPIO_BAT_SW_ON, GPIOF_OUT_INIT_LOW, "battery switch" }, |
314 | int value; | 314 | { TOSA_GPIO_BAT0_V_ON, GPIOF_OUT_INIT_LOW, "main battery" }, |
315 | } gpios[] = { | 315 | { TOSA_GPIO_BAT1_V_ON, GPIOF_OUT_INIT_LOW, "jacket battery" }, |
316 | { TOSA_GPIO_CHARGE_OFF, "main charge off", 1, 1 }, | 316 | { TOSA_GPIO_BAT1_TH_ON, GPIOF_OUT_INIT_LOW, "main battery temp" }, |
317 | { TOSA_GPIO_CHARGE_OFF_JC, "jacket charge off", 1, 1 }, | 317 | { TOSA_GPIO_BAT0_TH_ON, GPIOF_OUT_INIT_LOW, "jacket battery temp" }, |
318 | { TOSA_GPIO_BAT_SW_ON, "battery switch", 1, 0 }, | 318 | { TOSA_GPIO_BU_CHRG_ON, GPIOF_OUT_INIT_LOW, "backup battery" }, |
319 | { TOSA_GPIO_BAT0_V_ON, "main battery", 1, 0 }, | 319 | { TOSA_GPIO_BAT0_CRG, GPIOF_IN, "main battery full" }, |
320 | { TOSA_GPIO_BAT1_V_ON, "jacket battery", 1, 0 }, | 320 | { TOSA_GPIO_BAT1_CRG, GPIOF_IN, "jacket battery full" }, |
321 | { TOSA_GPIO_BAT1_TH_ON, "main battery temp", 1, 0 }, | 321 | { TOSA_GPIO_BAT0_LOW, GPIOF_IN, "main battery low" }, |
322 | { TOSA_GPIO_BAT0_TH_ON, "jacket battery temp", 1, 0 }, | 322 | { TOSA_GPIO_BAT1_LOW, GPIOF_IN, "jacket battery low" }, |
323 | { TOSA_GPIO_BU_CHRG_ON, "backup battery", 1, 0 }, | 323 | { TOSA_GPIO_JACKET_DETECT, GPIOF_IN, "jacket detect" }, |
324 | { TOSA_GPIO_BAT0_CRG, "main battery full", 0, 0 }, | ||
325 | { TOSA_GPIO_BAT1_CRG, "jacket battery full", 0, 0 }, | ||
326 | { TOSA_GPIO_BAT0_LOW, "main battery low", 0, 0 }, | ||
327 | { TOSA_GPIO_BAT1_LOW, "jacket battery low", 0, 0 }, | ||
328 | { TOSA_GPIO_JACKET_DETECT, "jacket detect", 0, 0 }, | ||
329 | }; | 324 | }; |
330 | 325 | ||
331 | #ifdef CONFIG_PM | 326 | #ifdef CONFIG_PM |
@@ -350,27 +345,13 @@ static int tosa_bat_resume(struct platform_device *dev) | |||
350 | static int __devinit tosa_bat_probe(struct platform_device *dev) | 345 | static int __devinit tosa_bat_probe(struct platform_device *dev) |
351 | { | 346 | { |
352 | int ret; | 347 | int ret; |
353 | int i; | ||
354 | 348 | ||
355 | if (!machine_is_tosa()) | 349 | if (!machine_is_tosa()) |
356 | return -ENODEV; | 350 | return -ENODEV; |
357 | 351 | ||
358 | for (i = 0; i < ARRAY_SIZE(gpios); i++) { | 352 | ret = gpio_request_array(tosa_bat_gpios, ARRAY_SIZE(tosa_bat_gpios)); |
359 | ret = gpio_request(gpios[i].gpio, gpios[i].name); | 353 | if (ret) |
360 | if (ret) { | 354 | return ret; |
361 | i--; | ||
362 | goto err_gpio; | ||
363 | } | ||
364 | |||
365 | if (gpios[i].output) | ||
366 | ret = gpio_direction_output(gpios[i].gpio, | ||
367 | gpios[i].value); | ||
368 | else | ||
369 | ret = gpio_direction_input(gpios[i].gpio); | ||
370 | |||
371 | if (ret) | ||
372 | goto err_gpio; | ||
373 | } | ||
374 | 355 | ||
375 | mutex_init(&tosa_bat_main.work_lock); | 356 | mutex_init(&tosa_bat_main.work_lock); |
376 | mutex_init(&tosa_bat_jacket.work_lock); | 357 | mutex_init(&tosa_bat_jacket.work_lock); |
@@ -424,18 +405,12 @@ err_psy_reg_main: | |||
424 | /* see comment in tosa_bat_remove */ | 405 | /* see comment in tosa_bat_remove */ |
425 | cancel_work_sync(&bat_work); | 406 | cancel_work_sync(&bat_work); |
426 | 407 | ||
427 | i--; | 408 | gpio_free_array(tosa_bat_gpios, ARRAY_SIZE(tosa_bat_gpios)); |
428 | err_gpio: | ||
429 | for (; i >= 0; i--) | ||
430 | gpio_free(gpios[i].gpio); | ||
431 | |||
432 | return ret; | 409 | return ret; |
433 | } | 410 | } |
434 | 411 | ||
435 | static int __devexit tosa_bat_remove(struct platform_device *dev) | 412 | static int __devexit tosa_bat_remove(struct platform_device *dev) |
436 | { | 413 | { |
437 | int i; | ||
438 | |||
439 | free_irq(gpio_to_irq(TOSA_GPIO_JACKET_DETECT), &tosa_bat_jacket); | 414 | free_irq(gpio_to_irq(TOSA_GPIO_JACKET_DETECT), &tosa_bat_jacket); |
440 | free_irq(gpio_to_irq(TOSA_GPIO_BAT1_CRG), &tosa_bat_jacket); | 415 | free_irq(gpio_to_irq(TOSA_GPIO_BAT1_CRG), &tosa_bat_jacket); |
441 | free_irq(gpio_to_irq(TOSA_GPIO_BAT0_CRG), &tosa_bat_main); | 416 | free_irq(gpio_to_irq(TOSA_GPIO_BAT0_CRG), &tosa_bat_main); |
@@ -450,10 +425,7 @@ static int __devexit tosa_bat_remove(struct platform_device *dev) | |||
450 | * unregistered now. | 425 | * unregistered now. |
451 | */ | 426 | */ |
452 | cancel_work_sync(&bat_work); | 427 | cancel_work_sync(&bat_work); |
453 | 428 | gpio_free_array(tosa_bat_gpios, ARRAY_SIZE(tosa_bat_gpios)); | |
454 | for (i = ARRAY_SIZE(gpios) - 1; i >= 0; i--) | ||
455 | gpio_free(gpios[i].gpio); | ||
456 | |||
457 | return 0; | 429 | return 0; |
458 | } | 430 | } |
459 | 431 | ||
@@ -466,18 +438,7 @@ static struct platform_driver tosa_bat_driver = { | |||
466 | .resume = tosa_bat_resume, | 438 | .resume = tosa_bat_resume, |
467 | }; | 439 | }; |
468 | 440 | ||
469 | static int __init tosa_bat_init(void) | 441 | module_platform_driver(tosa_bat_driver); |
470 | { | ||
471 | return platform_driver_register(&tosa_bat_driver); | ||
472 | } | ||
473 | |||
474 | static void __exit tosa_bat_exit(void) | ||
475 | { | ||
476 | platform_driver_unregister(&tosa_bat_driver); | ||
477 | } | ||
478 | |||
479 | module_init(tosa_bat_init); | ||
480 | module_exit(tosa_bat_exit); | ||
481 | 442 | ||
482 | MODULE_LICENSE("GPL"); | 443 | MODULE_LICENSE("GPL"); |
483 | MODULE_AUTHOR("Dmitry Baryshkov"); | 444 | MODULE_AUTHOR("Dmitry Baryshkov"); |
diff --git a/drivers/power/wm831x_backup.c b/drivers/power/wm831x_backup.c index e648cbea1e6a..6243e6975126 100644 --- a/drivers/power/wm831x_backup.c +++ b/drivers/power/wm831x_backup.c | |||
@@ -226,17 +226,7 @@ static struct platform_driver wm831x_backup_driver = { | |||
226 | }, | 226 | }, |
227 | }; | 227 | }; |
228 | 228 | ||
229 | static int __init wm831x_backup_init(void) | 229 | module_platform_driver(wm831x_backup_driver); |
230 | { | ||
231 | return platform_driver_register(&wm831x_backup_driver); | ||
232 | } | ||
233 | module_init(wm831x_backup_init); | ||
234 | |||
235 | static void __exit wm831x_backup_exit(void) | ||
236 | { | ||
237 | platform_driver_unregister(&wm831x_backup_driver); | ||
238 | } | ||
239 | module_exit(wm831x_backup_exit); | ||
240 | 230 | ||
241 | MODULE_DESCRIPTION("Backup battery charger driver for WM831x PMICs"); | 231 | MODULE_DESCRIPTION("Backup battery charger driver for WM831x PMICs"); |
242 | MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>"); | 232 | MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>"); |
diff --git a/drivers/power/wm831x_power.c b/drivers/power/wm831x_power.c index 6cc2ca6427f3..987332b71d8d 100644 --- a/drivers/power/wm831x_power.c +++ b/drivers/power/wm831x_power.c | |||
@@ -27,6 +27,7 @@ struct wm831x_power { | |||
27 | char wall_name[20]; | 27 | char wall_name[20]; |
28 | char usb_name[20]; | 28 | char usb_name[20]; |
29 | char battery_name[20]; | 29 | char battery_name[20]; |
30 | bool have_battery; | ||
30 | }; | 31 | }; |
31 | 32 | ||
32 | static int wm831x_power_check_online(struct wm831x *wm831x, int supply, | 33 | static int wm831x_power_check_online(struct wm831x *wm831x, int supply, |
@@ -449,7 +450,8 @@ static irqreturn_t wm831x_bat_irq(int irq, void *data) | |||
449 | 450 | ||
450 | /* The battery charger is autonomous so we don't need to do | 451 | /* The battery charger is autonomous so we don't need to do |
451 | * anything except kick user space */ | 452 | * anything except kick user space */ |
452 | power_supply_changed(&wm831x_power->battery); | 453 | if (wm831x_power->have_battery) |
454 | power_supply_changed(&wm831x_power->battery); | ||
453 | 455 | ||
454 | return IRQ_HANDLED; | 456 | return IRQ_HANDLED; |
455 | } | 457 | } |
@@ -479,7 +481,8 @@ static irqreturn_t wm831x_pwr_src_irq(int irq, void *data) | |||
479 | dev_dbg(wm831x->dev, "Power source changed\n"); | 481 | dev_dbg(wm831x->dev, "Power source changed\n"); |
480 | 482 | ||
481 | /* Just notify for everything - little harm in overnotifying. */ | 483 | /* Just notify for everything - little harm in overnotifying. */ |
482 | power_supply_changed(&wm831x_power->battery); | 484 | if (wm831x_power->have_battery) |
485 | power_supply_changed(&wm831x_power->battery); | ||
483 | power_supply_changed(&wm831x_power->usb); | 486 | power_supply_changed(&wm831x_power->usb); |
484 | power_supply_changed(&wm831x_power->wall); | 487 | power_supply_changed(&wm831x_power->wall); |
485 | 488 | ||
@@ -537,15 +540,6 @@ static __devinit int wm831x_power_probe(struct platform_device *pdev) | |||
537 | if (ret) | 540 | if (ret) |
538 | goto err_kmalloc; | 541 | goto err_kmalloc; |
539 | 542 | ||
540 | battery->name = power->battery_name; | ||
541 | battery->properties = wm831x_bat_props; | ||
542 | battery->num_properties = ARRAY_SIZE(wm831x_bat_props); | ||
543 | battery->get_property = wm831x_bat_get_prop; | ||
544 | battery->use_for_apm = 1; | ||
545 | ret = power_supply_register(&pdev->dev, battery); | ||
546 | if (ret) | ||
547 | goto err_wall; | ||
548 | |||
549 | usb->name = power->usb_name, | 543 | usb->name = power->usb_name, |
550 | usb->type = POWER_SUPPLY_TYPE_USB; | 544 | usb->type = POWER_SUPPLY_TYPE_USB; |
551 | usb->properties = wm831x_usb_props; | 545 | usb->properties = wm831x_usb_props; |
@@ -553,7 +547,23 @@ static __devinit int wm831x_power_probe(struct platform_device *pdev) | |||
553 | usb->get_property = wm831x_usb_get_prop; | 547 | usb->get_property = wm831x_usb_get_prop; |
554 | ret = power_supply_register(&pdev->dev, usb); | 548 | ret = power_supply_register(&pdev->dev, usb); |
555 | if (ret) | 549 | if (ret) |
556 | goto err_battery; | 550 | goto err_wall; |
551 | |||
552 | ret = wm831x_reg_read(wm831x, WM831X_CHARGER_CONTROL_1); | ||
553 | if (ret < 0) | ||
554 | goto err_wall; | ||
555 | power->have_battery = ret & WM831X_CHG_ENA; | ||
556 | |||
557 | if (power->have_battery) { | ||
558 | battery->name = power->battery_name; | ||
559 | battery->properties = wm831x_bat_props; | ||
560 | battery->num_properties = ARRAY_SIZE(wm831x_bat_props); | ||
561 | battery->get_property = wm831x_bat_get_prop; | ||
562 | battery->use_for_apm = 1; | ||
563 | ret = power_supply_register(&pdev->dev, battery); | ||
564 | if (ret) | ||
565 | goto err_usb; | ||
566 | } | ||
557 | 567 | ||
558 | irq = platform_get_irq_byname(pdev, "SYSLO"); | 568 | irq = platform_get_irq_byname(pdev, "SYSLO"); |
559 | ret = request_threaded_irq(irq, NULL, wm831x_syslo_irq, | 569 | ret = request_threaded_irq(irq, NULL, wm831x_syslo_irq, |
@@ -562,7 +572,7 @@ static __devinit int wm831x_power_probe(struct platform_device *pdev) | |||
562 | if (ret != 0) { | 572 | if (ret != 0) { |
563 | dev_err(&pdev->dev, "Failed to request SYSLO IRQ %d: %d\n", | 573 | dev_err(&pdev->dev, "Failed to request SYSLO IRQ %d: %d\n", |
564 | irq, ret); | 574 | irq, ret); |
565 | goto err_usb; | 575 | goto err_battery; |
566 | } | 576 | } |
567 | 577 | ||
568 | irq = platform_get_irq_byname(pdev, "PWR SRC"); | 578 | irq = platform_get_irq_byname(pdev, "PWR SRC"); |
@@ -601,10 +611,11 @@ err_bat_irq: | |||
601 | err_syslo: | 611 | err_syslo: |
602 | irq = platform_get_irq_byname(pdev, "SYSLO"); | 612 | irq = platform_get_irq_byname(pdev, "SYSLO"); |
603 | free_irq(irq, power); | 613 | free_irq(irq, power); |
614 | err_battery: | ||
615 | if (power->have_battery) | ||
616 | power_supply_unregister(battery); | ||
604 | err_usb: | 617 | err_usb: |
605 | power_supply_unregister(usb); | 618 | power_supply_unregister(usb); |
606 | err_battery: | ||
607 | power_supply_unregister(battery); | ||
608 | err_wall: | 619 | err_wall: |
609 | power_supply_unregister(wall); | 620 | power_supply_unregister(wall); |
610 | err_kmalloc: | 621 | err_kmalloc: |
@@ -628,7 +639,8 @@ static __devexit int wm831x_power_remove(struct platform_device *pdev) | |||
628 | irq = platform_get_irq_byname(pdev, "SYSLO"); | 639 | irq = platform_get_irq_byname(pdev, "SYSLO"); |
629 | free_irq(irq, wm831x_power); | 640 | free_irq(irq, wm831x_power); |
630 | 641 | ||
631 | power_supply_unregister(&wm831x_power->battery); | 642 | if (wm831x_power->have_battery) |
643 | power_supply_unregister(&wm831x_power->battery); | ||
632 | power_supply_unregister(&wm831x_power->wall); | 644 | power_supply_unregister(&wm831x_power->wall); |
633 | power_supply_unregister(&wm831x_power->usb); | 645 | power_supply_unregister(&wm831x_power->usb); |
634 | kfree(wm831x_power); | 646 | kfree(wm831x_power); |
@@ -643,17 +655,7 @@ static struct platform_driver wm831x_power_driver = { | |||
643 | }, | 655 | }, |
644 | }; | 656 | }; |
645 | 657 | ||
646 | static int __init wm831x_power_init(void) | 658 | module_platform_driver(wm831x_power_driver); |
647 | { | ||
648 | return platform_driver_register(&wm831x_power_driver); | ||
649 | } | ||
650 | module_init(wm831x_power_init); | ||
651 | |||
652 | static void __exit wm831x_power_exit(void) | ||
653 | { | ||
654 | platform_driver_unregister(&wm831x_power_driver); | ||
655 | } | ||
656 | module_exit(wm831x_power_exit); | ||
657 | 659 | ||
658 | MODULE_DESCRIPTION("Power supply driver for WM831x PMICs"); | 660 | MODULE_DESCRIPTION("Power supply driver for WM831x PMICs"); |
659 | MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>"); | 661 | MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>"); |
diff --git a/drivers/power/wm8350_power.c b/drivers/power/wm8350_power.c index 0693902d6151..fae04d384657 100644 --- a/drivers/power/wm8350_power.c +++ b/drivers/power/wm8350_power.c | |||
@@ -522,17 +522,7 @@ static struct platform_driver wm8350_power_driver = { | |||
522 | }, | 522 | }, |
523 | }; | 523 | }; |
524 | 524 | ||
525 | static int __init wm8350_power_init(void) | 525 | module_platform_driver(wm8350_power_driver); |
526 | { | ||
527 | return platform_driver_register(&wm8350_power_driver); | ||
528 | } | ||
529 | module_init(wm8350_power_init); | ||
530 | |||
531 | static void __exit wm8350_power_exit(void) | ||
532 | { | ||
533 | platform_driver_unregister(&wm8350_power_driver); | ||
534 | } | ||
535 | module_exit(wm8350_power_exit); | ||
536 | 526 | ||
537 | MODULE_LICENSE("GPL"); | 527 | MODULE_LICENSE("GPL"); |
538 | MODULE_DESCRIPTION("Power supply driver for WM8350"); | 528 | MODULE_DESCRIPTION("Power supply driver for WM8350"); |
diff --git a/drivers/power/wm97xx_battery.c b/drivers/power/wm97xx_battery.c index 156559e56fa5..d2d4c08c681c 100644 --- a/drivers/power/wm97xx_battery.c +++ b/drivers/power/wm97xx_battery.c | |||
@@ -25,9 +25,8 @@ | |||
25 | #include <linux/irq.h> | 25 | #include <linux/irq.h> |
26 | #include <linux/slab.h> | 26 | #include <linux/slab.h> |
27 | 27 | ||
28 | static DEFINE_MUTEX(bat_lock); | ||
29 | static struct work_struct bat_work; | 28 | static struct work_struct bat_work; |
30 | static struct mutex work_lock; | 29 | static DEFINE_MUTEX(work_lock); |
31 | static int bat_status = POWER_SUPPLY_STATUS_UNKNOWN; | 30 | static int bat_status = POWER_SUPPLY_STATUS_UNKNOWN; |
32 | static enum power_supply_property *prop; | 31 | static enum power_supply_property *prop; |
33 | 32 | ||
@@ -181,8 +180,6 @@ static int __devinit wm97xx_bat_probe(struct platform_device *dev) | |||
181 | if (dev->id != -1) | 180 | if (dev->id != -1) |
182 | return -EINVAL; | 181 | return -EINVAL; |
183 | 182 | ||
184 | mutex_init(&work_lock); | ||
185 | |||
186 | if (!pdata) { | 183 | if (!pdata) { |
187 | dev_err(&dev->dev, "No platform_data supplied\n"); | 184 | dev_err(&dev->dev, "No platform_data supplied\n"); |
188 | return -EINVAL; | 185 | return -EINVAL; |
@@ -196,7 +193,7 @@ static int __devinit wm97xx_bat_probe(struct platform_device *dev) | |||
196 | if (ret) | 193 | if (ret) |
197 | goto err2; | 194 | goto err2; |
198 | ret = request_irq(gpio_to_irq(pdata->charge_gpio), | 195 | ret = request_irq(gpio_to_irq(pdata->charge_gpio), |
199 | wm97xx_chrg_irq, IRQF_DISABLED, | 196 | wm97xx_chrg_irq, 0, |
200 | "AC Detect", dev); | 197 | "AC Detect", dev); |
201 | if (ret) | 198 | if (ret) |
202 | goto err2; | 199 | goto err2; |
@@ -291,18 +288,7 @@ static struct platform_driver wm97xx_bat_driver = { | |||
291 | .remove = __devexit_p(wm97xx_bat_remove), | 288 | .remove = __devexit_p(wm97xx_bat_remove), |
292 | }; | 289 | }; |
293 | 290 | ||
294 | static int __init wm97xx_bat_init(void) | 291 | module_platform_driver(wm97xx_bat_driver); |
295 | { | ||
296 | return platform_driver_register(&wm97xx_bat_driver); | ||
297 | } | ||
298 | |||
299 | static void __exit wm97xx_bat_exit(void) | ||
300 | { | ||
301 | platform_driver_unregister(&wm97xx_bat_driver); | ||
302 | } | ||
303 | |||
304 | module_init(wm97xx_bat_init); | ||
305 | module_exit(wm97xx_bat_exit); | ||
306 | 292 | ||
307 | MODULE_LICENSE("GPL"); | 293 | MODULE_LICENSE("GPL"); |
308 | MODULE_AUTHOR("Marek Vasut <marek.vasut@gmail.com>"); | 294 | MODULE_AUTHOR("Marek Vasut <marek.vasut@gmail.com>"); |
diff --git a/drivers/power/z2_battery.c b/drivers/power/z2_battery.c index d119c38b3ff6..636ebb2a0e80 100644 --- a/drivers/power/z2_battery.c +++ b/drivers/power/z2_battery.c | |||
@@ -218,7 +218,7 @@ static int __devinit z2_batt_probe(struct i2c_client *client, | |||
218 | irq_set_irq_type(gpio_to_irq(info->charge_gpio), | 218 | irq_set_irq_type(gpio_to_irq(info->charge_gpio), |
219 | IRQ_TYPE_EDGE_BOTH); | 219 | IRQ_TYPE_EDGE_BOTH); |
220 | ret = request_irq(gpio_to_irq(info->charge_gpio), | 220 | ret = request_irq(gpio_to_irq(info->charge_gpio), |
221 | z2_charge_switch_irq, IRQF_DISABLED, | 221 | z2_charge_switch_irq, 0, |
222 | "AC Detect", charger); | 222 | "AC Detect", charger); |
223 | if (ret) | 223 | if (ret) |
224 | goto err3; | 224 | goto err3; |
@@ -313,7 +313,7 @@ static struct i2c_driver z2_batt_driver = { | |||
313 | .pm = Z2_BATTERY_PM_OPS | 313 | .pm = Z2_BATTERY_PM_OPS |
314 | }, | 314 | }, |
315 | .probe = z2_batt_probe, | 315 | .probe = z2_batt_probe, |
316 | .remove = z2_batt_remove, | 316 | .remove = __devexit_p(z2_batt_remove), |
317 | .id_table = z2_batt_id, | 317 | .id_table = z2_batt_id, |
318 | }; | 318 | }; |
319 | 319 | ||