aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/power
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2012-07-31 21:08:25 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2012-07-31 21:08:25 -0400
commit4b24ff71108164e047cf2c95990b77651163e315 (patch)
tree4b478906379adf22ff259fc1f2cce0da796df415 /drivers/power
parentbca1a5c0eabe0f17081760c61e8d08e73dd6b6a6 (diff)
parent4b1bf5871f7d59de6484cc887e205d6d2f1e6fbd (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/Kconfig1
-rw-r--r--drivers/power/bq27x00_battery.c155
-rw-r--r--drivers/power/charger-manager.c152
-rw-r--r--drivers/power/ds2781_battery.c2
-rw-r--r--drivers/power/gpio-charger.c2
-rw-r--r--drivers/power/lp8727_charger.c2
-rw-r--r--drivers/power/max17042_battery.c8
-rw-r--r--drivers/power/olpc_battery.c62
-rw-r--r--drivers/power/pda_power.c4
-rw-r--r--drivers/power/power_supply_core.c65
-rw-r--r--drivers/power/power_supply_sysfs.c8
-rw-r--r--drivers/power/sbs-battery.c2
-rw-r--r--drivers/power/smb347-charger.c123
-rw-r--r--drivers/power/test_power.c75
-rw-r--r--drivers/power/twl4030_charger.c80
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
268config CHARGER_MANAGER 268config 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
72struct bq27x00_device_info; 80struct bq27x00_device_info;
73struct bq27x00_access_methods { 81struct 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
77enum bq27x00_chip { BQ27000, BQ27500 }; 85enum bq27x00_chip { BQ27000, BQ27500, BQ27425};
78 86
79struct bq27x00_reg_cache { 87struct 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
91struct bq27x00_device_info { 101struct 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
140static 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
128static unsigned int poll_interval = 360; 154static unsigned int poll_interval = 360;
@@ -137,10 +163,24 @@ MODULE_PARM_DESC(poll_interval, "battery poll interval in seconds - " \
137static inline int bq27x00_read(struct bq27x00_device_info *di, u8 reg, 163static 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 */
176static 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 */
355static 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 */
376static 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
309static void bq27x00_update(struct bq27x00_device_info *di) 405static 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)
729static const struct i2c_device_id bq27x00_id[] = { 853static 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};
734MODULE_DEVICE_TABLE(i2c, bq27x00_id); 859MODULE_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}
995EXPORT_SYMBOL_GPL(setup_charger_manager); 992EXPORT_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 */
1000static 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 */
1031static 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 */
1050static 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
997static int charger_manager_probe(struct platform_device *pdev) 1074static 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
1199err_chg_enable: 1297err_chg_enable:
1200 regulator_bulk_free(desc->num_charger_regulators, 1298err_extcon:
1201 desc->charger_regulators); 1299 for (i = 0 ; i < desc->num_charger_regulators ; i++) {
1202err_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 }
1307err_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);
1204err_register: 1312err_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
67int w1_ds2781_read(struct ds2781_device_info *dev_info, char *buf, 67static 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
268static 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
174static 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
192static struct thermal_zone_device_ops psy_tzd_ops = {
193 .get_temp = power_supply_read_temp,
194};
195
196static 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
213static 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
220static int psy_register_thermal(struct power_supply *psy)
221{
222 return 0;
223}
224
225static void psy_unregister_thermal(struct power_supply *psy)
226{
227}
228#endif
229
172int power_supply_register(struct device *parent, struct power_supply *psy) 230int 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
208create_triggers_failed: 270create_triggers_failed:
271 psy_unregister_thermal(psy);
272register_thermal_failed:
209 device_del(dev); 273 device_del(dev);
210kobject_set_name_failed: 274kobject_set_name_failed:
211device_add_failed: 275device_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}
225EXPORT_SYMBOL_GPL(power_supply_unregister); 290EXPORT_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 */
200static 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 */
200static int current_to_hw(const unsigned int *tbl, size_t size, unsigned int val) 208static 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 */
856static 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 */
886static 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
844static int smb347_mains_get_property(struct power_supply *psy, 907static 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
858static enum power_supply_property smb347_mains_properties[] = { 943static 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
862static int smb347_usb_get_property(struct power_supply *psy, 949static 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
876static enum power_supply_property smb347_usb_properties[] = { 985static 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
880static int smb347_battery_get_property(struct power_supply *psy, 991static 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
24static int ac_online = 1; 24static int ac_online = 1;
25static int usb_online = 1;
25static int battery_status = POWER_SUPPLY_STATUS_DISCHARGING; 26static int battery_status = POWER_SUPPLY_STATUS_DISCHARGING;
26static int battery_health = POWER_SUPPLY_HEALTH_GOOD; 27static int battery_health = POWER_SUPPLY_HEALTH_GOOD;
27static int battery_present = 1; /* true */ 28static int battery_present = 1; /* true */
28static int battery_technology = POWER_SUPPLY_TECHNOLOGY_LION; 29static int battery_technology = POWER_SUPPLY_TECHNOLOGY_LION;
29static int battery_capacity = 50; 30static int battery_capacity = 50;
31static int battery_voltage = 3300;
30 32
31static int test_power_get_ac_property(struct power_supply *psy, 33static 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
47static 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
45static int test_power_get_battery_property(struct power_supply *psy, 61static 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
119static char *test_power_ac_supplied_to[] = { 143static 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
311static 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
318static 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
278static int param_set_battery_status(const char *key, 324static 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
399static 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
355static struct kernel_param_ops param_ops_ac_online = { 414static 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
419static struct kernel_param_ops param_ops_usb_online = {
420 .set = param_set_usb_online,
421 .get = param_get_usb_online,
422};
423
360static struct kernel_param_ops param_ops_battery_status = { 424static 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
449static 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
394module_param(ac_online, ac_online, 0644); 464module_param(ac_online, ac_online, 0644);
395MODULE_PARM_DESC(ac_online, "AC charging state <on|off>"); 465MODULE_PARM_DESC(ac_online, "AC charging state <on|off>");
396 466
467module_param(usb_online, usb_online, 0644);
468MODULE_PARM_DESC(usb_online, "USB charging state <on|off>");
469
397module_param(battery_status, battery_status, 0644); 470module_param(battery_status, battery_status, 0644);
398MODULE_PARM_DESC(battery_status, 471MODULE_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,
413module_param(battery_capacity, battery_capacity, 0644); 486module_param(battery_capacity, battery_capacity, 0644);
414MODULE_PARM_DESC(battery_capacity, "battery capacity (percentage)"); 487MODULE_PARM_DESC(battery_capacity, "battery capacity (percentage)");
415 488
489module_param(battery_voltage, battery_voltage, 0644);
490MODULE_PARM_DESC(battery_voltage, "battery voltage (millivolts)");
416 491
417MODULE_DESCRIPTION("Power supply driver for testing"); 492MODULE_DESCRIPTION("Power supply driver for testing");
418MODULE_AUTHOR("Anton Vorontsov <cbouatmailru@gmail.com>"); 493MODULE_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
105static int twl4030_clear_set_boot_bci(u8 clear, u8 set) 120static 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 */
157static int twl4030_charger_enable_usb(struct twl4030_bci *bci, bool enable) 172static 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 */
233static 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 */
208static irqreturn_t twl4030_charger_interrupt(int irq, void *arg) 276static irqreturn_t twl4030_charger_interrupt(int irq, void *arg)
@@ -425,6 +493,7 @@ static enum power_supply_property twl4030_charger_props[] = {
425static int __init twl4030_bci_probe(struct platform_device *pdev) 493static 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,