upload tizen1.0 source
[kernel/linux-2.6.36.git] / drivers / power / max17040_battery.c
1 /*
2  *  max17040_battery.c
3  *  fuel-gauge systems for lithium-ion (Li+) batteries
4  *
5  *  Copyright (C) 2009 Samsung Electronics
6  *  Minkyu Kang <mk7.kang@samsung.com>
7  *
8  * This program is not provided / owned by Maxim Integrated Products.
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License version 2 as
12  * published by the Free Software Foundation.
13  */
14
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/max17040_battery.h>
24 #include <linux/slab.h>
25
26 #define MAX17040_VCELL_MSB      0x02
27 #define MAX17040_VCELL_LSB      0x03
28 #define MAX17040_SOC_MSB        0x04
29 #define MAX17040_SOC_LSB        0x05
30 #define MAX17040_MODE_MSB       0x06
31 #define MAX17040_MODE_LSB       0x07
32 #define MAX17040_VER_MSB        0x08
33 #define MAX17040_VER_LSB        0x09
34 #define MAX17040_RCOMP_MSB      0x0C
35 #define MAX17040_RCOMP_LSB      0x0D
36 #define MAX17040_CMD_MSB        0xFE
37 #define MAX17040_CMD_LSB        0xFF
38
39 #define MAX17040_DELAY          1000
40 #define MAX17040_BATTERY_FULL   95
41
42 struct max17040_chip {
43         struct i2c_client               *client;
44         struct delayed_work             work;
45         struct power_supply             battery;
46         struct max17040_platform_data   *pdata;
47
48         /* device status */
49         int operate;
50         /* State Of Connect */
51         int online;
52         /* battery voltage */
53         int vcell;
54         /* battery capacity */
55         int soc;
56         /* battery compensation */
57         unsigned int rcomp;
58 };
59
60 static int max17040_write_reg(struct i2c_client *client,
61                 int reg, unsigned int value)
62 {
63         int ret;
64
65         ret = i2c_smbus_write_i2c_block_data(client, reg, 2, (u8 *)&value);
66
67         if (ret < 0)
68                 dev_err(&client->dev, "%s: err %d\n", __func__, ret);
69
70         return ret;
71 }
72
73 static int max17040_read_reg(struct i2c_client *client, int reg)
74 {
75         int ret;
76
77         ret = i2c_smbus_read_byte_data(client, reg);
78
79         if (ret < 0)
80                 dev_err(&client->dev, "%s: err %d\n", __func__, ret);
81
82         return ret;
83 }
84
85 static void max17040_set_rcomp(struct i2c_client *client, unsigned int value)
86 {
87         unsigned int revert;
88
89         revert = (value >> 8) + ((value & 0xff) << 8);
90         max17040_write_reg(client, MAX17040_RCOMP_MSB, revert);
91 }
92
93 static void max17040_reset(struct i2c_client *client, int reset)
94 {
95         struct max17040_chip *chip = i2c_get_clientdata(client);
96         int ret;
97
98         if (reset) {
99                 /* Power On Reset */
100                 ret = max17040_write_reg(client, MAX17040_CMD_MSB, 0x5400);
101                 mdelay(200);
102         } else {
103                 /* Quick Start */
104                 ret = max17040_write_reg(client, MAX17040_MODE_MSB, 0x4000);
105         }
106
107         if (ret < 0) {
108                 chip->operate = 0;
109         } else {
110                 chip->operate = 1;
111
112                 if (chip->pdata->rcomp)
113                         max17040_set_rcomp(client, chip->pdata->rcomp);
114
115                 if (chip->pdata->poll)
116                         schedule_delayed_work(&chip->work, MAX17040_DELAY);
117         }
118 }
119
120 static unsigned int max17040_get_vcell(struct i2c_client *client)
121 {
122         struct max17040_chip *chip = i2c_get_clientdata(client);
123         u8 msb;
124         u8 lsb;
125
126         msb = max17040_read_reg(client, MAX17040_VCELL_MSB);
127         lsb = max17040_read_reg(client, MAX17040_VCELL_LSB);
128
129         chip->vcell = ((msb << 4) + (lsb >> 4)) * 125 / 100;
130
131         return (msb << 4) + (lsb >> 4);
132 }
133
134 static void max17040_get_soc(struct i2c_client *client)
135 {
136         struct max17040_chip *chip = i2c_get_clientdata(client);
137         u8 msb;
138         u8 lsb;
139
140         msb = max17040_read_reg(client, MAX17040_SOC_MSB);
141         lsb = max17040_read_reg(client, MAX17040_SOC_LSB);
142
143         chip->soc = msb;
144 }
145
146 static void max17040_get_version(struct i2c_client *client)
147 {
148         u8 msb;
149         u8 lsb;
150
151         msb = max17040_read_reg(client, MAX17040_VER_MSB);
152         lsb = max17040_read_reg(client, MAX17040_VER_LSB);
153
154         dev_info(&client->dev, "MAX17040 Fuel-Gauge Ver %d%d\n", msb, lsb);
155 }
156
157 static void max17040_get_rcomp(struct i2c_client *client)
158 {
159         struct max17040_chip *chip = i2c_get_clientdata(client);
160         u8 msb;
161         u8 lsb;
162
163         msb = max17040_read_reg(client, MAX17040_RCOMP_MSB);
164         lsb = max17040_read_reg(client, MAX17040_RCOMP_LSB);
165
166         chip->rcomp = (msb << 8) + lsb;
167 }
168
169 static void max17040_work(struct work_struct *work)
170 {
171         struct max17040_chip *chip;
172
173         chip = container_of(work, struct max17040_chip, work.work);
174
175         max17040_get_vcell(chip->client);
176         max17040_get_soc(chip->client);
177
178         schedule_delayed_work(&chip->work, MAX17040_DELAY);
179 }
180
181 static enum power_supply_property max17040_battery_props[] = {
182         POWER_SUPPLY_PROP_VOLTAGE_NOW,
183         POWER_SUPPLY_PROP_CAPACITY,
184         POWER_SUPPLY_PROP_CHARGE_FULL,
185 };
186
187 static int max17040_get_property(struct power_supply *psy,
188                             enum power_supply_property psp,
189                             union power_supply_propval *val)
190 {
191         struct max17040_chip *chip = container_of(psy,
192                                 struct max17040_chip, battery);
193
194         if (!chip->operate) {
195                 val->intval = 0;
196                 return 0;
197         }
198
199         switch (psp) {
200         case POWER_SUPPLY_PROP_VOLTAGE_NOW:
201                 if (!chip->pdata->poll)
202                         max17040_get_vcell(chip->client);
203                 val->intval = chip->vcell * 1000; /* uA is the standard */
204                 break;
205         case POWER_SUPPLY_PROP_CAPACITY:
206                 if (!chip->pdata->poll)
207                         max17040_get_soc(chip->client);
208                 val->intval = chip->soc;
209                 break;
210         case POWER_SUPPLY_PROP_CHARGE_FULL:
211                 if (!chip->pdata->poll)
212                         max17040_get_soc(chip->client);
213                 if (chip->soc > MAX17040_BATTERY_FULL)
214                         val->intval = 1;
215                 else
216                         val->intval = 0;
217                 break;
218         default:
219                 return -EINVAL;
220         }
221         return 0;
222 }
223
224 static ssize_t max17040_show_rcomp(struct device *dev,
225                 struct device_attribute *attr, char *buf)
226 {
227         struct max17040_chip *chip = dev_get_drvdata(dev);
228
229         max17040_get_rcomp(chip->client);
230         return sprintf(buf, "%x\n", chip->rcomp);
231 }
232
233 static ssize_t max17040_store_rcomp(struct device *dev,
234                 struct device_attribute *attr, const char *buf, size_t count)
235 {
236         struct max17040_chip *chip = dev_get_drvdata(dev);
237         unsigned int value;
238
239         strict_strtoul(buf, 16, (unsigned long *)&value);
240
241         if (!count)
242                 return -EINVAL;
243
244         max17040_set_rcomp(chip->client, value);
245
246         return count;
247 }
248
249 DEVICE_ATTR(rcomp, S_IRUGO|S_IWUSR,
250                 max17040_show_rcomp, max17040_store_rcomp);
251
252 static ssize_t max17040_show_operate(struct device *dev,
253                 struct device_attribute *attr, char *buf)
254 {
255         struct max17040_chip *chip = dev_get_drvdata(dev);
256         return sprintf(buf, "%x\n", chip->operate);
257 }
258
259 static ssize_t max17040_store_operate(struct device *dev,
260                 struct device_attribute *attr, const char *buf, size_t count)
261 {
262         struct max17040_chip *chip = dev_get_drvdata(dev);
263         unsigned int value;
264
265         strict_strtoul(buf, 16, (unsigned long *)&value);
266
267         if (!count)
268                 return -EINVAL;
269
270         if (value)
271                 max17040_reset(chip->client, 1);
272
273         return count;
274 }
275
276 DEVICE_ATTR(operate, S_IRUGO|S_IWUSR,
277                 max17040_show_operate, max17040_store_operate);
278
279 static int __devinit max17040_probe(struct i2c_client *client,
280                         const struct i2c_device_id *id)
281 {
282         struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
283         struct max17040_chip *chip;
284         int ret;
285
286         if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE))
287                 return -EIO;
288
289         chip = kzalloc(sizeof(*chip), GFP_KERNEL);
290         if (!chip)
291                 return -ENOMEM;
292
293         chip->client = client;
294         chip->pdata = client->dev.platform_data;
295
296         i2c_set_clientdata(client, chip);
297
298         chip->battery.name              = "max17040_battery";
299         chip->battery.type              = POWER_SUPPLY_TYPE_BATTERY;
300         chip->battery.get_property      = max17040_get_property;
301         chip->battery.properties        = max17040_battery_props;
302         chip->battery.num_properties    = ARRAY_SIZE(max17040_battery_props);
303
304         ret = power_supply_register(&client->dev, &chip->battery);
305         if (ret) {
306                 dev_err(&client->dev, "failed: power supply register\n");
307                 i2c_set_clientdata(client, NULL);
308                 kfree(chip);
309                 return ret;
310         }
311
312         ret = device_create_file(&client->dev, &dev_attr_rcomp);
313         ret = device_create_file(&client->dev, &dev_attr_operate);
314
315         INIT_DELAYED_WORK_DEFERRABLE(&chip->work, max17040_work);
316
317         max17040_reset(client, chip->pdata->reset);
318         max17040_get_version(client);
319
320         return 0;
321 }
322
323 static int __devexit max17040_remove(struct i2c_client *client)
324 {
325         struct max17040_chip *chip = i2c_get_clientdata(client);
326
327         power_supply_unregister(&chip->battery);
328         device_remove_file(&client->dev, &dev_attr_rcomp);
329         device_remove_file(&client->dev, &dev_attr_operate);
330
331         if (chip->pdata->poll)
332                 cancel_delayed_work(&chip->work);
333         i2c_set_clientdata(client, NULL);
334         kfree(chip);
335         return 0;
336 }
337
338 #ifdef CONFIG_PM
339
340 static int max17040_suspend(struct i2c_client *client,
341                 pm_message_t state)
342 {
343         struct max17040_chip *chip = i2c_get_clientdata(client);
344
345         if (chip->pdata->poll)
346                 cancel_delayed_work(&chip->work);
347         return 0;
348 }
349
350 static int max17040_resume(struct i2c_client *client)
351 {
352         struct max17040_chip *chip = i2c_get_clientdata(client);
353
354         if (chip->pdata->poll)
355                 schedule_delayed_work(&chip->work, MAX17040_DELAY);
356         return 0;
357 }
358
359 #else
360
361 #define max17040_suspend NULL
362 #define max17040_resume NULL
363
364 #endif /* CONFIG_PM */
365
366 static const struct i2c_device_id max17040_id[] = {
367         { "max17040", 0 },
368         { }
369 };
370 MODULE_DEVICE_TABLE(i2c, max17040_id);
371
372 static struct i2c_driver max17040_i2c_driver = {
373         .driver = {
374                 .name   = "max17040",
375         },
376         .probe          = max17040_probe,
377         .remove         = __devexit_p(max17040_remove),
378         .suspend        = max17040_suspend,
379         .resume         = max17040_resume,
380         .id_table       = max17040_id,
381 };
382
383 static int __init max17040_init(void)
384 {
385         return i2c_add_driver(&max17040_i2c_driver);
386 }
387 module_init(max17040_init);
388
389 static void __exit max17040_exit(void)
390 {
391         i2c_del_driver(&max17040_i2c_driver);
392 }
393 module_exit(max17040_exit);
394
395 MODULE_AUTHOR("Minkyu Kang <mk7.kang@samsung.com>");
396 MODULE_DESCRIPTION("MAX17040 Fuel Gauge");
397 MODULE_LICENSE("GPL");