diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-07-31 21:08:25 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-07-31 21:08:25 -0400 |
commit | 4b24ff71108164e047cf2c95990b77651163e315 (patch) | |
tree | 4b478906379adf22ff259fc1f2cce0da796df415 /drivers/power | |
parent | bca1a5c0eabe0f17081760c61e8d08e73dd6b6a6 (diff) | |
parent | 4b1bf5871f7d59de6484cc887e205d6d2f1e6fbd (diff) |
Merge tag 'for-v3.6' of git://git.infradead.org/battery-2.6
Pull battery updates from Anton Vorontsov:
"The tag contains just a few battery-related changes for v3.6. It's is
all pretty straightforward, except one thing.
One of our patches added thermal support for power supply class, but
thermal/ subsystem changed under our feet. We (well, Stephen, that
is) caught the issue and it was decided[1] that I'd just delay the
battery pull request, and then will fix it up by merging upstream back
into battery tree at the specific commit.
That's not all though: another[2] small fixup for thermal subsystem
was needed to get rid of a warning in power supply subsystem (the
warning was not drivers/power's "fault", the thermal registration
function just needed a proper const annotation, which is also done by
a small commit on top of the merge.
So, to sum this up:
- The 'master' branch of the battery tree was in the -next tree for
weeks, was never rebased, altered etc. It should be all OK;
- Although, for-v3.6 tag contains the 'master' branch + merge + the
warning fix.
[1] http://lkml.org/lkml/2012/6/19/23
[2] http://lkml.org/lkml/2012/6/18/28"
* tag 'for-v3.6' of git://git.infradead.org/battery-2.6: (23 commits)
thermal: Constify 'type' argument for the registration routine
olpc-battery: update CHARGE_FULL_DESIGN property for BYD LiFe batteries
olpc-battery: Add VOLTAGE_MAX_DESIGN property
charger-manager: Fix build break related to EXTCON
lp8727_charger: Move header file into platform_data directory
power_supply: Add min/max alert properties for CAPACITY, TEMP, TEMP_AMBIENT
bq27x00_battery: Add support for BQ27425 chip
charger-manager: Set current limit of regulator for over current protection
charger-manager: Use EXTCON Subsystem to detect charger cables for charging
test_power: Add VOLTAGE_NOW and BATTERY_TEMP properties
test_power: Add support for USB AC source
gpio-charger: Use cansleep version of gpio_set_value
bq27x00_battery: Add support for power average and health properties
sbs-battery: Don't trigger false supply_changed event
twl4030_charger: Allow charger to control the regulator that feeds it
twl4030_charger: Add backup-battery charging
twl4030_charger: Fix some typos
max17042_battery: Support CHARGE_COUNTER power supply attribute
smb347-charger: Add constant charge and current properties
power_supply: Add constant charge_current and charge_voltage properties
...
Diffstat (limited to 'drivers/power')
-rw-r--r-- | drivers/power/Kconfig | 1 | ||||
-rw-r--r-- | drivers/power/bq27x00_battery.c | 155 | ||||
-rw-r--r-- | drivers/power/charger-manager.c | 152 | ||||
-rw-r--r-- | drivers/power/ds2781_battery.c | 2 | ||||
-rw-r--r-- | drivers/power/gpio-charger.c | 2 | ||||
-rw-r--r-- | drivers/power/lp8727_charger.c | 2 | ||||
-rw-r--r-- | drivers/power/max17042_battery.c | 8 | ||||
-rw-r--r-- | drivers/power/olpc_battery.c | 62 | ||||
-rw-r--r-- | drivers/power/pda_power.c | 4 | ||||
-rw-r--r-- | drivers/power/power_supply_core.c | 65 | ||||
-rw-r--r-- | drivers/power/power_supply_sysfs.c | 8 | ||||
-rw-r--r-- | drivers/power/sbs-battery.c | 2 | ||||
-rw-r--r-- | drivers/power/smb347-charger.c | 123 | ||||
-rw-r--r-- | drivers/power/test_power.c | 75 | ||||
-rw-r--r-- | drivers/power/twl4030_charger.c | 80 |
15 files changed, 691 insertions, 50 deletions
diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig index aa764ecc4e60..c1892f321c46 100644 --- a/drivers/power/Kconfig +++ b/drivers/power/Kconfig | |||
@@ -268,6 +268,7 @@ config CHARGER_GPIO | |||
268 | config CHARGER_MANAGER | 268 | config CHARGER_MANAGER |
269 | bool "Battery charger manager for multiple chargers" | 269 | bool "Battery charger manager for multiple chargers" |
270 | depends on REGULATOR && RTC_CLASS | 270 | depends on REGULATOR && RTC_CLASS |
271 | select EXTCON | ||
271 | help | 272 | help |
272 | Say Y to enable charger-manager support, which allows multiple | 273 | Say Y to enable charger-manager support, which allows multiple |
273 | chargers attached to a battery and multiple batteries attached to a | 274 | chargers attached to a battery and multiple batteries attached to a |
diff --git a/drivers/power/bq27x00_battery.c b/drivers/power/bq27x00_battery.c index f5d6d379f2fb..181ddece5181 100644 --- a/drivers/power/bq27x00_battery.c +++ b/drivers/power/bq27x00_battery.c | |||
@@ -22,6 +22,7 @@ | |||
22 | * Datasheets: | 22 | * Datasheets: |
23 | * http://focus.ti.com/docs/prod/folders/print/bq27000.html | 23 | * http://focus.ti.com/docs/prod/folders/print/bq27000.html |
24 | * http://focus.ti.com/docs/prod/folders/print/bq27500.html | 24 | * http://focus.ti.com/docs/prod/folders/print/bq27500.html |
25 | * http://www.ti.com/product/bq27425-g1 | ||
25 | */ | 26 | */ |
26 | 27 | ||
27 | #include <linux/module.h> | 28 | #include <linux/module.h> |
@@ -51,6 +52,7 @@ | |||
51 | #define BQ27x00_REG_LMD 0x12 /* Last measured discharge */ | 52 | #define BQ27x00_REG_LMD 0x12 /* Last measured discharge */ |
52 | #define BQ27x00_REG_CYCT 0x2A /* Cycle count total */ | 53 | #define BQ27x00_REG_CYCT 0x2A /* Cycle count total */ |
53 | #define BQ27x00_REG_AE 0x22 /* Available energy */ | 54 | #define BQ27x00_REG_AE 0x22 /* Available energy */ |
55 | #define BQ27x00_POWER_AVG 0x24 | ||
54 | 56 | ||
55 | #define BQ27000_REG_RSOC 0x0B /* Relative State-of-Charge */ | 57 | #define BQ27000_REG_RSOC 0x0B /* Relative State-of-Charge */ |
56 | #define BQ27000_REG_ILMD 0x76 /* Initial last measured discharge */ | 58 | #define BQ27000_REG_ILMD 0x76 /* Initial last measured discharge */ |
@@ -66,15 +68,21 @@ | |||
66 | #define BQ27500_FLAG_SOCF BIT(1) /* State-of-Charge threshold final */ | 68 | #define BQ27500_FLAG_SOCF BIT(1) /* State-of-Charge threshold final */ |
67 | #define BQ27500_FLAG_SOC1 BIT(2) /* State-of-Charge threshold 1 */ | 69 | #define BQ27500_FLAG_SOC1 BIT(2) /* State-of-Charge threshold 1 */ |
68 | #define BQ27500_FLAG_FC BIT(9) | 70 | #define BQ27500_FLAG_FC BIT(9) |
71 | #define BQ27500_FLAG_OTC BIT(15) | ||
72 | |||
73 | /* bq27425 register addresses are same as bq27x00 addresses minus 4 */ | ||
74 | #define BQ27425_REG_OFFSET 0x04 | ||
75 | #define BQ27425_REG_SOC 0x18 /* Register address plus offset */ | ||
69 | 76 | ||
70 | #define BQ27000_RS 20 /* Resistor sense */ | 77 | #define BQ27000_RS 20 /* Resistor sense */ |
78 | #define BQ27x00_POWER_CONSTANT (256 * 29200 / 1000) | ||
71 | 79 | ||
72 | struct bq27x00_device_info; | 80 | struct bq27x00_device_info; |
73 | struct bq27x00_access_methods { | 81 | struct bq27x00_access_methods { |
74 | int (*read)(struct bq27x00_device_info *di, u8 reg, bool single); | 82 | int (*read)(struct bq27x00_device_info *di, u8 reg, bool single); |
75 | }; | 83 | }; |
76 | 84 | ||
77 | enum bq27x00_chip { BQ27000, BQ27500 }; | 85 | enum bq27x00_chip { BQ27000, BQ27500, BQ27425}; |
78 | 86 | ||
79 | struct bq27x00_reg_cache { | 87 | struct bq27x00_reg_cache { |
80 | int temperature; | 88 | int temperature; |
@@ -86,6 +94,8 @@ struct bq27x00_reg_cache { | |||
86 | int capacity; | 94 | int capacity; |
87 | int energy; | 95 | int energy; |
88 | int flags; | 96 | int flags; |
97 | int power_avg; | ||
98 | int health; | ||
89 | }; | 99 | }; |
90 | 100 | ||
91 | struct bq27x00_device_info { | 101 | struct bq27x00_device_info { |
@@ -123,6 +133,22 @@ static enum power_supply_property bq27x00_battery_props[] = { | |||
123 | POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, | 133 | POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, |
124 | POWER_SUPPLY_PROP_CYCLE_COUNT, | 134 | POWER_SUPPLY_PROP_CYCLE_COUNT, |
125 | POWER_SUPPLY_PROP_ENERGY_NOW, | 135 | POWER_SUPPLY_PROP_ENERGY_NOW, |
136 | POWER_SUPPLY_PROP_POWER_AVG, | ||
137 | POWER_SUPPLY_PROP_HEALTH, | ||
138 | }; | ||
139 | |||
140 | static enum power_supply_property bq27425_battery_props[] = { | ||
141 | POWER_SUPPLY_PROP_STATUS, | ||
142 | POWER_SUPPLY_PROP_PRESENT, | ||
143 | POWER_SUPPLY_PROP_VOLTAGE_NOW, | ||
144 | POWER_SUPPLY_PROP_CURRENT_NOW, | ||
145 | POWER_SUPPLY_PROP_CAPACITY, | ||
146 | POWER_SUPPLY_PROP_CAPACITY_LEVEL, | ||
147 | POWER_SUPPLY_PROP_TEMP, | ||
148 | POWER_SUPPLY_PROP_TECHNOLOGY, | ||
149 | POWER_SUPPLY_PROP_CHARGE_FULL, | ||
150 | POWER_SUPPLY_PROP_CHARGE_NOW, | ||
151 | POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, | ||
126 | }; | 152 | }; |
127 | 153 | ||
128 | static unsigned int poll_interval = 360; | 154 | static unsigned int poll_interval = 360; |
@@ -137,10 +163,24 @@ MODULE_PARM_DESC(poll_interval, "battery poll interval in seconds - " \ | |||
137 | static inline int bq27x00_read(struct bq27x00_device_info *di, u8 reg, | 163 | static inline int bq27x00_read(struct bq27x00_device_info *di, u8 reg, |
138 | bool single) | 164 | bool single) |
139 | { | 165 | { |
166 | if (di->chip == BQ27425) | ||
167 | return di->bus.read(di, reg - BQ27425_REG_OFFSET, single); | ||
140 | return di->bus.read(di, reg, single); | 168 | return di->bus.read(di, reg, single); |
141 | } | 169 | } |
142 | 170 | ||
143 | /* | 171 | /* |
172 | * Higher versions of the chip like BQ27425 and BQ27500 | ||
173 | * differ from BQ27000 and BQ27200 in calculation of certain | ||
174 | * parameters. Hence we need to check for the chip type. | ||
175 | */ | ||
176 | static bool bq27xxx_is_chip_version_higher(struct bq27x00_device_info *di) | ||
177 | { | ||
178 | if (di->chip == BQ27425 || di->chip == BQ27500) | ||
179 | return true; | ||
180 | return false; | ||
181 | } | ||
182 | |||
183 | /* | ||
144 | * Return the battery Relative State-of-Charge | 184 | * Return the battery Relative State-of-Charge |
145 | * Or < 0 if something fails. | 185 | * Or < 0 if something fails. |
146 | */ | 186 | */ |
@@ -150,6 +190,8 @@ static int bq27x00_battery_read_rsoc(struct bq27x00_device_info *di) | |||
150 | 190 | ||
151 | if (di->chip == BQ27500) | 191 | if (di->chip == BQ27500) |
152 | rsoc = bq27x00_read(di, BQ27500_REG_SOC, false); | 192 | rsoc = bq27x00_read(di, BQ27500_REG_SOC, false); |
193 | else if (di->chip == BQ27425) | ||
194 | rsoc = bq27x00_read(di, BQ27425_REG_SOC, false); | ||
153 | else | 195 | else |
154 | rsoc = bq27x00_read(di, BQ27000_REG_RSOC, true); | 196 | rsoc = bq27x00_read(di, BQ27000_REG_RSOC, true); |
155 | 197 | ||
@@ -174,7 +216,7 @@ static int bq27x00_battery_read_charge(struct bq27x00_device_info *di, u8 reg) | |||
174 | return charge; | 216 | return charge; |
175 | } | 217 | } |
176 | 218 | ||
177 | if (di->chip == BQ27500) | 219 | if (bq27xxx_is_chip_version_higher(di)) |
178 | charge *= 1000; | 220 | charge *= 1000; |
179 | else | 221 | else |
180 | charge = charge * 3570 / BQ27000_RS; | 222 | charge = charge * 3570 / BQ27000_RS; |
@@ -208,7 +250,7 @@ static int bq27x00_battery_read_ilmd(struct bq27x00_device_info *di) | |||
208 | { | 250 | { |
209 | int ilmd; | 251 | int ilmd; |
210 | 252 | ||
211 | if (di->chip == BQ27500) | 253 | if (bq27xxx_is_chip_version_higher(di)) |
212 | ilmd = bq27x00_read(di, BQ27500_REG_DCAP, false); | 254 | ilmd = bq27x00_read(di, BQ27500_REG_DCAP, false); |
213 | else | 255 | else |
214 | ilmd = bq27x00_read(di, BQ27000_REG_ILMD, true); | 256 | ilmd = bq27x00_read(di, BQ27000_REG_ILMD, true); |
@@ -218,7 +260,7 @@ static int bq27x00_battery_read_ilmd(struct bq27x00_device_info *di) | |||
218 | return ilmd; | 260 | return ilmd; |
219 | } | 261 | } |
220 | 262 | ||
221 | if (di->chip == BQ27500) | 263 | if (bq27xxx_is_chip_version_higher(di)) |
222 | ilmd *= 1000; | 264 | ilmd *= 1000; |
223 | else | 265 | else |
224 | ilmd = ilmd * 256 * 3570 / BQ27000_RS; | 266 | ilmd = ilmd * 256 * 3570 / BQ27000_RS; |
@@ -262,7 +304,7 @@ static int bq27x00_battery_read_temperature(struct bq27x00_device_info *di) | |||
262 | return temp; | 304 | return temp; |
263 | } | 305 | } |
264 | 306 | ||
265 | if (di->chip == BQ27500) | 307 | if (bq27xxx_is_chip_version_higher(di)) |
266 | temp -= 2731; | 308 | temp -= 2731; |
267 | else | 309 | else |
268 | temp = ((temp * 5) - 5463) / 2; | 310 | temp = ((temp * 5) - 5463) / 2; |
@@ -306,14 +348,70 @@ static int bq27x00_battery_read_time(struct bq27x00_device_info *di, u8 reg) | |||
306 | return tval * 60; | 348 | return tval * 60; |
307 | } | 349 | } |
308 | 350 | ||
351 | /* | ||
352 | * Read a power avg register. | ||
353 | * Return < 0 if something fails. | ||
354 | */ | ||
355 | static int bq27x00_battery_read_pwr_avg(struct bq27x00_device_info *di, u8 reg) | ||
356 | { | ||
357 | int tval; | ||
358 | |||
359 | tval = bq27x00_read(di, reg, false); | ||
360 | if (tval < 0) { | ||
361 | dev_err(di->dev, "error reading power avg rgister %02x: %d\n", | ||
362 | reg, tval); | ||
363 | return tval; | ||
364 | } | ||
365 | |||
366 | if (di->chip == BQ27500) | ||
367 | return tval; | ||
368 | else | ||
369 | return (tval * BQ27x00_POWER_CONSTANT) / BQ27000_RS; | ||
370 | } | ||
371 | |||
372 | /* | ||
373 | * Read flag register. | ||
374 | * Return < 0 if something fails. | ||
375 | */ | ||
376 | static int bq27x00_battery_read_health(struct bq27x00_device_info *di) | ||
377 | { | ||
378 | int tval; | ||
379 | |||
380 | tval = bq27x00_read(di, BQ27x00_REG_FLAGS, false); | ||
381 | if (tval < 0) { | ||
382 | dev_err(di->dev, "error reading flag register:%d\n", tval); | ||
383 | return tval; | ||
384 | } | ||
385 | |||
386 | if ((di->chip == BQ27500)) { | ||
387 | if (tval & BQ27500_FLAG_SOCF) | ||
388 | tval = POWER_SUPPLY_HEALTH_DEAD; | ||
389 | else if (tval & BQ27500_FLAG_OTC) | ||
390 | tval = POWER_SUPPLY_HEALTH_OVERHEAT; | ||
391 | else | ||
392 | tval = POWER_SUPPLY_HEALTH_GOOD; | ||
393 | return tval; | ||
394 | } else { | ||
395 | if (tval & BQ27000_FLAG_EDV1) | ||
396 | tval = POWER_SUPPLY_HEALTH_DEAD; | ||
397 | else | ||
398 | tval = POWER_SUPPLY_HEALTH_GOOD; | ||
399 | return tval; | ||
400 | } | ||
401 | |||
402 | return -1; | ||
403 | } | ||
404 | |||
309 | static void bq27x00_update(struct bq27x00_device_info *di) | 405 | static void bq27x00_update(struct bq27x00_device_info *di) |
310 | { | 406 | { |
311 | struct bq27x00_reg_cache cache = {0, }; | 407 | struct bq27x00_reg_cache cache = {0, }; |
312 | bool is_bq27500 = di->chip == BQ27500; | 408 | bool is_bq27500 = di->chip == BQ27500; |
409 | bool is_bq27425 = di->chip == BQ27425; | ||
313 | 410 | ||
314 | cache.flags = bq27x00_read(di, BQ27x00_REG_FLAGS, !is_bq27500); | 411 | cache.flags = bq27x00_read(di, BQ27x00_REG_FLAGS, !is_bq27500); |
315 | if (cache.flags >= 0) { | 412 | if (cache.flags >= 0) { |
316 | if (!is_bq27500 && (cache.flags & BQ27000_FLAG_CI)) { | 413 | if (!is_bq27500 && !is_bq27425 |
414 | && (cache.flags & BQ27000_FLAG_CI)) { | ||
317 | dev_info(di->dev, "battery is not calibrated! ignoring capacity values\n"); | 415 | dev_info(di->dev, "battery is not calibrated! ignoring capacity values\n"); |
318 | cache.capacity = -ENODATA; | 416 | cache.capacity = -ENODATA; |
319 | cache.energy = -ENODATA; | 417 | cache.energy = -ENODATA; |
@@ -321,16 +419,30 @@ static void bq27x00_update(struct bq27x00_device_info *di) | |||
321 | cache.time_to_empty_avg = -ENODATA; | 419 | cache.time_to_empty_avg = -ENODATA; |
322 | cache.time_to_full = -ENODATA; | 420 | cache.time_to_full = -ENODATA; |
323 | cache.charge_full = -ENODATA; | 421 | cache.charge_full = -ENODATA; |
422 | cache.health = -ENODATA; | ||
324 | } else { | 423 | } else { |
325 | cache.capacity = bq27x00_battery_read_rsoc(di); | 424 | cache.capacity = bq27x00_battery_read_rsoc(di); |
326 | cache.energy = bq27x00_battery_read_energy(di); | 425 | if (!is_bq27425) { |
327 | cache.time_to_empty = bq27x00_battery_read_time(di, BQ27x00_REG_TTE); | 426 | cache.energy = bq27x00_battery_read_energy(di); |
328 | cache.time_to_empty_avg = bq27x00_battery_read_time(di, BQ27x00_REG_TTECP); | 427 | cache.time_to_empty = |
329 | cache.time_to_full = bq27x00_battery_read_time(di, BQ27x00_REG_TTF); | 428 | bq27x00_battery_read_time(di, |
429 | BQ27x00_REG_TTE); | ||
430 | cache.time_to_empty_avg = | ||
431 | bq27x00_battery_read_time(di, | ||
432 | BQ27x00_REG_TTECP); | ||
433 | cache.time_to_full = | ||
434 | bq27x00_battery_read_time(di, | ||
435 | BQ27x00_REG_TTF); | ||
436 | } | ||
330 | cache.charge_full = bq27x00_battery_read_lmd(di); | 437 | cache.charge_full = bq27x00_battery_read_lmd(di); |
438 | cache.health = bq27x00_battery_read_health(di); | ||
331 | } | 439 | } |
332 | cache.temperature = bq27x00_battery_read_temperature(di); | 440 | cache.temperature = bq27x00_battery_read_temperature(di); |
441 | if (!is_bq27425) | ||
442 | cache.cycle_count = bq27x00_battery_read_cyct(di); | ||
333 | cache.cycle_count = bq27x00_battery_read_cyct(di); | 443 | cache.cycle_count = bq27x00_battery_read_cyct(di); |
444 | cache.power_avg = | ||
445 | bq27x00_battery_read_pwr_avg(di, BQ27x00_POWER_AVG); | ||
334 | 446 | ||
335 | /* We only have to read charge design full once */ | 447 | /* We only have to read charge design full once */ |
336 | if (di->charge_design_full <= 0) | 448 | if (di->charge_design_full <= 0) |
@@ -376,7 +488,7 @@ static int bq27x00_battery_current(struct bq27x00_device_info *di, | |||
376 | return curr; | 488 | return curr; |
377 | } | 489 | } |
378 | 490 | ||
379 | if (di->chip == BQ27500) { | 491 | if (bq27xxx_is_chip_version_higher(di)) { |
380 | /* bq27500 returns signed value */ | 492 | /* bq27500 returns signed value */ |
381 | val->intval = (int)((s16)curr) * 1000; | 493 | val->intval = (int)((s16)curr) * 1000; |
382 | } else { | 494 | } else { |
@@ -397,7 +509,7 @@ static int bq27x00_battery_status(struct bq27x00_device_info *di, | |||
397 | { | 509 | { |
398 | int status; | 510 | int status; |
399 | 511 | ||
400 | if (di->chip == BQ27500) { | 512 | if (bq27xxx_is_chip_version_higher(di)) { |
401 | if (di->cache.flags & BQ27500_FLAG_FC) | 513 | if (di->cache.flags & BQ27500_FLAG_FC) |
402 | status = POWER_SUPPLY_STATUS_FULL; | 514 | status = POWER_SUPPLY_STATUS_FULL; |
403 | else if (di->cache.flags & BQ27500_FLAG_DSC) | 515 | else if (di->cache.flags & BQ27500_FLAG_DSC) |
@@ -425,7 +537,7 @@ static int bq27x00_battery_capacity_level(struct bq27x00_device_info *di, | |||
425 | { | 537 | { |
426 | int level; | 538 | int level; |
427 | 539 | ||
428 | if (di->chip == BQ27500) { | 540 | if (bq27xxx_is_chip_version_higher(di)) { |
429 | if (di->cache.flags & BQ27500_FLAG_FC) | 541 | if (di->cache.flags & BQ27500_FLAG_FC) |
430 | level = POWER_SUPPLY_CAPACITY_LEVEL_FULL; | 542 | level = POWER_SUPPLY_CAPACITY_LEVEL_FULL; |
431 | else if (di->cache.flags & BQ27500_FLAG_SOC1) | 543 | else if (di->cache.flags & BQ27500_FLAG_SOC1) |
@@ -550,6 +662,12 @@ static int bq27x00_battery_get_property(struct power_supply *psy, | |||
550 | case POWER_SUPPLY_PROP_ENERGY_NOW: | 662 | case POWER_SUPPLY_PROP_ENERGY_NOW: |
551 | ret = bq27x00_simple_value(di->cache.energy, val); | 663 | ret = bq27x00_simple_value(di->cache.energy, val); |
552 | break; | 664 | break; |
665 | case POWER_SUPPLY_PROP_POWER_AVG: | ||
666 | ret = bq27x00_simple_value(di->cache.power_avg, val); | ||
667 | break; | ||
668 | case POWER_SUPPLY_PROP_HEALTH: | ||
669 | ret = bq27x00_simple_value(di->cache.health, val); | ||
670 | break; | ||
553 | default: | 671 | default: |
554 | return -EINVAL; | 672 | return -EINVAL; |
555 | } | 673 | } |
@@ -570,8 +688,14 @@ static int bq27x00_powersupply_init(struct bq27x00_device_info *di) | |||
570 | int ret; | 688 | int ret; |
571 | 689 | ||
572 | di->bat.type = POWER_SUPPLY_TYPE_BATTERY; | 690 | di->bat.type = POWER_SUPPLY_TYPE_BATTERY; |
573 | di->bat.properties = bq27x00_battery_props; | 691 | di->chip = BQ27425; |
574 | di->bat.num_properties = ARRAY_SIZE(bq27x00_battery_props); | 692 | if (di->chip == BQ27425) { |
693 | di->bat.properties = bq27425_battery_props; | ||
694 | di->bat.num_properties = ARRAY_SIZE(bq27425_battery_props); | ||
695 | } else { | ||
696 | di->bat.properties = bq27x00_battery_props; | ||
697 | di->bat.num_properties = ARRAY_SIZE(bq27x00_battery_props); | ||
698 | } | ||
575 | di->bat.get_property = bq27x00_battery_get_property; | 699 | di->bat.get_property = bq27x00_battery_get_property; |
576 | di->bat.external_power_changed = bq27x00_external_power_changed; | 700 | di->bat.external_power_changed = bq27x00_external_power_changed; |
577 | 701 | ||
@@ -729,6 +853,7 @@ static int bq27x00_battery_remove(struct i2c_client *client) | |||
729 | static const struct i2c_device_id bq27x00_id[] = { | 853 | static const struct i2c_device_id bq27x00_id[] = { |
730 | { "bq27200", BQ27000 }, /* bq27200 is same as bq27000, but with i2c */ | 854 | { "bq27200", BQ27000 }, /* bq27200 is same as bq27000, but with i2c */ |
731 | { "bq27500", BQ27500 }, | 855 | { "bq27500", BQ27500 }, |
856 | { "bq27425", BQ27425 }, | ||
732 | {}, | 857 | {}, |
733 | }; | 858 | }; |
734 | MODULE_DEVICE_TABLE(i2c, bq27x00_id); | 859 | MODULE_DEVICE_TABLE(i2c, bq27x00_id); |
diff --git a/drivers/power/charger-manager.c b/drivers/power/charger-manager.c index 86935ec18954..526e5c931294 100644 --- a/drivers/power/charger-manager.c +++ b/drivers/power/charger-manager.c | |||
@@ -271,16 +271,13 @@ static int try_charger_enable(struct charger_manager *cm, bool enable) | |||
271 | if (enable) { | 271 | if (enable) { |
272 | if (cm->emergency_stop) | 272 | if (cm->emergency_stop) |
273 | return -EAGAIN; | 273 | return -EAGAIN; |
274 | err = regulator_bulk_enable(desc->num_charger_regulators, | 274 | for (i = 0 ; i < desc->num_charger_regulators ; i++) |
275 | desc->charger_regulators); | 275 | regulator_enable(desc->charger_regulators[i].consumer); |
276 | } else { | 276 | } else { |
277 | /* | 277 | /* |
278 | * Abnormal battery state - Stop charging forcibly, | 278 | * Abnormal battery state - Stop charging forcibly, |
279 | * even if charger was enabled at the other places | 279 | * even if charger was enabled at the other places |
280 | */ | 280 | */ |
281 | err = regulator_bulk_disable(desc->num_charger_regulators, | ||
282 | desc->charger_regulators); | ||
283 | |||
284 | for (i = 0; i < desc->num_charger_regulators; i++) { | 281 | for (i = 0; i < desc->num_charger_regulators; i++) { |
285 | if (regulator_is_enabled( | 282 | if (regulator_is_enabled( |
286 | desc->charger_regulators[i].consumer)) { | 283 | desc->charger_regulators[i].consumer)) { |
@@ -288,7 +285,7 @@ static int try_charger_enable(struct charger_manager *cm, bool enable) | |||
288 | desc->charger_regulators[i].consumer); | 285 | desc->charger_regulators[i].consumer); |
289 | dev_warn(cm->dev, | 286 | dev_warn(cm->dev, |
290 | "Disable regulator(%s) forcibly.\n", | 287 | "Disable regulator(%s) forcibly.\n", |
291 | desc->charger_regulators[i].supply); | 288 | desc->charger_regulators[i].regulator_name); |
292 | } | 289 | } |
293 | } | 290 | } |
294 | } | 291 | } |
@@ -994,11 +991,92 @@ int setup_charger_manager(struct charger_global_desc *gd) | |||
994 | } | 991 | } |
995 | EXPORT_SYMBOL_GPL(setup_charger_manager); | 992 | EXPORT_SYMBOL_GPL(setup_charger_manager); |
996 | 993 | ||
994 | /** | ||
995 | * charger_extcon_work - enable/diable charger according to the state | ||
996 | * of charger cable | ||
997 | * | ||
998 | * @work: work_struct of the function charger_extcon_work. | ||
999 | */ | ||
1000 | static void charger_extcon_work(struct work_struct *work) | ||
1001 | { | ||
1002 | struct charger_cable *cable = | ||
1003 | container_of(work, struct charger_cable, wq); | ||
1004 | int ret; | ||
1005 | |||
1006 | if (cable->attached && cable->min_uA != 0 && cable->max_uA != 0) { | ||
1007 | ret = regulator_set_current_limit(cable->charger->consumer, | ||
1008 | cable->min_uA, cable->max_uA); | ||
1009 | if (ret < 0) { | ||
1010 | pr_err("Cannot set current limit of %s (%s)\n", | ||
1011 | cable->charger->regulator_name, cable->name); | ||
1012 | return; | ||
1013 | } | ||
1014 | |||
1015 | pr_info("Set current limit of %s : %duA ~ %duA\n", | ||
1016 | cable->charger->regulator_name, | ||
1017 | cable->min_uA, cable->max_uA); | ||
1018 | } | ||
1019 | |||
1020 | try_charger_enable(cable->cm, cable->attached); | ||
1021 | } | ||
1022 | |||
1023 | /** | ||
1024 | * charger_extcon_notifier - receive the state of charger cable | ||
1025 | * when registered cable is attached or detached. | ||
1026 | * | ||
1027 | * @self: the notifier block of the charger_extcon_notifier. | ||
1028 | * @event: the cable state. | ||
1029 | * @ptr: the data pointer of notifier block. | ||
1030 | */ | ||
1031 | static int charger_extcon_notifier(struct notifier_block *self, | ||
1032 | unsigned long event, void *ptr) | ||
1033 | { | ||
1034 | struct charger_cable *cable = | ||
1035 | container_of(self, struct charger_cable, nb); | ||
1036 | |||
1037 | cable->attached = event; | ||
1038 | schedule_work(&cable->wq); | ||
1039 | |||
1040 | return NOTIFY_DONE; | ||
1041 | } | ||
1042 | |||
1043 | /** | ||
1044 | * charger_extcon_init - register external connector to use it | ||
1045 | * as the charger cable | ||
1046 | * | ||
1047 | * @cm: the Charger Manager representing the battery. | ||
1048 | * @cable: the Charger cable representing the external connector. | ||
1049 | */ | ||
1050 | static int charger_extcon_init(struct charger_manager *cm, | ||
1051 | struct charger_cable *cable) | ||
1052 | { | ||
1053 | int ret = 0; | ||
1054 | |||
1055 | /* | ||
1056 | * Charger manager use Extcon framework to identify | ||
1057 | * the charger cable among various external connector | ||
1058 | * cable (e.g., TA, USB, MHL, Dock). | ||
1059 | */ | ||
1060 | INIT_WORK(&cable->wq, charger_extcon_work); | ||
1061 | cable->nb.notifier_call = charger_extcon_notifier; | ||
1062 | ret = extcon_register_interest(&cable->extcon_dev, | ||
1063 | cable->extcon_name, cable->name, &cable->nb); | ||
1064 | if (ret < 0) { | ||
1065 | pr_info("Cannot register extcon_dev for %s(cable: %s).\n", | ||
1066 | cable->extcon_name, | ||
1067 | cable->name); | ||
1068 | ret = -EINVAL; | ||
1069 | } | ||
1070 | |||
1071 | return ret; | ||
1072 | } | ||
1073 | |||
997 | static int charger_manager_probe(struct platform_device *pdev) | 1074 | static int charger_manager_probe(struct platform_device *pdev) |
998 | { | 1075 | { |
999 | struct charger_desc *desc = dev_get_platdata(&pdev->dev); | 1076 | struct charger_desc *desc = dev_get_platdata(&pdev->dev); |
1000 | struct charger_manager *cm; | 1077 | struct charger_manager *cm; |
1001 | int ret = 0, i = 0; | 1078 | int ret = 0, i = 0; |
1079 | int j = 0; | ||
1002 | union power_supply_propval val; | 1080 | union power_supply_propval val; |
1003 | 1081 | ||
1004 | if (g_desc && !rtc_dev && g_desc->rtc_name) { | 1082 | if (g_desc && !rtc_dev && g_desc->rtc_name) { |
@@ -1167,11 +1245,31 @@ static int charger_manager_probe(struct platform_device *pdev) | |||
1167 | goto err_register; | 1245 | goto err_register; |
1168 | } | 1246 | } |
1169 | 1247 | ||
1170 | ret = regulator_bulk_get(&pdev->dev, desc->num_charger_regulators, | 1248 | for (i = 0 ; i < desc->num_charger_regulators ; i++) { |
1171 | desc->charger_regulators); | 1249 | struct charger_regulator *charger |
1172 | if (ret) { | 1250 | = &desc->charger_regulators[i]; |
1173 | dev_err(&pdev->dev, "Cannot get charger regulators.\n"); | 1251 | |
1174 | goto err_bulk_get; | 1252 | charger->consumer = regulator_get(&pdev->dev, |
1253 | charger->regulator_name); | ||
1254 | if (charger->consumer == NULL) { | ||
1255 | dev_err(&pdev->dev, "Cannot find charger(%s)n", | ||
1256 | charger->regulator_name); | ||
1257 | ret = -EINVAL; | ||
1258 | goto err_chg_get; | ||
1259 | } | ||
1260 | |||
1261 | for (j = 0 ; j < charger->num_cables ; j++) { | ||
1262 | struct charger_cable *cable = &charger->cables[j]; | ||
1263 | |||
1264 | ret = charger_extcon_init(cm, cable); | ||
1265 | if (ret < 0) { | ||
1266 | dev_err(&pdev->dev, "Cannot find charger(%s)n", | ||
1267 | charger->regulator_name); | ||
1268 | goto err_extcon; | ||
1269 | } | ||
1270 | cable->charger = charger; | ||
1271 | cable->cm = cm; | ||
1272 | } | ||
1175 | } | 1273 | } |
1176 | 1274 | ||
1177 | ret = try_charger_enable(cm, true); | 1275 | ret = try_charger_enable(cm, true); |
@@ -1197,9 +1295,19 @@ static int charger_manager_probe(struct platform_device *pdev) | |||
1197 | return 0; | 1295 | return 0; |
1198 | 1296 | ||
1199 | err_chg_enable: | 1297 | err_chg_enable: |
1200 | regulator_bulk_free(desc->num_charger_regulators, | 1298 | err_extcon: |
1201 | desc->charger_regulators); | 1299 | for (i = 0 ; i < desc->num_charger_regulators ; i++) { |
1202 | err_bulk_get: | 1300 | struct charger_regulator *charger |
1301 | = &desc->charger_regulators[i]; | ||
1302 | for (j = 0 ; j < charger->num_cables ; j++) { | ||
1303 | struct charger_cable *cable = &charger->cables[j]; | ||
1304 | extcon_unregister_interest(&cable->extcon_dev); | ||
1305 | } | ||
1306 | } | ||
1307 | err_chg_get: | ||
1308 | for (i = 0 ; i < desc->num_charger_regulators ; i++) | ||
1309 | regulator_put(desc->charger_regulators[i].consumer); | ||
1310 | |||
1203 | power_supply_unregister(&cm->charger_psy); | 1311 | power_supply_unregister(&cm->charger_psy); |
1204 | err_register: | 1312 | err_register: |
1205 | kfree(cm->charger_psy.properties); | 1313 | kfree(cm->charger_psy.properties); |
@@ -1218,6 +1326,8 @@ static int __devexit charger_manager_remove(struct platform_device *pdev) | |||
1218 | { | 1326 | { |
1219 | struct charger_manager *cm = platform_get_drvdata(pdev); | 1327 | struct charger_manager *cm = platform_get_drvdata(pdev); |
1220 | struct charger_desc *desc = cm->desc; | 1328 | struct charger_desc *desc = cm->desc; |
1329 | int i = 0; | ||
1330 | int j = 0; | ||
1221 | 1331 | ||
1222 | /* Remove from the list */ | 1332 | /* Remove from the list */ |
1223 | mutex_lock(&cm_list_mtx); | 1333 | mutex_lock(&cm_list_mtx); |
@@ -1229,8 +1339,18 @@ static int __devexit charger_manager_remove(struct platform_device *pdev) | |||
1229 | if (delayed_work_pending(&cm_monitor_work)) | 1339 | if (delayed_work_pending(&cm_monitor_work)) |
1230 | cancel_delayed_work_sync(&cm_monitor_work); | 1340 | cancel_delayed_work_sync(&cm_monitor_work); |
1231 | 1341 | ||
1232 | regulator_bulk_free(desc->num_charger_regulators, | 1342 | for (i = 0 ; i < desc->num_charger_regulators ; i++) { |
1233 | desc->charger_regulators); | 1343 | struct charger_regulator *charger |
1344 | = &desc->charger_regulators[i]; | ||
1345 | for (j = 0 ; j < charger->num_cables ; j++) { | ||
1346 | struct charger_cable *cable = &charger->cables[j]; | ||
1347 | extcon_unregister_interest(&cable->extcon_dev); | ||
1348 | } | ||
1349 | } | ||
1350 | |||
1351 | for (i = 0 ; i < desc->num_charger_regulators ; i++) | ||
1352 | regulator_put(desc->charger_regulators[i].consumer); | ||
1353 | |||
1234 | power_supply_unregister(&cm->charger_psy); | 1354 | power_supply_unregister(&cm->charger_psy); |
1235 | 1355 | ||
1236 | try_charger_enable(cm, false); | 1356 | try_charger_enable(cm, false); |
diff --git a/drivers/power/ds2781_battery.c b/drivers/power/ds2781_battery.c index 5f92a4bb33f9..7a1ff4e4cf9a 100644 --- a/drivers/power/ds2781_battery.c +++ b/drivers/power/ds2781_battery.c | |||
@@ -64,7 +64,7 @@ static inline int ds2781_battery_io(struct ds2781_device_info *dev_info, | |||
64 | return w1_ds2781_io(dev_info->w1_dev, buf, addr, count, io); | 64 | return w1_ds2781_io(dev_info->w1_dev, buf, addr, count, io); |
65 | } | 65 | } |
66 | 66 | ||
67 | int w1_ds2781_read(struct ds2781_device_info *dev_info, char *buf, | 67 | static int w1_ds2781_read(struct ds2781_device_info *dev_info, char *buf, |
68 | int addr, size_t count) | 68 | int addr, size_t count) |
69 | { | 69 | { |
70 | return ds2781_battery_io(dev_info, buf, addr, count, 0); | 70 | return ds2781_battery_io(dev_info, buf, addr, count, 0); |
diff --git a/drivers/power/gpio-charger.c b/drivers/power/gpio-charger.c index 8672c9177dd7..cb2aa3195687 100644 --- a/drivers/power/gpio-charger.c +++ b/drivers/power/gpio-charger.c | |||
@@ -54,7 +54,7 @@ static int gpio_charger_get_property(struct power_supply *psy, | |||
54 | 54 | ||
55 | switch (psp) { | 55 | switch (psp) { |
56 | case POWER_SUPPLY_PROP_ONLINE: | 56 | case POWER_SUPPLY_PROP_ONLINE: |
57 | val->intval = gpio_get_value(pdata->gpio); | 57 | val->intval = gpio_get_value_cansleep(pdata->gpio); |
58 | val->intval ^= pdata->gpio_active_low; | 58 | val->intval ^= pdata->gpio_active_low; |
59 | break; | 59 | break; |
60 | default: | 60 | default: |
diff --git a/drivers/power/lp8727_charger.c b/drivers/power/lp8727_charger.c index d8b75780bfef..6a364f4798f7 100644 --- a/drivers/power/lp8727_charger.c +++ b/drivers/power/lp8727_charger.c | |||
@@ -15,7 +15,7 @@ | |||
15 | #include <linux/interrupt.h> | 15 | #include <linux/interrupt.h> |
16 | #include <linux/i2c.h> | 16 | #include <linux/i2c.h> |
17 | #include <linux/power_supply.h> | 17 | #include <linux/power_supply.h> |
18 | #include <linux/lp8727.h> | 18 | #include <linux/platform_data/lp8727.h> |
19 | 19 | ||
20 | #define DEBOUNCE_MSEC 270 | 20 | #define DEBOUNCE_MSEC 270 |
21 | 21 | ||
diff --git a/drivers/power/max17042_battery.c b/drivers/power/max17042_battery.c index 140788b309f8..74abc6c755b4 100644 --- a/drivers/power/max17042_battery.c +++ b/drivers/power/max17042_battery.c | |||
@@ -113,6 +113,7 @@ static enum power_supply_property max17042_battery_props[] = { | |||
113 | POWER_SUPPLY_PROP_VOLTAGE_OCV, | 113 | POWER_SUPPLY_PROP_VOLTAGE_OCV, |
114 | POWER_SUPPLY_PROP_CAPACITY, | 114 | POWER_SUPPLY_PROP_CAPACITY, |
115 | POWER_SUPPLY_PROP_CHARGE_FULL, | 115 | POWER_SUPPLY_PROP_CHARGE_FULL, |
116 | POWER_SUPPLY_PROP_CHARGE_COUNTER, | ||
116 | POWER_SUPPLY_PROP_TEMP, | 117 | POWER_SUPPLY_PROP_TEMP, |
117 | POWER_SUPPLY_PROP_CURRENT_NOW, | 118 | POWER_SUPPLY_PROP_CURRENT_NOW, |
118 | POWER_SUPPLY_PROP_CURRENT_AVG, | 119 | POWER_SUPPLY_PROP_CURRENT_AVG, |
@@ -201,6 +202,13 @@ static int max17042_get_property(struct power_supply *psy, | |||
201 | 202 | ||
202 | val->intval = ret * 1000 / 2; | 203 | val->intval = ret * 1000 / 2; |
203 | break; | 204 | break; |
205 | case POWER_SUPPLY_PROP_CHARGE_COUNTER: | ||
206 | ret = max17042_read_reg(chip->client, MAX17042_QH); | ||
207 | if (ret < 0) | ||
208 | return ret; | ||
209 | |||
210 | val->intval = ret * 1000 / 2; | ||
211 | break; | ||
204 | case POWER_SUPPLY_PROP_TEMP: | 212 | case POWER_SUPPLY_PROP_TEMP: |
205 | ret = max17042_read_reg(chip->client, MAX17042_TEMP); | 213 | ret = max17042_read_reg(chip->client, MAX17042_TEMP); |
206 | if (ret < 0) | 214 | if (ret < 0) |
diff --git a/drivers/power/olpc_battery.c b/drivers/power/olpc_battery.c index 7385092f9bc8..55b10b813353 100644 --- a/drivers/power/olpc_battery.c +++ b/drivers/power/olpc_battery.c | |||
@@ -231,11 +231,9 @@ static int olpc_bat_get_charge_full_design(union power_supply_propval *val) | |||
231 | 231 | ||
232 | case POWER_SUPPLY_TECHNOLOGY_LiFe: | 232 | case POWER_SUPPLY_TECHNOLOGY_LiFe: |
233 | switch (mfr) { | 233 | switch (mfr) { |
234 | case 1: /* Gold Peak */ | 234 | case 1: /* Gold Peak, fall through */ |
235 | val->intval = 2800000; | ||
236 | break; | ||
237 | case 2: /* BYD */ | 235 | case 2: /* BYD */ |
238 | val->intval = 3100000; | 236 | val->intval = 2800000; |
239 | break; | 237 | break; |
240 | default: | 238 | default: |
241 | return -EIO; | 239 | return -EIO; |
@@ -267,6 +265,55 @@ static int olpc_bat_get_charge_now(union power_supply_propval *val) | |||
267 | return 0; | 265 | return 0; |
268 | } | 266 | } |
269 | 267 | ||
268 | static int olpc_bat_get_voltage_max_design(union power_supply_propval *val) | ||
269 | { | ||
270 | uint8_t ec_byte; | ||
271 | union power_supply_propval tech; | ||
272 | int mfr; | ||
273 | int ret; | ||
274 | |||
275 | ret = olpc_bat_get_tech(&tech); | ||
276 | if (ret) | ||
277 | return ret; | ||
278 | |||
279 | ec_byte = BAT_ADDR_MFR_TYPE; | ||
280 | ret = olpc_ec_cmd(EC_BAT_EEPROM, &ec_byte, 1, &ec_byte, 1); | ||
281 | if (ret) | ||
282 | return ret; | ||
283 | |||
284 | mfr = ec_byte >> 4; | ||
285 | |||
286 | switch (tech.intval) { | ||
287 | case POWER_SUPPLY_TECHNOLOGY_NiMH: | ||
288 | switch (mfr) { | ||
289 | case 1: /* Gold Peak */ | ||
290 | val->intval = 6000000; | ||
291 | break; | ||
292 | default: | ||
293 | return -EIO; | ||
294 | } | ||
295 | break; | ||
296 | |||
297 | case POWER_SUPPLY_TECHNOLOGY_LiFe: | ||
298 | switch (mfr) { | ||
299 | case 1: /* Gold Peak */ | ||
300 | val->intval = 6400000; | ||
301 | break; | ||
302 | case 2: /* BYD */ | ||
303 | val->intval = 6500000; | ||
304 | break; | ||
305 | default: | ||
306 | return -EIO; | ||
307 | } | ||
308 | break; | ||
309 | |||
310 | default: | ||
311 | return -EIO; | ||
312 | } | ||
313 | |||
314 | return ret; | ||
315 | } | ||
316 | |||
270 | /********************************************************************* | 317 | /********************************************************************* |
271 | * Battery properties | 318 | * Battery properties |
272 | *********************************************************************/ | 319 | *********************************************************************/ |
@@ -401,6 +448,11 @@ static int olpc_bat_get_property(struct power_supply *psy, | |||
401 | sprintf(bat_serial, "%016llx", (long long)be64_to_cpu(ser_buf)); | 448 | sprintf(bat_serial, "%016llx", (long long)be64_to_cpu(ser_buf)); |
402 | val->strval = bat_serial; | 449 | val->strval = bat_serial; |
403 | break; | 450 | break; |
451 | case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN: | ||
452 | ret = olpc_bat_get_voltage_max_design(val); | ||
453 | if (ret) | ||
454 | return ret; | ||
455 | break; | ||
404 | default: | 456 | default: |
405 | ret = -EINVAL; | 457 | ret = -EINVAL; |
406 | break; | 458 | break; |
@@ -428,6 +480,7 @@ static enum power_supply_property olpc_xo1_bat_props[] = { | |||
428 | POWER_SUPPLY_PROP_MANUFACTURER, | 480 | POWER_SUPPLY_PROP_MANUFACTURER, |
429 | POWER_SUPPLY_PROP_SERIAL_NUMBER, | 481 | POWER_SUPPLY_PROP_SERIAL_NUMBER, |
430 | POWER_SUPPLY_PROP_CHARGE_COUNTER, | 482 | POWER_SUPPLY_PROP_CHARGE_COUNTER, |
483 | POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN, | ||
431 | }; | 484 | }; |
432 | 485 | ||
433 | /* XO-1.5 does not have ambient temperature property */ | 486 | /* XO-1.5 does not have ambient temperature property */ |
@@ -449,6 +502,7 @@ static enum power_supply_property olpc_xo15_bat_props[] = { | |||
449 | POWER_SUPPLY_PROP_MANUFACTURER, | 502 | POWER_SUPPLY_PROP_MANUFACTURER, |
450 | POWER_SUPPLY_PROP_SERIAL_NUMBER, | 503 | POWER_SUPPLY_PROP_SERIAL_NUMBER, |
451 | POWER_SUPPLY_PROP_CHARGE_COUNTER, | 504 | POWER_SUPPLY_PROP_CHARGE_COUNTER, |
505 | POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN, | ||
452 | }; | 506 | }; |
453 | 507 | ||
454 | /* EEPROM reading goes completely around the power_supply API, sadly */ | 508 | /* EEPROM reading goes completely around the power_supply API, sadly */ |
diff --git a/drivers/power/pda_power.c b/drivers/power/pda_power.c index 8dbcd53c5e67..6a1ca735e935 100644 --- a/drivers/power/pda_power.c +++ b/drivers/power/pda_power.c | |||
@@ -134,13 +134,13 @@ static void update_charger(void) | |||
134 | regulator_set_current_limit(ac_draw, max_uA, max_uA); | 134 | regulator_set_current_limit(ac_draw, max_uA, max_uA); |
135 | if (!regulator_enabled) { | 135 | if (!regulator_enabled) { |
136 | dev_dbg(dev, "charger on (AC)\n"); | 136 | dev_dbg(dev, "charger on (AC)\n"); |
137 | regulator_enable(ac_draw); | 137 | WARN_ON(regulator_enable(ac_draw)); |
138 | regulator_enabled = 1; | 138 | regulator_enabled = 1; |
139 | } | 139 | } |
140 | } else { | 140 | } else { |
141 | if (regulator_enabled) { | 141 | if (regulator_enabled) { |
142 | dev_dbg(dev, "charger off\n"); | 142 | dev_dbg(dev, "charger off\n"); |
143 | regulator_disable(ac_draw); | 143 | WARN_ON(regulator_disable(ac_draw)); |
144 | regulator_enabled = 0; | 144 | regulator_enabled = 0; |
145 | } | 145 | } |
146 | } | 146 | } |
diff --git a/drivers/power/power_supply_core.c b/drivers/power/power_supply_core.c index 6ad612726785..08cc8a3c15af 100644 --- a/drivers/power/power_supply_core.c +++ b/drivers/power/power_supply_core.c | |||
@@ -17,6 +17,7 @@ | |||
17 | #include <linux/device.h> | 17 | #include <linux/device.h> |
18 | #include <linux/err.h> | 18 | #include <linux/err.h> |
19 | #include <linux/power_supply.h> | 19 | #include <linux/power_supply.h> |
20 | #include <linux/thermal.h> | ||
20 | #include "power_supply.h" | 21 | #include "power_supply.h" |
21 | 22 | ||
22 | /* exported for the APM Power driver, APM emulation */ | 23 | /* exported for the APM Power driver, APM emulation */ |
@@ -169,6 +170,63 @@ static void power_supply_dev_release(struct device *dev) | |||
169 | kfree(dev); | 170 | kfree(dev); |
170 | } | 171 | } |
171 | 172 | ||
173 | #ifdef CONFIG_THERMAL | ||
174 | static int power_supply_read_temp(struct thermal_zone_device *tzd, | ||
175 | unsigned long *temp) | ||
176 | { | ||
177 | struct power_supply *psy; | ||
178 | union power_supply_propval val; | ||
179 | int ret; | ||
180 | |||
181 | WARN_ON(tzd == NULL); | ||
182 | psy = tzd->devdata; | ||
183 | ret = psy->get_property(psy, POWER_SUPPLY_PROP_TEMP, &val); | ||
184 | |||
185 | /* Convert tenths of degree Celsius to milli degree Celsius. */ | ||
186 | if (!ret) | ||
187 | *temp = val.intval * 100; | ||
188 | |||
189 | return ret; | ||
190 | } | ||
191 | |||
192 | static struct thermal_zone_device_ops psy_tzd_ops = { | ||
193 | .get_temp = power_supply_read_temp, | ||
194 | }; | ||
195 | |||
196 | static int psy_register_thermal(struct power_supply *psy) | ||
197 | { | ||
198 | int i; | ||
199 | |||
200 | /* Register battery zone device psy reports temperature */ | ||
201 | for (i = 0; i < psy->num_properties; i++) { | ||
202 | if (psy->properties[i] == POWER_SUPPLY_PROP_TEMP) { | ||
203 | psy->tzd = thermal_zone_device_register(psy->name, 0, 0, | ||
204 | psy, &psy_tzd_ops, 0, 0, 0, 0); | ||
205 | if (IS_ERR(psy->tzd)) | ||
206 | return PTR_ERR(psy->tzd); | ||
207 | break; | ||
208 | } | ||
209 | } | ||
210 | return 0; | ||
211 | } | ||
212 | |||
213 | static void psy_unregister_thermal(struct power_supply *psy) | ||
214 | { | ||
215 | if (IS_ERR_OR_NULL(psy->tzd)) | ||
216 | return; | ||
217 | thermal_zone_device_unregister(psy->tzd); | ||
218 | } | ||
219 | #else | ||
220 | static int psy_register_thermal(struct power_supply *psy) | ||
221 | { | ||
222 | return 0; | ||
223 | } | ||
224 | |||
225 | static void psy_unregister_thermal(struct power_supply *psy) | ||
226 | { | ||
227 | } | ||
228 | #endif | ||
229 | |||
172 | int power_supply_register(struct device *parent, struct power_supply *psy) | 230 | int power_supply_register(struct device *parent, struct power_supply *psy) |
173 | { | 231 | { |
174 | struct device *dev; | 232 | struct device *dev; |
@@ -197,6 +255,10 @@ int power_supply_register(struct device *parent, struct power_supply *psy) | |||
197 | if (rc) | 255 | if (rc) |
198 | goto device_add_failed; | 256 | goto device_add_failed; |
199 | 257 | ||
258 | rc = psy_register_thermal(psy); | ||
259 | if (rc) | ||
260 | goto register_thermal_failed; | ||
261 | |||
200 | rc = power_supply_create_triggers(psy); | 262 | rc = power_supply_create_triggers(psy); |
201 | if (rc) | 263 | if (rc) |
202 | goto create_triggers_failed; | 264 | goto create_triggers_failed; |
@@ -206,6 +268,8 @@ int power_supply_register(struct device *parent, struct power_supply *psy) | |||
206 | goto success; | 268 | goto success; |
207 | 269 | ||
208 | create_triggers_failed: | 270 | create_triggers_failed: |
271 | psy_unregister_thermal(psy); | ||
272 | register_thermal_failed: | ||
209 | device_del(dev); | 273 | device_del(dev); |
210 | kobject_set_name_failed: | 274 | kobject_set_name_failed: |
211 | device_add_failed: | 275 | device_add_failed: |
@@ -220,6 +284,7 @@ void power_supply_unregister(struct power_supply *psy) | |||
220 | cancel_work_sync(&psy->changed_work); | 284 | cancel_work_sync(&psy->changed_work); |
221 | sysfs_remove_link(&psy->dev->kobj, "powers"); | 285 | sysfs_remove_link(&psy->dev->kobj, "powers"); |
222 | power_supply_remove_triggers(psy); | 286 | power_supply_remove_triggers(psy); |
287 | psy_unregister_thermal(psy); | ||
223 | device_unregister(psy->dev); | 288 | device_unregister(psy->dev); |
224 | } | 289 | } |
225 | EXPORT_SYMBOL_GPL(power_supply_unregister); | 290 | EXPORT_SYMBOL_GPL(power_supply_unregister); |
diff --git a/drivers/power/power_supply_sysfs.c b/drivers/power/power_supply_sysfs.c index 4150747f9186..1d96614a17a4 100644 --- a/drivers/power/power_supply_sysfs.c +++ b/drivers/power/power_supply_sysfs.c | |||
@@ -159,6 +159,8 @@ static struct device_attribute power_supply_attrs[] = { | |||
159 | POWER_SUPPLY_ATTR(charge_now), | 159 | POWER_SUPPLY_ATTR(charge_now), |
160 | POWER_SUPPLY_ATTR(charge_avg), | 160 | POWER_SUPPLY_ATTR(charge_avg), |
161 | POWER_SUPPLY_ATTR(charge_counter), | 161 | POWER_SUPPLY_ATTR(charge_counter), |
162 | POWER_SUPPLY_ATTR(constant_charge_current), | ||
163 | POWER_SUPPLY_ATTR(constant_charge_voltage), | ||
162 | POWER_SUPPLY_ATTR(energy_full_design), | 164 | POWER_SUPPLY_ATTR(energy_full_design), |
163 | POWER_SUPPLY_ATTR(energy_empty_design), | 165 | POWER_SUPPLY_ATTR(energy_empty_design), |
164 | POWER_SUPPLY_ATTR(energy_full), | 166 | POWER_SUPPLY_ATTR(energy_full), |
@@ -166,9 +168,15 @@ static struct device_attribute power_supply_attrs[] = { | |||
166 | POWER_SUPPLY_ATTR(energy_now), | 168 | POWER_SUPPLY_ATTR(energy_now), |
167 | POWER_SUPPLY_ATTR(energy_avg), | 169 | POWER_SUPPLY_ATTR(energy_avg), |
168 | POWER_SUPPLY_ATTR(capacity), | 170 | POWER_SUPPLY_ATTR(capacity), |
171 | POWER_SUPPLY_ATTR(capacity_alert_min), | ||
172 | POWER_SUPPLY_ATTR(capacity_alert_max), | ||
169 | POWER_SUPPLY_ATTR(capacity_level), | 173 | POWER_SUPPLY_ATTR(capacity_level), |
170 | POWER_SUPPLY_ATTR(temp), | 174 | POWER_SUPPLY_ATTR(temp), |
175 | POWER_SUPPLY_ATTR(temp_alert_min), | ||
176 | POWER_SUPPLY_ATTR(temp_alert_max), | ||
171 | POWER_SUPPLY_ATTR(temp_ambient), | 177 | POWER_SUPPLY_ATTR(temp_ambient), |
178 | POWER_SUPPLY_ATTR(temp_ambient_alert_min), | ||
179 | POWER_SUPPLY_ATTR(temp_ambient_alert_max), | ||
172 | POWER_SUPPLY_ATTR(time_to_empty_now), | 180 | POWER_SUPPLY_ATTR(time_to_empty_now), |
173 | POWER_SUPPLY_ATTR(time_to_empty_avg), | 181 | POWER_SUPPLY_ATTR(time_to_empty_avg), |
174 | POWER_SUPPLY_ATTR(time_to_full_now), | 182 | POWER_SUPPLY_ATTR(time_to_full_now), |
diff --git a/drivers/power/sbs-battery.c b/drivers/power/sbs-battery.c index a5b6849d4123..a65e8f54157e 100644 --- a/drivers/power/sbs-battery.c +++ b/drivers/power/sbs-battery.c | |||
@@ -469,7 +469,7 @@ static int sbs_get_property(struct power_supply *psy, | |||
469 | 469 | ||
470 | case POWER_SUPPLY_PROP_TECHNOLOGY: | 470 | case POWER_SUPPLY_PROP_TECHNOLOGY: |
471 | val->intval = POWER_SUPPLY_TECHNOLOGY_LION; | 471 | val->intval = POWER_SUPPLY_TECHNOLOGY_LION; |
472 | break; | 472 | goto done; /* don't trigger power_supply_changed()! */ |
473 | 473 | ||
474 | case POWER_SUPPLY_PROP_ENERGY_NOW: | 474 | case POWER_SUPPLY_PROP_ENERGY_NOW: |
475 | case POWER_SUPPLY_PROP_ENERGY_FULL: | 475 | case POWER_SUPPLY_PROP_ENERGY_FULL: |
diff --git a/drivers/power/smb347-charger.c b/drivers/power/smb347-charger.c index f8eedd8a676f..332dd0110bda 100644 --- a/drivers/power/smb347-charger.c +++ b/drivers/power/smb347-charger.c | |||
@@ -196,6 +196,14 @@ static const unsigned int ccc_tbl[] = { | |||
196 | 1200000, | 196 | 1200000, |
197 | }; | 197 | }; |
198 | 198 | ||
199 | /* Convert register value to current using lookup table */ | ||
200 | static int hw_to_current(const unsigned int *tbl, size_t size, unsigned int val) | ||
201 | { | ||
202 | if (val >= size) | ||
203 | return -EINVAL; | ||
204 | return tbl[val]; | ||
205 | } | ||
206 | |||
199 | /* Convert current to register value using lookup table */ | 207 | /* Convert current to register value using lookup table */ |
200 | static int current_to_hw(const unsigned int *tbl, size_t size, unsigned int val) | 208 | static int current_to_hw(const unsigned int *tbl, size_t size, unsigned int val) |
201 | { | 209 | { |
@@ -841,22 +849,101 @@ fail: | |||
841 | return ret; | 849 | return ret; |
842 | } | 850 | } |
843 | 851 | ||
852 | /* | ||
853 | * Returns the constant charge current programmed | ||
854 | * into the charger in uA. | ||
855 | */ | ||
856 | static int get_const_charge_current(struct smb347_charger *smb) | ||
857 | { | ||
858 | int ret, intval; | ||
859 | unsigned int v; | ||
860 | |||
861 | if (!smb347_is_ps_online(smb)) | ||
862 | return -ENODATA; | ||
863 | |||
864 | ret = regmap_read(smb->regmap, STAT_B, &v); | ||
865 | if (ret < 0) | ||
866 | return ret; | ||
867 | |||
868 | /* | ||
869 | * The current value is composition of FCC and PCC values | ||
870 | * and we can detect which table to use from bit 5. | ||
871 | */ | ||
872 | if (v & 0x20) { | ||
873 | intval = hw_to_current(fcc_tbl, ARRAY_SIZE(fcc_tbl), v & 7); | ||
874 | } else { | ||
875 | v >>= 3; | ||
876 | intval = hw_to_current(pcc_tbl, ARRAY_SIZE(pcc_tbl), v & 7); | ||
877 | } | ||
878 | |||
879 | return intval; | ||
880 | } | ||
881 | |||
882 | /* | ||
883 | * Returns the constant charge voltage programmed | ||
884 | * into the charger in uV. | ||
885 | */ | ||
886 | static int get_const_charge_voltage(struct smb347_charger *smb) | ||
887 | { | ||
888 | int ret, intval; | ||
889 | unsigned int v; | ||
890 | |||
891 | if (!smb347_is_ps_online(smb)) | ||
892 | return -ENODATA; | ||
893 | |||
894 | ret = regmap_read(smb->regmap, STAT_A, &v); | ||
895 | if (ret < 0) | ||
896 | return ret; | ||
897 | |||
898 | v &= STAT_A_FLOAT_VOLTAGE_MASK; | ||
899 | if (v > 0x3d) | ||
900 | v = 0x3d; | ||
901 | |||
902 | intval = 3500000 + v * 20000; | ||
903 | |||
904 | return intval; | ||
905 | } | ||
906 | |||
844 | static int smb347_mains_get_property(struct power_supply *psy, | 907 | static int smb347_mains_get_property(struct power_supply *psy, |
845 | enum power_supply_property prop, | 908 | enum power_supply_property prop, |
846 | union power_supply_propval *val) | 909 | union power_supply_propval *val) |
847 | { | 910 | { |
848 | struct smb347_charger *smb = | 911 | struct smb347_charger *smb = |
849 | container_of(psy, struct smb347_charger, mains); | 912 | container_of(psy, struct smb347_charger, mains); |
913 | int ret; | ||
850 | 914 | ||
851 | if (prop == POWER_SUPPLY_PROP_ONLINE) { | 915 | switch (prop) { |
916 | case POWER_SUPPLY_PROP_ONLINE: | ||
852 | val->intval = smb->mains_online; | 917 | val->intval = smb->mains_online; |
853 | return 0; | 918 | break; |
919 | |||
920 | case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE: | ||
921 | ret = get_const_charge_voltage(smb); | ||
922 | if (ret < 0) | ||
923 | return ret; | ||
924 | else | ||
925 | val->intval = ret; | ||
926 | break; | ||
927 | |||
928 | case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT: | ||
929 | ret = get_const_charge_current(smb); | ||
930 | if (ret < 0) | ||
931 | return ret; | ||
932 | else | ||
933 | val->intval = ret; | ||
934 | break; | ||
935 | |||
936 | default: | ||
937 | return -EINVAL; | ||
854 | } | 938 | } |
855 | return -EINVAL; | 939 | |
940 | return 0; | ||
856 | } | 941 | } |
857 | 942 | ||
858 | static enum power_supply_property smb347_mains_properties[] = { | 943 | static enum power_supply_property smb347_mains_properties[] = { |
859 | POWER_SUPPLY_PROP_ONLINE, | 944 | POWER_SUPPLY_PROP_ONLINE, |
945 | POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT, | ||
946 | POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE, | ||
860 | }; | 947 | }; |
861 | 948 | ||
862 | static int smb347_usb_get_property(struct power_supply *psy, | 949 | static int smb347_usb_get_property(struct power_supply *psy, |
@@ -865,16 +952,40 @@ static int smb347_usb_get_property(struct power_supply *psy, | |||
865 | { | 952 | { |
866 | struct smb347_charger *smb = | 953 | struct smb347_charger *smb = |
867 | container_of(psy, struct smb347_charger, usb); | 954 | container_of(psy, struct smb347_charger, usb); |
955 | int ret; | ||
868 | 956 | ||
869 | if (prop == POWER_SUPPLY_PROP_ONLINE) { | 957 | switch (prop) { |
958 | case POWER_SUPPLY_PROP_ONLINE: | ||
870 | val->intval = smb->usb_online; | 959 | val->intval = smb->usb_online; |
871 | return 0; | 960 | break; |
961 | |||
962 | case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE: | ||
963 | ret = get_const_charge_voltage(smb); | ||
964 | if (ret < 0) | ||
965 | return ret; | ||
966 | else | ||
967 | val->intval = ret; | ||
968 | break; | ||
969 | |||
970 | case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT: | ||
971 | ret = get_const_charge_current(smb); | ||
972 | if (ret < 0) | ||
973 | return ret; | ||
974 | else | ||
975 | val->intval = ret; | ||
976 | break; | ||
977 | |||
978 | default: | ||
979 | return -EINVAL; | ||
872 | } | 980 | } |
873 | return -EINVAL; | 981 | |
982 | return 0; | ||
874 | } | 983 | } |
875 | 984 | ||
876 | static enum power_supply_property smb347_usb_properties[] = { | 985 | static enum power_supply_property smb347_usb_properties[] = { |
877 | POWER_SUPPLY_PROP_ONLINE, | 986 | POWER_SUPPLY_PROP_ONLINE, |
987 | POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT, | ||
988 | POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE, | ||
878 | }; | 989 | }; |
879 | 990 | ||
880 | static int smb347_battery_get_property(struct power_supply *psy, | 991 | static int smb347_battery_get_property(struct power_supply *psy, |
diff --git a/drivers/power/test_power.c b/drivers/power/test_power.c index b527c93bf2f3..b99a452a4fda 100644 --- a/drivers/power/test_power.c +++ b/drivers/power/test_power.c | |||
@@ -22,11 +22,13 @@ | |||
22 | #include <linux/vermagic.h> | 22 | #include <linux/vermagic.h> |
23 | 23 | ||
24 | static int ac_online = 1; | 24 | static int ac_online = 1; |
25 | static int usb_online = 1; | ||
25 | static int battery_status = POWER_SUPPLY_STATUS_DISCHARGING; | 26 | static int battery_status = POWER_SUPPLY_STATUS_DISCHARGING; |
26 | static int battery_health = POWER_SUPPLY_HEALTH_GOOD; | 27 | static int battery_health = POWER_SUPPLY_HEALTH_GOOD; |
27 | static int battery_present = 1; /* true */ | 28 | static int battery_present = 1; /* true */ |
28 | static int battery_technology = POWER_SUPPLY_TECHNOLOGY_LION; | 29 | static int battery_technology = POWER_SUPPLY_TECHNOLOGY_LION; |
29 | static int battery_capacity = 50; | 30 | static int battery_capacity = 50; |
31 | static int battery_voltage = 3300; | ||
30 | 32 | ||
31 | static int test_power_get_ac_property(struct power_supply *psy, | 33 | static int test_power_get_ac_property(struct power_supply *psy, |
32 | enum power_supply_property psp, | 34 | enum power_supply_property psp, |
@@ -42,6 +44,20 @@ static int test_power_get_ac_property(struct power_supply *psy, | |||
42 | return 0; | 44 | return 0; |
43 | } | 45 | } |
44 | 46 | ||
47 | static int test_power_get_usb_property(struct power_supply *psy, | ||
48 | enum power_supply_property psp, | ||
49 | union power_supply_propval *val) | ||
50 | { | ||
51 | switch (psp) { | ||
52 | case POWER_SUPPLY_PROP_ONLINE: | ||
53 | val->intval = usb_online; | ||
54 | break; | ||
55 | default: | ||
56 | return -EINVAL; | ||
57 | } | ||
58 | return 0; | ||
59 | } | ||
60 | |||
45 | static int test_power_get_battery_property(struct power_supply *psy, | 61 | static int test_power_get_battery_property(struct power_supply *psy, |
46 | enum power_supply_property psp, | 62 | enum power_supply_property psp, |
47 | union power_supply_propval *val) | 63 | union power_supply_propval *val) |
@@ -86,6 +102,12 @@ static int test_power_get_battery_property(struct power_supply *psy, | |||
86 | case POWER_SUPPLY_PROP_TIME_TO_FULL_NOW: | 102 | case POWER_SUPPLY_PROP_TIME_TO_FULL_NOW: |
87 | val->intval = 3600; | 103 | val->intval = 3600; |
88 | break; | 104 | break; |
105 | case POWER_SUPPLY_PROP_TEMP: | ||
106 | val->intval = 26; | ||
107 | break; | ||
108 | case POWER_SUPPLY_PROP_VOLTAGE_NOW: | ||
109 | val->intval = battery_voltage; | ||
110 | break; | ||
89 | default: | 111 | default: |
90 | pr_info("%s: some properties deliberately report errors.\n", | 112 | pr_info("%s: some properties deliberately report errors.\n", |
91 | __func__); | 113 | __func__); |
@@ -114,6 +136,8 @@ static enum power_supply_property test_power_battery_props[] = { | |||
114 | POWER_SUPPLY_PROP_MODEL_NAME, | 136 | POWER_SUPPLY_PROP_MODEL_NAME, |
115 | POWER_SUPPLY_PROP_MANUFACTURER, | 137 | POWER_SUPPLY_PROP_MANUFACTURER, |
116 | POWER_SUPPLY_PROP_SERIAL_NUMBER, | 138 | POWER_SUPPLY_PROP_SERIAL_NUMBER, |
139 | POWER_SUPPLY_PROP_TEMP, | ||
140 | POWER_SUPPLY_PROP_VOLTAGE_NOW, | ||
117 | }; | 141 | }; |
118 | 142 | ||
119 | static char *test_power_ac_supplied_to[] = { | 143 | static char *test_power_ac_supplied_to[] = { |
@@ -135,6 +159,14 @@ static struct power_supply test_power_supplies[] = { | |||
135 | .properties = test_power_battery_props, | 159 | .properties = test_power_battery_props, |
136 | .num_properties = ARRAY_SIZE(test_power_battery_props), | 160 | .num_properties = ARRAY_SIZE(test_power_battery_props), |
137 | .get_property = test_power_get_battery_property, | 161 | .get_property = test_power_get_battery_property, |
162 | }, { | ||
163 | .name = "test_usb", | ||
164 | .type = POWER_SUPPLY_TYPE_USB, | ||
165 | .supplied_to = test_power_ac_supplied_to, | ||
166 | .num_supplicants = ARRAY_SIZE(test_power_ac_supplied_to), | ||
167 | .properties = test_power_ac_props, | ||
168 | .num_properties = ARRAY_SIZE(test_power_ac_props), | ||
169 | .get_property = test_power_get_usb_property, | ||
138 | }, | 170 | }, |
139 | }; | 171 | }; |
140 | 172 | ||
@@ -167,6 +199,7 @@ static void __exit test_power_exit(void) | |||
167 | 199 | ||
168 | /* Let's see how we handle changes... */ | 200 | /* Let's see how we handle changes... */ |
169 | ac_online = 0; | 201 | ac_online = 0; |
202 | usb_online = 0; | ||
170 | battery_status = POWER_SUPPLY_STATUS_DISCHARGING; | 203 | battery_status = POWER_SUPPLY_STATUS_DISCHARGING; |
171 | for (i = 0; i < ARRAY_SIZE(test_power_supplies); i++) | 204 | for (i = 0; i < ARRAY_SIZE(test_power_supplies); i++) |
172 | power_supply_changed(&test_power_supplies[i]); | 205 | power_supply_changed(&test_power_supplies[i]); |
@@ -275,6 +308,19 @@ static int param_get_ac_online(char *buffer, const struct kernel_param *kp) | |||
275 | return strlen(buffer); | 308 | return strlen(buffer); |
276 | } | 309 | } |
277 | 310 | ||
311 | static int param_set_usb_online(const char *key, const struct kernel_param *kp) | ||
312 | { | ||
313 | usb_online = map_get_value(map_ac_online, key, usb_online); | ||
314 | power_supply_changed(&test_power_supplies[2]); | ||
315 | return 0; | ||
316 | } | ||
317 | |||
318 | static int param_get_usb_online(char *buffer, const struct kernel_param *kp) | ||
319 | { | ||
320 | strcpy(buffer, map_get_key(map_ac_online, usb_online, "unknown")); | ||
321 | return strlen(buffer); | ||
322 | } | ||
323 | |||
278 | static int param_set_battery_status(const char *key, | 324 | static int param_set_battery_status(const char *key, |
279 | const struct kernel_param *kp) | 325 | const struct kernel_param *kp) |
280 | { | 326 | { |
@@ -350,13 +396,31 @@ static int param_set_battery_capacity(const char *key, | |||
350 | 396 | ||
351 | #define param_get_battery_capacity param_get_int | 397 | #define param_get_battery_capacity param_get_int |
352 | 398 | ||
399 | static int param_set_battery_voltage(const char *key, | ||
400 | const struct kernel_param *kp) | ||
401 | { | ||
402 | int tmp; | ||
403 | |||
404 | if (1 != sscanf(key, "%d", &tmp)) | ||
405 | return -EINVAL; | ||
406 | |||
407 | battery_voltage = tmp; | ||
408 | power_supply_changed(&test_power_supplies[1]); | ||
409 | return 0; | ||
410 | } | ||
353 | 411 | ||
412 | #define param_get_battery_voltage param_get_int | ||
354 | 413 | ||
355 | static struct kernel_param_ops param_ops_ac_online = { | 414 | static struct kernel_param_ops param_ops_ac_online = { |
356 | .set = param_set_ac_online, | 415 | .set = param_set_ac_online, |
357 | .get = param_get_ac_online, | 416 | .get = param_get_ac_online, |
358 | }; | 417 | }; |
359 | 418 | ||
419 | static struct kernel_param_ops param_ops_usb_online = { | ||
420 | .set = param_set_usb_online, | ||
421 | .get = param_get_usb_online, | ||
422 | }; | ||
423 | |||
360 | static struct kernel_param_ops param_ops_battery_status = { | 424 | static struct kernel_param_ops param_ops_battery_status = { |
361 | .set = param_set_battery_status, | 425 | .set = param_set_battery_status, |
362 | .get = param_get_battery_status, | 426 | .get = param_get_battery_status, |
@@ -382,18 +446,27 @@ static struct kernel_param_ops param_ops_battery_capacity = { | |||
382 | .get = param_get_battery_capacity, | 446 | .get = param_get_battery_capacity, |
383 | }; | 447 | }; |
384 | 448 | ||
449 | static struct kernel_param_ops param_ops_battery_voltage = { | ||
450 | .set = param_set_battery_voltage, | ||
451 | .get = param_get_battery_voltage, | ||
452 | }; | ||
385 | 453 | ||
386 | #define param_check_ac_online(name, p) __param_check(name, p, void); | 454 | #define param_check_ac_online(name, p) __param_check(name, p, void); |
455 | #define param_check_usb_online(name, p) __param_check(name, p, void); | ||
387 | #define param_check_battery_status(name, p) __param_check(name, p, void); | 456 | #define param_check_battery_status(name, p) __param_check(name, p, void); |
388 | #define param_check_battery_present(name, p) __param_check(name, p, void); | 457 | #define param_check_battery_present(name, p) __param_check(name, p, void); |
389 | #define param_check_battery_technology(name, p) __param_check(name, p, void); | 458 | #define param_check_battery_technology(name, p) __param_check(name, p, void); |
390 | #define param_check_battery_health(name, p) __param_check(name, p, void); | 459 | #define param_check_battery_health(name, p) __param_check(name, p, void); |
391 | #define param_check_battery_capacity(name, p) __param_check(name, p, void); | 460 | #define param_check_battery_capacity(name, p) __param_check(name, p, void); |
461 | #define param_check_battery_voltage(name, p) __param_check(name, p, void); | ||
392 | 462 | ||
393 | 463 | ||
394 | module_param(ac_online, ac_online, 0644); | 464 | module_param(ac_online, ac_online, 0644); |
395 | MODULE_PARM_DESC(ac_online, "AC charging state <on|off>"); | 465 | MODULE_PARM_DESC(ac_online, "AC charging state <on|off>"); |
396 | 466 | ||
467 | module_param(usb_online, usb_online, 0644); | ||
468 | MODULE_PARM_DESC(usb_online, "USB charging state <on|off>"); | ||
469 | |||
397 | module_param(battery_status, battery_status, 0644); | 470 | module_param(battery_status, battery_status, 0644); |
398 | MODULE_PARM_DESC(battery_status, | 471 | MODULE_PARM_DESC(battery_status, |
399 | "battery status <charging|discharging|not-charging|full>"); | 472 | "battery status <charging|discharging|not-charging|full>"); |
@@ -413,6 +486,8 @@ MODULE_PARM_DESC(battery_health, | |||
413 | module_param(battery_capacity, battery_capacity, 0644); | 486 | module_param(battery_capacity, battery_capacity, 0644); |
414 | MODULE_PARM_DESC(battery_capacity, "battery capacity (percentage)"); | 487 | MODULE_PARM_DESC(battery_capacity, "battery capacity (percentage)"); |
415 | 488 | ||
489 | module_param(battery_voltage, battery_voltage, 0644); | ||
490 | MODULE_PARM_DESC(battery_voltage, "battery voltage (millivolts)"); | ||
416 | 491 | ||
417 | MODULE_DESCRIPTION("Power supply driver for testing"); | 492 | MODULE_DESCRIPTION("Power supply driver for testing"); |
418 | MODULE_AUTHOR("Anton Vorontsov <cbouatmailru@gmail.com>"); | 493 | MODULE_AUTHOR("Anton Vorontsov <cbouatmailru@gmail.com>"); |
diff --git a/drivers/power/twl4030_charger.c b/drivers/power/twl4030_charger.c index 7cacbaa68efe..15f4d5d8611b 100644 --- a/drivers/power/twl4030_charger.c +++ b/drivers/power/twl4030_charger.c | |||
@@ -22,6 +22,7 @@ | |||
22 | #include <linux/power_supply.h> | 22 | #include <linux/power_supply.h> |
23 | #include <linux/notifier.h> | 23 | #include <linux/notifier.h> |
24 | #include <linux/usb/otg.h> | 24 | #include <linux/usb/otg.h> |
25 | #include <linux/regulator/machine.h> | ||
25 | 26 | ||
26 | #define TWL4030_BCIMSTATEC 0x02 | 27 | #define TWL4030_BCIMSTATEC 0x02 |
27 | #define TWL4030_BCIICHG 0x08 | 28 | #define TWL4030_BCIICHG 0x08 |
@@ -29,6 +30,7 @@ | |||
29 | #define TWL4030_BCIVBUS 0x0c | 30 | #define TWL4030_BCIVBUS 0x0c |
30 | #define TWL4030_BCIMFSTS4 0x10 | 31 | #define TWL4030_BCIMFSTS4 0x10 |
31 | #define TWL4030_BCICTL1 0x23 | 32 | #define TWL4030_BCICTL1 0x23 |
33 | #define TWL4030_BB_CFG 0x12 | ||
32 | 34 | ||
33 | #define TWL4030_BCIAUTOWEN BIT(5) | 35 | #define TWL4030_BCIAUTOWEN BIT(5) |
34 | #define TWL4030_CONFIG_DONE BIT(4) | 36 | #define TWL4030_CONFIG_DONE BIT(4) |
@@ -38,6 +40,17 @@ | |||
38 | #define TWL4030_USBFASTMCHG BIT(2) | 40 | #define TWL4030_USBFASTMCHG BIT(2) |
39 | #define TWL4030_STS_VBUS BIT(7) | 41 | #define TWL4030_STS_VBUS BIT(7) |
40 | #define TWL4030_STS_USB_ID BIT(2) | 42 | #define TWL4030_STS_USB_ID BIT(2) |
43 | #define TWL4030_BBCHEN BIT(4) | ||
44 | #define TWL4030_BBSEL_MASK 0b1100 | ||
45 | #define TWL4030_BBSEL_2V5 0b0000 | ||
46 | #define TWL4030_BBSEL_3V0 0b0100 | ||
47 | #define TWL4030_BBSEL_3V1 0b1000 | ||
48 | #define TWL4030_BBSEL_3V2 0b1100 | ||
49 | #define TWL4030_BBISEL_MASK 0b11 | ||
50 | #define TWL4030_BBISEL_25uA 0b00 | ||
51 | #define TWL4030_BBISEL_150uA 0b01 | ||
52 | #define TWL4030_BBISEL_500uA 0b10 | ||
53 | #define TWL4030_BBISEL_1000uA 0b11 | ||
41 | 54 | ||
42 | /* BCI interrupts */ | 55 | /* BCI interrupts */ |
43 | #define TWL4030_WOVF BIT(0) /* Watchdog overflow */ | 56 | #define TWL4030_WOVF BIT(0) /* Watchdog overflow */ |
@@ -75,6 +88,8 @@ struct twl4030_bci { | |||
75 | struct work_struct work; | 88 | struct work_struct work; |
76 | int irq_chg; | 89 | int irq_chg; |
77 | int irq_bci; | 90 | int irq_bci; |
91 | struct regulator *usb_reg; | ||
92 | int usb_enabled; | ||
78 | 93 | ||
79 | unsigned long event; | 94 | unsigned long event; |
80 | }; | 95 | }; |
@@ -104,7 +119,7 @@ static int twl4030_bci_read(u8 reg, u8 *val) | |||
104 | 119 | ||
105 | static int twl4030_clear_set_boot_bci(u8 clear, u8 set) | 120 | static int twl4030_clear_set_boot_bci(u8 clear, u8 set) |
106 | { | 121 | { |
107 | return twl4030_clear_set(TWL4030_MODULE_PM_MASTER, 0, | 122 | return twl4030_clear_set(TWL4030_MODULE_PM_MASTER, clear, |
108 | TWL4030_CONFIG_DONE | TWL4030_BCIAUTOWEN | set, | 123 | TWL4030_CONFIG_DONE | TWL4030_BCIAUTOWEN | set, |
109 | TWL4030_PM_MASTER_BOOT_BCI); | 124 | TWL4030_PM_MASTER_BOOT_BCI); |
110 | } | 125 | } |
@@ -152,14 +167,14 @@ static int twl4030_bci_have_vbus(struct twl4030_bci *bci) | |||
152 | } | 167 | } |
153 | 168 | ||
154 | /* | 169 | /* |
155 | * Enable/Disable USB Charge funtionality. | 170 | * Enable/Disable USB Charge functionality. |
156 | */ | 171 | */ |
157 | static int twl4030_charger_enable_usb(struct twl4030_bci *bci, bool enable) | 172 | static int twl4030_charger_enable_usb(struct twl4030_bci *bci, bool enable) |
158 | { | 173 | { |
159 | int ret; | 174 | int ret; |
160 | 175 | ||
161 | if (enable) { | 176 | if (enable) { |
162 | /* Check for USB charger conneted */ | 177 | /* Check for USB charger connected */ |
163 | if (!twl4030_bci_have_vbus(bci)) | 178 | if (!twl4030_bci_have_vbus(bci)) |
164 | return -ENODEV; | 179 | return -ENODEV; |
165 | 180 | ||
@@ -172,6 +187,12 @@ static int twl4030_charger_enable_usb(struct twl4030_bci *bci, bool enable) | |||
172 | return -EACCES; | 187 | return -EACCES; |
173 | } | 188 | } |
174 | 189 | ||
190 | /* Need to keep regulator on */ | ||
191 | if (!bci->usb_enabled) { | ||
192 | regulator_enable(bci->usb_reg); | ||
193 | bci->usb_enabled = 1; | ||
194 | } | ||
195 | |||
175 | /* forcing the field BCIAUTOUSB (BOOT_BCI[1]) to 1 */ | 196 | /* forcing the field BCIAUTOUSB (BOOT_BCI[1]) to 1 */ |
176 | ret = twl4030_clear_set_boot_bci(0, TWL4030_BCIAUTOUSB); | 197 | ret = twl4030_clear_set_boot_bci(0, TWL4030_BCIAUTOUSB); |
177 | if (ret < 0) | 198 | if (ret < 0) |
@@ -182,6 +203,10 @@ static int twl4030_charger_enable_usb(struct twl4030_bci *bci, bool enable) | |||
182 | TWL4030_USBFASTMCHG, TWL4030_BCIMFSTS4); | 203 | TWL4030_USBFASTMCHG, TWL4030_BCIMFSTS4); |
183 | } else { | 204 | } else { |
184 | ret = twl4030_clear_set_boot_bci(TWL4030_BCIAUTOUSB, 0); | 205 | ret = twl4030_clear_set_boot_bci(TWL4030_BCIAUTOUSB, 0); |
206 | if (bci->usb_enabled) { | ||
207 | regulator_disable(bci->usb_reg); | ||
208 | bci->usb_enabled = 0; | ||
209 | } | ||
185 | } | 210 | } |
186 | 211 | ||
187 | return ret; | 212 | return ret; |
@@ -203,6 +228,49 @@ static int twl4030_charger_enable_ac(bool enable) | |||
203 | } | 228 | } |
204 | 229 | ||
205 | /* | 230 | /* |
231 | * Enable/Disable charging of Backup Battery. | ||
232 | */ | ||
233 | static int twl4030_charger_enable_backup(int uvolt, int uamp) | ||
234 | { | ||
235 | int ret; | ||
236 | u8 flags; | ||
237 | |||
238 | if (uvolt < 2500000 || | ||
239 | uamp < 25) { | ||
240 | /* disable charging of backup battery */ | ||
241 | ret = twl4030_clear_set(TWL4030_MODULE_PM_RECEIVER, | ||
242 | TWL4030_BBCHEN, 0, TWL4030_BB_CFG); | ||
243 | return ret; | ||
244 | } | ||
245 | |||
246 | flags = TWL4030_BBCHEN; | ||
247 | if (uvolt >= 3200000) | ||
248 | flags |= TWL4030_BBSEL_3V2; | ||
249 | else if (uvolt >= 3100000) | ||
250 | flags |= TWL4030_BBSEL_3V1; | ||
251 | else if (uvolt >= 3000000) | ||
252 | flags |= TWL4030_BBSEL_3V0; | ||
253 | else | ||
254 | flags |= TWL4030_BBSEL_2V5; | ||
255 | |||
256 | if (uamp >= 1000) | ||
257 | flags |= TWL4030_BBISEL_1000uA; | ||
258 | else if (uamp >= 500) | ||
259 | flags |= TWL4030_BBISEL_500uA; | ||
260 | else if (uamp >= 150) | ||
261 | flags |= TWL4030_BBISEL_150uA; | ||
262 | else | ||
263 | flags |= TWL4030_BBISEL_25uA; | ||
264 | |||
265 | ret = twl4030_clear_set(TWL4030_MODULE_PM_RECEIVER, | ||
266 | TWL4030_BBSEL_MASK | TWL4030_BBISEL_MASK, | ||
267 | flags, | ||
268 | TWL4030_BB_CFG); | ||
269 | |||
270 | return ret; | ||
271 | } | ||
272 | |||
273 | /* | ||
206 | * TWL4030 CHG_PRES (AC charger presence) events | 274 | * TWL4030 CHG_PRES (AC charger presence) events |
207 | */ | 275 | */ |
208 | static irqreturn_t twl4030_charger_interrupt(int irq, void *arg) | 276 | static irqreturn_t twl4030_charger_interrupt(int irq, void *arg) |
@@ -425,6 +493,7 @@ static enum power_supply_property twl4030_charger_props[] = { | |||
425 | static int __init twl4030_bci_probe(struct platform_device *pdev) | 493 | static int __init twl4030_bci_probe(struct platform_device *pdev) |
426 | { | 494 | { |
427 | struct twl4030_bci *bci; | 495 | struct twl4030_bci *bci; |
496 | struct twl4030_bci_platform_data *pdata = pdev->dev.platform_data; | ||
428 | int ret; | 497 | int ret; |
429 | u32 reg; | 498 | u32 reg; |
430 | 499 | ||
@@ -456,6 +525,8 @@ static int __init twl4030_bci_probe(struct platform_device *pdev) | |||
456 | bci->usb.num_properties = ARRAY_SIZE(twl4030_charger_props); | 525 | bci->usb.num_properties = ARRAY_SIZE(twl4030_charger_props); |
457 | bci->usb.get_property = twl4030_bci_get_property; | 526 | bci->usb.get_property = twl4030_bci_get_property; |
458 | 527 | ||
528 | bci->usb_reg = regulator_get(bci->dev, "bci3v1"); | ||
529 | |||
459 | ret = power_supply_register(&pdev->dev, &bci->usb); | 530 | ret = power_supply_register(&pdev->dev, &bci->usb); |
460 | if (ret) { | 531 | if (ret) { |
461 | dev_err(&pdev->dev, "failed to register usb: %d\n", ret); | 532 | dev_err(&pdev->dev, "failed to register usb: %d\n", ret); |
@@ -504,6 +575,8 @@ static int __init twl4030_bci_probe(struct platform_device *pdev) | |||
504 | 575 | ||
505 | twl4030_charger_enable_ac(true); | 576 | twl4030_charger_enable_ac(true); |
506 | twl4030_charger_enable_usb(bci, true); | 577 | twl4030_charger_enable_usb(bci, true); |
578 | twl4030_charger_enable_backup(pdata->bb_uvolt, | ||
579 | pdata->bb_uamp); | ||
507 | 580 | ||
508 | return 0; | 581 | return 0; |
509 | 582 | ||
@@ -532,6 +605,7 @@ static int __exit twl4030_bci_remove(struct platform_device *pdev) | |||
532 | 605 | ||
533 | twl4030_charger_enable_ac(false); | 606 | twl4030_charger_enable_ac(false); |
534 | twl4030_charger_enable_usb(bci, false); | 607 | twl4030_charger_enable_usb(bci, false); |
608 | twl4030_charger_enable_backup(0, 0); | ||
535 | 609 | ||
536 | /* mask interrupts */ | 610 | /* mask interrupts */ |
537 | twl_i2c_write_u8(TWL4030_MODULE_INTERRUPTS, 0xff, | 611 | twl_i2c_write_u8(TWL4030_MODULE_INTERRUPTS, 0xff, |