aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/power/max17048_battery.c
diff options
context:
space:
mode:
authorJonathan Herman <hermanjl@cs.unc.edu>2013-01-22 10:38:37 -0500
committerJonathan Herman <hermanjl@cs.unc.edu>2013-01-22 10:38:37 -0500
commitfcc9d2e5a6c89d22b8b773a64fb4ad21ac318446 (patch)
treea57612d1888735a2ec7972891b68c1ac5ec8faea /drivers/power/max17048_battery.c
parent8dea78da5cee153b8af9c07a2745f6c55057fe12 (diff)
Added missing tegra files.HEADmaster
Diffstat (limited to 'drivers/power/max17048_battery.c')
-rw-r--r--drivers/power/max17048_battery.c579
1 files changed, 579 insertions, 0 deletions
diff --git a/drivers/power/max17048_battery.c b/drivers/power/max17048_battery.c
new file mode 100644
index 00000000000..44275e329c5
--- /dev/null
+++ b/drivers/power/max17048_battery.c
@@ -0,0 +1,579 @@
1/*
2 * max17048_battery.c
3 * fuel-gauge systems for lithium-ion (Li+) batteries
4 *
5 * Copyright (C) 2012 Nvidia Cooperation
6 * Chandler Zhang <chazhang@nvidia.com>
7 * Syed Rafiuddin <srafiuddin@nvidia.com>
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License version 2 as
11 * published by the Free Software Foundation.
12 */
13
14#include <asm/unaligned.h>
15#include <linux/module.h>
16#include <linux/init.h>
17#include <linux/platform_device.h>
18#include <linux/mutex.h>
19#include <linux/err.h>
20#include <linux/i2c.h>
21#include <linux/delay.h>
22#include <linux/power_supply.h>
23#include <linux/slab.h>
24#include <linux/max17048_battery.h>
25
26#define MAX17048_VCELL 0x02
27#define MAX17048_SOC 0x04
28#define MAX17048_VER 0x08
29#define MAX17048_HIBRT 0x0A
30#define MAX17048_CONFIG 0x0C
31#define MAX17048_OCV 0x0E
32#define MAX17048_VLRT 0x14
33#define MAX17048_VRESET 0x18
34#define MAX17048_STATUS 0x1A
35#define MAX17048_UNLOCK 0x3E
36#define MAX17048_TABLE 0x40
37#define MAX17048_RCOMPSEG1 0x80
38#define MAX17048_RCOMPSEG2 0x90
39#define MAX17048_CMD 0xFF
40#define MAX17048_UNLOCK_VALUE 0x4a57
41#define MAX17048_RESET_VALUE 0x5400
42#define MAX17048_DELAY 1000
43#define MAX17048_BATTERY_FULL 95
44#define MAX17048_VERSION_NO 0x11
45
46struct max17048_chip {
47 struct i2c_client *client;
48 struct delayed_work work;
49 struct power_supply battery;
50 struct power_supply ac;
51 struct power_supply usb;
52 struct max17048_battery_model *model_data;
53
54 /* State Of Connect */
55 int ac_online;
56 int usb_online;
57 /* battery voltage */
58 int vcell;
59 /* battery capacity */
60 int soc;
61 /* State Of Charge */
62 int status;
63
64 int lasttime_vcell;
65 int lasttime_soc;
66 int lasttime_status;
67};
68
69uint8_t max17048_custom_data[] = {
70 0xAA, 0x00, 0xB1, 0xF0, 0xB7, 0xE0, 0xB9, 0x60, 0xBB, 0x80,
71 0xBC, 0x40, 0xBD, 0x30, 0xBD, 0x50, 0xBD, 0xF0, 0xBE, 0x40,
72 0xBF, 0xD0, 0xC0, 0x90, 0xC4, 0x30, 0xC7, 0xC0, 0xCA, 0x60,
73 0xCF, 0x30, 0x01, 0x20, 0x09, 0xC0, 0x1F, 0xC0, 0x2B, 0xE0,
74 0x4F, 0xC0, 0x30, 0x00, 0x47, 0x80, 0x4F, 0xE0, 0x77, 0x00,
75 0x15, 0x60, 0x46, 0x20, 0x13, 0x80, 0x1A, 0x60, 0x12, 0x20,
76 0x14, 0xA0, 0x14, 0xA0};
77
78static int max17048_write_word(struct i2c_client *client, int reg, u16 value)
79{
80 int ret;
81
82 ret = i2c_smbus_write_word_data(client, reg, swab16(value));
83
84 if (ret < 0)
85 dev_err(&client->dev, "%s(): Failed in writing register"
86 "0x%02x err %d\n", __func__, reg, ret);
87
88 return ret;
89}
90
91static uint16_t max17048_read_word(struct i2c_client *client, int reg)
92{
93 uint16_t ret;
94
95 ret = i2c_smbus_read_word_data(client, reg);
96
97 if (ret < 0)
98 dev_err(&client->dev, "%s(): Failed in reading register"
99 "0x%02x err %d\n", __func__, reg, ret);
100
101 return swab16(ret);
102}
103
104static int max17048_get_property(struct power_supply *psy,
105 enum power_supply_property psp,
106 union power_supply_propval *val)
107{
108 struct max17048_chip *chip = container_of(psy,
109 struct max17048_chip, battery);
110
111 switch (psp) {
112 case POWER_SUPPLY_PROP_STATUS:
113 val->intval = chip->status;
114 break;
115 case POWER_SUPPLY_PROP_VOLTAGE_NOW:
116 val->intval = chip->vcell;
117 break;
118 case POWER_SUPPLY_PROP_CAPACITY:
119 val->intval = chip->soc;
120 break;
121 default:
122 return -EINVAL;
123 }
124 return 0;
125}
126
127static int max17048_ac_get_property(struct power_supply *psy,
128 enum power_supply_property psp,
129 union power_supply_propval *val)
130{
131 struct max17048_chip *chip = container_of(psy,
132 struct max17048_chip, ac);
133
134 if (psp == POWER_SUPPLY_PROP_ONLINE)
135 val->intval = chip->ac_online;
136 else
137 return -EINVAL;
138
139 return 0;
140}
141
142static int max17048_usb_get_property(struct power_supply *psy,
143 enum power_supply_property psp,
144 union power_supply_propval *val)
145{
146 struct max17048_chip *chip = container_of(psy,
147 struct max17048_chip, usb);
148
149 if (psp == POWER_SUPPLY_PROP_ONLINE)
150 val->intval = chip->usb_online;
151 else
152 return -EINVAL;
153
154 return 0;
155}
156
157static void max17048_get_vcell(struct i2c_client *client)
158{
159 struct max17048_chip *chip = i2c_get_clientdata(client);
160 uint16_t vcell;
161
162 vcell = max17048_read_word(client, MAX17048_VCELL);
163 if (vcell < 0)
164 dev_err(&client->dev, "%s: err %d\n", __func__, vcell);
165
166 chip->vcell = vcell;
167}
168
169static void max17048_get_soc(struct i2c_client *client)
170{
171 struct max17048_chip *chip = i2c_get_clientdata(client);
172 uint16_t soc;
173
174 soc = max17048_read_word(client, MAX17048_SOC);
175 if (soc < 0)
176 dev_err(&client->dev, "%s: err %d\n", __func__, soc);
177
178 chip->soc = soc >> 9;
179}
180
181static uint16_t max17048_get_version(struct i2c_client *client)
182{
183 return swab16(i2c_smbus_read_word_data(client, MAX17048_VER));
184}
185
186static void max17048_work(struct work_struct *work)
187{
188 struct max17048_chip *chip;
189
190 chip = container_of(work, struct max17048_chip, work.work);
191
192 max17048_get_vcell(chip->client);
193 max17048_get_soc(chip->client);
194
195 if (chip->vcell != chip->lasttime_vcell ||
196 chip->soc != chip->lasttime_soc ||
197 chip->status != chip->lasttime_status) {
198
199 chip->lasttime_vcell = chip->vcell;
200 chip->lasttime_soc = chip->soc;
201
202 power_supply_changed(&chip->battery);
203 }
204 schedule_delayed_work(&chip->work, MAX17048_DELAY);
205}
206
207static void max17048_battery_status(enum charging_states status,
208 enum charger_type chrg_type, void *data)
209{
210 struct max17048_chip *chip = data;
211
212 chip->ac_online = 0;
213 chip->usb_online = 0;
214
215 if (chrg_type == AC)
216 chip->ac_online = 1;
217 else if (chrg_type == USB)
218 chip->usb_online = 1;
219
220 if (status == progress)
221 chip->status = POWER_SUPPLY_STATUS_CHARGING;
222 else
223 chip->status = POWER_SUPPLY_STATUS_DISCHARGING;
224
225 if (chip->soc > MAX17048_BATTERY_FULL)
226 chip->status = POWER_SUPPLY_STATUS_FULL;
227
228 power_supply_changed(&chip->battery);
229 power_supply_changed(&chip->usb);
230 power_supply_changed(&chip->ac);
231}
232
233static enum power_supply_property max17048_battery_props[] = {
234 POWER_SUPPLY_PROP_STATUS,
235 POWER_SUPPLY_PROP_VOLTAGE_NOW,
236 POWER_SUPPLY_PROP_CAPACITY,
237};
238
239static enum power_supply_property max17048_ac_props[] = {
240 POWER_SUPPLY_PROP_ONLINE,
241};
242
243static enum power_supply_property max17048_usb_props[] = {
244 POWER_SUPPLY_PROP_ONLINE,
245};
246
247static int max17048_write_rcomp_seg(struct i2c_client *client,
248 uint16_t rcomp_seg)
249{
250 uint8_t rs1, rs2;
251 int ret;
252
253 rs2 = rcomp_seg | 0x00FF;
254 rs1 = rcomp_seg >> 8;
255 uint8_t rcomp_seg_table[16] = { rs1, rs2, rs1, rs2,
256 rs1, rs2, rs1, rs2,
257 rs1, rs2, rs1, rs2,
258 rs1, rs2, rs1, rs2};
259
260 ret = i2c_smbus_write_i2c_block_data(client, MAX17048_RCOMPSEG1,
261 16, (uint8_t *)rcomp_seg_table);
262 if (ret < 0) {
263 dev_err(&client->dev, "%s: err %d\n", __func__, ret);
264 return ret;
265 }
266
267 ret = i2c_smbus_write_i2c_block_data(client, MAX17048_RCOMPSEG2,
268 16, (uint8_t *)rcomp_seg_table);
269 if (ret < 0) {
270 dev_err(&client->dev, "%s: err %d\n", __func__, ret);
271 return ret;
272 }
273
274 return 0;
275}
276
277static int max17048_load_model_data(struct max17048_chip *chip)
278{
279 struct i2c_client *client = chip->client;
280 struct max17048_battery_model *mdata = chip->model_data;
281 uint16_t soc_tst, ocv;
282 int i, ret = 0;
283
284 /* read OCV */
285 ocv = max17048_read_word(client, MAX17048_OCV);
286 if (ocv == 0xffff) {
287 dev_err(&client->dev, "%s: Failed in unlocking"
288 "max17048 err: %d\n", __func__, ocv);
289 return -1;
290 }
291
292 /* write custom model data */
293 for (i = 0; i < 4; i += 1) {
294 if (i2c_smbus_write_i2c_block_data(client,
295 (MAX17048_TABLE+i*16), 16,
296 &max17048_custom_data[i*0x10]) < 0) {
297 dev_err(&client->dev, "%s: error writing model data:\n",
298 __func__);
299 return -1;
300 }
301 }
302
303 /* Write OCV Test value */
304 ret = max17048_write_word(client, MAX17048_OCV, mdata->ocvtest);
305 if (ret < 0)
306 return ret;
307
308 ret = max17048_write_rcomp_seg(client, mdata->rcomp_seg);
309 if (ret < 0)
310 return ret;
311
312 /* Disable hibernate */
313 ret = max17048_write_word(client, MAX17048_HIBRT, 0x0000);
314 if (ret < 0)
315 return ret;
316
317 /* Lock model access */
318 ret = max17048_write_word(client, MAX17048_UNLOCK, 0x0000);
319 if (ret < 0)
320 return ret;
321
322 /* Delay between 150ms to 600ms */
323 mdelay(200);
324
325 /* Read SOC Register and compare to expected result */
326 soc_tst = max17048_read_word(client, MAX17048_SOC);
327 if (!((soc_tst >> 8) >= mdata->soccheck_A &&
328 (soc_tst >> 8) <= mdata->soccheck_B)) {
329 dev_err(&client->dev, "%s: soc comparison failed %d\n",
330 __func__, ret);
331 return ret;
332 } else {
333 dev_info(&client->dev, "MAX17048 Custom data"
334 " loading successfull\n");
335 }
336
337 /* unlock model access */
338 ret = max17048_write_word(client, MAX17048_UNLOCK,
339 MAX17048_UNLOCK_VALUE);
340 if (ret < 0)
341 return ret;
342
343 /* Restore OCV */
344 ret = max17048_write_word(client, MAX17048_OCV, ocv);
345 if (ret < 0)
346 return ret;
347
348 return ret;
349}
350
351static int max17048_initialize(struct max17048_chip *chip)
352{
353 uint8_t ret, config, status;
354 uint16_t wrt_status;
355 struct i2c_client *client = chip->client;
356 struct max17048_battery_model *mdata = chip->model_data;
357
358 /* unlock model access */
359 ret = max17048_write_word(client, MAX17048_UNLOCK,
360 MAX17048_UNLOCK_VALUE);
361 if (ret < 0)
362 return ret;
363
364 /* load model data */
365 ret = max17048_load_model_data(chip);
366 if (ret < 0) {
367 dev_err(&client->dev, "%s: err %d\n", __func__, ret);
368 return ret;
369 }
370
371 if (mdata->bits == 19)
372 config = 32 - (mdata->alert_threshold * 2);
373 else if (mdata->bits == 18)
374 config = 32 - mdata->alert_threshold;
375
376 config = mdata->one_percent_alerts | config;
377
378 ret = max17048_write_word(client, MAX17048_CONFIG,
379 ((mdata->rcomp << 8) | config));
380 if (ret < 0)
381 return ret;
382
383 /* Voltage Alert configuration */
384 ret = max17048_write_word(client, MAX17048_VLRT, mdata->valert);
385 if (ret < 0)
386 return ret;
387
388 /* Hibernate configuration */
389 ret = max17048_write_word(client, MAX17048_HIBRT, mdata->hibernate);
390 if (ret < 0)
391 return ret;
392
393 ret = max17048_write_word(client, MAX17048_VRESET, mdata->vreset);
394 if (ret < 0)
395 return ret;
396
397 /* clears the reset indicator */
398 ret = max17048_read_word(client, MAX17048_STATUS);
399 if (ret < 0)
400 return ret;
401
402 /* Sets the EnVR bit if selected */
403 status = (ret & 0xFE) | mdata->alert_on_reset;
404 wrt_status = status << 8;
405
406 ret = max17048_write_word(client, MAX17048_STATUS, wrt_status);
407 if (ret < 0)
408 return ret;
409
410 /* Lock model access */
411 ret = max17048_write_word(client, MAX17048_UNLOCK, 0x0000);
412 if (ret < 0)
413 return ret;
414
415 /* Add delay */
416 mdelay(200);
417 return 0;
418}
419
420static int __devinit max17048_probe(struct i2c_client *client,
421 const struct i2c_device_id *id)
422{
423 struct max17048_chip *chip;
424 int ret;
425 uint16_t version;
426
427 chip = kzalloc(sizeof(*chip), GFP_KERNEL);
428 if (!chip)
429 return -ENOMEM;
430
431 chip->client = client;
432 chip->model_data = client->dev.platform_data;
433 chip->ac_online = 0;
434 chip->usb_online = 0;
435
436 i2c_set_clientdata(client, chip);
437
438 version = max17048_get_version(client);
439 if (version != MAX17048_VERSION_NO) {
440 ret = -ENODEV;
441 goto error2;
442 }
443 dev_info(&client->dev, "MAX17048 Fuel-Gauge Ver 0x%x\n", version);
444
445 ret = max17048_initialize(chip);
446 if (ret < 0) {
447 dev_err(&client->dev, "Error: Initializing fuel-gauge\n");
448 goto error2;
449 }
450
451 ret = register_callback(max17048_battery_status, chip);
452 if (ret < 0)
453 goto error2;
454
455 chip->battery.name = "battery";
456 chip->battery.type = POWER_SUPPLY_TYPE_BATTERY;
457 chip->battery.get_property = max17048_get_property;
458 chip->battery.properties = max17048_battery_props;
459 chip->battery.num_properties = ARRAY_SIZE(max17048_battery_props);
460
461 ret = power_supply_register(&client->dev, &chip->battery);
462 if (ret) {
463 dev_err(&client->dev, "failed: power supply register\n");
464 goto error2;
465 }
466
467 chip->ac.name = "maxim-ac";
468 chip->ac.type = POWER_SUPPLY_TYPE_MAINS;
469 chip->ac.get_property = max17048_ac_get_property;
470 chip->ac.properties = max17048_ac_props;
471 chip->ac.num_properties = ARRAY_SIZE(max17048_ac_props);
472
473 ret = power_supply_register(&client->dev, &chip->ac);
474 if (ret) {
475 dev_err(&client->dev, "failed: power supply register\n");
476 goto error1;
477 }
478
479 chip->usb.name = "maxim-usb";
480 chip->usb.type = POWER_SUPPLY_TYPE_USB;
481 chip->usb.get_property = max17048_usb_get_property;
482 chip->usb.properties = max17048_usb_props;
483 chip->usb.num_properties = ARRAY_SIZE(max17048_usb_props);
484
485 ret = power_supply_register(&client->dev, &chip->usb);
486 if (ret) {
487 dev_err(&client->dev, "failed: power supply register\n");
488 goto error;
489 }
490
491 INIT_DELAYED_WORK_DEFERRABLE(&chip->work, max17048_work);
492 schedule_delayed_work(&chip->work, MAX17048_DELAY);
493
494 ret = update_charger_status();
495 if (ret) {
496 dev_err(&client->dev, "failed: update_charger_status\n");
497 goto error;
498 }
499
500 return 0;
501error:
502 power_supply_unregister(&chip->ac);
503error1:
504 power_supply_unregister(&chip->battery);
505error2:
506 kfree(chip);
507 return ret;
508}
509
510static int __devexit max17048_remove(struct i2c_client *client)
511{
512 struct max17048_chip *chip = i2c_get_clientdata(client);
513
514 power_supply_unregister(&chip->battery);
515 power_supply_unregister(&chip->usb);
516 power_supply_unregister(&chip->ac);
517 cancel_delayed_work(&chip->work);
518 kfree(chip);
519 return 0;
520}
521
522#ifdef CONFIG_PM
523
524static int max17048_suspend(struct i2c_client *client,
525 pm_message_t state)
526{
527 struct max17048_chip *chip = i2c_get_clientdata(client);
528
529 cancel_delayed_work(&chip->work);
530 return 0;
531}
532
533static int max17048_resume(struct i2c_client *client)
534{
535 struct max17048_chip *chip = i2c_get_clientdata(client);
536
537 schedule_delayed_work(&chip->work, MAX17048_DELAY);
538 return 0;
539}
540
541#else
542
543#define max17048_suspend NULL
544#define max17048_resume NULL
545
546#endif /* CONFIG_PM */
547
548static const struct i2c_device_id max17048_id[] = {
549 { "max17048", 0 },
550 { }
551};
552MODULE_DEVICE_TABLE(i2c, max17048_id);
553
554static struct i2c_driver max17048_i2c_driver = {
555 .driver = {
556 .name = "max17048",
557 },
558 .probe = max17048_probe,
559 .remove = __devexit_p(max17048_remove),
560 .suspend = max17048_suspend,
561 .resume = max17048_resume,
562 .id_table = max17048_id,
563};
564
565static int __init max17048_init(void)
566{
567 return i2c_add_driver(&max17048_i2c_driver);
568}
569module_init(max17048_init);
570
571static void __exit max17048_exit(void)
572{
573 i2c_del_driver(&max17048_i2c_driver);
574}
575module_exit(max17048_exit);
576
577MODULE_AUTHOR("Chandler Zhang <chazhang@nvidia.com>");
578MODULE_DESCRIPTION("MAX17048 Fuel Gauge");
579MODULE_LICENSE("GPL");