aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/power/bq27x00_battery.c
diff options
context:
space:
mode:
authorLars-Peter Clausen <lars@metafoo.de>2011-01-07 14:12:47 -0500
committerLars-Peter Clausen <lars@metafoo.de>2011-02-22 05:02:43 -0500
commit297a533b3e621be520d44d8baf3bb72ce15c4110 (patch)
tree4fa3bd12e2ef2eb731a81670e7dfe9fc85bdc0b4 /drivers/power/bq27x00_battery.c
parent7fb7ba588c0f276609609565b21fcc853284a9a0 (diff)
bq27x00: Cache battery registers
This patch adds a register cache to the bq27x00 battery driver. Usually multiple, if not all, power_supply properties are queried at once, for example when an uevent is generated. Since some registers are used by multiple properties caching the registers should reduce the number of reads. The cache is valid for 5 seconds this roughly matches the internal update interval of the current register for the bq27000/bq27200. Fast changing properties(*_NOW) which can be obtained by reading a single register are not cached. It will also be used in the follow up patch to check if the battery status has been changed since the last update to emit power_supply_changed events. Signed-off-by: Lars-Peter Clausen <lars@metafoo.de> Tested-by: Grazvydas Ignotas <notasas@gmail.com>
Diffstat (limited to 'drivers/power/bq27x00_battery.c')
-rw-r--r--drivers/power/bq27x00_battery.c271
1 files changed, 150 insertions, 121 deletions
diff --git a/drivers/power/bq27x00_battery.c b/drivers/power/bq27x00_battery.c
index 44bc76be0780..dbe3fcb3b0ba 100644
--- a/drivers/power/bq27x00_battery.c
+++ b/drivers/power/bq27x00_battery.c
@@ -51,17 +51,30 @@
51 51
52struct bq27x00_device_info; 52struct bq27x00_device_info;
53struct bq27x00_access_methods { 53struct bq27x00_access_methods {
54 int (*read)(struct bq27x00_device_info *, u8 reg, int *rt_value, 54 int (*read)(struct bq27x00_device_info *di, u8 reg, bool single);
55 bool single);
56}; 55};
57 56
58enum bq27x00_chip { BQ27000, BQ27500 }; 57enum bq27x00_chip { BQ27000, BQ27500 };
59 58
59struct bq27x00_reg_cache {
60 int temperature;
61 int time_to_empty;
62 int time_to_empty_avg;
63 int time_to_full;
64 int capacity;
65 int flags;
66
67 int current_now;
68};
69
60struct bq27x00_device_info { 70struct bq27x00_device_info {
61 struct device *dev; 71 struct device *dev;
62 int id; 72 int id;
63 enum bq27x00_chip chip; 73 enum bq27x00_chip chip;
64 74
75 struct bq27x00_reg_cache cache;
76 unsigned long last_update;
77
65 struct power_supply bat; 78 struct power_supply bat;
66 79
67 struct bq27x00_access_methods bus; 80 struct bq27x00_access_methods bus;
@@ -85,48 +98,93 @@ static enum power_supply_property bq27x00_battery_props[] = {
85 */ 98 */
86 99
87static inline int bq27x00_read(struct bq27x00_device_info *di, u8 reg, 100static inline int bq27x00_read(struct bq27x00_device_info *di, u8 reg,
88 int *rt_value, bool single) 101 bool single)
89{ 102{
90 return di->bus.read(di, reg, rt_value, single); 103 return di->bus.read(di, reg, single);
91} 104}
92 105
93/* 106/*
94 * Return the battery temperature in tenths of degree Celsius 107 * Return the battery Relative State-of-Charge
95 * Or < 0 if something fails. 108 * Or < 0 if something fails.
96 */ 109 */
97static int bq27x00_battery_temperature(struct bq27x00_device_info *di) 110static int bq27x00_battery_read_rsoc(struct bq27x00_device_info *di)
98{ 111{
99 int ret; 112 int rsoc;
100 int temp = 0;
101
102 ret = bq27x00_read(di, BQ27x00_REG_TEMP, &temp, false);
103 if (ret) {
104 dev_err(di->dev, "error reading temperature\n");
105 return ret;
106 }
107 113
108 if (di->chip == BQ27500) 114 if (di->chip == BQ27500)
109 return temp - 2731; 115 rsoc = bq27x00_read(di, BQ27500_REG_SOC, false);
110 else 116 else
111 return ((temp * 5) - 5463) / 2; 117 rsoc = bq27x00_read(di, BQ27000_REG_RSOC, true);
118
119 if (rsoc < 0)
120 dev_err(di->dev, "error reading relative State-of-Charge\n");
121
122 return rsoc;
112} 123}
113 124
114/* 125/*
115 * Return the battery Voltage in milivolts 126 * Read a time register.
116 * Or < 0 if something fails. 127 * Return < 0 if something fails.
117 */ 128 */
118static int bq27x00_battery_voltage(struct bq27x00_device_info *di) 129static int bq27x00_battery_read_time(struct bq27x00_device_info *di, u8 reg)
119{ 130{
120 int ret; 131 int tval;
121 int volt = 0;
122 132
123 ret = bq27x00_read(di, BQ27x00_REG_VOLT, &volt, false); 133 tval = bq27x00_read(di, reg, false);
124 if (ret) { 134 if (tval < 0) {
125 dev_err(di->dev, "error reading voltage\n"); 135 dev_err(di->dev, "error reading register %02x: %d\n", reg, tval);
126 return ret; 136 return tval;
127 } 137 }
128 138
129 return volt * 1000; 139 if (tval == 65535)
140 return -ENODATA;
141
142 return tval * 60;
143}
144
145static void bq27x00_update(struct bq27x00_device_info *di)
146{
147 struct bq27x00_reg_cache cache = {0, };
148 bool is_bq27500 = di->chip == BQ27500;
149
150 cache.flags = bq27x00_read(di, BQ27x00_REG_FLAGS, is_bq27500);
151 if (cache.flags >= 0) {
152 cache.capacity = bq27x00_battery_read_rsoc(di);
153 cache.temperature = bq27x00_read(di, BQ27x00_REG_TEMP, false);
154 cache.time_to_empty = bq27x00_battery_read_time(di, BQ27x00_REG_TTE);
155 cache.time_to_empty_avg = bq27x00_battery_read_time(di, BQ27x00_REG_TTECP);
156 cache.time_to_full = bq27x00_battery_read_time(di, BQ27x00_REG_TTF);
157
158 if (!is_bq27500)
159 cache.current_now = bq27x00_read(di, BQ27x00_REG_AI, false);
160 }
161
162 /* Ignore current_now which is a snapshot of the current battery state
163 * and is likely to be different even between two consecutive reads */
164 if (memcmp(&di->cache, &cache, sizeof(cache) - sizeof(int)) != 0) {
165 di->cache = cache;
166 power_supply_changed(&di->bat);
167 }
168
169 di->last_update = jiffies;
170}
171
172/*
173 * Return the battery temperature in tenths of degree Celsius
174 * Or < 0 if something fails.
175 */
176static int bq27x00_battery_temperature(struct bq27x00_device_info *di,
177 union power_supply_propval *val)
178{
179 if (di->cache.temperature < 0)
180 return di->cache.temperature;
181
182 if (di->chip == BQ27500)
183 val->intval = di->cache.temperature - 2731;
184 else
185 val->intval = ((di->cache.temperature * 5) - 5463) / 2;
186
187 return 0;
130} 188}
131 189
132/* 190/*
@@ -134,109 +192,84 @@ static int bq27x00_battery_voltage(struct bq27x00_device_info *di)
134 * Note that current can be negative signed as well 192 * Note that current can be negative signed as well
135 * Or 0 if something fails. 193 * Or 0 if something fails.
136 */ 194 */
137static int bq27x00_battery_current(struct bq27x00_device_info *di) 195static int bq27x00_battery_current(struct bq27x00_device_info *di,
196 union power_supply_propval *val)
138{ 197{
139 int ret; 198 int curr;
140 int curr = 0;
141 int flags = 0;
142 199
143 ret = bq27x00_read(di, BQ27x00_REG_AI, &curr, false); 200 if (di->chip == BQ27500)
144 if (ret) { 201 curr = bq27x00_read(di, BQ27x00_REG_AI, false);
145 dev_err(di->dev, "error reading current\n"); 202 else
146 return 0; 203 curr = di->cache.current_now;
147 } 204
205 if (curr < 0)
206 return curr;
148 207
149 if (di->chip == BQ27500) { 208 if (di->chip == BQ27500) {
150 /* bq27500 returns signed value */ 209 /* bq27500 returns signed value */
151 curr = (int)((s16)curr) * 1000; 210 val->intval = (int)((s16)curr) * 1000;
152 } else { 211 } else {
153 ret = bq27x00_read(di, BQ27x00_REG_FLAGS, &flags, false); 212 if (di->cache.flags & BQ27000_FLAG_CHGS) {
154 if (ret < 0) {
155 dev_err(di->dev, "error reading flags\n");
156 return 0;
157 }
158 if (flags & BQ27000_FLAG_CHGS) {
159 dev_dbg(di->dev, "negative current!\n"); 213 dev_dbg(di->dev, "negative current!\n");
160 curr = -curr; 214 curr = -curr;
161 } 215 }
162 curr = curr * 3570 / BQ27000_RS;
163 }
164
165 return curr;
166}
167
168/*
169 * Return the battery Relative State-of-Charge
170 * Or < 0 if something fails.
171 */
172static int bq27x00_battery_rsoc(struct bq27x00_device_info *di)
173{
174 int ret;
175 int rsoc = 0;
176 216
177 if (di->chip == BQ27500) 217 val->intval = curr * 3570 / BQ27000_RS;
178 ret = bq27x00_read(di, BQ27500_REG_SOC, &rsoc, false);
179 else
180 ret = bq27x00_read(di, BQ27000_REG_RSOC, &rsoc, true);
181 if (ret) {
182 dev_err(di->dev, "error reading relative State-of-Charge\n");
183 return ret;
184 } 218 }
185 219
186 return rsoc; 220 return 0;
187} 221}
188 222
189static int bq27x00_battery_status(struct bq27x00_device_info *di, 223static int bq27x00_battery_status(struct bq27x00_device_info *di,
190 union power_supply_propval *val) 224 union power_supply_propval *val)
191{ 225{
192 int flags = 0;
193 int status; 226 int status;
194 int ret;
195
196 ret = bq27x00_read(di, BQ27x00_REG_FLAGS, &flags, false);
197 if (ret < 0) {
198 dev_err(di->dev, "error reading flags\n");
199 return ret;
200 }
201 227
202 if (di->chip == BQ27500) { 228 if (di->chip == BQ27500) {
203 if (flags & BQ27500_FLAG_FC) 229 if (di->cache.flags & BQ27500_FLAG_FC)
204 status = POWER_SUPPLY_STATUS_FULL; 230 status = POWER_SUPPLY_STATUS_FULL;
205 else if (flags & BQ27500_FLAG_DSC) 231 else if (di->cache.flags & BQ27500_FLAG_DSC)
206 status = POWER_SUPPLY_STATUS_DISCHARGING; 232 status = POWER_SUPPLY_STATUS_DISCHARGING;
207 else 233 else
208 status = POWER_SUPPLY_STATUS_CHARGING; 234 status = POWER_SUPPLY_STATUS_CHARGING;
209 } else { 235 } else {
210 if (flags & BQ27000_FLAG_CHGS) 236 if (di->cache.flags & BQ27000_FLAG_CHGS)
211 status = POWER_SUPPLY_STATUS_CHARGING; 237 status = POWER_SUPPLY_STATUS_CHARGING;
212 else 238 else
213 status = POWER_SUPPLY_STATUS_DISCHARGING; 239 status = POWER_SUPPLY_STATUS_DISCHARGING;
214 } 240 }
215 241
216 val->intval = status; 242 val->intval = status;
243
217 return 0; 244 return 0;
218} 245}
219 246
220/* 247/*
221 * Read a time register. 248 * Return the battery Voltage in milivolts
222 * Return < 0 if something fails. 249 * Or < 0 if something fails.
223 */ 250 */
224static int bq27x00_battery_time(struct bq27x00_device_info *di, int reg, 251static int bq27x00_battery_voltage(struct bq27x00_device_info *di,
225 union power_supply_propval *val) 252 union power_supply_propval *val)
226{ 253{
227 int tval = 0; 254 int volt;
228 int ret;
229 255
230 ret = bq27x00_read(di, reg, &tval, false); 256 volt = bq27x00_read(di, BQ27x00_REG_VOLT, false);
231 if (ret) { 257 if (volt < 0)
232 dev_err(di->dev, "error reading register %02x\n", reg); 258 return volt;
233 return ret;
234 }
235 259
236 if (tval == 65535) 260 val->intval = volt * 1000;
237 return -ENODATA; 261
262 return 0;
263}
264
265static int bq27x00_simple_value(int value,
266 union power_supply_propval *val)
267{
268 if (value < 0)
269 return value;
270
271 val->intval = value;
238 272
239 val->intval = tval * 60;
240 return 0; 273 return 0;
241} 274}
242 275
@@ -249,9 +282,11 @@ static int bq27x00_battery_get_property(struct power_supply *psy,
249{ 282{
250 int ret = 0; 283 int ret = 0;
251 struct bq27x00_device_info *di = to_bq27x00_device_info(psy); 284 struct bq27x00_device_info *di = to_bq27x00_device_info(psy);
252 int voltage = bq27x00_battery_voltage(di);
253 285
254 if (psp != POWER_SUPPLY_PROP_PRESENT && voltage <= 0) 286 if (time_is_before_jiffies(di->last_update + 5 * HZ))
287 bq27x00_update(di);
288
289 if (psp != POWER_SUPPLY_PROP_PRESENT && di->cache.flags < 0)
255 return -ENODEV; 290 return -ENODEV;
256 291
257 switch (psp) { 292 switch (psp) {
@@ -259,29 +294,28 @@ static int bq27x00_battery_get_property(struct power_supply *psy,
259 ret = bq27x00_battery_status(di, val); 294 ret = bq27x00_battery_status(di, val);
260 break; 295 break;
261 case POWER_SUPPLY_PROP_VOLTAGE_NOW: 296 case POWER_SUPPLY_PROP_VOLTAGE_NOW:
262 val->intval = voltage; 297 ret = bq27x00_battery_voltage(di, val);
263 break; 298 break;
264 case POWER_SUPPLY_PROP_PRESENT: 299 case POWER_SUPPLY_PROP_PRESENT:
265 if (psp == POWER_SUPPLY_PROP_PRESENT) 300 val->intval = di->cache.flags < 0 ? 0 : 1;
266 val->intval = voltage <= 0 ? 0 : 1;
267 break; 301 break;
268 case POWER_SUPPLY_PROP_CURRENT_NOW: 302 case POWER_SUPPLY_PROP_CURRENT_NOW:
269 val->intval = bq27x00_battery_current(di); 303 ret = bq27x00_battery_current(di, val);
270 break; 304 break;
271 case POWER_SUPPLY_PROP_CAPACITY: 305 case POWER_SUPPLY_PROP_CAPACITY:
272 val->intval = bq27x00_battery_rsoc(di); 306 ret = bq27x00_simple_value(di->cache.capacity, val);
273 break; 307 break;
274 case POWER_SUPPLY_PROP_TEMP: 308 case POWER_SUPPLY_PROP_TEMP:
275 val->intval = bq27x00_battery_temperature(di); 309 ret = bq27x00_battery_temperature(di, val);
276 break; 310 break;
277 case POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW: 311 case POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW:
278 ret = bq27x00_battery_time(di, BQ27x00_REG_TTE, val); 312 ret = bq27x00_simple_value(di->cache.time_to_empty, val);
279 break; 313 break;
280 case POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG: 314 case POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG:
281 ret = bq27x00_battery_time(di, BQ27x00_REG_TTECP, val); 315 ret = bq27x00_simple_value(di->cache.time_to_empty_avg, val);
282 break; 316 break;
283 case POWER_SUPPLY_PROP_TIME_TO_FULL_NOW: 317 case POWER_SUPPLY_PROP_TIME_TO_FULL_NOW:
284 ret = bq27x00_battery_time(di, BQ27x00_REG_TTF, val); 318 ret = bq27x00_simple_value(di->cache.time_to_full, val);
285 break; 319 break;
286 case POWER_SUPPLY_PROP_TECHNOLOGY: 320 case POWER_SUPPLY_PROP_TECHNOLOGY:
287 val->intval = POWER_SUPPLY_TECHNOLOGY_LION; 321 val->intval = POWER_SUPPLY_TECHNOLOGY_LION;
@@ -311,6 +345,8 @@ static int bq27x00_powersupply_init(struct bq27x00_device_info *di)
311 345
312 dev_info(di->dev, "support ver. %s enabled\n", DRIVER_VERSION); 346 dev_info(di->dev, "support ver. %s enabled\n", DRIVER_VERSION);
313 347
348 bq27x00_update(di);
349
314 return 0; 350 return 0;
315} 351}
316 352
@@ -324,13 +360,12 @@ static int bq27x00_powersupply_init(struct bq27x00_device_info *di)
324static DEFINE_IDR(battery_id); 360static DEFINE_IDR(battery_id);
325static DEFINE_MUTEX(battery_mutex); 361static DEFINE_MUTEX(battery_mutex);
326 362
327static int bq27x00_read_i2c(struct bq27x00_device_info *di, u8 reg, 363static int bq27x00_read_i2c(struct bq27x00_device_info *di, u8 reg, bool single)
328 int *rt_value, bool single)
329{ 364{
330 struct i2c_client *client = to_i2c_client(di->dev); 365 struct i2c_client *client = to_i2c_client(di->dev);
331 struct i2c_msg msg[1]; 366 struct i2c_msg msg[1];
332 unsigned char data[2]; 367 unsigned char data[2];
333 int err; 368 int ret;
334 369
335 if (!client->adapter) 370 if (!client->adapter)
336 return -ENODEV; 371 return -ENODEV;
@@ -341,26 +376,24 @@ static int bq27x00_read_i2c(struct bq27x00_device_info *di, u8 reg,
341 msg->buf = data; 376 msg->buf = data;
342 377
343 data[0] = reg; 378 data[0] = reg;
344 err = i2c_transfer(client->adapter, msg, 1); 379 ret = i2c_transfer(client->adapter, msg, 1);
345 380
346 if (err >= 0) { 381 if (ret >= 0) {
347 if (!single) 382 if (!single)
348 msg->len = 2; 383 msg->len = 2;
349 else 384 else
350 msg->len = 1; 385 msg->len = 1;
351 386
352 msg->flags = I2C_M_RD; 387 msg->flags = I2C_M_RD;
353 err = i2c_transfer(client->adapter, msg, 1); 388 ret = i2c_transfer(client->adapter, msg, 1);
354 if (err >= 0) { 389 if (ret >= 0) {
355 if (!single) 390 if (!single)
356 *rt_value = get_unaligned_le16(data); 391 ret = get_unaligned_le16(data);
357 else 392 else
358 *rt_value = data[0]; 393 ret = data[0];
359
360 return 0;
361 } 394 }
362 } 395 }
363 return err; 396 return ret;
364} 397}
365 398
366static int bq27x00_battery_probe(struct i2c_client *client, 399static int bq27x00_battery_probe(struct i2c_client *client,
@@ -477,7 +510,7 @@ static inline void bq27x00_battery_i2c_exit(void) {};
477#ifdef CONFIG_BATTERY_BQ27X00_PLATFORM 510#ifdef CONFIG_BATTERY_BQ27X00_PLATFORM
478 511
479static int bq27000_read_platform(struct bq27x00_device_info *di, u8 reg, 512static int bq27000_read_platform(struct bq27x00_device_info *di, u8 reg,
480 int *rt_value, bool single) 513 bool single)
481{ 514{
482 struct device *dev = di->dev; 515 struct device *dev = di->dev;
483 struct bq27000_platform_data *pdata = dev->platform_data; 516 struct bq27000_platform_data *pdata = dev->platform_data;
@@ -504,14 +537,10 @@ static int bq27000_read_platform(struct bq27x00_device_info *di, u8 reg,
504 if (timeout == 0) 537 if (timeout == 0)
505 return -EIO; 538 return -EIO;
506 539
507 *rt_value = (upper << 8) | lower; 540 return (upper << 8) | lower;
508 } else {
509 lower = pdata->read(dev, reg);
510 if (lower < 0)
511 return lower;
512 *rt_value = lower;
513 } 541 }
514 return 0; 542
543 return pdata->read(dev, reg);
515} 544}
516 545
517static int __devinit bq27000_battery_probe(struct platform_device *pdev) 546static int __devinit bq27000_battery_probe(struct platform_device *pdev)