3 * fuel-gauge systems for lithium-ion (Li+) batteries
5 * Copyright (C) 2009 Samsung Electronics
6 * Minkyu Kang <mk7.kang@samsung.com>
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.
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>
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
32 #define MAX17040_DELAY 1000
33 #define MAX17040_BATTERY_FULL 95
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
;
41 /* State Of Connect */
45 /* battery capacity */
51 static int max17040_get_property(struct power_supply
*psy
,
52 enum power_supply_property psp
,
53 union power_supply_propval
*val
)
55 struct max17040_chip
*chip
= power_supply_get_drvdata(psy
);
58 case POWER_SUPPLY_PROP_STATUS
:
59 val
->intval
= chip
->status
;
61 case POWER_SUPPLY_PROP_ONLINE
:
62 val
->intval
= chip
->online
;
64 case POWER_SUPPLY_PROP_VOLTAGE_NOW
:
65 val
->intval
= chip
->vcell
;
67 case POWER_SUPPLY_PROP_CAPACITY
:
68 val
->intval
= chip
->soc
;
76 static int max17040_write_reg(struct i2c_client
*client
, int reg
, u16 value
)
80 ret
= i2c_smbus_write_word_swapped(client
, reg
, value
);
83 dev_err(&client
->dev
, "%s: err %d\n", __func__
, ret
);
88 static int max17040_read_reg(struct i2c_client
*client
, int reg
)
92 ret
= i2c_smbus_read_word_swapped(client
, reg
);
95 dev_err(&client
->dev
, "%s: err %d\n", __func__
, ret
);
100 static void max17040_reset(struct i2c_client
*client
)
102 max17040_write_reg(client
, MAX17040_CMD
, 0x0054);
105 static void max17040_get_vcell(struct i2c_client
*client
)
107 struct max17040_chip
*chip
= i2c_get_clientdata(client
);
110 vcell
= max17040_read_reg(client
, MAX17040_VCELL
);
115 static void max17040_get_soc(struct i2c_client
*client
)
117 struct max17040_chip
*chip
= i2c_get_clientdata(client
);
120 soc
= max17040_read_reg(client
, MAX17040_SOC
);
122 chip
->soc
= (soc
>> 8);
125 static void max17040_get_version(struct i2c_client
*client
)
129 version
= max17040_read_reg(client
, MAX17040_VER
);
131 dev_info(&client
->dev
, "MAX17040 Fuel-Gauge Ver 0x%x\n", version
);
134 static void max17040_get_online(struct i2c_client
*client
)
136 struct max17040_chip
*chip
= i2c_get_clientdata(client
);
138 if (chip
->pdata
&& chip
->pdata
->battery_online
)
139 chip
->online
= chip
->pdata
->battery_online();
144 static void max17040_get_status(struct i2c_client
*client
)
146 struct max17040_chip
*chip
= i2c_get_clientdata(client
);
148 if (!chip
->pdata
|| !chip
->pdata
->charger_online
149 || !chip
->pdata
->charger_enable
) {
150 chip
->status
= POWER_SUPPLY_STATUS_UNKNOWN
;
154 if (chip
->pdata
->charger_online()) {
155 if (chip
->pdata
->charger_enable())
156 chip
->status
= POWER_SUPPLY_STATUS_CHARGING
;
158 chip
->status
= POWER_SUPPLY_STATUS_NOT_CHARGING
;
160 chip
->status
= POWER_SUPPLY_STATUS_DISCHARGING
;
163 if (chip
->soc
> MAX17040_BATTERY_FULL
)
164 chip
->status
= POWER_SUPPLY_STATUS_FULL
;
167 static void max17040_work(struct work_struct
*work
)
169 struct max17040_chip
*chip
;
171 chip
= container_of(work
, struct max17040_chip
, work
.work
);
173 max17040_get_vcell(chip
->client
);
174 max17040_get_soc(chip
->client
);
175 max17040_get_online(chip
->client
);
176 max17040_get_status(chip
->client
);
178 queue_delayed_work(system_power_efficient_wq
, &chip
->work
,
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
,
189 static const struct power_supply_desc max17040_battery_desc
= {
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
),
197 static int max17040_probe(struct i2c_client
*client
,
198 const struct i2c_device_id
*id
)
200 struct i2c_adapter
*adapter
= to_i2c_adapter(client
->dev
.parent
);
201 struct power_supply_config psy_cfg
= {};
202 struct max17040_chip
*chip
;
204 if (!i2c_check_functionality(adapter
, I2C_FUNC_SMBUS_BYTE
))
207 chip
= devm_kzalloc(&client
->dev
, sizeof(*chip
), GFP_KERNEL
);
211 chip
->client
= client
;
212 chip
->pdata
= client
->dev
.platform_data
;
214 i2c_set_clientdata(client
, chip
);
215 psy_cfg
.drv_data
= chip
;
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
);
224 max17040_reset(client
);
225 max17040_get_version(client
);
227 INIT_DEFERRABLE_WORK(&chip
->work
, max17040_work
);
228 queue_delayed_work(system_power_efficient_wq
, &chip
->work
,
234 static int max17040_remove(struct i2c_client
*client
)
236 struct max17040_chip
*chip
= i2c_get_clientdata(client
);
238 power_supply_unregister(chip
->battery
);
239 cancel_delayed_work(&chip
->work
);
243 #ifdef CONFIG_PM_SLEEP
245 static int max17040_suspend(struct device
*dev
)
247 struct i2c_client
*client
= to_i2c_client(dev
);
248 struct max17040_chip
*chip
= i2c_get_clientdata(client
);
250 cancel_delayed_work(&chip
->work
);
254 static int max17040_resume(struct device
*dev
)
256 struct i2c_client
*client
= to_i2c_client(dev
);
257 struct max17040_chip
*chip
= i2c_get_clientdata(client
);
259 queue_delayed_work(system_power_efficient_wq
, &chip
->work
,
264 static SIMPLE_DEV_PM_OPS(max17040_pm_ops
, max17040_suspend
, max17040_resume
);
265 #define MAX17040_PM_OPS (&max17040_pm_ops)
269 #define MAX17040_PM_OPS NULL
271 #endif /* CONFIG_PM_SLEEP */
273 static const struct i2c_device_id max17040_id
[] = {
275 { "max77836-battery" },
278 MODULE_DEVICE_TABLE(i2c
, max17040_id
);
280 static const struct of_device_id max17040_of_match
[] = {
281 { .compatible
= "maxim,max17040" },
282 { .compatible
= "maxim,max77836-battery" },
285 MODULE_DEVICE_TABLE(of
, max17040_of_match
);
287 static struct i2c_driver max17040_i2c_driver
= {
290 .of_match_table
= max17040_of_match
,
291 .pm
= MAX17040_PM_OPS
,
293 .probe
= max17040_probe
,
294 .remove
= max17040_remove
,
295 .id_table
= max17040_id
,
297 module_i2c_driver(max17040_i2c_driver
);
299 MODULE_AUTHOR("Minkyu Kang <mk7.kang@samsung.com>");
300 MODULE_DESCRIPTION("MAX17040 Fuel Gauge");
301 MODULE_LICENSE("GPL");