GNU Linux-libre 4.14.290-gnu1
[releases.git] / drivers / power / supply / 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 free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License version 2 as
10  * published by the Free Software Foundation.
11  */
12
13 #include <linux/module.h>
14 #include <linux/init.h>
15 #include <linux/platform_device.h>
16 #include <linux/mutex.h>
17 #include <linux/err.h>
18 #include <linux/i2c.h>
19 #include <linux/delay.h>
20 #include <linux/power_supply.h>
21 #include <linux/max17040_battery.h>
22 #include <linux/slab.h>
23
24 #define MAX17040_VCELL  0x02
25 #define MAX17040_SOC    0x04
26 #define MAX17040_MODE   0x06
27 #define MAX17040_VER    0x08
28 #define MAX17040_RCOMP  0x0C
29 #define MAX17040_CMD    0xFE
30
31
32 #define MAX17040_DELAY          1000
33 #define MAX17040_BATTERY_FULL   95
34
35 struct max17040_chip {
36         struct i2c_client               *client;
37         struct delayed_work             work;
38         struct power_supply             *battery;
39         struct max17040_platform_data   *pdata;
40
41         /* State Of Connect */
42         int online;
43         /* battery voltage */
44         int vcell;
45         /* battery capacity */
46         int soc;
47         /* State Of Charge */
48         int status;
49 };
50
51 static int max17040_get_property(struct power_supply *psy,
52                             enum power_supply_property psp,
53                             union power_supply_propval *val)
54 {
55         struct max17040_chip *chip = power_supply_get_drvdata(psy);
56
57         switch (psp) {
58         case POWER_SUPPLY_PROP_STATUS:
59                 val->intval = chip->status;
60                 break;
61         case POWER_SUPPLY_PROP_ONLINE:
62                 val->intval = chip->online;
63                 break;
64         case POWER_SUPPLY_PROP_VOLTAGE_NOW:
65                 val->intval = chip->vcell;
66                 break;
67         case POWER_SUPPLY_PROP_CAPACITY:
68                 val->intval = chip->soc;
69                 break;
70         default:
71                 return -EINVAL;
72         }
73         return 0;
74 }
75
76 static int max17040_write_reg(struct i2c_client *client, int reg, u16 value)
77 {
78         int ret;
79
80         ret = i2c_smbus_write_word_swapped(client, reg, value);
81
82         if (ret < 0)
83                 dev_err(&client->dev, "%s: err %d\n", __func__, ret);
84
85         return ret;
86 }
87
88 static int max17040_read_reg(struct i2c_client *client, int reg)
89 {
90         int ret;
91
92         ret = i2c_smbus_read_word_swapped(client, reg);
93
94         if (ret < 0)
95                 dev_err(&client->dev, "%s: err %d\n", __func__, ret);
96
97         return ret;
98 }
99
100 static void max17040_reset(struct i2c_client *client)
101 {
102         max17040_write_reg(client, MAX17040_CMD, 0x0054);
103 }
104
105 static void max17040_get_vcell(struct i2c_client *client)
106 {
107         struct max17040_chip *chip = i2c_get_clientdata(client);
108         u16 vcell;
109
110         vcell = max17040_read_reg(client, MAX17040_VCELL);
111
112         chip->vcell = (vcell >> 4) * 1250;
113 }
114
115 static void max17040_get_soc(struct i2c_client *client)
116 {
117         struct max17040_chip *chip = i2c_get_clientdata(client);
118         u16 soc;
119
120         soc = max17040_read_reg(client, MAX17040_SOC);
121
122         chip->soc = (soc >> 8);
123 }
124
125 static void max17040_get_version(struct i2c_client *client)
126 {
127         u16 version;
128
129         version = max17040_read_reg(client, MAX17040_VER);
130
131         dev_info(&client->dev, "MAX17040 Fuel-Gauge Ver 0x%x\n", version);
132 }
133
134 static void max17040_get_online(struct i2c_client *client)
135 {
136         struct max17040_chip *chip = i2c_get_clientdata(client);
137
138         if (chip->pdata && chip->pdata->battery_online)
139                 chip->online = chip->pdata->battery_online();
140         else
141                 chip->online = 1;
142 }
143
144 static void max17040_get_status(struct i2c_client *client)
145 {
146         struct max17040_chip *chip = i2c_get_clientdata(client);
147
148         if (!chip->pdata || !chip->pdata->charger_online
149                         || !chip->pdata->charger_enable) {
150                 chip->status = POWER_SUPPLY_STATUS_UNKNOWN;
151                 return;
152         }
153
154         if (chip->pdata->charger_online()) {
155                 if (chip->pdata->charger_enable())
156                         chip->status = POWER_SUPPLY_STATUS_CHARGING;
157                 else
158                         chip->status = POWER_SUPPLY_STATUS_NOT_CHARGING;
159         } else {
160                 chip->status = POWER_SUPPLY_STATUS_DISCHARGING;
161         }
162
163         if (chip->soc > MAX17040_BATTERY_FULL)
164                 chip->status = POWER_SUPPLY_STATUS_FULL;
165 }
166
167 static void max17040_work(struct work_struct *work)
168 {
169         struct max17040_chip *chip;
170
171         chip = container_of(work, struct max17040_chip, work.work);
172
173         max17040_get_vcell(chip->client);
174         max17040_get_soc(chip->client);
175         max17040_get_online(chip->client);
176         max17040_get_status(chip->client);
177
178         queue_delayed_work(system_power_efficient_wq, &chip->work,
179                            MAX17040_DELAY);
180 }
181
182 static enum power_supply_property max17040_battery_props[] = {
183         POWER_SUPPLY_PROP_STATUS,
184         POWER_SUPPLY_PROP_ONLINE,
185         POWER_SUPPLY_PROP_VOLTAGE_NOW,
186         POWER_SUPPLY_PROP_CAPACITY,
187 };
188
189 static const struct power_supply_desc max17040_battery_desc = {
190         .name           = "battery",
191         .type           = POWER_SUPPLY_TYPE_BATTERY,
192         .get_property   = max17040_get_property,
193         .properties     = max17040_battery_props,
194         .num_properties = ARRAY_SIZE(max17040_battery_props),
195 };
196
197 static int max17040_probe(struct i2c_client *client,
198                         const struct i2c_device_id *id)
199 {
200         struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
201         struct power_supply_config psy_cfg = {};
202         struct max17040_chip *chip;
203
204         if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE))
205                 return -EIO;
206
207         chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL);
208         if (!chip)
209                 return -ENOMEM;
210
211         chip->client = client;
212         chip->pdata = client->dev.platform_data;
213
214         i2c_set_clientdata(client, chip);
215         psy_cfg.drv_data = chip;
216
217         chip->battery = power_supply_register(&client->dev,
218                                 &max17040_battery_desc, &psy_cfg);
219         if (IS_ERR(chip->battery)) {
220                 dev_err(&client->dev, "failed: power supply register\n");
221                 return PTR_ERR(chip->battery);
222         }
223
224         max17040_reset(client);
225         max17040_get_version(client);
226
227         INIT_DEFERRABLE_WORK(&chip->work, max17040_work);
228         queue_delayed_work(system_power_efficient_wq, &chip->work,
229                            MAX17040_DELAY);
230
231         return 0;
232 }
233
234 static int max17040_remove(struct i2c_client *client)
235 {
236         struct max17040_chip *chip = i2c_get_clientdata(client);
237
238         power_supply_unregister(chip->battery);
239         cancel_delayed_work(&chip->work);
240         return 0;
241 }
242
243 #ifdef CONFIG_PM_SLEEP
244
245 static int max17040_suspend(struct device *dev)
246 {
247         struct i2c_client *client = to_i2c_client(dev);
248         struct max17040_chip *chip = i2c_get_clientdata(client);
249
250         cancel_delayed_work(&chip->work);
251         return 0;
252 }
253
254 static int max17040_resume(struct device *dev)
255 {
256         struct i2c_client *client = to_i2c_client(dev);
257         struct max17040_chip *chip = i2c_get_clientdata(client);
258
259         queue_delayed_work(system_power_efficient_wq, &chip->work,
260                            MAX17040_DELAY);
261         return 0;
262 }
263
264 static SIMPLE_DEV_PM_OPS(max17040_pm_ops, max17040_suspend, max17040_resume);
265 #define MAX17040_PM_OPS (&max17040_pm_ops)
266
267 #else
268
269 #define MAX17040_PM_OPS NULL
270
271 #endif /* CONFIG_PM_SLEEP */
272
273 static const struct i2c_device_id max17040_id[] = {
274         { "max17040" },
275         { "max77836-battery" },
276         { }
277 };
278 MODULE_DEVICE_TABLE(i2c, max17040_id);
279
280 static const struct of_device_id max17040_of_match[] = {
281         { .compatible = "maxim,max17040" },
282         { .compatible = "maxim,max77836-battery" },
283         { },
284 };
285 MODULE_DEVICE_TABLE(of, max17040_of_match);
286
287 static struct i2c_driver max17040_i2c_driver = {
288         .driver = {
289                 .name   = "max17040",
290                 .of_match_table = max17040_of_match,
291                 .pm     = MAX17040_PM_OPS,
292         },
293         .probe          = max17040_probe,
294         .remove         = max17040_remove,
295         .id_table       = max17040_id,
296 };
297 module_i2c_driver(max17040_i2c_driver);
298
299 MODULE_AUTHOR("Minkyu Kang <mk7.kang@samsung.com>");
300 MODULE_DESCRIPTION("MAX17040 Fuel Gauge");
301 MODULE_LICENSE("GPL");