diff options
-rw-r--r-- | drivers/power/Kconfig | 8 | ||||
-rw-r--r-- | drivers/power/Makefile | 1 | ||||
-rw-r--r-- | drivers/power/ltc2941-battery-gauge.c | 547 |
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 | ||
391 | config 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 | |||
391 | config AB8500_BM | 399 | config 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 | |||
20 | obj-$(CONFIG_BATTERY_DS2780) += ds2780_battery.o | 20 | obj-$(CONFIG_BATTERY_DS2780) += ds2780_battery.o |
21 | obj-$(CONFIG_BATTERY_DS2781) += ds2781_battery.o | 21 | obj-$(CONFIG_BATTERY_DS2781) += ds2781_battery.o |
22 | obj-$(CONFIG_BATTERY_DS2782) += ds2782_battery.o | 22 | obj-$(CONFIG_BATTERY_DS2782) += ds2782_battery.o |
23 | obj-$(CONFIG_BATTERY_GAUGE_LTC2941) += ltc2941-battery-gauge.o | ||
23 | obj-$(CONFIG_BATTERY_GOLDFISH) += goldfish_battery.o | 24 | obj-$(CONFIG_BATTERY_GOLDFISH) += goldfish_battery.o |
24 | obj-$(CONFIG_BATTERY_PMU) += pmu_battery.o | 25 | obj-$(CONFIG_BATTERY_PMU) += pmu_battery.o |
25 | obj-$(CONFIG_BATTERY_OLPC) += olpc_battery.o | 26 | obj-$(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 | |||
32 | enum 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 | |||
60 | struct 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 | |||
71 | static DEFINE_IDR(ltc294x_id); | ||
72 | static DEFINE_MUTEX(ltc294x_lock); | ||
73 | |||
74 | static inline int convert_bin_to_uAh( | ||
75 | const struct ltc294x_info *info, int Q) | ||
76 | { | ||
77 | return ((Q * (info->Qlsb / 10))) / 100; | ||
78 | } | ||
79 | |||
80 | static 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 | |||
89 | static 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 = ®_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 | |||
117 | static 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 | |||
135 | static 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 | |||
167 | error_exit: | ||
168 | return ret; | ||
169 | } | ||
170 | |||
171 | static 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 | |||
183 | static 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 | |||
196 | static 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 */ | ||
229 | error_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 | |||
237 | static 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 | |||
249 | static 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 | |||
262 | static 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 | |||
279 | static 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 | |||
293 | static 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 | |||
316 | static 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 | |||
331 | static 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 | |||
342 | static 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 | |||
352 | static 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 | |||
361 | static 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 | |||
369 | static 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(<c294x_lock); | ||
377 | idr_remove(<c294x_id, info->id); | ||
378 | mutex_unlock(<c294x_lock); | ||
379 | return 0; | ||
380 | } | ||
381 | |||
382 | static 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(<c294x_lock); | ||
393 | ret = idr_alloc(<c294x_id, client, 0, 0, GFP_KERNEL); | ||
394 | mutex_unlock(<c294x_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 | |||
486 | fail_register: | ||
487 | kfree(info->supply.name); | ||
488 | fail_comm: | ||
489 | fail_name: | ||
490 | fail_info: | ||
491 | mutex_lock(<c294x_lock); | ||
492 | idr_remove(<c294x_id, num); | ||
493 | mutex_unlock(<c294x_lock); | ||
494 | fail_id: | ||
495 | return ret; | ||
496 | } | ||
497 | |||
498 | #ifdef CONFIG_PM_SLEEP | ||
499 | |||
500 | static 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 | |||
509 | static 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 | |||
518 | static SIMPLE_DEV_PM_OPS(ltc294x_pm_ops, ltc294x_suspend, ltc294x_resume); | ||
519 | #define LTC294X_PM_OPS (<c294x_pm_ops) | ||
520 | |||
521 | #else | ||
522 | #define LTC294X_PM_OPS NULL | ||
523 | #endif /* CONFIG_PM_SLEEP */ | ||
524 | |||
525 | |||
526 | static const struct i2c_device_id ltc294x_i2c_id[] = { | ||
527 | {"ltc2941", LTC2941_NUM_REGS}, | ||
528 | {"ltc2943", LTC2943_NUM_REGS}, | ||
529 | { }, | ||
530 | }; | ||
531 | MODULE_DEVICE_TABLE(i2c, ltc294x_i2c_id); | ||
532 | |||
533 | static 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 | }; | ||
542 | module_i2c_driver(ltc294x_driver); | ||
543 | |||
544 | MODULE_AUTHOR("Auryn Verwegen, Topic Embedded Systems"); | ||
545 | MODULE_AUTHOR("Mike Looijmans, Topic Embedded Products"); | ||
546 | MODULE_DESCRIPTION("LTC2941/LTC2943 Battery Gas Gauge IC driver"); | ||
547 | MODULE_LICENSE("GPL"); | ||