Blame view

drivers/power/sbs-battery.c 21 KB
a7640bfa1   Rhyland Klein   power_supply: Add...
1
  /*
3ddca062f   Rhyland Klein   sbs-battery: Rena...
2
   * Gas Gauge driver for SBS Compliant Batteries
a7640bfa1   Rhyland Klein   power_supply: Add...
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
   *
   * Copyright (c) 2010, NVIDIA Corporation.
   *
   * This program is free software; you can redistribute it and/or modify
   * it under the terms of the GNU General Public License as published by
   * the Free Software Foundation; either version 2 of the License, or
   * (at your option) any later version.
   *
   * This program is distributed in the hope that it will be useful, but WITHOUT
   * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
   * more details.
   *
   * You should have received a copy of the GNU General Public License along
   * with this program; if not, write to the Free Software Foundation, Inc.,
   * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
   */
  
  #include <linux/init.h>
  #include <linux/module.h>
  #include <linux/kernel.h>
  #include <linux/err.h>
  #include <linux/power_supply.h>
  #include <linux/i2c.h>
  #include <linux/slab.h>
bb8791016   Rhyland Klein   bq20z75: Add opti...
28
29
  #include <linux/interrupt.h>
  #include <linux/gpio.h>
3ddca062f   Rhyland Klein   sbs-battery: Rena...
30
  #include <linux/power/sbs-battery.h>
a7640bfa1   Rhyland Klein   power_supply: Add...
31
32
33
34
35
36
37
38
39
40
41
  
  enum {
  	REG_MANUFACTURER_DATA,
  	REG_TEMPERATURE,
  	REG_VOLTAGE,
  	REG_CURRENT,
  	REG_CAPACITY,
  	REG_TIME_TO_EMPTY,
  	REG_TIME_TO_FULL,
  	REG_STATUS,
  	REG_CYCLE_COUNT,
d3ab61ecb   Rhyland Klein   bq20z75: Add supp...
42
43
  	REG_SERIAL_NUMBER,
  	REG_REMAINING_CAPACITY,
51d075660   Rhyland Klein   bq20z75: Add supp...
44
  	REG_REMAINING_CAPACITY_CHARGE,
d3ab61ecb   Rhyland Klein   bq20z75: Add supp...
45
  	REG_FULL_CHARGE_CAPACITY,
51d075660   Rhyland Klein   bq20z75: Add supp...
46
  	REG_FULL_CHARGE_CAPACITY_CHARGE,
d3ab61ecb   Rhyland Klein   bq20z75: Add supp...
47
  	REG_DESIGN_CAPACITY,
51d075660   Rhyland Klein   bq20z75: Add supp...
48
  	REG_DESIGN_CAPACITY_CHARGE,
d3ab61ecb   Rhyland Klein   bq20z75: Add supp...
49
  	REG_DESIGN_VOLTAGE,
a7640bfa1   Rhyland Klein   power_supply: Add...
50
  };
51d075660   Rhyland Klein   bq20z75: Add supp...
51
52
53
  /* Battery Mode defines */
  #define BATTERY_MODE_OFFSET		0x03
  #define BATTERY_MODE_MASK		0x8000
3ddca062f   Rhyland Klein   sbs-battery: Rena...
54
  enum sbs_battery_mode {
51d075660   Rhyland Klein   bq20z75: Add supp...
55
56
57
  	BATTERY_MODE_AMPS,
  	BATTERY_MODE_WATTS
  };
a7640bfa1   Rhyland Klein   power_supply: Add...
58
59
60
61
62
  /* manufacturer access defines */
  #define MANUFACTURER_ACCESS_STATUS	0x0006
  #define MANUFACTURER_ACCESS_SLEEP	0x0011
  
  /* battery status value bits */
d3ab61ecb   Rhyland Klein   bq20z75: Add supp...
63
  #define BATTERY_DISCHARGING		0x40
a7640bfa1   Rhyland Klein   power_supply: Add...
64
65
  #define BATTERY_FULL_CHARGED		0x20
  #define BATTERY_FULL_DISCHARGED		0x10
3ddca062f   Rhyland Klein   sbs-battery: Rena...
66
  #define SBS_DATA(_psp, _addr, _min_value, _max_value) { \
a7640bfa1   Rhyland Klein   power_supply: Add...
67
68
69
70
71
  	.psp = _psp, \
  	.addr = _addr, \
  	.min_value = _min_value, \
  	.max_value = _max_value, \
  }
3ddca062f   Rhyland Klein   sbs-battery: Rena...
72
  static const struct chip_data {
a7640bfa1   Rhyland Klein   power_supply: Add...
73
74
75
76
  	enum power_supply_property psp;
  	u8 addr;
  	int min_value;
  	int max_value;
3ddca062f   Rhyland Klein   sbs-battery: Rena...
77
  } sbs_data[] = {
a7640bfa1   Rhyland Klein   power_supply: Add...
78
  	[REG_MANUFACTURER_DATA] =
3ddca062f   Rhyland Klein   sbs-battery: Rena...
79
  		SBS_DATA(POWER_SUPPLY_PROP_PRESENT, 0x00, 0, 65535),
a7640bfa1   Rhyland Klein   power_supply: Add...
80
  	[REG_TEMPERATURE] =
3ddca062f   Rhyland Klein   sbs-battery: Rena...
81
  		SBS_DATA(POWER_SUPPLY_PROP_TEMP, 0x08, 0, 65535),
a7640bfa1   Rhyland Klein   power_supply: Add...
82
  	[REG_VOLTAGE] =
3ddca062f   Rhyland Klein   sbs-battery: Rena...
83
  		SBS_DATA(POWER_SUPPLY_PROP_VOLTAGE_NOW, 0x09, 0, 20000),
a7640bfa1   Rhyland Klein   power_supply: Add...
84
  	[REG_CURRENT] =
3ddca062f   Rhyland Klein   sbs-battery: Rena...
85
  		SBS_DATA(POWER_SUPPLY_PROP_CURRENT_NOW, 0x0A, -32768, 32767),
a7640bfa1   Rhyland Klein   power_supply: Add...
86
  	[REG_CAPACITY] =
3ddca062f   Rhyland Klein   sbs-battery: Rena...
87
  		SBS_DATA(POWER_SUPPLY_PROP_CAPACITY, 0x0E, 0, 100),
d3ab61ecb   Rhyland Klein   bq20z75: Add supp...
88
  	[REG_REMAINING_CAPACITY] =
3ddca062f   Rhyland Klein   sbs-battery: Rena...
89
  		SBS_DATA(POWER_SUPPLY_PROP_ENERGY_NOW, 0x0F, 0, 65535),
51d075660   Rhyland Klein   bq20z75: Add supp...
90
  	[REG_REMAINING_CAPACITY_CHARGE] =
3ddca062f   Rhyland Klein   sbs-battery: Rena...
91
  		SBS_DATA(POWER_SUPPLY_PROP_CHARGE_NOW, 0x0F, 0, 65535),
d3ab61ecb   Rhyland Klein   bq20z75: Add supp...
92
  	[REG_FULL_CHARGE_CAPACITY] =
3ddca062f   Rhyland Klein   sbs-battery: Rena...
93
  		SBS_DATA(POWER_SUPPLY_PROP_ENERGY_FULL, 0x10, 0, 65535),
51d075660   Rhyland Klein   bq20z75: Add supp...
94
  	[REG_FULL_CHARGE_CAPACITY_CHARGE] =
3ddca062f   Rhyland Klein   sbs-battery: Rena...
95
  		SBS_DATA(POWER_SUPPLY_PROP_CHARGE_FULL, 0x10, 0, 65535),
a7640bfa1   Rhyland Klein   power_supply: Add...
96
  	[REG_TIME_TO_EMPTY] =
3ddca062f   Rhyland Klein   sbs-battery: Rena...
97
  		SBS_DATA(POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG, 0x12, 0, 65535),
a7640bfa1   Rhyland Klein   power_supply: Add...
98
  	[REG_TIME_TO_FULL] =
3ddca062f   Rhyland Klein   sbs-battery: Rena...
99
  		SBS_DATA(POWER_SUPPLY_PROP_TIME_TO_FULL_AVG, 0x13, 0, 65535),
a7640bfa1   Rhyland Klein   power_supply: Add...
100
  	[REG_STATUS] =
3ddca062f   Rhyland Klein   sbs-battery: Rena...
101
  		SBS_DATA(POWER_SUPPLY_PROP_STATUS, 0x16, 0, 65535),
a7640bfa1   Rhyland Klein   power_supply: Add...
102
  	[REG_CYCLE_COUNT] =
3ddca062f   Rhyland Klein   sbs-battery: Rena...
103
  		SBS_DATA(POWER_SUPPLY_PROP_CYCLE_COUNT, 0x17, 0, 65535),
d3ab61ecb   Rhyland Klein   bq20z75: Add supp...
104
  	[REG_DESIGN_CAPACITY] =
3ddca062f   Rhyland Klein   sbs-battery: Rena...
105
  		SBS_DATA(POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN, 0x18, 0, 65535),
51d075660   Rhyland Klein   bq20z75: Add supp...
106
  	[REG_DESIGN_CAPACITY_CHARGE] =
3ddca062f   Rhyland Klein   sbs-battery: Rena...
107
  		SBS_DATA(POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, 0x18, 0, 65535),
d3ab61ecb   Rhyland Klein   bq20z75: Add supp...
108
  	[REG_DESIGN_VOLTAGE] =
3ddca062f   Rhyland Klein   sbs-battery: Rena...
109
  		SBS_DATA(POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN, 0x19, 0, 65535),
a7640bfa1   Rhyland Klein   power_supply: Add...
110
  	[REG_SERIAL_NUMBER] =
3ddca062f   Rhyland Klein   sbs-battery: Rena...
111
  		SBS_DATA(POWER_SUPPLY_PROP_SERIAL_NUMBER, 0x1C, 0, 65535),
a7640bfa1   Rhyland Klein   power_supply: Add...
112
  };
3ddca062f   Rhyland Klein   sbs-battery: Rena...
113
  static enum power_supply_property sbs_properties[] = {
a7640bfa1   Rhyland Klein   power_supply: Add...
114
115
116
117
118
119
120
121
122
123
124
125
  	POWER_SUPPLY_PROP_STATUS,
  	POWER_SUPPLY_PROP_HEALTH,
  	POWER_SUPPLY_PROP_PRESENT,
  	POWER_SUPPLY_PROP_TECHNOLOGY,
  	POWER_SUPPLY_PROP_CYCLE_COUNT,
  	POWER_SUPPLY_PROP_VOLTAGE_NOW,
  	POWER_SUPPLY_PROP_CURRENT_NOW,
  	POWER_SUPPLY_PROP_CAPACITY,
  	POWER_SUPPLY_PROP_TEMP,
  	POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG,
  	POWER_SUPPLY_PROP_TIME_TO_FULL_AVG,
  	POWER_SUPPLY_PROP_SERIAL_NUMBER,
d3ab61ecb   Rhyland Klein   bq20z75: Add supp...
126
127
128
129
  	POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN,
  	POWER_SUPPLY_PROP_ENERGY_NOW,
  	POWER_SUPPLY_PROP_ENERGY_FULL,
  	POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN,
51d075660   Rhyland Klein   bq20z75: Add supp...
130
131
132
  	POWER_SUPPLY_PROP_CHARGE_NOW,
  	POWER_SUPPLY_PROP_CHARGE_FULL,
  	POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
a7640bfa1   Rhyland Klein   power_supply: Add...
133
  };
3ddca062f   Rhyland Klein   sbs-battery: Rena...
134
  struct sbs_info {
bb8791016   Rhyland Klein   bq20z75: Add opti...
135
136
  	struct i2c_client		*client;
  	struct power_supply		power_supply;
3ddca062f   Rhyland Klein   sbs-battery: Rena...
137
  	struct sbs_platform_data	*pdata;
bb8791016   Rhyland Klein   bq20z75: Add opti...
138
139
140
141
  	bool				is_present;
  	bool				gpio_detect;
  	bool				enable_detection;
  	int				irq;
58ddafae2   Rhyland Klein   bq20z75: Add supp...
142
143
144
145
  	int				last_state;
  	int				poll_time;
  	struct delayed_work		work;
  	int				ignore_changes;
a7640bfa1   Rhyland Klein   power_supply: Add...
146
  };
3ddca062f   Rhyland Klein   sbs-battery: Rena...
147
  static int sbs_read_word_data(struct i2c_client *client, u8 address)
d3ab61ecb   Rhyland Klein   bq20z75: Add supp...
148
  {
3ddca062f   Rhyland Klein   sbs-battery: Rena...
149
  	struct sbs_info *chip = i2c_get_clientdata(client);
ff28fcef1   Rhyland Klein   bq20z75: Add i2c ...
150
151
  	s32 ret = 0;
  	int retries = 1;
3ddca062f   Rhyland Klein   sbs-battery: Rena...
152
153
  	if (chip->pdata)
  		retries = max(chip->pdata->i2c_retry_count + 1, 1);
ff28fcef1   Rhyland Klein   bq20z75: Add i2c ...
154
155
156
157
158
159
160
  
  	while (retries > 0) {
  		ret = i2c_smbus_read_word_data(client, address);
  		if (ret >= 0)
  			break;
  		retries--;
  	}
d3ab61ecb   Rhyland Klein   bq20z75: Add supp...
161

d3ab61ecb   Rhyland Klein   bq20z75: Add supp...
162
  	if (ret < 0) {
a7d9ace4e   Rhyland Klein   bq20z75: Fix issu...
163
  		dev_dbg(&client->dev,
d3ab61ecb   Rhyland Klein   bq20z75: Add supp...
164
165
166
167
168
  			"%s: i2c read at address 0x%x failed
  ",
  			__func__, address);
  		return ret;
  	}
ff28fcef1   Rhyland Klein   bq20z75: Add i2c ...
169

d3ab61ecb   Rhyland Klein   bq20z75: Add supp...
170
171
  	return le16_to_cpu(ret);
  }
3ddca062f   Rhyland Klein   sbs-battery: Rena...
172
  static int sbs_write_word_data(struct i2c_client *client, u8 address,
d3ab61ecb   Rhyland Klein   bq20z75: Add supp...
173
174
  	u16 value)
  {
3ddca062f   Rhyland Klein   sbs-battery: Rena...
175
  	struct sbs_info *chip = i2c_get_clientdata(client);
ff28fcef1   Rhyland Klein   bq20z75: Add i2c ...
176
177
  	s32 ret = 0;
  	int retries = 1;
3ddca062f   Rhyland Klein   sbs-battery: Rena...
178
179
  	if (chip->pdata)
  		retries = max(chip->pdata->i2c_retry_count + 1, 1);
ff28fcef1   Rhyland Klein   bq20z75: Add i2c ...
180
181
182
183
184
185
186
187
  
  	while (retries > 0) {
  		ret = i2c_smbus_write_word_data(client, address,
  			le16_to_cpu(value));
  		if (ret >= 0)
  			break;
  		retries--;
  	}
d3ab61ecb   Rhyland Klein   bq20z75: Add supp...
188

d3ab61ecb   Rhyland Klein   bq20z75: Add supp...
189
  	if (ret < 0) {
a7d9ace4e   Rhyland Klein   bq20z75: Fix issu...
190
  		dev_dbg(&client->dev,
d3ab61ecb   Rhyland Klein   bq20z75: Add supp...
191
192
193
194
195
  			"%s: i2c write to address 0x%x failed
  ",
  			__func__, address);
  		return ret;
  	}
ff28fcef1   Rhyland Klein   bq20z75: Add i2c ...
196

d3ab61ecb   Rhyland Klein   bq20z75: Add supp...
197
198
  	return 0;
  }
3ddca062f   Rhyland Klein   sbs-battery: Rena...
199
  static int sbs_get_battery_presence_and_health(
a7640bfa1   Rhyland Klein   power_supply: Add...
200
201
202
203
  	struct i2c_client *client, enum power_supply_property psp,
  	union power_supply_propval *val)
  {
  	s32 ret;
3ddca062f   Rhyland Klein   sbs-battery: Rena...
204
  	struct sbs_info *chip = i2c_get_clientdata(client);
bb8791016   Rhyland Klein   bq20z75: Add opti...
205
206
  
  	if (psp == POWER_SUPPLY_PROP_PRESENT &&
3ddca062f   Rhyland Klein   sbs-battery: Rena...
207
208
209
  		chip->gpio_detect) {
  		ret = gpio_get_value(chip->pdata->battery_detect);
  		if (ret == chip->pdata->battery_detect_present)
bb8791016   Rhyland Klein   bq20z75: Add opti...
210
211
212
  			val->intval = 1;
  		else
  			val->intval = 0;
3ddca062f   Rhyland Klein   sbs-battery: Rena...
213
  		chip->is_present = val->intval;
bb8791016   Rhyland Klein   bq20z75: Add opti...
214
215
  		return ret;
  	}
a7640bfa1   Rhyland Klein   power_supply: Add...
216
217
218
219
  
  	/* Write to ManufacturerAccess with
  	 * ManufacturerAccess command and then
  	 * read the status */
3ddca062f   Rhyland Klein   sbs-battery: Rena...
220
221
  	ret = sbs_write_word_data(client, sbs_data[REG_MANUFACTURER_DATA].addr,
  					MANUFACTURER_ACCESS_STATUS);
bb8791016   Rhyland Klein   bq20z75: Add opti...
222
223
224
  	if (ret < 0) {
  		if (psp == POWER_SUPPLY_PROP_PRESENT)
  			val->intval = 0; /* battery removed */
d3ab61ecb   Rhyland Klein   bq20z75: Add supp...
225
  		return ret;
bb8791016   Rhyland Klein   bq20z75: Add opti...
226
  	}
a7640bfa1   Rhyland Klein   power_supply: Add...
227

3ddca062f   Rhyland Klein   sbs-battery: Rena...
228
  	ret = sbs_read_word_data(client, sbs_data[REG_MANUFACTURER_DATA].addr);
a7d9ace4e   Rhyland Klein   bq20z75: Fix issu...
229
230
  	if (ret < 0)
  		return ret;
3ddca062f   Rhyland Klein   sbs-battery: Rena...
231
232
  	if (ret < sbs_data[REG_MANUFACTURER_DATA].min_value ||
  	    ret > sbs_data[REG_MANUFACTURER_DATA].max_value) {
a7640bfa1   Rhyland Klein   power_supply: Add...
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
  		val->intval = 0;
  		return 0;
  	}
  
  	/* Mask the upper nibble of 2nd byte and
  	 * lower byte of response then
  	 * shift the result by 8 to get status*/
  	ret &= 0x0F00;
  	ret >>= 8;
  	if (psp == POWER_SUPPLY_PROP_PRESENT) {
  		if (ret == 0x0F)
  			/* battery removed */
  			val->intval = 0;
  		else
  			val->intval = 1;
  	} else if (psp == POWER_SUPPLY_PROP_HEALTH) {
  		if (ret == 0x09)
  			val->intval = POWER_SUPPLY_HEALTH_UNSPEC_FAILURE;
  		else if (ret == 0x0B)
  			val->intval = POWER_SUPPLY_HEALTH_OVERHEAT;
  		else if (ret == 0x0C)
  			val->intval = POWER_SUPPLY_HEALTH_DEAD;
  		else
  			val->intval = POWER_SUPPLY_HEALTH_GOOD;
  	}
  
  	return 0;
  }
3ddca062f   Rhyland Klein   sbs-battery: Rena...
261
  static int sbs_get_battery_property(struct i2c_client *client,
a7640bfa1   Rhyland Klein   power_supply: Add...
262
263
264
  	int reg_offset, enum power_supply_property psp,
  	union power_supply_propval *val)
  {
3ddca062f   Rhyland Klein   sbs-battery: Rena...
265
  	struct sbs_info *chip = i2c_get_clientdata(client);
a7640bfa1   Rhyland Klein   power_supply: Add...
266
  	s32 ret;
3ddca062f   Rhyland Klein   sbs-battery: Rena...
267
  	ret = sbs_read_word_data(client, sbs_data[reg_offset].addr);
d3ab61ecb   Rhyland Klein   bq20z75: Add supp...
268
269
270
271
  	if (ret < 0)
  		return ret;
  
  	/* returned values are 16 bit */
3ddca062f   Rhyland Klein   sbs-battery: Rena...
272
  	if (sbs_data[reg_offset].min_value < 0)
d3ab61ecb   Rhyland Klein   bq20z75: Add supp...
273
  		ret = (s16)ret;
a7640bfa1   Rhyland Klein   power_supply: Add...
274

3ddca062f   Rhyland Klein   sbs-battery: Rena...
275
276
  	if (ret >= sbs_data[reg_offset].min_value &&
  	    ret <= sbs_data[reg_offset].max_value) {
a7640bfa1   Rhyland Klein   power_supply: Add...
277
  		val->intval = ret;
58ddafae2   Rhyland Klein   bq20z75: Add supp...
278
279
280
281
282
283
284
285
286
287
288
  		if (psp != POWER_SUPPLY_PROP_STATUS)
  			return 0;
  
  		if (ret & BATTERY_FULL_CHARGED)
  			val->intval = POWER_SUPPLY_STATUS_FULL;
  		else if (ret & BATTERY_FULL_DISCHARGED)
  			val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
  		else if (ret & BATTERY_DISCHARGING)
  			val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
  		else
  			val->intval = POWER_SUPPLY_STATUS_CHARGING;
3ddca062f   Rhyland Klein   sbs-battery: Rena...
289
290
291
292
293
294
  		if (chip->poll_time == 0)
  			chip->last_state = val->intval;
  		else if (chip->last_state != val->intval) {
  			cancel_delayed_work_sync(&chip->work);
  			power_supply_changed(&chip->power_supply);
  			chip->poll_time = 0;
a7640bfa1   Rhyland Klein   power_supply: Add...
295
  		}
a7640bfa1   Rhyland Klein   power_supply: Add...
296
297
298
299
300
301
302
303
304
  	} else {
  		if (psp == POWER_SUPPLY_PROP_STATUS)
  			val->intval = POWER_SUPPLY_STATUS_UNKNOWN;
  		else
  			val->intval = 0;
  	}
  
  	return 0;
  }
3ddca062f   Rhyland Klein   sbs-battery: Rena...
305
  static void  sbs_unit_adjustment(struct i2c_client *client,
d3ab61ecb   Rhyland Klein   bq20z75: Add supp...
306
307
308
309
  	enum power_supply_property psp, union power_supply_propval *val)
  {
  #define BASE_UNIT_CONVERSION		1000
  #define BATTERY_MODE_CAP_MULT_WATT	(10 * BASE_UNIT_CONVERSION)
909a78b32   Benson Leung   bq20z75: Fix time...
310
311
  #define TIME_UNIT_CONVERSION		60
  #define TEMP_KELVIN_TO_CELSIUS		2731
d3ab61ecb   Rhyland Klein   bq20z75: Add supp...
312
313
314
315
  	switch (psp) {
  	case POWER_SUPPLY_PROP_ENERGY_NOW:
  	case POWER_SUPPLY_PROP_ENERGY_FULL:
  	case POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN:
3ddca062f   Rhyland Klein   sbs-battery: Rena...
316
  		/* sbs provides energy in units of 10mWh.
909a78b32   Benson Leung   bq20z75: Fix time...
317
318
  		 * Convert to µWh
  		 */
d3ab61ecb   Rhyland Klein   bq20z75: Add supp...
319
320
321
322
323
324
  		val->intval *= BATTERY_MODE_CAP_MULT_WATT;
  		break;
  
  	case POWER_SUPPLY_PROP_VOLTAGE_NOW:
  	case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN:
  	case POWER_SUPPLY_PROP_CURRENT_NOW:
51d075660   Rhyland Klein   bq20z75: Add supp...
325
326
327
  	case POWER_SUPPLY_PROP_CHARGE_NOW:
  	case POWER_SUPPLY_PROP_CHARGE_FULL:
  	case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN:
d3ab61ecb   Rhyland Klein   bq20z75: Add supp...
328
329
330
331
  		val->intval *= BASE_UNIT_CONVERSION;
  		break;
  
  	case POWER_SUPPLY_PROP_TEMP:
3ddca062f   Rhyland Klein   sbs-battery: Rena...
332
  		/* sbs provides battery temperature in 0.1K
909a78b32   Benson Leung   bq20z75: Fix time...
333
334
335
  		 * so convert it to 0.1°C
  		 */
  		val->intval -= TEMP_KELVIN_TO_CELSIUS;
d3ab61ecb   Rhyland Klein   bq20z75: Add supp...
336
337
338
339
  		break;
  
  	case POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG:
  	case POWER_SUPPLY_PROP_TIME_TO_FULL_AVG:
3ddca062f   Rhyland Klein   sbs-battery: Rena...
340
  		/* sbs provides time to empty and time to full in minutes.
909a78b32   Benson Leung   bq20z75: Fix time...
341
342
  		 * Convert to seconds
  		 */
d3ab61ecb   Rhyland Klein   bq20z75: Add supp...
343
344
345
346
347
348
349
350
351
  		val->intval *= TIME_UNIT_CONVERSION;
  		break;
  
  	default:
  		dev_dbg(&client->dev,
  			"%s: no need for unit conversion %d
  ", __func__, psp);
  	}
  }
3ddca062f   Rhyland Klein   sbs-battery: Rena...
352
353
  static enum sbs_battery_mode sbs_set_battery_mode(struct i2c_client *client,
  	enum sbs_battery_mode mode)
51d075660   Rhyland Klein   bq20z75: Add supp...
354
355
  {
  	int ret, original_val;
3ddca062f   Rhyland Klein   sbs-battery: Rena...
356
  	original_val = sbs_read_word_data(client, BATTERY_MODE_OFFSET);
51d075660   Rhyland Klein   bq20z75: Add supp...
357
358
359
360
361
362
363
364
365
366
  	if (original_val < 0)
  		return original_val;
  
  	if ((original_val & BATTERY_MODE_MASK) == mode)
  		return mode;
  
  	if (mode == BATTERY_MODE_AMPS)
  		ret = original_val & ~BATTERY_MODE_MASK;
  	else
  		ret = original_val | BATTERY_MODE_MASK;
3ddca062f   Rhyland Klein   sbs-battery: Rena...
367
  	ret = sbs_write_word_data(client, BATTERY_MODE_OFFSET, ret);
51d075660   Rhyland Klein   bq20z75: Add supp...
368
369
370
371
372
  	if (ret < 0)
  		return ret;
  
  	return original_val & BATTERY_MODE_MASK;
  }
3ddca062f   Rhyland Klein   sbs-battery: Rena...
373
  static int sbs_get_battery_capacity(struct i2c_client *client,
d3ab61ecb   Rhyland Klein   bq20z75: Add supp...
374
  	int reg_offset, enum power_supply_property psp,
a7640bfa1   Rhyland Klein   power_supply: Add...
375
376
377
  	union power_supply_propval *val)
  {
  	s32 ret;
3ddca062f   Rhyland Klein   sbs-battery: Rena...
378
  	enum sbs_battery_mode mode = BATTERY_MODE_WATTS;
51d075660   Rhyland Klein   bq20z75: Add supp...
379
380
381
  
  	if (power_supply_is_amp_property(psp))
  		mode = BATTERY_MODE_AMPS;
3ddca062f   Rhyland Klein   sbs-battery: Rena...
382
  	mode = sbs_set_battery_mode(client, mode);
51d075660   Rhyland Klein   bq20z75: Add supp...
383
384
  	if (mode < 0)
  		return mode;
a7640bfa1   Rhyland Klein   power_supply: Add...
385

3ddca062f   Rhyland Klein   sbs-battery: Rena...
386
  	ret = sbs_read_word_data(client, sbs_data[reg_offset].addr);
d3ab61ecb   Rhyland Klein   bq20z75: Add supp...
387
388
  	if (ret < 0)
  		return ret;
a7640bfa1   Rhyland Klein   power_supply: Add...
389

d3ab61ecb   Rhyland Klein   bq20z75: Add supp...
390
  	if (psp == POWER_SUPPLY_PROP_CAPACITY) {
3ddca062f   Rhyland Klein   sbs-battery: Rena...
391
  		/* sbs spec says that this can be >100 %
d3ab61ecb   Rhyland Klein   bq20z75: Add supp...
392
393
394
395
  		* even if max value is 100 % */
  		val->intval = min(ret, 100);
  	} else
  		val->intval = ret;
3ddca062f   Rhyland Klein   sbs-battery: Rena...
396
  	ret = sbs_set_battery_mode(client, mode);
51d075660   Rhyland Klein   bq20z75: Add supp...
397
398
  	if (ret < 0)
  		return ret;
d3ab61ecb   Rhyland Klein   bq20z75: Add supp...
399
400
  	return 0;
  }
3ddca062f   Rhyland Klein   sbs-battery: Rena...
401
402
  static char sbs_serial[5];
  static int sbs_get_battery_serial_number(struct i2c_client *client,
d3ab61ecb   Rhyland Klein   bq20z75: Add supp...
403
404
405
  	union power_supply_propval *val)
  {
  	int ret;
3ddca062f   Rhyland Klein   sbs-battery: Rena...
406
  	ret = sbs_read_word_data(client, sbs_data[REG_SERIAL_NUMBER].addr);
d3ab61ecb   Rhyland Klein   bq20z75: Add supp...
407
408
  	if (ret < 0)
  		return ret;
3ddca062f   Rhyland Klein   sbs-battery: Rena...
409
410
  	ret = sprintf(sbs_serial, "%04x", ret);
  	val->strval = sbs_serial;
a7640bfa1   Rhyland Klein   power_supply: Add...
411
412
413
  
  	return 0;
  }
3ddca062f   Rhyland Klein   sbs-battery: Rena...
414
  static int sbs_get_property_index(struct i2c_client *client,
51d075660   Rhyland Klein   bq20z75: Add supp...
415
416
417
  	enum power_supply_property psp)
  {
  	int count;
3ddca062f   Rhyland Klein   sbs-battery: Rena...
418
419
  	for (count = 0; count < ARRAY_SIZE(sbs_data); count++)
  		if (psp == sbs_data[count].psp)
51d075660   Rhyland Klein   bq20z75: Add supp...
420
421
422
423
424
425
426
427
  			return count;
  
  	dev_warn(&client->dev,
  		"%s: Invalid Property - %d
  ", __func__, psp);
  
  	return -EINVAL;
  }
3ddca062f   Rhyland Klein   sbs-battery: Rena...
428
  static int sbs_get_property(struct power_supply *psy,
a7640bfa1   Rhyland Klein   power_supply: Add...
429
430
431
  	enum power_supply_property psp,
  	union power_supply_propval *val)
  {
bb8791016   Rhyland Klein   bq20z75: Add opti...
432
  	int ret = 0;
3ddca062f   Rhyland Klein   sbs-battery: Rena...
433
434
435
  	struct sbs_info *chip = container_of(psy,
  				struct sbs_info, power_supply);
  	struct i2c_client *client = chip->client;
a7640bfa1   Rhyland Klein   power_supply: Add...
436
437
438
439
  
  	switch (psp) {
  	case POWER_SUPPLY_PROP_PRESENT:
  	case POWER_SUPPLY_PROP_HEALTH:
3ddca062f   Rhyland Klein   sbs-battery: Rena...
440
  		ret = sbs_get_battery_presence_and_health(client, psp, val);
a7d9ace4e   Rhyland Klein   bq20z75: Fix issu...
441
442
  		if (psp == POWER_SUPPLY_PROP_PRESENT)
  			return 0;
a7640bfa1   Rhyland Klein   power_supply: Add...
443
444
445
446
447
  		break;
  
  	case POWER_SUPPLY_PROP_TECHNOLOGY:
  		val->intval = POWER_SUPPLY_TECHNOLOGY_LION;
  		break;
d3ab61ecb   Rhyland Klein   bq20z75: Add supp...
448
449
450
  	case POWER_SUPPLY_PROP_ENERGY_NOW:
  	case POWER_SUPPLY_PROP_ENERGY_FULL:
  	case POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN:
51d075660   Rhyland Klein   bq20z75: Add supp...
451
452
453
  	case POWER_SUPPLY_PROP_CHARGE_NOW:
  	case POWER_SUPPLY_PROP_CHARGE_FULL:
  	case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN:
a7640bfa1   Rhyland Klein   power_supply: Add...
454
  	case POWER_SUPPLY_PROP_CAPACITY:
3ddca062f   Rhyland Klein   sbs-battery: Rena...
455
  		ret = sbs_get_property_index(client, psp);
bb8791016   Rhyland Klein   bq20z75: Add opti...
456
457
  		if (ret < 0)
  			break;
d3ab61ecb   Rhyland Klein   bq20z75: Add supp...
458

3ddca062f   Rhyland Klein   sbs-battery: Rena...
459
  		ret = sbs_get_battery_capacity(client, ret, psp, val);
d3ab61ecb   Rhyland Klein   bq20z75: Add supp...
460
461
462
  		break;
  
  	case POWER_SUPPLY_PROP_SERIAL_NUMBER:
3ddca062f   Rhyland Klein   sbs-battery: Rena...
463
  		ret = sbs_get_battery_serial_number(client, val);
a7640bfa1   Rhyland Klein   power_supply: Add...
464
465
466
467
468
469
470
471
472
  		break;
  
  	case POWER_SUPPLY_PROP_STATUS:
  	case POWER_SUPPLY_PROP_CYCLE_COUNT:
  	case POWER_SUPPLY_PROP_VOLTAGE_NOW:
  	case POWER_SUPPLY_PROP_CURRENT_NOW:
  	case POWER_SUPPLY_PROP_TEMP:
  	case POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG:
  	case POWER_SUPPLY_PROP_TIME_TO_FULL_AVG:
d3ab61ecb   Rhyland Klein   bq20z75: Add supp...
473
  	case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN:
3ddca062f   Rhyland Klein   sbs-battery: Rena...
474
  		ret = sbs_get_property_index(client, psp);
bb8791016   Rhyland Klein   bq20z75: Add opti...
475
476
  		if (ret < 0)
  			break;
d3ab61ecb   Rhyland Klein   bq20z75: Add supp...
477

3ddca062f   Rhyland Klein   sbs-battery: Rena...
478
  		ret = sbs_get_battery_property(client, ret, psp, val);
a7640bfa1   Rhyland Klein   power_supply: Add...
479
480
481
482
483
484
485
486
  		break;
  
  	default:
  		dev_err(&client->dev,
  			"%s: INVALID property
  ", __func__);
  		return -EINVAL;
  	}
3ddca062f   Rhyland Klein   sbs-battery: Rena...
487
  	if (!chip->enable_detection)
bb8791016   Rhyland Klein   bq20z75: Add opti...
488
  		goto done;
3ddca062f   Rhyland Klein   sbs-battery: Rena...
489
490
491
492
  	if (!chip->gpio_detect &&
  		chip->is_present != (ret >= 0)) {
  		chip->is_present = (ret >= 0);
  		power_supply_changed(&chip->power_supply);
bb8791016   Rhyland Klein   bq20z75: Add opti...
493
494
495
496
497
  	}
  
  done:
  	if (!ret) {
  		/* Convert units to match requirements for power supply class */
3ddca062f   Rhyland Klein   sbs-battery: Rena...
498
  		sbs_unit_adjustment(client, psp, val);
bb8791016   Rhyland Klein   bq20z75: Add opti...
499
  	}
d3ab61ecb   Rhyland Klein   bq20z75: Add supp...
500

a7640bfa1   Rhyland Klein   power_supply: Add...
501
  	dev_dbg(&client->dev,
a7d9ace4e   Rhyland Klein   bq20z75: Fix issu...
502
503
  		"%s: property = %d, value = %x
  ", __func__, psp, val->intval);
3ddca062f   Rhyland Klein   sbs-battery: Rena...
504
  	if (ret && chip->is_present)
a7d9ace4e   Rhyland Klein   bq20z75: Fix issu...
505
506
507
508
509
  		return ret;
  
  	/* battery not present, so return NODATA for properties */
  	if (ret)
  		return -ENODATA;
a7640bfa1   Rhyland Klein   power_supply: Add...
510

a7d9ace4e   Rhyland Klein   bq20z75: Fix issu...
511
  	return 0;
a7640bfa1   Rhyland Klein   power_supply: Add...
512
  }
3ddca062f   Rhyland Klein   sbs-battery: Rena...
513
  static irqreturn_t sbs_irq(int irq, void *devid)
bb8791016   Rhyland Klein   bq20z75: Add opti...
514
515
516
517
518
519
520
  {
  	struct power_supply *battery = devid;
  
  	power_supply_changed(battery);
  
  	return IRQ_HANDLED;
  }
3ddca062f   Rhyland Klein   sbs-battery: Rena...
521
  static void sbs_external_power_changed(struct power_supply *psy)
58ddafae2   Rhyland Klein   bq20z75: Add supp...
522
  {
3ddca062f   Rhyland Klein   sbs-battery: Rena...
523
  	struct sbs_info *chip;
58ddafae2   Rhyland Klein   bq20z75: Add supp...
524

3ddca062f   Rhyland Klein   sbs-battery: Rena...
525
  	chip = container_of(psy, struct sbs_info, power_supply);
58ddafae2   Rhyland Klein   bq20z75: Add supp...
526

3ddca062f   Rhyland Klein   sbs-battery: Rena...
527
528
  	if (chip->ignore_changes > 0) {
  		chip->ignore_changes--;
58ddafae2   Rhyland Klein   bq20z75: Add supp...
529
530
531
532
  		return;
  	}
  
  	/* cancel outstanding work */
3ddca062f   Rhyland Klein   sbs-battery: Rena...
533
  	cancel_delayed_work_sync(&chip->work);
58ddafae2   Rhyland Klein   bq20z75: Add supp...
534

3ddca062f   Rhyland Klein   sbs-battery: Rena...
535
536
  	schedule_delayed_work(&chip->work, HZ);
  	chip->poll_time = chip->pdata->poll_retry_count;
58ddafae2   Rhyland Klein   bq20z75: Add supp...
537
  }
3ddca062f   Rhyland Klein   sbs-battery: Rena...
538
  static void sbs_delayed_work(struct work_struct *work)
58ddafae2   Rhyland Klein   bq20z75: Add supp...
539
  {
3ddca062f   Rhyland Klein   sbs-battery: Rena...
540
  	struct sbs_info *chip;
58ddafae2   Rhyland Klein   bq20z75: Add supp...
541
  	s32 ret;
3ddca062f   Rhyland Klein   sbs-battery: Rena...
542
  	chip = container_of(work, struct sbs_info, work.work);
58ddafae2   Rhyland Klein   bq20z75: Add supp...
543

3ddca062f   Rhyland Klein   sbs-battery: Rena...
544
  	ret = sbs_read_word_data(chip->client, sbs_data[REG_STATUS].addr);
58ddafae2   Rhyland Klein   bq20z75: Add supp...
545
546
  	/* if the read failed, give up on this work */
  	if (ret < 0) {
3ddca062f   Rhyland Klein   sbs-battery: Rena...
547
  		chip->poll_time = 0;
58ddafae2   Rhyland Klein   bq20z75: Add supp...
548
549
550
551
552
553
554
555
556
557
558
  		return;
  	}
  
  	if (ret & BATTERY_FULL_CHARGED)
  		ret = POWER_SUPPLY_STATUS_FULL;
  	else if (ret & BATTERY_FULL_DISCHARGED)
  		ret = POWER_SUPPLY_STATUS_NOT_CHARGING;
  	else if (ret & BATTERY_DISCHARGING)
  		ret = POWER_SUPPLY_STATUS_DISCHARGING;
  	else
  		ret = POWER_SUPPLY_STATUS_CHARGING;
3ddca062f   Rhyland Klein   sbs-battery: Rena...
559
560
561
  	if (chip->last_state != ret) {
  		chip->poll_time = 0;
  		power_supply_changed(&chip->power_supply);
58ddafae2   Rhyland Klein   bq20z75: Add supp...
562
563
  		return;
  	}
3ddca062f   Rhyland Klein   sbs-battery: Rena...
564
565
566
  	if (chip->poll_time > 0) {
  		schedule_delayed_work(&chip->work, HZ);
  		chip->poll_time--;
58ddafae2   Rhyland Klein   bq20z75: Add supp...
567
568
569
  		return;
  	}
  }
6c75ea1e5   Rhyland Klein   bq20z75: Devicetr...
570
571
572
573
  #if defined(CONFIG_OF)
  
  #include <linux/of_device.h>
  #include <linux/of_gpio.h>
3ddca062f   Rhyland Klein   sbs-battery: Rena...
574
575
  static const struct of_device_id sbs_dt_ids[] = {
  	{ .compatible = "sbs,sbs-battery" },
6c75ea1e5   Rhyland Klein   bq20z75: Devicetr...
576
577
578
  	{ .compatible = "ti,bq20z75" },
  	{ }
  };
62df3935a   Olof Johansson   sbs-battery: Fix ...
579
  MODULE_DEVICE_TABLE(of, sbs_dt_ids);
6c75ea1e5   Rhyland Klein   bq20z75: Devicetr...
580

3ddca062f   Rhyland Klein   sbs-battery: Rena...
581
  static struct sbs_platform_data *sbs_of_populate_pdata(
6c75ea1e5   Rhyland Klein   bq20z75: Devicetr...
582
583
584
  		struct i2c_client *client)
  {
  	struct device_node *of_node = client->dev.of_node;
3ddca062f   Rhyland Klein   sbs-battery: Rena...
585
  	struct sbs_platform_data *pdata = client->dev.platform_data;
6c75ea1e5   Rhyland Klein   bq20z75: Devicetr...
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
  	enum of_gpio_flags gpio_flags;
  	int rc;
  	u32 prop;
  
  	/* verify this driver matches this device */
  	if (!of_node)
  		return NULL;
  
  	/* if platform data is set, honor it */
  	if (pdata)
  		return pdata;
  
  	/* first make sure at least one property is set, otherwise
  	 * it won't change behavior from running without pdata.
  	 */
3ddca062f   Rhyland Klein   sbs-battery: Rena...
601
602
603
  	if (!of_get_property(of_node, "sbs,i2c-retry-count", NULL) &&
  		!of_get_property(of_node, "sbs,poll-retry-count", NULL) &&
  		!of_get_property(of_node, "sbs,battery-detect-gpios", NULL))
6c75ea1e5   Rhyland Klein   bq20z75: Devicetr...
604
  		goto of_out;
3ddca062f   Rhyland Klein   sbs-battery: Rena...
605
  	pdata = devm_kzalloc(&client->dev, sizeof(struct sbs_platform_data),
6c75ea1e5   Rhyland Klein   bq20z75: Devicetr...
606
607
608
  				GFP_KERNEL);
  	if (!pdata)
  		goto of_out;
3ddca062f   Rhyland Klein   sbs-battery: Rena...
609
  	rc = of_property_read_u32(of_node, "sbs,i2c-retry-count", &prop);
6c75ea1e5   Rhyland Klein   bq20z75: Devicetr...
610
611
  	if (!rc)
  		pdata->i2c_retry_count = prop;
3ddca062f   Rhyland Klein   sbs-battery: Rena...
612
  	rc = of_property_read_u32(of_node, "sbs,poll-retry-count", &prop);
6c75ea1e5   Rhyland Klein   bq20z75: Devicetr...
613
614
  	if (!rc)
  		pdata->poll_retry_count = prop;
3ddca062f   Rhyland Klein   sbs-battery: Rena...
615
  	if (!of_get_property(of_node, "sbs,battery-detect-gpios", NULL)) {
6c75ea1e5   Rhyland Klein   bq20z75: Devicetr...
616
617
618
619
620
  		pdata->battery_detect = -1;
  		goto of_out;
  	}
  
  	pdata->battery_detect = of_get_named_gpio_flags(of_node,
3ddca062f   Rhyland Klein   sbs-battery: Rena...
621
  			"sbs,battery-detect-gpios", 0, &gpio_flags);
6c75ea1e5   Rhyland Klein   bq20z75: Devicetr...
622
623
624
625
626
627
628
629
630
631
  
  	if (gpio_flags & OF_GPIO_ACTIVE_LOW)
  		pdata->battery_detect_present = 0;
  	else
  		pdata->battery_detect_present = 1;
  
  of_out:
  	return pdata;
  }
  #else
3ddca062f   Rhyland Klein   sbs-battery: Rena...
632
633
  #define sbs_dt_ids NULL
  static struct sbs_platform_data *sbs_of_populate_pdata(
6c75ea1e5   Rhyland Klein   bq20z75: Devicetr...
634
635
636
637
638
  	struct i2c_client *client)
  {
  	return client->dev.platform_data;
  }
  #endif
3ddca062f   Rhyland Klein   sbs-battery: Rena...
639
  static int __devinit sbs_probe(struct i2c_client *client,
a7640bfa1   Rhyland Klein   power_supply: Add...
640
641
  	const struct i2c_device_id *id)
  {
3ddca062f   Rhyland Klein   sbs-battery: Rena...
642
643
  	struct sbs_info *chip;
  	struct sbs_platform_data *pdata = client->dev.platform_data;
a7640bfa1   Rhyland Klein   power_supply: Add...
644
  	int rc;
bb8791016   Rhyland Klein   bq20z75: Add opti...
645
  	int irq;
52f56c69b   Rhyland Klein   sbs-battery: Chan...
646
  	char *name;
a7640bfa1   Rhyland Klein   power_supply: Add...
647

52f56c69b   Rhyland Klein   sbs-battery: Chan...
648
649
650
651
  	name = kasprintf(GFP_KERNEL, "sbs-%s", dev_name(&client->dev));
  	if (!name) {
  		dev_err(&client->dev, "Failed to allocate device name
  ");
a7640bfa1   Rhyland Klein   power_supply: Add...
652
  		return -ENOMEM;
52f56c69b   Rhyland Klein   sbs-battery: Chan...
653
654
655
656
657
658
659
  	}
  
  	chip = kzalloc(sizeof(struct sbs_info), GFP_KERNEL);
  	if (!chip) {
  		rc = -ENOMEM;
  		goto exit_free_name;
  	}
a7640bfa1   Rhyland Klein   power_supply: Add...
660

3ddca062f   Rhyland Klein   sbs-battery: Rena...
661
662
663
  	chip->client = client;
  	chip->enable_detection = false;
  	chip->gpio_detect = false;
52f56c69b   Rhyland Klein   sbs-battery: Chan...
664
  	chip->power_supply.name = name;
3ddca062f   Rhyland Klein   sbs-battery: Rena...
665
666
667
668
  	chip->power_supply.type = POWER_SUPPLY_TYPE_BATTERY;
  	chip->power_supply.properties = sbs_properties;
  	chip->power_supply.num_properties = ARRAY_SIZE(sbs_properties);
  	chip->power_supply.get_property = sbs_get_property;
58ddafae2   Rhyland Klein   bq20z75: Add supp...
669
670
671
  	/* ignore first notification of external change, it is generated
  	 * from the power_supply_register call back
  	 */
3ddca062f   Rhyland Klein   sbs-battery: Rena...
672
673
674
  	chip->ignore_changes = 1;
  	chip->last_state = POWER_SUPPLY_STATUS_UNKNOWN;
  	chip->power_supply.external_power_changed = sbs_external_power_changed;
a7640bfa1   Rhyland Klein   power_supply: Add...
675

3ddca062f   Rhyland Klein   sbs-battery: Rena...
676
  	pdata = sbs_of_populate_pdata(client);
6c75ea1e5   Rhyland Klein   bq20z75: Devicetr...
677

bb8791016   Rhyland Klein   bq20z75: Add opti...
678
  	if (pdata) {
3ddca062f   Rhyland Klein   sbs-battery: Rena...
679
680
  		chip->gpio_detect = gpio_is_valid(pdata->battery_detect);
  		chip->pdata = pdata;
bb8791016   Rhyland Klein   bq20z75: Add opti...
681
  	}
3ddca062f   Rhyland Klein   sbs-battery: Rena...
682
  	i2c_set_clientdata(client, chip);
a7640bfa1   Rhyland Klein   power_supply: Add...
683

3ddca062f   Rhyland Klein   sbs-battery: Rena...
684
  	if (!chip->gpio_detect)
bb8791016   Rhyland Klein   bq20z75: Add opti...
685
686
687
688
689
690
  		goto skip_gpio;
  
  	rc = gpio_request(pdata->battery_detect, dev_name(&client->dev));
  	if (rc) {
  		dev_warn(&client->dev, "Failed to request gpio: %d
  ", rc);
3ddca062f   Rhyland Klein   sbs-battery: Rena...
691
  		chip->gpio_detect = false;
bb8791016   Rhyland Klein   bq20z75: Add opti...
692
693
694
695
696
697
698
699
  		goto skip_gpio;
  	}
  
  	rc = gpio_direction_input(pdata->battery_detect);
  	if (rc) {
  		dev_warn(&client->dev, "Failed to get gpio as input: %d
  ", rc);
  		gpio_free(pdata->battery_detect);
3ddca062f   Rhyland Klein   sbs-battery: Rena...
700
  		chip->gpio_detect = false;
bb8791016   Rhyland Klein   bq20z75: Add opti...
701
702
703
704
705
706
707
708
  		goto skip_gpio;
  	}
  
  	irq = gpio_to_irq(pdata->battery_detect);
  	if (irq <= 0) {
  		dev_warn(&client->dev, "Failed to get gpio as irq: %d
  ", irq);
  		gpio_free(pdata->battery_detect);
3ddca062f   Rhyland Klein   sbs-battery: Rena...
709
  		chip->gpio_detect = false;
bb8791016   Rhyland Klein   bq20z75: Add opti...
710
711
  		goto skip_gpio;
  	}
3ddca062f   Rhyland Klein   sbs-battery: Rena...
712
  	rc = request_irq(irq, sbs_irq,
bb8791016   Rhyland Klein   bq20z75: Add opti...
713
  		IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3ddca062f   Rhyland Klein   sbs-battery: Rena...
714
  		dev_name(&client->dev), &chip->power_supply);
bb8791016   Rhyland Klein   bq20z75: Add opti...
715
716
717
718
  	if (rc) {
  		dev_warn(&client->dev, "Failed to request irq: %d
  ", rc);
  		gpio_free(pdata->battery_detect);
3ddca062f   Rhyland Klein   sbs-battery: Rena...
719
  		chip->gpio_detect = false;
bb8791016   Rhyland Klein   bq20z75: Add opti...
720
721
  		goto skip_gpio;
  	}
3ddca062f   Rhyland Klein   sbs-battery: Rena...
722
  	chip->irq = irq;
bb8791016   Rhyland Klein   bq20z75: Add opti...
723
724
  
  skip_gpio:
3ddca062f   Rhyland Klein   sbs-battery: Rena...
725
  	rc = power_supply_register(&client->dev, &chip->power_supply);
a7640bfa1   Rhyland Klein   power_supply: Add...
726
727
728
729
  	if (rc) {
  		dev_err(&client->dev,
  			"%s: Failed to register power supply
  ", __func__);
bb8791016   Rhyland Klein   bq20z75: Add opti...
730
  		goto exit_psupply;
a7640bfa1   Rhyland Klein   power_supply: Add...
731
732
733
734
735
  	}
  
  	dev_info(&client->dev,
  		"%s: battery gas gauge device registered
  ", client->name);
3ddca062f   Rhyland Klein   sbs-battery: Rena...
736
  	INIT_DELAYED_WORK(&chip->work, sbs_delayed_work);
58ddafae2   Rhyland Klein   bq20z75: Add supp...
737

3ddca062f   Rhyland Klein   sbs-battery: Rena...
738
  	chip->enable_detection = true;
ee177d96e   Rhyland Klein   bq20z75: Enable d...
739

a7640bfa1   Rhyland Klein   power_supply: Add...
740
  	return 0;
bb8791016   Rhyland Klein   bq20z75: Add opti...
741
742
  
  exit_psupply:
3ddca062f   Rhyland Klein   sbs-battery: Rena...
743
744
745
  	if (chip->irq)
  		free_irq(chip->irq, &chip->power_supply);
  	if (chip->gpio_detect)
bb8791016   Rhyland Klein   bq20z75: Add opti...
746
  		gpio_free(pdata->battery_detect);
3ddca062f   Rhyland Klein   sbs-battery: Rena...
747
  	kfree(chip);
bb8791016   Rhyland Klein   bq20z75: Add opti...
748

52f56c69b   Rhyland Klein   sbs-battery: Chan...
749
750
  exit_free_name:
  	kfree(name);
bb8791016   Rhyland Klein   bq20z75: Add opti...
751
  	return rc;
a7640bfa1   Rhyland Klein   power_supply: Add...
752
  }
3ddca062f   Rhyland Klein   sbs-battery: Rena...
753
  static int __devexit sbs_remove(struct i2c_client *client)
a7640bfa1   Rhyland Klein   power_supply: Add...
754
  {
3ddca062f   Rhyland Klein   sbs-battery: Rena...
755
  	struct sbs_info *chip = i2c_get_clientdata(client);
a7640bfa1   Rhyland Klein   power_supply: Add...
756

3ddca062f   Rhyland Klein   sbs-battery: Rena...
757
758
759
760
  	if (chip->irq)
  		free_irq(chip->irq, &chip->power_supply);
  	if (chip->gpio_detect)
  		gpio_free(chip->pdata->battery_detect);
bb8791016   Rhyland Klein   bq20z75: Add opti...
761

3ddca062f   Rhyland Klein   sbs-battery: Rena...
762
  	power_supply_unregister(&chip->power_supply);
58ddafae2   Rhyland Klein   bq20z75: Add supp...
763

3ddca062f   Rhyland Klein   sbs-battery: Rena...
764
  	cancel_delayed_work_sync(&chip->work);
58ddafae2   Rhyland Klein   bq20z75: Add supp...
765

52f56c69b   Rhyland Klein   sbs-battery: Chan...
766
  	kfree(chip->power_supply.name);
3ddca062f   Rhyland Klein   sbs-battery: Rena...
767
768
  	kfree(chip);
  	chip = NULL;
a7640bfa1   Rhyland Klein   power_supply: Add...
769
770
771
772
773
  
  	return 0;
  }
  
  #if defined CONFIG_PM
3ddca062f   Rhyland Klein   sbs-battery: Rena...
774
  static int sbs_suspend(struct i2c_client *client,
a7640bfa1   Rhyland Klein   power_supply: Add...
775
776
  	pm_message_t state)
  {
3ddca062f   Rhyland Klein   sbs-battery: Rena...
777
  	struct sbs_info *chip = i2c_get_clientdata(client);
a7640bfa1   Rhyland Klein   power_supply: Add...
778
  	s32 ret;
3ddca062f   Rhyland Klein   sbs-battery: Rena...
779
780
  	if (chip->poll_time > 0)
  		cancel_delayed_work_sync(&chip->work);
58ddafae2   Rhyland Klein   bq20z75: Add supp...
781

a7640bfa1   Rhyland Klein   power_supply: Add...
782
  	/* write to manufacturer access with sleep command */
3ddca062f   Rhyland Klein   sbs-battery: Rena...
783
  	ret = sbs_write_word_data(client, sbs_data[REG_MANUFACTURER_DATA].addr,
a7640bfa1   Rhyland Klein   power_supply: Add...
784
  		MANUFACTURER_ACCESS_SLEEP);
3ddca062f   Rhyland Klein   sbs-battery: Rena...
785
  	if (chip->is_present && ret < 0)
d3ab61ecb   Rhyland Klein   bq20z75: Add supp...
786
  		return ret;
a7640bfa1   Rhyland Klein   power_supply: Add...
787
788
789
790
  
  	return 0;
  }
  #else
3ddca062f   Rhyland Klein   sbs-battery: Rena...
791
  #define sbs_suspend		NULL
a7640bfa1   Rhyland Klein   power_supply: Add...
792
  #endif
3ddca062f   Rhyland Klein   sbs-battery: Rena...
793
794
  /* any smbus transaction will wake up sbs */
  #define sbs_resume		NULL
a7640bfa1   Rhyland Klein   power_supply: Add...
795

3ddca062f   Rhyland Klein   sbs-battery: Rena...
796
  static const struct i2c_device_id sbs_id[] = {
a7640bfa1   Rhyland Klein   power_supply: Add...
797
  	{ "bq20z75", 0 },
3ddca062f   Rhyland Klein   sbs-battery: Rena...
798
  	{ "sbs-battery", 1 },
a7640bfa1   Rhyland Klein   power_supply: Add...
799
800
  	{}
  };
3ddca062f   Rhyland Klein   sbs-battery: Rena...
801
802
803
804
805
806
807
808
  MODULE_DEVICE_TABLE(i2c, sbs_id);
  
  static struct i2c_driver sbs_battery_driver = {
  	.probe		= sbs_probe,
  	.remove		= __devexit_p(sbs_remove),
  	.suspend	= sbs_suspend,
  	.resume		= sbs_resume,
  	.id_table	= sbs_id,
a7640bfa1   Rhyland Klein   power_supply: Add...
809
  	.driver = {
3ddca062f   Rhyland Klein   sbs-battery: Rena...
810
811
  		.name	= "sbs-battery",
  		.of_match_table = sbs_dt_ids,
a7640bfa1   Rhyland Klein   power_supply: Add...
812
813
  	},
  };
3ddca062f   Rhyland Klein   sbs-battery: Rena...
814
  static int __init sbs_battery_init(void)
a7640bfa1   Rhyland Klein   power_supply: Add...
815
  {
3ddca062f   Rhyland Klein   sbs-battery: Rena...
816
  	return i2c_add_driver(&sbs_battery_driver);
a7640bfa1   Rhyland Klein   power_supply: Add...
817
  }
3ddca062f   Rhyland Klein   sbs-battery: Rena...
818
  module_init(sbs_battery_init);
a7640bfa1   Rhyland Klein   power_supply: Add...
819

3ddca062f   Rhyland Klein   sbs-battery: Rena...
820
  static void __exit sbs_battery_exit(void)
a7640bfa1   Rhyland Klein   power_supply: Add...
821
  {
3ddca062f   Rhyland Klein   sbs-battery: Rena...
822
  	i2c_del_driver(&sbs_battery_driver);
a7640bfa1   Rhyland Klein   power_supply: Add...
823
  }
3ddca062f   Rhyland Klein   sbs-battery: Rena...
824
  module_exit(sbs_battery_exit);
a7640bfa1   Rhyland Klein   power_supply: Add...
825

3ddca062f   Rhyland Klein   sbs-battery: Rena...
826
  MODULE_DESCRIPTION("SBS battery monitor driver");
a7640bfa1   Rhyland Klein   power_supply: Add...
827
  MODULE_LICENSE("GPL");