aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/power/Kconfig8
-rw-r--r--drivers/power/Makefile1
-rw-r--r--drivers/power/ltc2941-battery-gauge.c547
3 files changed, 556 insertions, 0 deletions
diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig
index a79f16afb588..27b751b995fb 100644
--- a/drivers/power/Kconfig
+++ b/drivers/power/Kconfig
@@ -388,6 +388,14 @@ config CHARGER_TPS65090
388 Say Y here to enable support for battery charging with TPS65090 388 Say Y here to enable support for battery charging with TPS65090
389 PMIC chips. 389 PMIC chips.
390 390
391config BATTERY_GAUGE_LTC2941
392 tristate "LTC2941/LTC2943 Battery Gauge Driver"
393 depends on I2C
394 help
395 Say Y here to include support for LTC2941 and LTC2943 Battery
396 Gauge IC. The driver reports the charge count continuously, and
397 measures the voltage and temperature every 10 seconds.
398
391config AB8500_BM 399config AB8500_BM
392 bool "AB8500 Battery Management Driver" 400 bool "AB8500 Battery Management Driver"
393 depends on AB8500_CORE && AB8500_GPADC 401 depends on AB8500_CORE && AB8500_GPADC
diff --git a/drivers/power/Makefile b/drivers/power/Makefile
index 31216cb7e8a1..36f9e0d10111 100644
--- a/drivers/power/Makefile
+++ b/drivers/power/Makefile
@@ -20,6 +20,7 @@ obj-$(CONFIG_BATTERY_DS2760) += ds2760_battery.o
20obj-$(CONFIG_BATTERY_DS2780) += ds2780_battery.o 20obj-$(CONFIG_BATTERY_DS2780) += ds2780_battery.o
21obj-$(CONFIG_BATTERY_DS2781) += ds2781_battery.o 21obj-$(CONFIG_BATTERY_DS2781) += ds2781_battery.o
22obj-$(CONFIG_BATTERY_DS2782) += ds2782_battery.o 22obj-$(CONFIG_BATTERY_DS2782) += ds2782_battery.o
23obj-$(CONFIG_BATTERY_GAUGE_LTC2941) += ltc2941-battery-gauge.o
23obj-$(CONFIG_BATTERY_GOLDFISH) += goldfish_battery.o 24obj-$(CONFIG_BATTERY_GOLDFISH) += goldfish_battery.o
24obj-$(CONFIG_BATTERY_PMU) += pmu_battery.o 25obj-$(CONFIG_BATTERY_PMU) += pmu_battery.o
25obj-$(CONFIG_BATTERY_OLPC) += olpc_battery.o 26obj-$(CONFIG_BATTERY_OLPC) += olpc_battery.o
diff --git a/drivers/power/ltc2941-battery-gauge.c b/drivers/power/ltc2941-battery-gauge.c
new file mode 100644
index 000000000000..e31c927a6d16
--- /dev/null
+++ b/drivers/power/ltc2941-battery-gauge.c
@@ -0,0 +1,547 @@
1/*
2 * I2C client/driver for the Linear Technology LTC2941 and LTC2943
3 * Battery Gas Gauge IC
4 *
5 * Copyright (C) 2014 Topic Embedded Systems
6 *
7 * Author: Auryn Verwegen
8 * Author: Mike Looijmans
9 */
10#include <linux/kernel.h>
11#include <linux/module.h>
12#include <linux/types.h>
13#include <linux/errno.h>
14#include <linux/swab.h>
15#include <linux/i2c.h>
16#include <linux/delay.h>
17#include <linux/idr.h>
18#include <linux/power_supply.h>
19#include <linux/slab.h>
20
21#define I16_MSB(x) ((x >> 8) & 0xFF)
22#define I16_LSB(x) (x & 0xFF)
23
24#define LTC294X_WORK_DELAY 10 /* Update delay in seconds */
25
26#define LTC294X_MAX_VALUE 0xFFFF
27#define LTC294X_MID_SUPPLY 0x7FFF
28
29#define LTC2941_MAX_PRESCALER_EXP 7
30#define LTC2943_MAX_PRESCALER_EXP 6
31
32enum ltc294x_reg {
33 LTC294X_REG_STATUS = 0x00,
34 LTC294X_REG_CONTROL = 0x01,
35 LTC294X_REG_ACC_CHARGE_MSB = 0x02,
36 LTC294X_REG_ACC_CHARGE_LSB = 0x03,
37 LTC294X_REG_THRESH_HIGH_MSB = 0x04,
38 LTC294X_REG_THRESH_HIGH_LSB = 0x05,
39 LTC294X_REG_THRESH_LOW_MSB = 0x06,
40 LTC294X_REG_THRESH_LOW_LSB = 0x07,
41 LTC294X_REG_VOLTAGE_MSB = 0x08,
42 LTC294X_REG_VOLTAGE_LSB = 0x09,
43 LTC294X_REG_CURRENT_MSB = 0x0E,
44 LTC294X_REG_CURRENT_LSB = 0x0F,
45 LTC294X_REG_TEMPERATURE_MSB = 0x14,
46 LTC294X_REG_TEMPERATURE_LSB = 0x15,
47};
48
49#define LTC2943_REG_CONTROL_MODE_MASK (BIT(7) | BIT(6))
50#define LTC2943_REG_CONTROL_MODE_SCAN BIT(7)
51#define LTC294X_REG_CONTROL_PRESCALER_MASK (BIT(5) | BIT(4) | BIT(3))
52#define LTC294X_REG_CONTROL_SHUTDOWN_MASK (BIT(0))
53#define LTC294X_REG_CONTROL_PRESCALER_SET(x) \
54 ((x << 3) & LTC294X_REG_CONTROL_PRESCALER_MASK)
55#define LTC294X_REG_CONTROL_ALCC_CONFIG_DISABLED 0
56
57#define LTC2941_NUM_REGS 0x08
58#define LTC2943_NUM_REGS 0x18
59
60struct ltc294x_info {
61 struct i2c_client *client; /* I2C Client pointer */
62 struct power_supply supply; /* Supply pointer */
63 struct delayed_work work; /* Work scheduler */
64 int num_regs; /* Number of registers (chip type) */
65 int id; /* Identifier of ltc294x chip */
66 int charge; /* Last charge register content */
67 int r_sense; /* mOhm */
68 int Qlsb; /* nAh */
69};
70
71static DEFINE_IDR(ltc294x_id);
72static DEFINE_MUTEX(ltc294x_lock);
73
74static inline int convert_bin_to_uAh(
75 const struct ltc294x_info *info, int Q)
76{
77 return ((Q * (info->Qlsb / 10))) / 100;
78}
79
80static inline int convert_uAh_to_bin(
81 const struct ltc294x_info *info, int uAh)
82{
83 int Q;
84
85 Q = (uAh * 100) / (info->Qlsb/10);
86 return (Q < LTC294X_MAX_VALUE) ? Q : LTC294X_MAX_VALUE;
87}
88
89static int ltc294x_read_regs(struct i2c_client *client,
90 enum ltc294x_reg reg, u8 *buf, int num_regs)
91{
92 int ret;
93 struct i2c_msg msgs[2] = { };
94 u8 reg_start = reg;
95
96 msgs[0].addr = client->addr;
97 msgs[0].len = 1;
98 msgs[0].buf = &reg_start;
99
100 msgs[1].addr = client->addr;
101 msgs[1].len = num_regs;
102 msgs[1].buf = buf;
103 msgs[1].flags = I2C_M_RD;
104
105 ret = i2c_transfer(client->adapter, &msgs[0], 2);
106 if (ret < 0) {
107 dev_err(&client->dev, "ltc2941 read_reg failed!\n");
108 return ret;
109 }
110
111 dev_dbg(&client->dev, "%s (%#x, %d) -> %#x\n",
112 __func__, reg, num_regs, *buf);
113
114 return 0;
115}
116
117static int ltc294x_write_regs(struct i2c_client *client,
118 enum ltc294x_reg reg, const u8 *buf, int num_regs)
119{
120 int ret;
121 u8 reg_start = reg;
122
123 ret = i2c_smbus_write_i2c_block_data(client, reg_start, num_regs, buf);
124 if (ret < 0) {
125 dev_err(&client->dev, "ltc2941 write_reg failed!\n");
126 return ret;
127 }
128
129 dev_dbg(&client->dev, "%s (%#x, %d) -> %#x\n",
130 __func__, reg, num_regs, *buf);
131
132 return 0;
133}
134
135static int ltc294x_reset(const struct ltc294x_info *info, int prescaler_exp)
136{
137 int ret;
138 u8 value;
139 u8 control;
140
141 /* Read status and control registers */
142 ret = ltc294x_read_regs(info->client, LTC294X_REG_CONTROL, &value, 1);
143 if (ret < 0) {
144 dev_err(&info->client->dev,
145 "Could not read registers from device\n");
146 goto error_exit;
147 }
148
149 control = LTC294X_REG_CONTROL_PRESCALER_SET(prescaler_exp) |
150 LTC294X_REG_CONTROL_ALCC_CONFIG_DISABLED;
151 /* Put the 2943 into "monitor" mode, so it measures every 10 sec */
152 if (info->num_regs == LTC2943_NUM_REGS)
153 control |= LTC2943_REG_CONTROL_MODE_SCAN;
154
155 if (value != control) {
156 ret = ltc294x_write_regs(info->client,
157 LTC294X_REG_CONTROL, &control, 1);
158 if (ret < 0) {
159 dev_err(&info->client->dev,
160 "Could not write register\n");
161 goto error_exit;
162 }
163 }
164
165 return 0;
166
167error_exit:
168 return ret;
169}
170
171static int ltc294x_read_charge_register(const struct ltc294x_info *info)
172{
173 int ret;
174 u8 datar[2];
175
176 ret = ltc294x_read_regs(info->client,
177 LTC294X_REG_ACC_CHARGE_MSB, &datar[0], 2);
178 if (ret < 0)
179 return ret;
180 return (datar[0] << 8) + datar[1];
181}
182
183static int ltc294x_get_charge_now(const struct ltc294x_info *info, int *val)
184{
185 int value = ltc294x_read_charge_register(info);
186
187 if (value < 0)
188 return value;
189 /* When r_sense < 0, this counts up when the battery discharges */
190 if (info->Qlsb < 0)
191 value -= 0xFFFF;
192 *val = convert_bin_to_uAh(info, value);
193 return 0;
194}
195
196static int ltc294x_set_charge_now(const struct ltc294x_info *info, int val)
197{
198 int ret;
199 u8 dataw[2];
200 u8 ctrl_reg;
201 s32 value;
202
203 value = convert_uAh_to_bin(info, val);
204 /* Direction depends on how sense+/- were connected */
205 if (info->Qlsb < 0)
206 value += 0xFFFF;
207 if ((value < 0) || (value > 0xFFFF)) /* input validation */
208 return -EINVAL;
209
210 /* Read control register */
211 ret = ltc294x_read_regs(info->client,
212 LTC294X_REG_CONTROL, &ctrl_reg, 1);
213 if (ret < 0)
214 return ret;
215 /* Disable analog section */
216 ctrl_reg |= LTC294X_REG_CONTROL_SHUTDOWN_MASK;
217 ret = ltc294x_write_regs(info->client,
218 LTC294X_REG_CONTROL, &ctrl_reg, 1);
219 if (ret < 0)
220 return ret;
221 /* Set new charge value */
222 dataw[0] = I16_MSB(value);
223 dataw[1] = I16_LSB(value);
224 ret = ltc294x_write_regs(info->client,
225 LTC294X_REG_ACC_CHARGE_MSB, &dataw[0], 2);
226 if (ret < 0)
227 goto error_exit;
228 /* Enable analog section */
229error_exit:
230 ctrl_reg &= ~LTC294X_REG_CONTROL_SHUTDOWN_MASK;
231 ret = ltc294x_write_regs(info->client,
232 LTC294X_REG_CONTROL, &ctrl_reg, 1);
233
234 return ret < 0 ? ret : 0;
235}
236
237static int ltc294x_get_charge_counter(
238 const struct ltc294x_info *info, int *val)
239{
240 int value = ltc294x_read_charge_register(info);
241
242 if (value < 0)
243 return value;
244 value -= LTC294X_MID_SUPPLY;
245 *val = convert_bin_to_uAh(info, value);
246 return 0;
247}
248
249static int ltc294x_get_voltage(const struct ltc294x_info *info, int *val)
250{
251 int ret;
252 u8 datar[2];
253 u32 value;
254
255 ret = ltc294x_read_regs(info->client,
256 LTC294X_REG_VOLTAGE_MSB, &datar[0], 2);
257 value = (datar[0] << 8) | datar[1];
258 *val = ((value * 23600) / 0xFFFF) * 1000; /* in uV */
259 return ret;
260}
261
262static int ltc294x_get_current(const struct ltc294x_info *info, int *val)
263{
264 int ret;
265 u8 datar[2];
266 s32 value;
267
268 ret = ltc294x_read_regs(info->client,
269 LTC294X_REG_CURRENT_MSB, &datar[0], 2);
270 value = (datar[0] << 8) | datar[1];
271 value -= 0x7FFF;
272 /* Value is in range -32k..+32k, r_sense is usually 10..50 mOhm,
273 * the formula below keeps everything in s32 range while preserving
274 * enough digits */
275 *val = 1000 * ((60000 * value) / (info->r_sense * 0x7FFF)); /* in uA */
276 return ret;
277}
278
279static int ltc294x_get_temperature(const struct ltc294x_info *info, int *val)
280{
281 int ret;
282 u8 datar[2];
283 u32 value;
284
285 ret = ltc294x_read_regs(info->client,
286 LTC294X_REG_TEMPERATURE_MSB, &datar[0], 2);
287 value = (datar[0] << 8) | datar[1];
288 /* Full-scale is 510 Kelvin, convert to centidegrees */
289 *val = (((51000 * value) / 0xFFFF) - 27215);
290 return ret;
291}
292
293static int ltc294x_get_property(struct power_supply *psy,
294 enum power_supply_property prop,
295 union power_supply_propval *val)
296{
297 struct ltc294x_info *info =
298 container_of(psy, struct ltc294x_info, supply);
299
300 switch (prop) {
301 case POWER_SUPPLY_PROP_CHARGE_NOW:
302 return ltc294x_get_charge_now(info, &val->intval);
303 case POWER_SUPPLY_PROP_CHARGE_COUNTER:
304 return ltc294x_get_charge_counter(info, &val->intval);
305 case POWER_SUPPLY_PROP_VOLTAGE_NOW:
306 return ltc294x_get_voltage(info, &val->intval);
307 case POWER_SUPPLY_PROP_CURRENT_NOW:
308 return ltc294x_get_current(info, &val->intval);
309 case POWER_SUPPLY_PROP_TEMP:
310 return ltc294x_get_temperature(info, &val->intval);
311 default:
312 return -EINVAL;
313 }
314}
315
316static int ltc294x_set_property(struct power_supply *psy,
317 enum power_supply_property psp,
318 const union power_supply_propval *val)
319{
320 struct ltc294x_info *info =
321 container_of(psy, struct ltc294x_info, supply);
322
323 switch (psp) {
324 case POWER_SUPPLY_PROP_CHARGE_NOW:
325 return ltc294x_set_charge_now(info, val->intval);
326 default:
327 return -EPERM;
328 }
329}
330
331static int ltc294x_property_is_writeable(
332 struct power_supply *psy, enum power_supply_property psp)
333{
334 switch (psp) {
335 case POWER_SUPPLY_PROP_CHARGE_NOW:
336 return 1;
337 default:
338 return 0;
339 }
340}
341
342static void ltc294x_update(struct ltc294x_info *info)
343{
344 int charge = ltc294x_read_charge_register(info);
345
346 if (charge != info->charge) {
347 info->charge = charge;
348 power_supply_changed(&info->supply);
349 }
350}
351
352static void ltc294x_work(struct work_struct *work)
353{
354 struct ltc294x_info *info;
355
356 info = container_of(work, struct ltc294x_info, work.work);
357 ltc294x_update(info);
358 schedule_delayed_work(&info->work, LTC294X_WORK_DELAY * HZ);
359}
360
361static enum power_supply_property ltc294x_properties[] = {
362 POWER_SUPPLY_PROP_CHARGE_COUNTER,
363 POWER_SUPPLY_PROP_CHARGE_NOW,
364 POWER_SUPPLY_PROP_VOLTAGE_NOW,
365 POWER_SUPPLY_PROP_CURRENT_NOW,
366 POWER_SUPPLY_PROP_TEMP,
367};
368
369static int ltc294x_i2c_remove(struct i2c_client *client)
370{
371 struct ltc294x_info *info = i2c_get_clientdata(client);
372
373 cancel_delayed_work(&info->work);
374 power_supply_unregister(&info->supply);
375 kfree(info->supply.name);
376 mutex_lock(&ltc294x_lock);
377 idr_remove(&ltc294x_id, info->id);
378 mutex_unlock(&ltc294x_lock);
379 return 0;
380}
381
382static int ltc294x_i2c_probe(struct i2c_client *client,
383 const struct i2c_device_id *id)
384{
385 struct ltc294x_info *info;
386 int ret;
387 int num;
388 u32 prescaler_exp;
389 s32 r_sense;
390 struct device_node *np;
391
392 mutex_lock(&ltc294x_lock);
393 ret = idr_alloc(&ltc294x_id, client, 0, 0, GFP_KERNEL);
394 mutex_unlock(&ltc294x_lock);
395 if (ret < 0)
396 goto fail_id;
397
398 num = ret;
399
400 info = devm_kzalloc(&client->dev, sizeof(*info), GFP_KERNEL);
401 if (info == NULL) {
402 ret = -ENOMEM;
403 goto fail_info;
404 }
405
406 i2c_set_clientdata(client, info);
407
408 info->num_regs = id->driver_data;
409 info->supply.name = kasprintf(GFP_KERNEL, "%s-%d", client->name, num);
410 if (!info->supply.name) {
411 ret = -ENOMEM;
412 goto fail_name;
413 }
414
415 np = of_node_get(client->dev.of_node);
416
417 /* r_sense can be negative, when sense+ is connected to the battery
418 * instead of the sense-. This results in reversed measurements. */
419 ret = of_property_read_u32(np, "lltc,resistor-sense", &r_sense);
420 if (ret < 0) {
421 dev_err(&client->dev,
422 "Could not find lltc,resistor-sense in devicetree\n");
423 goto fail_name;
424 }
425 info->r_sense = r_sense;
426
427 ret = of_property_read_u32(np, "lltc,prescaler-exponent",
428 &prescaler_exp);
429 if (ret < 0) {
430 dev_warn(&client->dev,
431 "lltc,prescaler-exponent not in devicetree\n");
432 prescaler_exp = LTC2941_MAX_PRESCALER_EXP;
433 }
434
435 if (info->num_regs == LTC2943_NUM_REGS) {
436 if (prescaler_exp > LTC2943_MAX_PRESCALER_EXP)
437 prescaler_exp = LTC2943_MAX_PRESCALER_EXP;
438 info->Qlsb = ((340 * 50000) / r_sense) /
439 (4096 / (1 << (2*prescaler_exp)));
440 } else {
441 if (prescaler_exp > LTC2941_MAX_PRESCALER_EXP)
442 prescaler_exp = LTC2941_MAX_PRESCALER_EXP;
443 info->Qlsb = ((58 * 50000) / r_sense) /
444 (128 / (1 << prescaler_exp));
445 }
446
447 info->client = client;
448 info->id = num;
449 info->supply.type = POWER_SUPPLY_TYPE_BATTERY;
450 info->supply.properties = ltc294x_properties;
451 if (info->num_regs >= LTC294X_REG_TEMPERATURE_LSB)
452 info->supply.num_properties =
453 ARRAY_SIZE(ltc294x_properties);
454 else if (info->num_regs >= LTC294X_REG_CURRENT_LSB)
455 info->supply.num_properties =
456 ARRAY_SIZE(ltc294x_properties) - 1;
457 else if (info->num_regs >= LTC294X_REG_VOLTAGE_LSB)
458 info->supply.num_properties =
459 ARRAY_SIZE(ltc294x_properties) - 2;
460 else
461 info->supply.num_properties =
462 ARRAY_SIZE(ltc294x_properties) - 3;
463 info->supply.get_property = ltc294x_get_property;
464 info->supply.set_property = ltc294x_set_property;
465 info->supply.property_is_writeable = ltc294x_property_is_writeable;
466 info->supply.external_power_changed = NULL;
467
468 INIT_DELAYED_WORK(&info->work, ltc294x_work);
469
470 ret = ltc294x_reset(info, prescaler_exp);
471 if (ret < 0) {
472 dev_err(&client->dev, "Communication with chip failed\n");
473 goto fail_comm;
474 }
475
476 ret = power_supply_register(&client->dev, &info->supply);
477 if (ret) {
478 dev_err(&client->dev, "failed to register ltc2941\n");
479 goto fail_register;
480 } else {
481 schedule_delayed_work(&info->work, LTC294X_WORK_DELAY * HZ);
482 }
483
484 return 0;
485
486fail_register:
487 kfree(info->supply.name);
488fail_comm:
489fail_name:
490fail_info:
491 mutex_lock(&ltc294x_lock);
492 idr_remove(&ltc294x_id, num);
493 mutex_unlock(&ltc294x_lock);
494fail_id:
495 return ret;
496}
497
498#ifdef CONFIG_PM_SLEEP
499
500static int ltc294x_suspend(struct device *dev)
501{
502 struct i2c_client *client = to_i2c_client(dev);
503 struct ltc294x_info *info = i2c_get_clientdata(client);
504
505 cancel_delayed_work(&info->work);
506 return 0;
507}
508
509static int ltc294x_resume(struct device *dev)
510{
511 struct i2c_client *client = to_i2c_client(dev);
512 struct ltc294x_info *info = i2c_get_clientdata(client);
513
514 schedule_delayed_work(&info->work, LTC294X_WORK_DELAY * HZ);
515 return 0;
516}
517
518static SIMPLE_DEV_PM_OPS(ltc294x_pm_ops, ltc294x_suspend, ltc294x_resume);
519#define LTC294X_PM_OPS (&ltc294x_pm_ops)
520
521#else
522#define LTC294X_PM_OPS NULL
523#endif /* CONFIG_PM_SLEEP */
524
525
526static const struct i2c_device_id ltc294x_i2c_id[] = {
527 {"ltc2941", LTC2941_NUM_REGS},
528 {"ltc2943", LTC2943_NUM_REGS},
529 { },
530};
531MODULE_DEVICE_TABLE(i2c, ltc294x_i2c_id);
532
533static struct i2c_driver ltc294x_driver = {
534 .driver = {
535 .name = "LTC2941",
536 .pm = LTC294X_PM_OPS,
537 },
538 .probe = ltc294x_i2c_probe,
539 .remove = ltc294x_i2c_remove,
540 .id_table = ltc294x_i2c_id,
541};
542module_i2c_driver(ltc294x_driver);
543
544MODULE_AUTHOR("Auryn Verwegen, Topic Embedded Systems");
545MODULE_AUTHOR("Mike Looijmans, Topic Embedded Products");
546MODULE_DESCRIPTION("LTC2941/LTC2943 Battery Gas Gauge IC driver");
547MODULE_LICENSE("GPL");