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