1 /*
2  * I2C client/driver for the Maxim/Dallas DS2782 Stand-Alone Fuel Gauge IC
3  *
4  * Copyright (C) 2009 Bluewater Systems Ltd
5  *
6  * Author: Ryan Mallon
7  *
8  * DS2786 added by Yulia Vilensky <vilensky@compulab.co.il>
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 
16 #include <linux/kernel.h>
17 #include <linux/module.h>
18 #include <linux/types.h>
19 #include <linux/errno.h>
20 #include <linux/swab.h>
21 #include <linux/i2c.h>
22 #include <linux/idr.h>
23 #include <linux/power_supply.h>
24 #include <linux/slab.h>
25 #include <linux/ds2782_battery.h>
26 
27 #define DS2782_REG_RARC		0x06	/* Remaining active relative capacity */
28 
29 #define DS278x_REG_VOLT_MSB	0x0c
30 #define DS278x_REG_TEMP_MSB	0x0a
31 #define DS278x_REG_CURRENT_MSB	0x0e
32 
33 /* EEPROM Block */
34 #define DS2782_REG_RSNSP	0x69	/* Sense resistor value */
35 
36 /* Current unit measurement in uA for a 1 milli-ohm sense resistor */
37 #define DS2782_CURRENT_UNITS	1563
38 
39 #define DS2786_REG_RARC		0x02	/* Remaining active relative capacity */
40 
41 #define DS2786_CURRENT_UNITS	25
42 
43 struct ds278x_info;
44 
45 struct ds278x_battery_ops {
46 	int (*get_battery_current)(struct ds278x_info *info, int *current_uA);
47 	int (*get_battery_voltage)(struct ds278x_info *info, int *voltage_uV);
48 	int (*get_battery_capacity)(struct ds278x_info *info, int *capacity);
49 };
50 
51 #define to_ds278x_info(x) container_of(x, struct ds278x_info, battery)
52 
53 struct ds278x_info {
54 	struct i2c_client	*client;
55 	struct power_supply	battery;
56 	struct ds278x_battery_ops  *ops;
57 	int			id;
58 	int                     rsns;
59 };
60 
61 static DEFINE_IDR(battery_id);
62 static DEFINE_MUTEX(battery_lock);
63 
ds278x_read_reg(struct ds278x_info * info,int reg,u8 * val)64 static inline int ds278x_read_reg(struct ds278x_info *info, int reg, u8 *val)
65 {
66 	int ret;
67 
68 	ret = i2c_smbus_read_byte_data(info->client, reg);
69 	if (ret < 0) {
70 		dev_err(&info->client->dev, "register read failed\n");
71 		return ret;
72 	}
73 
74 	*val = ret;
75 	return 0;
76 }
77 
ds278x_read_reg16(struct ds278x_info * info,int reg_msb,s16 * val)78 static inline int ds278x_read_reg16(struct ds278x_info *info, int reg_msb,
79 				    s16 *val)
80 {
81 	int ret;
82 
83 	ret = swab16(i2c_smbus_read_word_data(info->client, reg_msb));
84 	if (ret < 0) {
85 		dev_err(&info->client->dev, "register read failed\n");
86 		return ret;
87 	}
88 
89 	*val = ret;
90 	return 0;
91 }
92 
ds278x_get_temp(struct ds278x_info * info,int * temp)93 static int ds278x_get_temp(struct ds278x_info *info, int *temp)
94 {
95 	s16 raw;
96 	int err;
97 
98 	/*
99 	 * Temperature is measured in units of 0.125 degrees celcius, the
100 	 * power_supply class measures temperature in tenths of degrees
101 	 * celsius. The temperature value is stored as a 10 bit number, plus
102 	 * sign in the upper bits of a 16 bit register.
103 	 */
104 	err = ds278x_read_reg16(info, DS278x_REG_TEMP_MSB, &raw);
105 	if (err)
106 		return err;
107 	*temp = ((raw / 32) * 125) / 100;
108 	return 0;
109 }
110 
ds2782_get_current(struct ds278x_info * info,int * current_uA)111 static int ds2782_get_current(struct ds278x_info *info, int *current_uA)
112 {
113 	int sense_res;
114 	int err;
115 	u8 sense_res_raw;
116 	s16 raw;
117 
118 	/*
119 	 * The units of measurement for current are dependent on the value of
120 	 * the sense resistor.
121 	 */
122 	err = ds278x_read_reg(info, DS2782_REG_RSNSP, &sense_res_raw);
123 	if (err)
124 		return err;
125 	if (sense_res_raw == 0) {
126 		dev_err(&info->client->dev, "sense resistor value is 0\n");
127 		return -ENXIO;
128 	}
129 	sense_res = 1000 / sense_res_raw;
130 
131 	dev_dbg(&info->client->dev, "sense resistor = %d milli-ohms\n",
132 		sense_res);
133 	err = ds278x_read_reg16(info, DS278x_REG_CURRENT_MSB, &raw);
134 	if (err)
135 		return err;
136 	*current_uA = raw * (DS2782_CURRENT_UNITS / sense_res);
137 	return 0;
138 }
139 
ds2782_get_voltage(struct ds278x_info * info,int * voltage_uV)140 static int ds2782_get_voltage(struct ds278x_info *info, int *voltage_uV)
141 {
142 	s16 raw;
143 	int err;
144 
145 	/*
146 	 * Voltage is measured in units of 4.88mV. The voltage is stored as
147 	 * a 10-bit number plus sign, in the upper bits of a 16-bit register
148 	 */
149 	err = ds278x_read_reg16(info, DS278x_REG_VOLT_MSB, &raw);
150 	if (err)
151 		return err;
152 	*voltage_uV = (raw / 32) * 4800;
153 	return 0;
154 }
155 
ds2782_get_capacity(struct ds278x_info * info,int * capacity)156 static int ds2782_get_capacity(struct ds278x_info *info, int *capacity)
157 {
158 	int err;
159 	u8 raw;
160 
161 	err = ds278x_read_reg(info, DS2782_REG_RARC, &raw);
162 	if (err)
163 		return err;
164 	*capacity = raw;
165 	return 0;
166 }
167 
ds2786_get_current(struct ds278x_info * info,int * current_uA)168 static int ds2786_get_current(struct ds278x_info *info, int *current_uA)
169 {
170 	int err;
171 	s16 raw;
172 
173 	err = ds278x_read_reg16(info, DS278x_REG_CURRENT_MSB, &raw);
174 	if (err)
175 		return err;
176 	*current_uA = (raw / 16) * (DS2786_CURRENT_UNITS / info->rsns);
177 	return 0;
178 }
179 
ds2786_get_voltage(struct ds278x_info * info,int * voltage_uV)180 static int ds2786_get_voltage(struct ds278x_info *info, int *voltage_uV)
181 {
182 	s16 raw;
183 	int err;
184 
185 	/*
186 	 * Voltage is measured in units of 1.22mV. The voltage is stored as
187 	 * a 10-bit number plus sign, in the upper bits of a 16-bit register
188 	 */
189 	err = ds278x_read_reg16(info, DS278x_REG_VOLT_MSB, &raw);
190 	if (err)
191 		return err;
192 	*voltage_uV = (raw / 8) * 1220;
193 	return 0;
194 }
195 
ds2786_get_capacity(struct ds278x_info * info,int * capacity)196 static int ds2786_get_capacity(struct ds278x_info *info, int *capacity)
197 {
198 	int err;
199 	u8 raw;
200 
201 	err = ds278x_read_reg(info, DS2786_REG_RARC, &raw);
202 	if (err)
203 		return err;
204 	/* Relative capacity is displayed with resolution 0.5 % */
205 	*capacity = raw/2 ;
206 	return 0;
207 }
208 
ds278x_get_status(struct ds278x_info * info,int * status)209 static int ds278x_get_status(struct ds278x_info *info, int *status)
210 {
211 	int err;
212 	int current_uA;
213 	int capacity;
214 
215 	err = info->ops->get_battery_current(info, &current_uA);
216 	if (err)
217 		return err;
218 
219 	err = info->ops->get_battery_capacity(info, &capacity);
220 	if (err)
221 		return err;
222 
223 	if (capacity == 100)
224 		*status = POWER_SUPPLY_STATUS_FULL;
225 	else if (current_uA == 0)
226 		*status = POWER_SUPPLY_STATUS_NOT_CHARGING;
227 	else if (current_uA < 0)
228 		*status = POWER_SUPPLY_STATUS_DISCHARGING;
229 	else
230 		*status = POWER_SUPPLY_STATUS_CHARGING;
231 
232 	return 0;
233 }
234 
ds278x_battery_get_property(struct power_supply * psy,enum power_supply_property prop,union power_supply_propval * val)235 static int ds278x_battery_get_property(struct power_supply *psy,
236 				       enum power_supply_property prop,
237 				       union power_supply_propval *val)
238 {
239 	struct ds278x_info *info = to_ds278x_info(psy);
240 	int ret;
241 
242 	switch (prop) {
243 	case POWER_SUPPLY_PROP_STATUS:
244 		ret = ds278x_get_status(info, &val->intval);
245 		break;
246 
247 	case POWER_SUPPLY_PROP_CAPACITY:
248 		ret = info->ops->get_battery_capacity(info, &val->intval);
249 		break;
250 
251 	case POWER_SUPPLY_PROP_VOLTAGE_NOW:
252 		ret = info->ops->get_battery_voltage(info, &val->intval);
253 		break;
254 
255 	case POWER_SUPPLY_PROP_CURRENT_NOW:
256 		ret = info->ops->get_battery_current(info, &val->intval);
257 		break;
258 
259 	case POWER_SUPPLY_PROP_TEMP:
260 		ret = ds278x_get_temp(info, &val->intval);
261 		break;
262 
263 	default:
264 		ret = -EINVAL;
265 	}
266 
267 	return ret;
268 }
269 
270 static enum power_supply_property ds278x_battery_props[] = {
271 	POWER_SUPPLY_PROP_STATUS,
272 	POWER_SUPPLY_PROP_CAPACITY,
273 	POWER_SUPPLY_PROP_VOLTAGE_NOW,
274 	POWER_SUPPLY_PROP_CURRENT_NOW,
275 	POWER_SUPPLY_PROP_TEMP,
276 };
277 
ds278x_power_supply_init(struct power_supply * battery)278 static void ds278x_power_supply_init(struct power_supply *battery)
279 {
280 	battery->type			= POWER_SUPPLY_TYPE_BATTERY;
281 	battery->properties		= ds278x_battery_props;
282 	battery->num_properties		= ARRAY_SIZE(ds278x_battery_props);
283 	battery->get_property		= ds278x_battery_get_property;
284 	battery->external_power_changed	= NULL;
285 }
286 
ds278x_battery_remove(struct i2c_client * client)287 static int ds278x_battery_remove(struct i2c_client *client)
288 {
289 	struct ds278x_info *info = i2c_get_clientdata(client);
290 
291 	power_supply_unregister(&info->battery);
292 	kfree(info->battery.name);
293 
294 	mutex_lock(&battery_lock);
295 	idr_remove(&battery_id, info->id);
296 	mutex_unlock(&battery_lock);
297 
298 	kfree(info);
299 	return 0;
300 }
301 
302 enum ds278x_num_id {
303 	DS2782 = 0,
304 	DS2786,
305 };
306 
307 static struct ds278x_battery_ops ds278x_ops[] = {
308 	[DS2782] = {
309 		.get_battery_current  = ds2782_get_current,
310 		.get_battery_voltage  = ds2782_get_voltage,
311 		.get_battery_capacity = ds2782_get_capacity,
312 	},
313 	[DS2786] = {
314 		.get_battery_current  = ds2786_get_current,
315 		.get_battery_voltage  = ds2786_get_voltage,
316 		.get_battery_capacity = ds2786_get_capacity,
317 	}
318 };
319 
ds278x_battery_probe(struct i2c_client * client,const struct i2c_device_id * id)320 static int ds278x_battery_probe(struct i2c_client *client,
321 				const struct i2c_device_id *id)
322 {
323 	struct ds278x_platform_data *pdata = client->dev.platform_data;
324 	struct ds278x_info *info;
325 	int ret;
326 	int num;
327 
328 	/*
329 	 * ds2786 should have the sense resistor value set
330 	 * in the platform data
331 	 */
332 	if (id->driver_data == DS2786 && !pdata) {
333 		dev_err(&client->dev, "missing platform data for ds2786\n");
334 		return -EINVAL;
335 	}
336 
337 	/* Get an ID for this battery */
338 	ret = idr_pre_get(&battery_id, GFP_KERNEL);
339 	if (ret == 0) {
340 		ret = -ENOMEM;
341 		goto fail_id;
342 	}
343 
344 	mutex_lock(&battery_lock);
345 	ret = idr_get_new(&battery_id, client, &num);
346 	mutex_unlock(&battery_lock);
347 	if (ret < 0)
348 		goto fail_id;
349 
350 	info = kzalloc(sizeof(*info), GFP_KERNEL);
351 	if (!info) {
352 		ret = -ENOMEM;
353 		goto fail_info;
354 	}
355 
356 	info->battery.name = kasprintf(GFP_KERNEL, "%s-%d", client->name, num);
357 	if (!info->battery.name) {
358 		ret = -ENOMEM;
359 		goto fail_name;
360 	}
361 
362 	if (id->driver_data == DS2786)
363 		info->rsns = pdata->rsns;
364 
365 	i2c_set_clientdata(client, info);
366 	info->client = client;
367 	info->id = num;
368 	info->ops  = &ds278x_ops[id->driver_data];
369 	ds278x_power_supply_init(&info->battery);
370 
371 	ret = power_supply_register(&client->dev, &info->battery);
372 	if (ret) {
373 		dev_err(&client->dev, "failed to register battery\n");
374 		goto fail_register;
375 	}
376 
377 	return 0;
378 
379 fail_register:
380 	kfree(info->battery.name);
381 fail_name:
382 	kfree(info);
383 fail_info:
384 	mutex_lock(&battery_lock);
385 	idr_remove(&battery_id, num);
386 	mutex_unlock(&battery_lock);
387 fail_id:
388 	return ret;
389 }
390 
391 static const struct i2c_device_id ds278x_id[] = {
392 	{"ds2782", DS2782},
393 	{"ds2786", DS2786},
394 	{},
395 };
396 MODULE_DEVICE_TABLE(i2c, ds278x_id);
397 
398 static struct i2c_driver ds278x_battery_driver = {
399 	.driver 	= {
400 		.name	= "ds2782-battery",
401 	},
402 	.probe		= ds278x_battery_probe,
403 	.remove		= ds278x_battery_remove,
404 	.id_table	= ds278x_id,
405 };
406 
ds278x_init(void)407 static int __init ds278x_init(void)
408 {
409 	return i2c_add_driver(&ds278x_battery_driver);
410 }
411 module_init(ds278x_init);
412 
ds278x_exit(void)413 static void __exit ds278x_exit(void)
414 {
415 	i2c_del_driver(&ds278x_battery_driver);
416 }
417 module_exit(ds278x_exit);
418 
419 MODULE_AUTHOR("Ryan Mallon");
420 MODULE_DESCRIPTION("Maxim/Dallas DS2782 Stand-Alone Fuel Gauage IC driver");
421 MODULE_LICENSE("GPL");
422