1 /*
2  * Fuel gauge driver for Maxim 17042 / 8966 / 8997
3  *  Note that Maxim 8966 and 8997 are mfd and this is its subdevice.
4  *
5  * Copyright (C) 2011 Samsung Electronics
6  * MyungJoo Ham <myungjoo.ham@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 as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21  *
22  * This driver is based on max17040_battery.c
23  */
24 
25 #include <linux/init.h>
26 #include <linux/slab.h>
27 #include <linux/i2c.h>
28 #include <linux/mod_devicetable.h>
29 #include <linux/power_supply.h>
30 #include <linux/power/max17042_battery.h>
31 
32 enum max17042_register {
33 	MAX17042_STATUS		= 0x00,
34 	MAX17042_VALRT_Th	= 0x01,
35 	MAX17042_TALRT_Th	= 0x02,
36 	MAX17042_SALRT_Th	= 0x03,
37 	MAX17042_AtRate		= 0x04,
38 	MAX17042_RepCap		= 0x05,
39 	MAX17042_RepSOC		= 0x06,
40 	MAX17042_Age		= 0x07,
41 	MAX17042_TEMP		= 0x08,
42 	MAX17042_VCELL		= 0x09,
43 	MAX17042_Current	= 0x0A,
44 	MAX17042_AvgCurrent	= 0x0B,
45 	MAX17042_Qresidual	= 0x0C,
46 	MAX17042_SOC		= 0x0D,
47 	MAX17042_AvSOC		= 0x0E,
48 	MAX17042_RemCap		= 0x0F,
49 	MAX17402_FullCAP	= 0x10,
50 	MAX17042_TTE		= 0x11,
51 	MAX17042_V_empty	= 0x12,
52 
53 	MAX17042_RSLOW		= 0x14,
54 
55 	MAX17042_AvgTA		= 0x16,
56 	MAX17042_Cycles		= 0x17,
57 	MAX17042_DesignCap	= 0x18,
58 	MAX17042_AvgVCELL	= 0x19,
59 	MAX17042_MinMaxTemp	= 0x1A,
60 	MAX17042_MinMaxVolt	= 0x1B,
61 	MAX17042_MinMaxCurr	= 0x1C,
62 	MAX17042_CONFIG		= 0x1D,
63 	MAX17042_ICHGTerm	= 0x1E,
64 	MAX17042_AvCap		= 0x1F,
65 	MAX17042_ManName	= 0x20,
66 	MAX17042_DevName	= 0x21,
67 	MAX17042_DevChem	= 0x22,
68 
69 	MAX17042_TempNom	= 0x24,
70 	MAX17042_TempCold	= 0x25,
71 	MAX17042_TempHot	= 0x26,
72 	MAX17042_AIN		= 0x27,
73 	MAX17042_LearnCFG	= 0x28,
74 	MAX17042_SHFTCFG	= 0x29,
75 	MAX17042_RelaxCFG	= 0x2A,
76 	MAX17042_MiscCFG	= 0x2B,
77 	MAX17042_TGAIN		= 0x2C,
78 	MAx17042_TOFF		= 0x2D,
79 	MAX17042_CGAIN		= 0x2E,
80 	MAX17042_COFF		= 0x2F,
81 
82 	MAX17042_Q_empty	= 0x33,
83 	MAX17042_T_empty	= 0x34,
84 
85 	MAX17042_RCOMP0		= 0x38,
86 	MAX17042_TempCo		= 0x39,
87 	MAX17042_Rx		= 0x3A,
88 	MAX17042_T_empty0	= 0x3B,
89 	MAX17042_TaskPeriod	= 0x3C,
90 	MAX17042_FSTAT		= 0x3D,
91 
92 	MAX17042_SHDNTIMER	= 0x3F,
93 
94 	MAX17042_VFRemCap	= 0x4A,
95 
96 	MAX17042_QH		= 0x4D,
97 	MAX17042_QL		= 0x4E,
98 };
99 
100 struct max17042_chip {
101 	struct i2c_client *client;
102 	struct power_supply battery;
103 	struct max17042_platform_data *pdata;
104 };
105 
max17042_write_reg(struct i2c_client * client,u8 reg,u16 value)106 static int max17042_write_reg(struct i2c_client *client, u8 reg, u16 value)
107 {
108 	int ret = i2c_smbus_write_word_data(client, reg, value);
109 
110 	if (ret < 0)
111 		dev_err(&client->dev, "%s: err %d\n", __func__, ret);
112 
113 	return ret;
114 }
115 
max17042_read_reg(struct i2c_client * client,u8 reg)116 static int max17042_read_reg(struct i2c_client *client, u8 reg)
117 {
118 	int ret = i2c_smbus_read_word_data(client, reg);
119 
120 	if (ret < 0)
121 		dev_err(&client->dev, "%s: err %d\n", __func__, ret);
122 
123 	return ret;
124 }
125 
126 static enum power_supply_property max17042_battery_props[] = {
127 	POWER_SUPPLY_PROP_VOLTAGE_NOW,
128 	POWER_SUPPLY_PROP_VOLTAGE_AVG,
129 	POWER_SUPPLY_PROP_CAPACITY,
130 };
131 
max17042_get_property(struct power_supply * psy,enum power_supply_property psp,union power_supply_propval * val)132 static int max17042_get_property(struct power_supply *psy,
133 			    enum power_supply_property psp,
134 			    union power_supply_propval *val)
135 {
136 	struct max17042_chip *chip = container_of(psy,
137 				struct max17042_chip, battery);
138 
139 	switch (psp) {
140 	case POWER_SUPPLY_PROP_VOLTAGE_NOW:
141 		val->intval = max17042_read_reg(chip->client,
142 				MAX17042_VCELL) * 83; /* 1000 / 12 = 83 */
143 		break;
144 	case POWER_SUPPLY_PROP_VOLTAGE_AVG:
145 		val->intval = max17042_read_reg(chip->client,
146 				MAX17042_AvgVCELL) * 83;
147 		break;
148 	case POWER_SUPPLY_PROP_CAPACITY:
149 		val->intval = max17042_read_reg(chip->client,
150 				MAX17042_SOC) / 256;
151 		break;
152 	default:
153 		return -EINVAL;
154 	}
155 	return 0;
156 }
157 
max17042_probe(struct i2c_client * client,const struct i2c_device_id * id)158 static int __devinit max17042_probe(struct i2c_client *client,
159 			const struct i2c_device_id *id)
160 {
161 	struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
162 	struct max17042_chip *chip;
163 	int ret;
164 
165 	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA))
166 		return -EIO;
167 
168 	chip = kzalloc(sizeof(*chip), GFP_KERNEL);
169 	if (!chip)
170 		return -ENOMEM;
171 
172 	chip->client = client;
173 	chip->pdata = client->dev.platform_data;
174 
175 	i2c_set_clientdata(client, chip);
176 
177 	chip->battery.name		= "max17042_battery";
178 	chip->battery.type		= POWER_SUPPLY_TYPE_BATTERY;
179 	chip->battery.get_property	= max17042_get_property;
180 	chip->battery.properties	= max17042_battery_props;
181 	chip->battery.num_properties	= ARRAY_SIZE(max17042_battery_props);
182 
183 	ret = power_supply_register(&client->dev, &chip->battery);
184 	if (ret) {
185 		dev_err(&client->dev, "failed: power supply register\n");
186 		i2c_set_clientdata(client, NULL);
187 		kfree(chip);
188 		return ret;
189 	}
190 
191 	if (!chip->pdata->enable_current_sense) {
192 		max17042_write_reg(client, MAX17042_CGAIN, 0x0000);
193 		max17042_write_reg(client, MAX17042_MiscCFG, 0x0003);
194 		max17042_write_reg(client, MAX17042_LearnCFG, 0x0007);
195 	}
196 
197 	return 0;
198 }
199 
max17042_remove(struct i2c_client * client)200 static int __devexit max17042_remove(struct i2c_client *client)
201 {
202 	struct max17042_chip *chip = i2c_get_clientdata(client);
203 
204 	power_supply_unregister(&chip->battery);
205 	i2c_set_clientdata(client, NULL);
206 	kfree(chip);
207 	return 0;
208 }
209 
210 static const struct i2c_device_id max17042_id[] = {
211 	{ "max17042", 0 },
212 	{ }
213 };
214 MODULE_DEVICE_TABLE(i2c, max17042_id);
215 
216 static struct i2c_driver max17042_i2c_driver = {
217 	.driver	= {
218 		.name	= "max17042",
219 	},
220 	.probe		= max17042_probe,
221 	.remove		= __devexit_p(max17042_remove),
222 	.id_table	= max17042_id,
223 };
224 
max17042_init(void)225 static int __init max17042_init(void)
226 {
227 	return i2c_add_driver(&max17042_i2c_driver);
228 }
229 module_init(max17042_init);
230 
max17042_exit(void)231 static void __exit max17042_exit(void)
232 {
233 	i2c_del_driver(&max17042_i2c_driver);
234 }
235 module_exit(max17042_exit);
236 
237 MODULE_AUTHOR("MyungJoo Ham <myungjoo.ham@samsung.com>");
238 MODULE_DESCRIPTION("MAX17042 Fuel Gauge");
239 MODULE_LICENSE("GPL");
240