diff options
-rw-r--r-- | drivers/power/bq2415x_charger.c | 1644 | ||||
-rw-r--r-- | include/linux/power/bq2415x_charger.h | 90 |
2 files changed, 1734 insertions, 0 deletions
diff --git a/drivers/power/bq2415x_charger.c b/drivers/power/bq2415x_charger.c new file mode 100644 index 000000000000..017b3c27f769 --- /dev/null +++ b/drivers/power/bq2415x_charger.c | |||
@@ -0,0 +1,1644 @@ | |||
1 | /* | ||
2 | bq2415x_charger.c - bq2415x charger driver | ||
3 | Copyright (C) 2011-2012 Pali Rohár <pali.rohar@gmail.com> | ||
4 | |||
5 | This program is free software; you can redistribute it and/or modify | ||
6 | it under the terms of the GNU General Public License as published by | ||
7 | the Free Software Foundation; either version 2 of the License, or | ||
8 | (at your option) any later version. | ||
9 | |||
10 | This program is distributed in the hope that it will be useful, | ||
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | GNU General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU General Public License along | ||
16 | with this program; if not, write to the Free Software Foundation, Inc., | ||
17 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
18 | */ | ||
19 | |||
20 | /* | ||
21 | Datasheets: | ||
22 | http://www.ti.com/product/bq24150 | ||
23 | http://www.ti.com/product/bq24150a | ||
24 | http://www.ti.com/product/bq24152 | ||
25 | http://www.ti.com/product/bq24153 | ||
26 | http://www.ti.com/product/bq24153a | ||
27 | http://www.ti.com/product/bq24155 | ||
28 | */ | ||
29 | |||
30 | #include <linux/version.h> | ||
31 | #include <linux/kernel.h> | ||
32 | #include <linux/module.h> | ||
33 | #include <linux/param.h> | ||
34 | #include <linux/err.h> | ||
35 | #include <linux/workqueue.h> | ||
36 | #include <linux/sysfs.h> | ||
37 | #include <linux/platform_device.h> | ||
38 | #include <linux/power_supply.h> | ||
39 | #include <linux/idr.h> | ||
40 | #include <linux/i2c.h> | ||
41 | #include <linux/slab.h> | ||
42 | |||
43 | #include <linux/power/bq2415x_charger.h> | ||
44 | |||
45 | /* timeout for resetting chip timer */ | ||
46 | #define BQ2415X_TIMER_TIMEOUT 10 | ||
47 | |||
48 | #define BQ2415X_REG_STATUS 0x00 | ||
49 | #define BQ2415X_REG_CONTROL 0x01 | ||
50 | #define BQ2415X_REG_VOLTAGE 0x02 | ||
51 | #define BQ2415X_REG_VENDER 0x03 | ||
52 | #define BQ2415X_REG_CURRENT 0x04 | ||
53 | |||
54 | /* reset state for all registers */ | ||
55 | #define BQ2415X_RESET_STATUS BIT(6) | ||
56 | #define BQ2415X_RESET_CONTROL (BIT(4)|BIT(5)) | ||
57 | #define BQ2415X_RESET_VOLTAGE (BIT(1)|BIT(3)) | ||
58 | #define BQ2415X_RESET_CURRENT (BIT(0)|BIT(3)|BIT(7)) | ||
59 | |||
60 | /* status register */ | ||
61 | #define BQ2415X_BIT_TMR_RST 7 | ||
62 | #define BQ2415X_BIT_OTG 7 | ||
63 | #define BQ2415X_BIT_EN_STAT 6 | ||
64 | #define BQ2415X_MASK_STAT (BIT(4)|BIT(5)) | ||
65 | #define BQ2415X_SHIFT_STAT 4 | ||
66 | #define BQ2415X_BIT_BOOST 3 | ||
67 | #define BQ2415X_MASK_FAULT (BIT(0)|BIT(1)|BIT(2)) | ||
68 | #define BQ2415X_SHIFT_FAULT 0 | ||
69 | |||
70 | /* control register */ | ||
71 | #define BQ2415X_MASK_LIMIT (BIT(6)|BIT(7)) | ||
72 | #define BQ2415X_SHIFT_LIMIT 6 | ||
73 | #define BQ2415X_MASK_VLOWV (BIT(4)|BIT(5)) | ||
74 | #define BQ2415X_SHIFT_VLOWV 4 | ||
75 | #define BQ2415X_BIT_TE 3 | ||
76 | #define BQ2415X_BIT_CE 2 | ||
77 | #define BQ2415X_BIT_HZ_MODE 1 | ||
78 | #define BQ2415X_BIT_OPA_MODE 0 | ||
79 | |||
80 | /* voltage register */ | ||
81 | #define BQ2415X_MASK_VO (BIT(2)|BIT(3)|BIT(4)|BIT(5)|BIT(6)|BIT(7)) | ||
82 | #define BQ2415X_SHIFT_VO 2 | ||
83 | #define BQ2415X_BIT_OTG_PL 1 | ||
84 | #define BQ2415X_BIT_OTG_EN 0 | ||
85 | |||
86 | /* vender register */ | ||
87 | #define BQ2415X_MASK_VENDER (BIT(5)|BIT(6)|BIT(7)) | ||
88 | #define BQ2415X_SHIFT_VENDER 5 | ||
89 | #define BQ2415X_MASK_PN (BIT(3)|BIT(4)) | ||
90 | #define BQ2415X_SHIFT_PN 3 | ||
91 | #define BQ2415X_MASK_REVISION (BIT(0)|BIT(1)|BIT(2)) | ||
92 | #define BQ2415X_SHIFT_REVISION 0 | ||
93 | |||
94 | /* current register */ | ||
95 | #define BQ2415X_MASK_RESET BIT(7) | ||
96 | #define BQ2415X_MASK_VI_CHRG (BIT(4)|BIT(5)|BIT(6)) | ||
97 | #define BQ2415X_SHIFT_VI_CHRG 4 | ||
98 | /* N/A BIT(3) */ | ||
99 | #define BQ2415X_MASK_VI_TERM (BIT(0)|BIT(1)|BIT(2)) | ||
100 | #define BQ2415X_SHIFT_VI_TERM 0 | ||
101 | |||
102 | |||
103 | enum bq2415x_command { | ||
104 | BQ2415X_TIMER_RESET, | ||
105 | BQ2415X_OTG_STATUS, | ||
106 | BQ2415X_STAT_PIN_STATUS, | ||
107 | BQ2415X_STAT_PIN_ENABLE, | ||
108 | BQ2415X_STAT_PIN_DISABLE, | ||
109 | BQ2415X_CHARGE_STATUS, | ||
110 | BQ2415X_BOOST_STATUS, | ||
111 | BQ2415X_FAULT_STATUS, | ||
112 | |||
113 | BQ2415X_CHARGE_TERMINATION_STATUS, | ||
114 | BQ2415X_CHARGE_TERMINATION_ENABLE, | ||
115 | BQ2415X_CHARGE_TERMINATION_DISABLE, | ||
116 | BQ2415X_CHARGER_STATUS, | ||
117 | BQ2415X_CHARGER_ENABLE, | ||
118 | BQ2415X_CHARGER_DISABLE, | ||
119 | BQ2415X_HIGH_IMPEDANCE_STATUS, | ||
120 | BQ2415X_HIGH_IMPEDANCE_ENABLE, | ||
121 | BQ2415X_HIGH_IMPEDANCE_DISABLE, | ||
122 | BQ2415X_BOOST_MODE_STATUS, | ||
123 | BQ2415X_BOOST_MODE_ENABLE, | ||
124 | BQ2415X_BOOST_MODE_DISABLE, | ||
125 | |||
126 | BQ2415X_OTG_LEVEL, | ||
127 | BQ2415X_OTG_ACTIVATE_HIGH, | ||
128 | BQ2415X_OTG_ACTIVATE_LOW, | ||
129 | BQ2415X_OTG_PIN_STATUS, | ||
130 | BQ2415X_OTG_PIN_ENABLE, | ||
131 | BQ2415X_OTG_PIN_DISABLE, | ||
132 | |||
133 | BQ2415X_VENDER_CODE, | ||
134 | BQ2415X_PART_NUMBER, | ||
135 | BQ2415X_REVISION, | ||
136 | }; | ||
137 | |||
138 | enum bq2415x_chip { | ||
139 | BQUNKNOWN, | ||
140 | BQ24150, | ||
141 | BQ24150A, | ||
142 | BQ24151, | ||
143 | BQ24151A, | ||
144 | BQ24152, | ||
145 | BQ24153, | ||
146 | BQ24153A, | ||
147 | BQ24155, | ||
148 | BQ24156, | ||
149 | BQ24156A, | ||
150 | BQ24158, | ||
151 | }; | ||
152 | |||
153 | static char *bq2415x_chip_name[] = { | ||
154 | "unknown", | ||
155 | "bq24150", | ||
156 | "bq24150a", | ||
157 | "bq24151", | ||
158 | "bq24151a", | ||
159 | "bq24152", | ||
160 | "bq24153", | ||
161 | "bq24153a", | ||
162 | "bq24155", | ||
163 | "bq24156", | ||
164 | "bq24156a", | ||
165 | "bq24158", | ||
166 | }; | ||
167 | |||
168 | struct bq2415x_device { | ||
169 | struct device *dev; | ||
170 | struct bq2415x_platform_data init_data; | ||
171 | struct power_supply charger; | ||
172 | struct delayed_work work; | ||
173 | enum bq2415x_mode reported_mode;/* mode reported by hook function */ | ||
174 | enum bq2415x_mode mode; /* current configured mode */ | ||
175 | enum bq2415x_chip chip; | ||
176 | const char *timer_error; | ||
177 | char *model; | ||
178 | char *name; | ||
179 | int autotimer; /* 1 - if driver automatically reset timer, 0 - not */ | ||
180 | int automode; /* 1 - enabled, 0 - disabled; -1 - not supported */ | ||
181 | int id; | ||
182 | }; | ||
183 | |||
184 | /* each registered chip must have unique id */ | ||
185 | static DEFINE_IDR(bq2415x_id); | ||
186 | |||
187 | static DEFINE_MUTEX(bq2415x_id_mutex); | ||
188 | static DEFINE_MUTEX(bq2415x_timer_mutex); | ||
189 | static DEFINE_MUTEX(bq2415x_i2c_mutex); | ||
190 | |||
191 | /**** i2c read functions ****/ | ||
192 | |||
193 | /* read value from register */ | ||
194 | static int bq2415x_i2c_read(struct bq2415x_device *bq, u8 reg) | ||
195 | { | ||
196 | struct i2c_client *client = to_i2c_client(bq->dev); | ||
197 | struct i2c_msg msg[2]; | ||
198 | u8 val; | ||
199 | int ret; | ||
200 | |||
201 | if (!client->adapter) | ||
202 | return -ENODEV; | ||
203 | |||
204 | msg[0].addr = client->addr; | ||
205 | msg[0].flags = 0; | ||
206 | msg[0].buf = ® | ||
207 | msg[0].len = sizeof(reg); | ||
208 | msg[1].addr = client->addr; | ||
209 | msg[1].flags = I2C_M_RD; | ||
210 | msg[1].buf = &val; | ||
211 | msg[1].len = sizeof(val); | ||
212 | |||
213 | mutex_lock(&bq2415x_i2c_mutex); | ||
214 | ret = i2c_transfer(client->adapter, msg, ARRAY_SIZE(msg)); | ||
215 | mutex_unlock(&bq2415x_i2c_mutex); | ||
216 | |||
217 | if (ret < 0) | ||
218 | return ret; | ||
219 | |||
220 | return val; | ||
221 | } | ||
222 | |||
223 | /* read value from register, apply mask and right shift it */ | ||
224 | static int bq2415x_i2c_read_mask(struct bq2415x_device *bq, u8 reg, | ||
225 | u8 mask, u8 shift) | ||
226 | { | ||
227 | int ret; | ||
228 | |||
229 | if (shift > 8) | ||
230 | return -EINVAL; | ||
231 | |||
232 | ret = bq2415x_i2c_read(bq, reg); | ||
233 | if (ret < 0) | ||
234 | return ret; | ||
235 | else | ||
236 | return (ret & mask) >> shift; | ||
237 | } | ||
238 | |||
239 | /* read value from register and return one specified bit */ | ||
240 | static int bq2415x_i2c_read_bit(struct bq2415x_device *bq, u8 reg, u8 bit) | ||
241 | { | ||
242 | if (bit > 8) | ||
243 | return -EINVAL; | ||
244 | else | ||
245 | return bq2415x_i2c_read_mask(bq, reg, BIT(bit), bit); | ||
246 | } | ||
247 | |||
248 | /**** i2c write functions ****/ | ||
249 | |||
250 | /* write value to register */ | ||
251 | static int bq2415x_i2c_write(struct bq2415x_device *bq, u8 reg, u8 val) | ||
252 | { | ||
253 | struct i2c_client *client = to_i2c_client(bq->dev); | ||
254 | struct i2c_msg msg[1]; | ||
255 | u8 data[2]; | ||
256 | int ret; | ||
257 | |||
258 | data[0] = reg; | ||
259 | data[1] = val; | ||
260 | |||
261 | msg[0].addr = client->addr; | ||
262 | msg[0].flags = 0; | ||
263 | msg[0].buf = data; | ||
264 | msg[0].len = ARRAY_SIZE(data); | ||
265 | |||
266 | mutex_lock(&bq2415x_i2c_mutex); | ||
267 | ret = i2c_transfer(client->adapter, msg, ARRAY_SIZE(msg)); | ||
268 | mutex_unlock(&bq2415x_i2c_mutex); | ||
269 | |||
270 | /* i2c_transfer returns number of messages transferred */ | ||
271 | if (ret < 0) | ||
272 | return ret; | ||
273 | else if (ret != 1) | ||
274 | return -EIO; | ||
275 | |||
276 | return 0; | ||
277 | } | ||
278 | |||
279 | /* read value from register, change it with mask left shifted and write back */ | ||
280 | static int bq2415x_i2c_write_mask(struct bq2415x_device *bq, u8 reg, u8 val, | ||
281 | u8 mask, u8 shift) | ||
282 | { | ||
283 | int ret; | ||
284 | |||
285 | if (shift > 8) | ||
286 | return -EINVAL; | ||
287 | |||
288 | ret = bq2415x_i2c_read(bq, reg); | ||
289 | if (ret < 0) | ||
290 | return ret; | ||
291 | |||
292 | ret &= ~mask; | ||
293 | ret |= val << shift; | ||
294 | |||
295 | return bq2415x_i2c_write(bq, reg, ret); | ||
296 | } | ||
297 | |||
298 | /* change only one bit in register */ | ||
299 | static int bq2415x_i2c_write_bit(struct bq2415x_device *bq, u8 reg, | ||
300 | bool val, u8 bit) | ||
301 | { | ||
302 | if (bit > 8) | ||
303 | return -EINVAL; | ||
304 | else | ||
305 | return bq2415x_i2c_write_mask(bq, reg, val, BIT(bit), bit); | ||
306 | } | ||
307 | |||
308 | /**** global functions ****/ | ||
309 | |||
310 | /* exec command function */ | ||
311 | static int bq2415x_exec_command(struct bq2415x_device *bq, | ||
312 | enum bq2415x_command command) | ||
313 | { | ||
314 | int ret; | ||
315 | switch (command) { | ||
316 | case BQ2415X_TIMER_RESET: | ||
317 | return bq2415x_i2c_write_bit(bq, BQ2415X_REG_STATUS, | ||
318 | 1, BQ2415X_BIT_TMR_RST); | ||
319 | case BQ2415X_OTG_STATUS: | ||
320 | return bq2415x_i2c_read_bit(bq, BQ2415X_REG_STATUS, | ||
321 | BQ2415X_BIT_OTG); | ||
322 | case BQ2415X_STAT_PIN_STATUS: | ||
323 | return bq2415x_i2c_read_bit(bq, BQ2415X_REG_STATUS, | ||
324 | BQ2415X_BIT_EN_STAT); | ||
325 | case BQ2415X_STAT_PIN_ENABLE: | ||
326 | return bq2415x_i2c_write_bit(bq, BQ2415X_REG_STATUS, 1, | ||
327 | BQ2415X_BIT_EN_STAT); | ||
328 | case BQ2415X_STAT_PIN_DISABLE: | ||
329 | return bq2415x_i2c_write_bit(bq, BQ2415X_REG_STATUS, 0, | ||
330 | BQ2415X_BIT_EN_STAT); | ||
331 | case BQ2415X_CHARGE_STATUS: | ||
332 | return bq2415x_i2c_read_mask(bq, BQ2415X_REG_STATUS, | ||
333 | BQ2415X_MASK_STAT, BQ2415X_SHIFT_STAT); | ||
334 | case BQ2415X_BOOST_STATUS: | ||
335 | return bq2415x_i2c_read_bit(bq, BQ2415X_REG_STATUS, | ||
336 | BQ2415X_BIT_BOOST); | ||
337 | case BQ2415X_FAULT_STATUS: | ||
338 | return bq2415x_i2c_read_mask(bq, BQ2415X_REG_STATUS, | ||
339 | BQ2415X_MASK_FAULT, BQ2415X_SHIFT_FAULT); | ||
340 | |||
341 | case BQ2415X_CHARGE_TERMINATION_STATUS: | ||
342 | return bq2415x_i2c_read_bit(bq, BQ2415X_REG_CONTROL, | ||
343 | BQ2415X_BIT_TE); | ||
344 | case BQ2415X_CHARGE_TERMINATION_ENABLE: | ||
345 | return bq2415x_i2c_write_bit(bq, BQ2415X_REG_CONTROL, | ||
346 | 1, BQ2415X_BIT_TE); | ||
347 | case BQ2415X_CHARGE_TERMINATION_DISABLE: | ||
348 | return bq2415x_i2c_write_bit(bq, BQ2415X_REG_CONTROL, | ||
349 | 0, BQ2415X_BIT_TE); | ||
350 | case BQ2415X_CHARGER_STATUS: | ||
351 | ret = bq2415x_i2c_read_bit(bq, BQ2415X_REG_CONTROL, | ||
352 | BQ2415X_BIT_CE); | ||
353 | if (ret < 0) | ||
354 | return ret; | ||
355 | else | ||
356 | return ret > 0 ? 0 : 1; | ||
357 | case BQ2415X_CHARGER_ENABLE: | ||
358 | return bq2415x_i2c_write_bit(bq, BQ2415X_REG_CONTROL, | ||
359 | 0, BQ2415X_BIT_CE); | ||
360 | case BQ2415X_CHARGER_DISABLE: | ||
361 | return bq2415x_i2c_write_bit(bq, BQ2415X_REG_CONTROL, | ||
362 | 1, BQ2415X_BIT_CE); | ||
363 | case BQ2415X_HIGH_IMPEDANCE_STATUS: | ||
364 | return bq2415x_i2c_read_bit(bq, BQ2415X_REG_CONTROL, | ||
365 | BQ2415X_BIT_HZ_MODE); | ||
366 | case BQ2415X_HIGH_IMPEDANCE_ENABLE: | ||
367 | return bq2415x_i2c_write_bit(bq, BQ2415X_REG_CONTROL, | ||
368 | 1, BQ2415X_BIT_HZ_MODE); | ||
369 | case BQ2415X_HIGH_IMPEDANCE_DISABLE: | ||
370 | return bq2415x_i2c_write_bit(bq, BQ2415X_REG_CONTROL, | ||
371 | 0, BQ2415X_BIT_HZ_MODE); | ||
372 | case BQ2415X_BOOST_MODE_STATUS: | ||
373 | return bq2415x_i2c_read_bit(bq, BQ2415X_REG_CONTROL, | ||
374 | BQ2415X_BIT_OPA_MODE); | ||
375 | case BQ2415X_BOOST_MODE_ENABLE: | ||
376 | return bq2415x_i2c_write_bit(bq, BQ2415X_REG_CONTROL, | ||
377 | 1, BQ2415X_BIT_OPA_MODE); | ||
378 | case BQ2415X_BOOST_MODE_DISABLE: | ||
379 | return bq2415x_i2c_write_bit(bq, BQ2415X_REG_CONTROL, | ||
380 | 0, BQ2415X_BIT_OPA_MODE); | ||
381 | |||
382 | case BQ2415X_OTG_LEVEL: | ||
383 | return bq2415x_i2c_read_bit(bq, BQ2415X_REG_VOLTAGE, | ||
384 | BQ2415X_BIT_OTG_PL); | ||
385 | case BQ2415X_OTG_ACTIVATE_HIGH: | ||
386 | return bq2415x_i2c_write_bit(bq, BQ2415X_REG_VOLTAGE, | ||
387 | 1, BQ2415X_BIT_OTG_PL); | ||
388 | case BQ2415X_OTG_ACTIVATE_LOW: | ||
389 | return bq2415x_i2c_write_bit(bq, BQ2415X_REG_VOLTAGE, | ||
390 | 0, BQ2415X_BIT_OTG_PL); | ||
391 | case BQ2415X_OTG_PIN_STATUS: | ||
392 | return bq2415x_i2c_read_bit(bq, BQ2415X_REG_VOLTAGE, | ||
393 | BQ2415X_BIT_OTG_EN); | ||
394 | case BQ2415X_OTG_PIN_ENABLE: | ||
395 | return bq2415x_i2c_write_bit(bq, BQ2415X_REG_VOLTAGE, | ||
396 | 1, BQ2415X_BIT_OTG_EN); | ||
397 | case BQ2415X_OTG_PIN_DISABLE: | ||
398 | return bq2415x_i2c_write_bit(bq, BQ2415X_REG_VOLTAGE, | ||
399 | 0, BQ2415X_BIT_OTG_EN); | ||
400 | |||
401 | case BQ2415X_VENDER_CODE: | ||
402 | return bq2415x_i2c_read_mask(bq, BQ2415X_REG_VENDER, | ||
403 | BQ2415X_MASK_VENDER, BQ2415X_SHIFT_VENDER); | ||
404 | case BQ2415X_PART_NUMBER: | ||
405 | return bq2415x_i2c_read_mask(bq, BQ2415X_REG_VENDER, | ||
406 | BQ2415X_MASK_PN, BQ2415X_SHIFT_PN); | ||
407 | case BQ2415X_REVISION: | ||
408 | return bq2415x_i2c_read_mask(bq, BQ2415X_REG_VENDER, | ||
409 | BQ2415X_MASK_REVISION, BQ2415X_SHIFT_REVISION); | ||
410 | |||
411 | default: | ||
412 | return -EINVAL; | ||
413 | } | ||
414 | } | ||
415 | |||
416 | /* detect chip type */ | ||
417 | static enum bq2415x_chip bq2415x_detect_chip(struct bq2415x_device *bq) | ||
418 | { | ||
419 | struct i2c_client *client = to_i2c_client(bq->dev); | ||
420 | int ret = bq2415x_exec_command(bq, BQ2415X_PART_NUMBER); | ||
421 | |||
422 | if (ret < 0) | ||
423 | return ret; | ||
424 | |||
425 | switch (client->addr) { | ||
426 | case 0x6b: | ||
427 | switch (ret) { | ||
428 | case 0: | ||
429 | if (bq->chip == BQ24151A) | ||
430 | return bq->chip; | ||
431 | else | ||
432 | return BQ24151; | ||
433 | case 1: | ||
434 | if (bq->chip == BQ24150A || | ||
435 | bq->chip == BQ24152 || | ||
436 | bq->chip == BQ24155) | ||
437 | return bq->chip; | ||
438 | else | ||
439 | return BQ24150; | ||
440 | case 2: | ||
441 | if (bq->chip == BQ24153A) | ||
442 | return bq->chip; | ||
443 | else | ||
444 | return BQ24153; | ||
445 | default: | ||
446 | return BQUNKNOWN; | ||
447 | } | ||
448 | break; | ||
449 | |||
450 | case 0x6a: | ||
451 | switch (ret) { | ||
452 | case 0: | ||
453 | if (bq->chip == BQ24156A) | ||
454 | return bq->chip; | ||
455 | else | ||
456 | return BQ24156; | ||
457 | case 2: | ||
458 | return BQ24158; | ||
459 | default: | ||
460 | return BQUNKNOWN; | ||
461 | } | ||
462 | break; | ||
463 | } | ||
464 | |||
465 | return BQUNKNOWN; | ||
466 | } | ||
467 | |||
468 | /* detect chip revision */ | ||
469 | static int bq2415x_detect_revision(struct bq2415x_device *bq) | ||
470 | { | ||
471 | int ret = bq2415x_exec_command(bq, BQ2415X_REVISION); | ||
472 | int chip = bq2415x_detect_chip(bq); | ||
473 | if (ret < 0 || chip < 0) | ||
474 | return -1; | ||
475 | |||
476 | switch (chip) { | ||
477 | case BQ24150: | ||
478 | case BQ24150A: | ||
479 | case BQ24151: | ||
480 | case BQ24151A: | ||
481 | case BQ24152: | ||
482 | if (ret >= 0 && ret <= 3) | ||
483 | return ret; | ||
484 | else | ||
485 | return -1; | ||
486 | |||
487 | case BQ24153: | ||
488 | case BQ24153A: | ||
489 | case BQ24156: | ||
490 | case BQ24156A: | ||
491 | case BQ24158: | ||
492 | if (ret == 3) | ||
493 | return 0; | ||
494 | else if (ret == 1) | ||
495 | return 1; | ||
496 | else | ||
497 | return -1; | ||
498 | |||
499 | case BQ24155: | ||
500 | if (ret == 3) | ||
501 | return 3; | ||
502 | else | ||
503 | return -1; | ||
504 | |||
505 | case BQUNKNOWN: | ||
506 | return -1; | ||
507 | } | ||
508 | |||
509 | return -1; | ||
510 | } | ||
511 | |||
512 | /* return chip vender code */ | ||
513 | static int bq2415x_get_vender_code(struct bq2415x_device *bq) | ||
514 | { | ||
515 | int ret = bq2415x_exec_command(bq, BQ2415X_VENDER_CODE); | ||
516 | if (ret < 0) | ||
517 | return 0; | ||
518 | else /* convert to binary */ | ||
519 | return (ret & 0x1) + | ||
520 | ((ret >> 1) & 0x1) * 10 + | ||
521 | ((ret >> 2) & 0x1) * 100; | ||
522 | } | ||
523 | |||
524 | /* reset all chip registers to default state */ | ||
525 | static void bq2415x_reset_chip(struct bq2415x_device *bq) | ||
526 | { | ||
527 | bq2415x_i2c_write(bq, BQ2415X_REG_CURRENT, BQ2415X_RESET_CURRENT); | ||
528 | bq2415x_i2c_write(bq, BQ2415X_REG_VOLTAGE, BQ2415X_RESET_VOLTAGE); | ||
529 | bq2415x_i2c_write(bq, BQ2415X_REG_CONTROL, BQ2415X_RESET_CONTROL); | ||
530 | bq2415x_i2c_write(bq, BQ2415X_REG_STATUS, BQ2415X_RESET_STATUS); | ||
531 | bq->timer_error = NULL; | ||
532 | } | ||
533 | |||
534 | /**** properties functions ****/ | ||
535 | |||
536 | /* set current limit in mA */ | ||
537 | static int bq2415x_set_current_limit(struct bq2415x_device *bq, int mA) | ||
538 | { | ||
539 | int val; | ||
540 | if (mA <= 100) | ||
541 | val = 0; | ||
542 | else if (mA <= 500) | ||
543 | val = 1; | ||
544 | else if (mA <= 800) | ||
545 | val = 2; | ||
546 | else | ||
547 | val = 3; | ||
548 | return bq2415x_i2c_write_mask(bq, BQ2415X_REG_CONTROL, val, | ||
549 | BQ2415X_MASK_LIMIT, BQ2415X_SHIFT_LIMIT); | ||
550 | } | ||
551 | |||
552 | /* get current limit in mA */ | ||
553 | static int bq2415x_get_current_limit(struct bq2415x_device *bq) | ||
554 | { | ||
555 | int ret = bq2415x_i2c_read_mask(bq, BQ2415X_REG_CONTROL, | ||
556 | BQ2415X_MASK_LIMIT, BQ2415X_SHIFT_LIMIT); | ||
557 | if (ret < 0) | ||
558 | return ret; | ||
559 | else if (ret == 0) | ||
560 | return 100; | ||
561 | else if (ret == 1) | ||
562 | return 500; | ||
563 | else if (ret == 2) | ||
564 | return 800; | ||
565 | else if (ret == 3) | ||
566 | return 1800; | ||
567 | else | ||
568 | return -EINVAL; | ||
569 | } | ||
570 | |||
571 | /* set weak battery voltage in mV */ | ||
572 | static int bq2415x_set_weak_battery_voltage(struct bq2415x_device *bq, int mV) | ||
573 | { | ||
574 | /* round to 100mV */ | ||
575 | int val; | ||
576 | if (mV <= 3400 + 50) | ||
577 | val = 0; | ||
578 | else if (mV <= 3500 + 50) | ||
579 | val = 1; | ||
580 | else if (mV <= 3600 + 50) | ||
581 | val = 2; | ||
582 | else | ||
583 | val = 3; | ||
584 | return bq2415x_i2c_write_mask(bq, BQ2415X_REG_CONTROL, val, | ||
585 | BQ2415X_MASK_VLOWV, BQ2415X_SHIFT_VLOWV); | ||
586 | } | ||
587 | |||
588 | /* get weak battery voltage in mV */ | ||
589 | static int bq2415x_get_weak_battery_voltage(struct bq2415x_device *bq) | ||
590 | { | ||
591 | int ret = bq2415x_i2c_read_mask(bq, BQ2415X_REG_CONTROL, | ||
592 | BQ2415X_MASK_VLOWV, BQ2415X_SHIFT_VLOWV); | ||
593 | if (ret < 0) | ||
594 | return ret; | ||
595 | else | ||
596 | return 100 * (34 + ret); | ||
597 | } | ||
598 | |||
599 | /* set battery regulation voltage in mV */ | ||
600 | static int bq2415x_set_battery_regulation_voltage(struct bq2415x_device *bq, | ||
601 | int mV) | ||
602 | { | ||
603 | int val = (mV/10 - 350) / 2; | ||
604 | |||
605 | if (val < 0) | ||
606 | val = 0; | ||
607 | else if (val > 94) /* FIXME: Max is 94 or 122 ? Set max value ? */ | ||
608 | return -EINVAL; | ||
609 | |||
610 | return bq2415x_i2c_write_mask(bq, BQ2415X_REG_VOLTAGE, val, | ||
611 | BQ2415X_MASK_VO, BQ2415X_SHIFT_VO); | ||
612 | } | ||
613 | |||
614 | /* get battery regulation voltage in mV */ | ||
615 | static int bq2415x_get_battery_regulation_voltage(struct bq2415x_device *bq) | ||
616 | { | ||
617 | int ret = bq2415x_i2c_read_mask(bq, BQ2415X_REG_VOLTAGE, | ||
618 | BQ2415X_MASK_VO, BQ2415X_SHIFT_VO); | ||
619 | if (ret < 0) | ||
620 | return ret; | ||
621 | else | ||
622 | return 10 * (350 + 2*ret); | ||
623 | } | ||
624 | |||
625 | /* set charge current in mA (platform data must provide resistor sense) */ | ||
626 | static int bq2415x_set_charge_current(struct bq2415x_device *bq, int mA) | ||
627 | { | ||
628 | int val; | ||
629 | if (bq->init_data.resistor_sense <= 0) | ||
630 | return -ENOSYS; | ||
631 | |||
632 | val = (mA * bq->init_data.resistor_sense - 37400) / 6800; | ||
633 | |||
634 | if (val < 0) | ||
635 | val = 0; | ||
636 | else if (val > 7) | ||
637 | val = 7; | ||
638 | |||
639 | return bq2415x_i2c_write_mask(bq, BQ2415X_REG_CURRENT, val, | ||
640 | BQ2415X_MASK_VI_CHRG | BQ2415X_MASK_RESET, | ||
641 | BQ2415X_SHIFT_VI_CHRG); | ||
642 | } | ||
643 | |||
644 | /* get charge current in mA (platform data must provide resistor sense) */ | ||
645 | static int bq2415x_get_charge_current(struct bq2415x_device *bq) | ||
646 | { | ||
647 | int ret; | ||
648 | if (bq->init_data.resistor_sense <= 0) | ||
649 | return -ENOSYS; | ||
650 | |||
651 | ret = bq2415x_i2c_read_mask(bq, BQ2415X_REG_CURRENT, | ||
652 | BQ2415X_MASK_VI_CHRG, BQ2415X_SHIFT_VI_CHRG); | ||
653 | if (ret < 0) | ||
654 | return ret; | ||
655 | else | ||
656 | return (37400 + 6800*ret) / bq->init_data.resistor_sense; | ||
657 | } | ||
658 | |||
659 | /* set termination current in mA (platform data must provide resistor sense) */ | ||
660 | static int bq2415x_set_termination_current(struct bq2415x_device *bq, int mA) | ||
661 | { | ||
662 | int val; | ||
663 | if (bq->init_data.resistor_sense <= 0) | ||
664 | return -ENOSYS; | ||
665 | |||
666 | val = (mA * bq->init_data.resistor_sense - 3400) / 3400; | ||
667 | |||
668 | if (val < 0) | ||
669 | val = 0; | ||
670 | else if (val > 7) | ||
671 | val = 7; | ||
672 | |||
673 | return bq2415x_i2c_write_mask(bq, BQ2415X_REG_CURRENT, val, | ||
674 | BQ2415X_MASK_VI_TERM | BQ2415X_MASK_RESET, | ||
675 | BQ2415X_SHIFT_VI_TERM); | ||
676 | } | ||
677 | |||
678 | /* get termination current in mA (platform data must provide resistor sense) */ | ||
679 | static int bq2415x_get_termination_current(struct bq2415x_device *bq) | ||
680 | { | ||
681 | int ret; | ||
682 | if (bq->init_data.resistor_sense <= 0) | ||
683 | return -ENOSYS; | ||
684 | |||
685 | ret = bq2415x_i2c_read_mask(bq, BQ2415X_REG_CURRENT, | ||
686 | BQ2415X_MASK_VI_TERM, BQ2415X_SHIFT_VI_TERM); | ||
687 | if (ret < 0) | ||
688 | return ret; | ||
689 | else | ||
690 | return (3400 + 3400*ret) / bq->init_data.resistor_sense; | ||
691 | } | ||
692 | |||
693 | /* set default value of property */ | ||
694 | #define bq2415x_set_default_value(bq, prop) \ | ||
695 | do { \ | ||
696 | int ret = 0; \ | ||
697 | if (bq->init_data.prop != -1) \ | ||
698 | ret = bq2415x_set_##prop(bq, bq->init_data.prop); \ | ||
699 | if (ret < 0) \ | ||
700 | return ret; \ | ||
701 | } while (0) | ||
702 | |||
703 | /* set default values of all properties */ | ||
704 | static int bq2415x_set_defaults(struct bq2415x_device *bq) | ||
705 | { | ||
706 | bq2415x_exec_command(bq, BQ2415X_BOOST_MODE_DISABLE); | ||
707 | bq2415x_exec_command(bq, BQ2415X_CHARGER_DISABLE); | ||
708 | bq2415x_exec_command(bq, BQ2415X_CHARGE_TERMINATION_DISABLE); | ||
709 | bq2415x_set_default_value(bq, current_limit); | ||
710 | bq2415x_set_default_value(bq, weak_battery_voltage); | ||
711 | bq2415x_set_default_value(bq, battery_regulation_voltage); | ||
712 | if (bq->init_data.resistor_sense > 0) { | ||
713 | bq2415x_set_default_value(bq, charge_current); | ||
714 | bq2415x_set_default_value(bq, termination_current); | ||
715 | bq2415x_exec_command(bq, BQ2415X_CHARGE_TERMINATION_ENABLE); | ||
716 | } | ||
717 | bq2415x_exec_command(bq, BQ2415X_CHARGER_ENABLE); | ||
718 | return 0; | ||
719 | } | ||
720 | |||
721 | /**** charger mode functions ****/ | ||
722 | |||
723 | /* set charger mode */ | ||
724 | static int bq2415x_set_mode(struct bq2415x_device *bq, enum bq2415x_mode mode) | ||
725 | { | ||
726 | int ret = 0; | ||
727 | int charger = 0; | ||
728 | int boost = 0; | ||
729 | |||
730 | if (mode == BQ2415X_MODE_HOST_CHARGER || | ||
731 | mode == BQ2415X_MODE_DEDICATED_CHARGER) | ||
732 | charger = 1; | ||
733 | |||
734 | if (mode == BQ2415X_MODE_BOOST) | ||
735 | boost = 1; | ||
736 | |||
737 | if (!charger) | ||
738 | ret = bq2415x_exec_command(bq, BQ2415X_CHARGER_DISABLE); | ||
739 | |||
740 | if (!boost) | ||
741 | ret = bq2415x_exec_command(bq, BQ2415X_BOOST_MODE_DISABLE); | ||
742 | |||
743 | if (ret < 0) | ||
744 | return ret; | ||
745 | |||
746 | switch (mode) { | ||
747 | case BQ2415X_MODE_NONE: | ||
748 | dev_dbg(bq->dev, "changing mode to: N/A\n"); | ||
749 | ret = bq2415x_set_current_limit(bq, 100); | ||
750 | break; | ||
751 | case BQ2415X_MODE_HOST_CHARGER: | ||
752 | dev_dbg(bq->dev, "changing mode to: Host/HUB charger\n"); | ||
753 | ret = bq2415x_set_current_limit(bq, 500); | ||
754 | break; | ||
755 | case BQ2415X_MODE_DEDICATED_CHARGER: | ||
756 | dev_dbg(bq->dev, "changing mode to: Dedicated charger\n"); | ||
757 | ret = bq2415x_set_current_limit(bq, 1800); | ||
758 | break; | ||
759 | case BQ2415X_MODE_BOOST: /* Boost mode */ | ||
760 | dev_dbg(bq->dev, "changing mode to: Boost\n"); | ||
761 | ret = bq2415x_set_current_limit(bq, 100); | ||
762 | break; | ||
763 | } | ||
764 | |||
765 | if (ret < 0) | ||
766 | return ret; | ||
767 | |||
768 | if (charger) | ||
769 | ret = bq2415x_exec_command(bq, BQ2415X_CHARGER_ENABLE); | ||
770 | else if (boost) | ||
771 | ret = bq2415x_exec_command(bq, BQ2415X_BOOST_MODE_ENABLE); | ||
772 | |||
773 | if (ret < 0) | ||
774 | return ret; | ||
775 | |||
776 | bq2415x_set_default_value(bq, weak_battery_voltage); | ||
777 | bq2415x_set_default_value(bq, battery_regulation_voltage); | ||
778 | |||
779 | bq->mode = mode; | ||
780 | sysfs_notify(&bq->charger.dev->kobj, NULL, "mode"); | ||
781 | |||
782 | return 0; | ||
783 | |||
784 | } | ||
785 | |||
786 | /* hook function called by other driver which set reported mode */ | ||
787 | static void bq2415x_hook_function(enum bq2415x_mode mode, void *data) | ||
788 | { | ||
789 | struct bq2415x_device *bq = data; | ||
790 | |||
791 | if (!bq) | ||
792 | return; | ||
793 | |||
794 | dev_dbg(bq->dev, "hook function was called\n"); | ||
795 | bq->reported_mode = mode; | ||
796 | |||
797 | /* if automode is not enabled do not tell about reported_mode */ | ||
798 | if (bq->automode < 1) | ||
799 | return; | ||
800 | |||
801 | sysfs_notify(&bq->charger.dev->kobj, NULL, "reported_mode"); | ||
802 | bq2415x_set_mode(bq, bq->reported_mode); | ||
803 | |||
804 | } | ||
805 | |||
806 | /**** timer functions ****/ | ||
807 | |||
808 | /* enable/disable auto resetting chip timer */ | ||
809 | static void bq2415x_set_autotimer(struct bq2415x_device *bq, int state) | ||
810 | { | ||
811 | mutex_lock(&bq2415x_timer_mutex); | ||
812 | |||
813 | if (bq->autotimer == state) { | ||
814 | mutex_unlock(&bq2415x_timer_mutex); | ||
815 | return; | ||
816 | } | ||
817 | |||
818 | bq->autotimer = state; | ||
819 | |||
820 | if (state) { | ||
821 | schedule_delayed_work(&bq->work, BQ2415X_TIMER_TIMEOUT * HZ); | ||
822 | bq2415x_exec_command(bq, BQ2415X_TIMER_RESET); | ||
823 | bq->timer_error = NULL; | ||
824 | } else { | ||
825 | cancel_delayed_work_sync(&bq->work); | ||
826 | } | ||
827 | |||
828 | mutex_unlock(&bq2415x_timer_mutex); | ||
829 | } | ||
830 | |||
831 | /* called by bq2415x_timer_work on timer error */ | ||
832 | static void bq2415x_timer_error(struct bq2415x_device *bq, const char *msg) | ||
833 | { | ||
834 | bq->timer_error = msg; | ||
835 | sysfs_notify(&bq->charger.dev->kobj, NULL, "timer"); | ||
836 | dev_err(bq->dev, "%s\n", msg); | ||
837 | if (bq->automode > 0) | ||
838 | bq->automode = 0; | ||
839 | bq2415x_set_mode(bq, BQ2415X_MODE_NONE); | ||
840 | bq2415x_set_autotimer(bq, 0); | ||
841 | } | ||
842 | |||
843 | /* delayed work function for auto resetting chip timer */ | ||
844 | static void bq2415x_timer_work(struct work_struct *work) | ||
845 | { | ||
846 | struct bq2415x_device *bq = container_of(work, struct bq2415x_device, | ||
847 | work.work); | ||
848 | int ret, error, boost; | ||
849 | |||
850 | if (!bq->autotimer) | ||
851 | return; | ||
852 | |||
853 | ret = bq2415x_exec_command(bq, BQ2415X_TIMER_RESET); | ||
854 | if (ret < 0) { | ||
855 | bq2415x_timer_error(bq, "Resetting timer failed"); | ||
856 | return; | ||
857 | } | ||
858 | |||
859 | boost = bq2415x_exec_command(bq, BQ2415X_BOOST_MODE_STATUS); | ||
860 | if (boost < 0) { | ||
861 | bq2415x_timer_error(bq, "Unknown error"); | ||
862 | return; | ||
863 | } | ||
864 | |||
865 | error = bq2415x_exec_command(bq, BQ2415X_FAULT_STATUS); | ||
866 | if (error < 0) { | ||
867 | bq2415x_timer_error(bq, "Unknown error"); | ||
868 | return; | ||
869 | } | ||
870 | |||
871 | if (boost) { | ||
872 | switch (error) { | ||
873 | /* Non fatal errors, chip is OK */ | ||
874 | case 0: /* No error */ | ||
875 | break; | ||
876 | case 6: /* Timer expired */ | ||
877 | dev_err(bq->dev, "Timer expired\n"); | ||
878 | break; | ||
879 | case 3: /* Battery voltage too low */ | ||
880 | dev_err(bq->dev, "Battery voltage to low\n"); | ||
881 | break; | ||
882 | |||
883 | /* Fatal errors, disable and reset chip */ | ||
884 | case 1: /* Overvoltage protection (chip fried) */ | ||
885 | bq2415x_timer_error(bq, | ||
886 | "Overvoltage protection (chip fried)"); | ||
887 | return; | ||
888 | case 2: /* Overload */ | ||
889 | bq2415x_timer_error(bq, "Overload"); | ||
890 | return; | ||
891 | case 4: /* Battery overvoltage protection */ | ||
892 | bq2415x_timer_error(bq, | ||
893 | "Battery overvoltage protection"); | ||
894 | return; | ||
895 | case 5: /* Thermal shutdown (too hot) */ | ||
896 | bq2415x_timer_error(bq, | ||
897 | "Thermal shutdown (too hot)"); | ||
898 | return; | ||
899 | case 7: /* N/A */ | ||
900 | bq2415x_timer_error(bq, "Unknown error"); | ||
901 | return; | ||
902 | } | ||
903 | } else { | ||
904 | switch (error) { | ||
905 | /* Non fatal errors, chip is OK */ | ||
906 | case 0: /* No error */ | ||
907 | break; | ||
908 | case 2: /* Sleep mode */ | ||
909 | dev_err(bq->dev, "Sleep mode\n"); | ||
910 | break; | ||
911 | case 3: /* Poor input source */ | ||
912 | dev_err(bq->dev, "Poor input source\n"); | ||
913 | break; | ||
914 | case 6: /* Timer expired */ | ||
915 | dev_err(bq->dev, "Timer expired\n"); | ||
916 | break; | ||
917 | case 7: /* No battery */ | ||
918 | dev_err(bq->dev, "No battery\n"); | ||
919 | break; | ||
920 | |||
921 | /* Fatal errors, disable and reset chip */ | ||
922 | case 1: /* Overvoltage protection (chip fried) */ | ||
923 | bq2415x_timer_error(bq, | ||
924 | "Overvoltage protection (chip fried)"); | ||
925 | return; | ||
926 | case 4: /* Battery overvoltage protection */ | ||
927 | bq2415x_timer_error(bq, | ||
928 | "Battery overvoltage protection"); | ||
929 | return; | ||
930 | case 5: /* Thermal shutdown (too hot) */ | ||
931 | bq2415x_timer_error(bq, | ||
932 | "Thermal shutdown (too hot)"); | ||
933 | return; | ||
934 | } | ||
935 | } | ||
936 | |||
937 | schedule_delayed_work(&bq->work, BQ2415X_TIMER_TIMEOUT * HZ); | ||
938 | } | ||
939 | |||
940 | /**** power supply interface code ****/ | ||
941 | |||
942 | static enum power_supply_property bq2415x_power_supply_props[] = { | ||
943 | /* TODO: maybe add more power supply properties */ | ||
944 | POWER_SUPPLY_PROP_STATUS, | ||
945 | POWER_SUPPLY_PROP_MODEL_NAME, | ||
946 | }; | ||
947 | |||
948 | static int bq2415x_power_supply_get_property(struct power_supply *psy, | ||
949 | enum power_supply_property psp, union power_supply_propval *val) | ||
950 | { | ||
951 | struct bq2415x_device *bq = container_of(psy, struct bq2415x_device, | ||
952 | charger); | ||
953 | int ret; | ||
954 | |||
955 | switch (psp) { | ||
956 | case POWER_SUPPLY_PROP_STATUS: | ||
957 | ret = bq2415x_exec_command(bq, BQ2415X_CHARGE_STATUS); | ||
958 | if (ret < 0) | ||
959 | return ret; | ||
960 | else if (ret == 0) /* Ready */ | ||
961 | val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING; | ||
962 | else if (ret == 1) /* Charge in progress */ | ||
963 | val->intval = POWER_SUPPLY_STATUS_CHARGING; | ||
964 | else if (ret == 2) /* Charge done */ | ||
965 | val->intval = POWER_SUPPLY_STATUS_FULL; | ||
966 | else | ||
967 | val->intval = POWER_SUPPLY_STATUS_UNKNOWN; | ||
968 | break; | ||
969 | case POWER_SUPPLY_PROP_MODEL_NAME: | ||
970 | val->strval = bq->model; | ||
971 | break; | ||
972 | default: | ||
973 | return -EINVAL; | ||
974 | } | ||
975 | return 0; | ||
976 | } | ||
977 | |||
978 | static int bq2415x_power_supply_init(struct bq2415x_device *bq) | ||
979 | { | ||
980 | int ret; | ||
981 | int chip; | ||
982 | char revstr[8]; | ||
983 | |||
984 | bq->charger.name = bq->name; | ||
985 | bq->charger.type = POWER_SUPPLY_TYPE_USB; | ||
986 | bq->charger.properties = bq2415x_power_supply_props; | ||
987 | bq->charger.num_properties = ARRAY_SIZE(bq2415x_power_supply_props); | ||
988 | bq->charger.get_property = bq2415x_power_supply_get_property; | ||
989 | |||
990 | ret = bq2415x_detect_chip(bq); | ||
991 | if (ret < 0) | ||
992 | chip = BQUNKNOWN; | ||
993 | else | ||
994 | chip = ret; | ||
995 | |||
996 | ret = bq2415x_detect_revision(bq); | ||
997 | if (ret < 0) | ||
998 | strcpy(revstr, "unknown"); | ||
999 | else | ||
1000 | sprintf(revstr, "1.%d", ret); | ||
1001 | |||
1002 | bq->model = kasprintf(GFP_KERNEL, | ||
1003 | "chip %s, revision %s, vender code %.3d", | ||
1004 | bq2415x_chip_name[chip], revstr, | ||
1005 | bq2415x_get_vender_code(bq)); | ||
1006 | if (!bq->model) { | ||
1007 | dev_err(bq->dev, "failed to allocate model name\n"); | ||
1008 | return -ENOMEM; | ||
1009 | } | ||
1010 | |||
1011 | ret = power_supply_register(bq->dev, &bq->charger); | ||
1012 | if (ret) { | ||
1013 | kfree(bq->model); | ||
1014 | return ret; | ||
1015 | } | ||
1016 | |||
1017 | return 0; | ||
1018 | } | ||
1019 | |||
1020 | static void bq2415x_power_supply_exit(struct bq2415x_device *bq) | ||
1021 | { | ||
1022 | bq->autotimer = 0; | ||
1023 | if (bq->automode > 0) | ||
1024 | bq->automode = 0; | ||
1025 | cancel_delayed_work_sync(&bq->work); | ||
1026 | power_supply_unregister(&bq->charger); | ||
1027 | kfree(bq->model); | ||
1028 | } | ||
1029 | |||
1030 | /**** additional sysfs entries for power supply interface ****/ | ||
1031 | |||
1032 | /* show *_status entries */ | ||
1033 | static ssize_t bq2415x_sysfs_show_status(struct device *dev, | ||
1034 | struct device_attribute *attr, char *buf) | ||
1035 | { | ||
1036 | struct power_supply *psy = dev_get_drvdata(dev); | ||
1037 | struct bq2415x_device *bq = container_of(psy, struct bq2415x_device, | ||
1038 | charger); | ||
1039 | enum bq2415x_command command; | ||
1040 | int ret; | ||
1041 | |||
1042 | if (strcmp(attr->attr.name, "otg_status") == 0) | ||
1043 | command = BQ2415X_OTG_STATUS; | ||
1044 | else if (strcmp(attr->attr.name, "charge_status") == 0) | ||
1045 | command = BQ2415X_CHARGE_STATUS; | ||
1046 | else if (strcmp(attr->attr.name, "boost_status") == 0) | ||
1047 | command = BQ2415X_BOOST_STATUS; | ||
1048 | else if (strcmp(attr->attr.name, "fault_status") == 0) | ||
1049 | command = BQ2415X_FAULT_STATUS; | ||
1050 | else | ||
1051 | return -EINVAL; | ||
1052 | |||
1053 | ret = bq2415x_exec_command(bq, command); | ||
1054 | if (ret < 0) | ||
1055 | return ret; | ||
1056 | else | ||
1057 | return sprintf(buf, "%d\n", ret); | ||
1058 | } | ||
1059 | |||
1060 | /* set timer entry: | ||
1061 | auto - enable auto mode | ||
1062 | off - disable auto mode | ||
1063 | (other values) - reset chip timer | ||
1064 | */ | ||
1065 | static ssize_t bq2415x_sysfs_set_timer(struct device *dev, | ||
1066 | struct device_attribute *attr, const char *buf, size_t count) | ||
1067 | { | ||
1068 | struct power_supply *psy = dev_get_drvdata(dev); | ||
1069 | struct bq2415x_device *bq = container_of(psy, struct bq2415x_device, | ||
1070 | charger); | ||
1071 | int ret = 0; | ||
1072 | |||
1073 | if (strncmp(buf, "auto", 4) == 0) | ||
1074 | bq2415x_set_autotimer(bq, 1); | ||
1075 | else if (strncmp(buf, "off", 3) == 0) | ||
1076 | bq2415x_set_autotimer(bq, 0); | ||
1077 | else | ||
1078 | ret = bq2415x_exec_command(bq, BQ2415X_TIMER_RESET); | ||
1079 | |||
1080 | if (ret < 0) | ||
1081 | return ret; | ||
1082 | else | ||
1083 | return count; | ||
1084 | } | ||
1085 | |||
1086 | /* show timer entry (auto or off) */ | ||
1087 | static ssize_t bq2415x_sysfs_show_timer(struct device *dev, | ||
1088 | struct device_attribute *attr, char *buf) | ||
1089 | { | ||
1090 | struct power_supply *psy = dev_get_drvdata(dev); | ||
1091 | struct bq2415x_device *bq = container_of(psy, struct bq2415x_device, | ||
1092 | charger); | ||
1093 | |||
1094 | if (bq->timer_error) | ||
1095 | return sprintf(buf, "%s\n", bq->timer_error); | ||
1096 | |||
1097 | if (bq->autotimer) | ||
1098 | return sprintf(buf, "auto\n"); | ||
1099 | else | ||
1100 | return sprintf(buf, "off\n"); | ||
1101 | } | ||
1102 | |||
1103 | /* set mode entry: | ||
1104 | auto - if automode is supported, enable it and set mode to reported | ||
1105 | none - disable charger and boost mode | ||
1106 | host - charging mode for host/hub chargers (current limit 500mA) | ||
1107 | dedicated - charging mode for dedicated chargers (unlimited current limit) | ||
1108 | boost - disable charger and enable boost mode | ||
1109 | */ | ||
1110 | static ssize_t bq2415x_sysfs_set_mode(struct device *dev, | ||
1111 | struct device_attribute *attr, const char *buf, size_t count) | ||
1112 | { | ||
1113 | struct power_supply *psy = dev_get_drvdata(dev); | ||
1114 | struct bq2415x_device *bq = container_of(psy, struct bq2415x_device, | ||
1115 | charger); | ||
1116 | enum bq2415x_mode mode; | ||
1117 | int ret = 0; | ||
1118 | |||
1119 | if (strncmp(buf, "auto", 4) == 0) { | ||
1120 | if (bq->automode < 0) | ||
1121 | return -ENOSYS; | ||
1122 | bq->automode = 1; | ||
1123 | mode = bq->reported_mode; | ||
1124 | } else if (strncmp(buf, "none", 4) == 0) { | ||
1125 | if (bq->automode > 0) | ||
1126 | bq->automode = 0; | ||
1127 | mode = BQ2415X_MODE_NONE; | ||
1128 | } else if (strncmp(buf, "host", 4) == 0) { | ||
1129 | if (bq->automode > 0) | ||
1130 | bq->automode = 0; | ||
1131 | mode = BQ2415X_MODE_HOST_CHARGER; | ||
1132 | } else if (strncmp(buf, "dedicated", 9) == 0) { | ||
1133 | if (bq->automode > 0) | ||
1134 | bq->automode = 0; | ||
1135 | mode = BQ2415X_MODE_DEDICATED_CHARGER; | ||
1136 | } else if (strncmp(buf, "boost", 5) == 0) { | ||
1137 | if (bq->automode > 0) | ||
1138 | bq->automode = 0; | ||
1139 | mode = BQ2415X_MODE_BOOST; | ||
1140 | } else if (strncmp(buf, "reset", 5) == 0) { | ||
1141 | bq2415x_reset_chip(bq); | ||
1142 | bq2415x_set_defaults(bq); | ||
1143 | if (bq->automode <= 0) | ||
1144 | return count; | ||
1145 | bq->automode = 1; | ||
1146 | mode = bq->reported_mode; | ||
1147 | } else | ||
1148 | return -EINVAL; | ||
1149 | |||
1150 | ret = bq2415x_set_mode(bq, mode); | ||
1151 | if (ret < 0) | ||
1152 | return ret; | ||
1153 | else | ||
1154 | return count; | ||
1155 | } | ||
1156 | |||
1157 | /* show mode entry (auto, none, host, dedicated or boost) */ | ||
1158 | static ssize_t bq2415x_sysfs_show_mode(struct device *dev, | ||
1159 | struct device_attribute *attr, char *buf) | ||
1160 | { | ||
1161 | struct power_supply *psy = dev_get_drvdata(dev); | ||
1162 | struct bq2415x_device *bq = container_of(psy, struct bq2415x_device, | ||
1163 | charger); | ||
1164 | ssize_t ret = 0; | ||
1165 | |||
1166 | if (bq->automode > 0) | ||
1167 | ret += sprintf(buf+ret, "auto ("); | ||
1168 | |||
1169 | switch (bq->mode) { | ||
1170 | case BQ2415X_MODE_NONE: | ||
1171 | ret += sprintf(buf+ret, "none"); | ||
1172 | break; | ||
1173 | case BQ2415X_MODE_HOST_CHARGER: | ||
1174 | ret += sprintf(buf+ret, "host"); | ||
1175 | break; | ||
1176 | case BQ2415X_MODE_DEDICATED_CHARGER: | ||
1177 | ret += sprintf(buf+ret, "dedicated"); | ||
1178 | break; | ||
1179 | case BQ2415X_MODE_BOOST: | ||
1180 | ret += sprintf(buf+ret, "boost"); | ||
1181 | break; | ||
1182 | } | ||
1183 | |||
1184 | if (bq->automode > 0) | ||
1185 | ret += sprintf(buf+ret, ")"); | ||
1186 | |||
1187 | ret += sprintf(buf+ret, "\n"); | ||
1188 | return ret; | ||
1189 | } | ||
1190 | |||
1191 | /* show reported_mode entry (none, host, dedicated or boost) */ | ||
1192 | static ssize_t bq2415x_sysfs_show_reported_mode(struct device *dev, | ||
1193 | struct device_attribute *attr, char *buf) | ||
1194 | { | ||
1195 | struct power_supply *psy = dev_get_drvdata(dev); | ||
1196 | struct bq2415x_device *bq = container_of(psy, struct bq2415x_device, | ||
1197 | charger); | ||
1198 | |||
1199 | if (bq->automode < 0) | ||
1200 | return -EINVAL; | ||
1201 | |||
1202 | switch (bq->reported_mode) { | ||
1203 | case BQ2415X_MODE_NONE: | ||
1204 | return sprintf(buf, "none\n"); | ||
1205 | case BQ2415X_MODE_HOST_CHARGER: | ||
1206 | return sprintf(buf, "host\n"); | ||
1207 | case BQ2415X_MODE_DEDICATED_CHARGER: | ||
1208 | return sprintf(buf, "dedicated\n"); | ||
1209 | case BQ2415X_MODE_BOOST: | ||
1210 | return sprintf(buf, "boost\n"); | ||
1211 | } | ||
1212 | |||
1213 | return -EINVAL; | ||
1214 | } | ||
1215 | |||
1216 | /* directly set raw value to chip register, format: 'register value' */ | ||
1217 | static ssize_t bq2415x_sysfs_set_registers(struct device *dev, | ||
1218 | struct device_attribute *attr, const char *buf, size_t count) | ||
1219 | { | ||
1220 | struct power_supply *psy = dev_get_drvdata(dev); | ||
1221 | struct bq2415x_device *bq = container_of(psy, struct bq2415x_device, | ||
1222 | charger); | ||
1223 | ssize_t ret = 0; | ||
1224 | unsigned int reg; | ||
1225 | unsigned int val; | ||
1226 | |||
1227 | if (sscanf(buf, "%x %x", ®, &val) != 2) | ||
1228 | return -EINVAL; | ||
1229 | |||
1230 | if (reg > 4 || val > 255) | ||
1231 | return -EINVAL; | ||
1232 | |||
1233 | ret = bq2415x_i2c_write(bq, reg, val); | ||
1234 | if (ret < 0) | ||
1235 | return ret; | ||
1236 | else | ||
1237 | return count; | ||
1238 | } | ||
1239 | |||
1240 | /* print value of chip register, format: 'register=value' */ | ||
1241 | static ssize_t bq2415x_sysfs_print_reg(struct bq2415x_device *bq, | ||
1242 | u8 reg, char *buf) | ||
1243 | { | ||
1244 | int ret = bq2415x_i2c_read(bq, reg); | ||
1245 | if (ret < 0) | ||
1246 | return sprintf(buf, "%#.2x=error %d\n", reg, ret); | ||
1247 | else | ||
1248 | return sprintf(buf, "%#.2x=%#.2x\n", reg, ret); | ||
1249 | } | ||
1250 | |||
1251 | /* show all raw values of chip register, format per line: 'register=value' */ | ||
1252 | static ssize_t bq2415x_sysfs_show_registers(struct device *dev, | ||
1253 | struct device_attribute *attr, char *buf) | ||
1254 | { | ||
1255 | struct power_supply *psy = dev_get_drvdata(dev); | ||
1256 | struct bq2415x_device *bq = container_of(psy, struct bq2415x_device, | ||
1257 | charger); | ||
1258 | ssize_t ret = 0; | ||
1259 | |||
1260 | ret += bq2415x_sysfs_print_reg(bq, BQ2415X_REG_STATUS, buf+ret); | ||
1261 | ret += bq2415x_sysfs_print_reg(bq, BQ2415X_REG_CONTROL, buf+ret); | ||
1262 | ret += bq2415x_sysfs_print_reg(bq, BQ2415X_REG_VOLTAGE, buf+ret); | ||
1263 | ret += bq2415x_sysfs_print_reg(bq, BQ2415X_REG_VENDER, buf+ret); | ||
1264 | ret += bq2415x_sysfs_print_reg(bq, BQ2415X_REG_CURRENT, buf+ret); | ||
1265 | return ret; | ||
1266 | } | ||
1267 | |||
1268 | /* set current and voltage limit entries (in mA or mV) */ | ||
1269 | static ssize_t bq2415x_sysfs_set_limit(struct device *dev, | ||
1270 | struct device_attribute *attr, const char *buf, size_t count) | ||
1271 | { | ||
1272 | struct power_supply *psy = dev_get_drvdata(dev); | ||
1273 | struct bq2415x_device *bq = container_of(psy, struct bq2415x_device, | ||
1274 | charger); | ||
1275 | long val; | ||
1276 | int ret; | ||
1277 | |||
1278 | if (kstrtol(buf, 10, &val) < 0) | ||
1279 | return -EINVAL; | ||
1280 | |||
1281 | if (strcmp(attr->attr.name, "current_limit") == 0) | ||
1282 | ret = bq2415x_set_current_limit(bq, val); | ||
1283 | else if (strcmp(attr->attr.name, "weak_battery_voltage") == 0) | ||
1284 | ret = bq2415x_set_weak_battery_voltage(bq, val); | ||
1285 | else if (strcmp(attr->attr.name, "battery_regulation_voltage") == 0) | ||
1286 | ret = bq2415x_set_battery_regulation_voltage(bq, val); | ||
1287 | else if (strcmp(attr->attr.name, "charge_current") == 0) | ||
1288 | ret = bq2415x_set_charge_current(bq, val); | ||
1289 | else if (strcmp(attr->attr.name, "termination_current") == 0) | ||
1290 | ret = bq2415x_set_termination_current(bq, val); | ||
1291 | else | ||
1292 | return -EINVAL; | ||
1293 | |||
1294 | if (ret < 0) | ||
1295 | return ret; | ||
1296 | else | ||
1297 | return count; | ||
1298 | } | ||
1299 | |||
1300 | /* show current and voltage limit entries (in mA or mV) */ | ||
1301 | static ssize_t bq2415x_sysfs_show_limit(struct device *dev, | ||
1302 | struct device_attribute *attr, char *buf) | ||
1303 | { | ||
1304 | struct power_supply *psy = dev_get_drvdata(dev); | ||
1305 | struct bq2415x_device *bq = container_of(psy, struct bq2415x_device, | ||
1306 | charger); | ||
1307 | int ret; | ||
1308 | |||
1309 | if (strcmp(attr->attr.name, "current_limit") == 0) | ||
1310 | ret = bq2415x_get_current_limit(bq); | ||
1311 | else if (strcmp(attr->attr.name, "weak_battery_voltage") == 0) | ||
1312 | ret = bq2415x_get_weak_battery_voltage(bq); | ||
1313 | else if (strcmp(attr->attr.name, "battery_regulation_voltage") == 0) | ||
1314 | ret = bq2415x_get_battery_regulation_voltage(bq); | ||
1315 | else if (strcmp(attr->attr.name, "charge_current") == 0) | ||
1316 | ret = bq2415x_get_charge_current(bq); | ||
1317 | else if (strcmp(attr->attr.name, "termination_current") == 0) | ||
1318 | ret = bq2415x_get_termination_current(bq); | ||
1319 | else | ||
1320 | return -EINVAL; | ||
1321 | |||
1322 | if (ret < 0) | ||
1323 | return ret; | ||
1324 | else | ||
1325 | return sprintf(buf, "%d\n", ret); | ||
1326 | } | ||
1327 | |||
1328 | /* set *_enable entries */ | ||
1329 | static ssize_t bq2415x_sysfs_set_enable(struct device *dev, | ||
1330 | struct device_attribute *attr, const char *buf, size_t count) | ||
1331 | { | ||
1332 | struct power_supply *psy = dev_get_drvdata(dev); | ||
1333 | struct bq2415x_device *bq = container_of(psy, struct bq2415x_device, | ||
1334 | charger); | ||
1335 | enum bq2415x_command command; | ||
1336 | long val; | ||
1337 | int ret; | ||
1338 | |||
1339 | if (kstrtol(buf, 10, &val) < 0) | ||
1340 | return -EINVAL; | ||
1341 | |||
1342 | if (strcmp(attr->attr.name, "charge_termination_enable") == 0) | ||
1343 | command = val ? BQ2415X_CHARGE_TERMINATION_ENABLE : | ||
1344 | BQ2415X_CHARGE_TERMINATION_DISABLE; | ||
1345 | else if (strcmp(attr->attr.name, "high_impedance_enable") == 0) | ||
1346 | command = val ? BQ2415X_HIGH_IMPEDANCE_ENABLE : | ||
1347 | BQ2415X_HIGH_IMPEDANCE_DISABLE; | ||
1348 | else if (strcmp(attr->attr.name, "otg_pin_enable") == 0) | ||
1349 | command = val ? BQ2415X_OTG_PIN_ENABLE : | ||
1350 | BQ2415X_OTG_PIN_DISABLE; | ||
1351 | else if (strcmp(attr->attr.name, "stat_pin_enable") == 0) | ||
1352 | command = val ? BQ2415X_STAT_PIN_ENABLE : | ||
1353 | BQ2415X_STAT_PIN_DISABLE; | ||
1354 | else | ||
1355 | return -EINVAL; | ||
1356 | |||
1357 | ret = bq2415x_exec_command(bq, command); | ||
1358 | if (ret < 0) | ||
1359 | return ret; | ||
1360 | else | ||
1361 | return count; | ||
1362 | } | ||
1363 | |||
1364 | /* show *_enable entries */ | ||
1365 | static ssize_t bq2415x_sysfs_show_enable(struct device *dev, | ||
1366 | struct device_attribute *attr, char *buf) | ||
1367 | { | ||
1368 | struct power_supply *psy = dev_get_drvdata(dev); | ||
1369 | struct bq2415x_device *bq = container_of(psy, struct bq2415x_device, | ||
1370 | charger); | ||
1371 | enum bq2415x_command command; | ||
1372 | int ret; | ||
1373 | |||
1374 | if (strcmp(attr->attr.name, "charge_termination_enable") == 0) | ||
1375 | command = BQ2415X_CHARGE_TERMINATION_STATUS; | ||
1376 | else if (strcmp(attr->attr.name, "high_impedance_enable") == 0) | ||
1377 | command = BQ2415X_HIGH_IMPEDANCE_STATUS; | ||
1378 | else if (strcmp(attr->attr.name, "otg_pin_enable") == 0) | ||
1379 | command = BQ2415X_OTG_PIN_STATUS; | ||
1380 | else if (strcmp(attr->attr.name, "stat_pin_enable") == 0) | ||
1381 | command = BQ2415X_STAT_PIN_STATUS; | ||
1382 | else | ||
1383 | return -EINVAL; | ||
1384 | |||
1385 | ret = bq2415x_exec_command(bq, command); | ||
1386 | if (ret < 0) | ||
1387 | return ret; | ||
1388 | else | ||
1389 | return sprintf(buf, "%d\n", ret); | ||
1390 | } | ||
1391 | |||
1392 | static DEVICE_ATTR(current_limit, S_IWUSR | S_IRUGO, | ||
1393 | bq2415x_sysfs_show_limit, bq2415x_sysfs_set_limit); | ||
1394 | static DEVICE_ATTR(weak_battery_voltage, S_IWUSR | S_IRUGO, | ||
1395 | bq2415x_sysfs_show_limit, bq2415x_sysfs_set_limit); | ||
1396 | static DEVICE_ATTR(battery_regulation_voltage, S_IWUSR | S_IRUGO, | ||
1397 | bq2415x_sysfs_show_limit, bq2415x_sysfs_set_limit); | ||
1398 | static DEVICE_ATTR(charge_current, S_IWUSR | S_IRUGO, | ||
1399 | bq2415x_sysfs_show_limit, bq2415x_sysfs_set_limit); | ||
1400 | static DEVICE_ATTR(termination_current, S_IWUSR | S_IRUGO, | ||
1401 | bq2415x_sysfs_show_limit, bq2415x_sysfs_set_limit); | ||
1402 | |||
1403 | static DEVICE_ATTR(charge_termination_enable, S_IWUSR | S_IRUGO, | ||
1404 | bq2415x_sysfs_show_enable, bq2415x_sysfs_set_enable); | ||
1405 | static DEVICE_ATTR(high_impedance_enable, S_IWUSR | S_IRUGO, | ||
1406 | bq2415x_sysfs_show_enable, bq2415x_sysfs_set_enable); | ||
1407 | static DEVICE_ATTR(otg_pin_enable, S_IWUSR | S_IRUGO, | ||
1408 | bq2415x_sysfs_show_enable, bq2415x_sysfs_set_enable); | ||
1409 | static DEVICE_ATTR(stat_pin_enable, S_IWUSR | S_IRUGO, | ||
1410 | bq2415x_sysfs_show_enable, bq2415x_sysfs_set_enable); | ||
1411 | |||
1412 | static DEVICE_ATTR(reported_mode, S_IRUGO, | ||
1413 | bq2415x_sysfs_show_reported_mode, NULL); | ||
1414 | static DEVICE_ATTR(mode, S_IWUSR | S_IRUGO, | ||
1415 | bq2415x_sysfs_show_mode, bq2415x_sysfs_set_mode); | ||
1416 | static DEVICE_ATTR(timer, S_IWUSR | S_IRUGO, | ||
1417 | bq2415x_sysfs_show_timer, bq2415x_sysfs_set_timer); | ||
1418 | |||
1419 | static DEVICE_ATTR(registers, S_IWUSR | S_IRUGO, | ||
1420 | bq2415x_sysfs_show_registers, bq2415x_sysfs_set_registers); | ||
1421 | |||
1422 | static DEVICE_ATTR(otg_status, S_IRUGO, bq2415x_sysfs_show_status, NULL); | ||
1423 | static DEVICE_ATTR(charge_status, S_IRUGO, bq2415x_sysfs_show_status, NULL); | ||
1424 | static DEVICE_ATTR(boost_status, S_IRUGO, bq2415x_sysfs_show_status, NULL); | ||
1425 | static DEVICE_ATTR(fault_status, S_IRUGO, bq2415x_sysfs_show_status, NULL); | ||
1426 | |||
1427 | static struct attribute *bq2415x_sysfs_attributes[] = { | ||
1428 | &dev_attr_current_limit.attr, | ||
1429 | &dev_attr_weak_battery_voltage.attr, | ||
1430 | &dev_attr_battery_regulation_voltage.attr, | ||
1431 | &dev_attr_charge_current.attr, | ||
1432 | &dev_attr_termination_current.attr, | ||
1433 | |||
1434 | &dev_attr_charge_termination_enable.attr, | ||
1435 | &dev_attr_high_impedance_enable.attr, | ||
1436 | &dev_attr_otg_pin_enable.attr, | ||
1437 | &dev_attr_stat_pin_enable.attr, | ||
1438 | |||
1439 | &dev_attr_reported_mode.attr, | ||
1440 | &dev_attr_mode.attr, | ||
1441 | &dev_attr_timer.attr, | ||
1442 | |||
1443 | &dev_attr_registers.attr, | ||
1444 | |||
1445 | &dev_attr_otg_status.attr, | ||
1446 | &dev_attr_charge_status.attr, | ||
1447 | &dev_attr_boost_status.attr, | ||
1448 | &dev_attr_fault_status.attr, | ||
1449 | NULL, | ||
1450 | }; | ||
1451 | |||
1452 | static const struct attribute_group bq2415x_sysfs_attr_group = { | ||
1453 | .attrs = bq2415x_sysfs_attributes, | ||
1454 | }; | ||
1455 | |||
1456 | static int bq2415x_sysfs_init(struct bq2415x_device *bq) | ||
1457 | { | ||
1458 | return sysfs_create_group(&bq->charger.dev->kobj, | ||
1459 | &bq2415x_sysfs_attr_group); | ||
1460 | } | ||
1461 | |||
1462 | static void bq2415x_sysfs_exit(struct bq2415x_device *bq) | ||
1463 | { | ||
1464 | sysfs_remove_group(&bq->charger.dev->kobj, &bq2415x_sysfs_attr_group); | ||
1465 | } | ||
1466 | |||
1467 | /* main bq2415x probe function */ | ||
1468 | static int bq2415x_probe(struct i2c_client *client, | ||
1469 | const struct i2c_device_id *id) | ||
1470 | { | ||
1471 | int ret; | ||
1472 | int num; | ||
1473 | char *name; | ||
1474 | struct bq2415x_device *bq; | ||
1475 | |||
1476 | if (!client->dev.platform_data) { | ||
1477 | dev_err(&client->dev, "platform data not set\n"); | ||
1478 | return -ENODEV; | ||
1479 | } | ||
1480 | |||
1481 | /* Get new ID for the new device */ | ||
1482 | ret = idr_pre_get(&bq2415x_id, GFP_KERNEL); | ||
1483 | if (ret == 0) | ||
1484 | return -ENOMEM; | ||
1485 | |||
1486 | mutex_lock(&bq2415x_id_mutex); | ||
1487 | ret = idr_get_new(&bq2415x_id, client, &num); | ||
1488 | mutex_unlock(&bq2415x_id_mutex); | ||
1489 | |||
1490 | if (ret < 0) | ||
1491 | return ret; | ||
1492 | |||
1493 | name = kasprintf(GFP_KERNEL, "%s-%d", id->name, num); | ||
1494 | if (!name) { | ||
1495 | dev_err(&client->dev, "failed to allocate device name\n"); | ||
1496 | ret = -ENOMEM; | ||
1497 | goto error_1; | ||
1498 | } | ||
1499 | |||
1500 | bq = kzalloc(sizeof(*bq), GFP_KERNEL); | ||
1501 | if (!bq) { | ||
1502 | dev_err(&client->dev, "failed to allocate device data\n"); | ||
1503 | ret = -ENOMEM; | ||
1504 | goto error_2; | ||
1505 | } | ||
1506 | |||
1507 | i2c_set_clientdata(client, bq); | ||
1508 | |||
1509 | bq->id = num; | ||
1510 | bq->dev = &client->dev; | ||
1511 | bq->chip = id->driver_data; | ||
1512 | bq->name = name; | ||
1513 | bq->mode = BQ2415X_MODE_NONE; | ||
1514 | bq->reported_mode = BQ2415X_MODE_NONE; | ||
1515 | bq->autotimer = 0; | ||
1516 | bq->automode = 0; | ||
1517 | |||
1518 | memcpy(&bq->init_data, client->dev.platform_data, | ||
1519 | sizeof(bq->init_data)); | ||
1520 | |||
1521 | bq2415x_reset_chip(bq); | ||
1522 | |||
1523 | ret = bq2415x_power_supply_init(bq); | ||
1524 | if (ret) { | ||
1525 | dev_err(bq->dev, "failed to register power supply: %d\n", ret); | ||
1526 | goto error_3; | ||
1527 | } | ||
1528 | |||
1529 | ret = bq2415x_sysfs_init(bq); | ||
1530 | if (ret) { | ||
1531 | dev_err(bq->dev, "failed to create sysfs entries: %d\n", ret); | ||
1532 | goto error_4; | ||
1533 | } | ||
1534 | |||
1535 | ret = bq2415x_set_defaults(bq); | ||
1536 | if (ret) { | ||
1537 | dev_err(bq->dev, "failed to set default values: %d\n", ret); | ||
1538 | goto error_5; | ||
1539 | } | ||
1540 | |||
1541 | if (bq->init_data.set_mode_hook) { | ||
1542 | if (bq->init_data.set_mode_hook( | ||
1543 | bq2415x_hook_function, bq)) { | ||
1544 | bq->automode = 1; | ||
1545 | bq2415x_set_mode(bq, bq->reported_mode); | ||
1546 | dev_info(bq->dev, "automode enabled\n"); | ||
1547 | } else { | ||
1548 | bq->automode = -1; | ||
1549 | dev_info(bq->dev, "automode failed\n"); | ||
1550 | } | ||
1551 | } else { | ||
1552 | bq->automode = -1; | ||
1553 | dev_info(bq->dev, "automode not supported\n"); | ||
1554 | } | ||
1555 | |||
1556 | INIT_DELAYED_WORK(&bq->work, bq2415x_timer_work); | ||
1557 | bq2415x_set_autotimer(bq, 1); | ||
1558 | |||
1559 | dev_info(bq->dev, "driver registered\n"); | ||
1560 | return 0; | ||
1561 | |||
1562 | error_5: | ||
1563 | bq2415x_sysfs_exit(bq); | ||
1564 | error_4: | ||
1565 | bq2415x_power_supply_exit(bq); | ||
1566 | error_3: | ||
1567 | kfree(bq); | ||
1568 | error_2: | ||
1569 | kfree(name); | ||
1570 | error_1: | ||
1571 | mutex_lock(&bq2415x_id_mutex); | ||
1572 | idr_remove(&bq2415x_id, num); | ||
1573 | mutex_unlock(&bq2415x_id_mutex); | ||
1574 | |||
1575 | return ret; | ||
1576 | } | ||
1577 | |||
1578 | /* main bq2415x remove function */ | ||
1579 | |||
1580 | static int bq2415x_remove(struct i2c_client *client) | ||
1581 | { | ||
1582 | struct bq2415x_device *bq = i2c_get_clientdata(client); | ||
1583 | |||
1584 | if (bq->init_data.set_mode_hook) | ||
1585 | bq->init_data.set_mode_hook(NULL, NULL); | ||
1586 | |||
1587 | bq2415x_sysfs_exit(bq); | ||
1588 | bq2415x_power_supply_exit(bq); | ||
1589 | |||
1590 | bq2415x_reset_chip(bq); | ||
1591 | |||
1592 | mutex_lock(&bq2415x_id_mutex); | ||
1593 | idr_remove(&bq2415x_id, bq->id); | ||
1594 | mutex_unlock(&bq2415x_id_mutex); | ||
1595 | |||
1596 | dev_info(bq->dev, "driver unregistered\n"); | ||
1597 | |||
1598 | kfree(bq->name); | ||
1599 | kfree(bq); | ||
1600 | |||
1601 | return 0; | ||
1602 | } | ||
1603 | |||
1604 | static const struct i2c_device_id bq2415x_i2c_id_table[] = { | ||
1605 | { "bq2415x", BQUNKNOWN }, | ||
1606 | { "bq24150", BQ24150 }, | ||
1607 | { "bq24150a", BQ24150A }, | ||
1608 | { "bq24151", BQ24151 }, | ||
1609 | { "bq24151a", BQ24151A }, | ||
1610 | { "bq24152", BQ24152 }, | ||
1611 | { "bq24153", BQ24153 }, | ||
1612 | { "bq24153a", BQ24153A }, | ||
1613 | { "bq24155", BQ24155 }, | ||
1614 | { "bq24156", BQ24156 }, | ||
1615 | { "bq24156a", BQ24156A }, | ||
1616 | { "bq24158", BQ24158 }, | ||
1617 | {}, | ||
1618 | }; | ||
1619 | MODULE_DEVICE_TABLE(i2c, bq2415x_i2c_id_table); | ||
1620 | |||
1621 | static struct i2c_driver bq2415x_driver = { | ||
1622 | .driver = { | ||
1623 | .name = "bq2415x-charger", | ||
1624 | }, | ||
1625 | .probe = bq2415x_probe, | ||
1626 | .remove = bq2415x_remove, | ||
1627 | .id_table = bq2415x_i2c_id_table, | ||
1628 | }; | ||
1629 | |||
1630 | static int __init bq2415x_init(void) | ||
1631 | { | ||
1632 | return i2c_add_driver(&bq2415x_driver); | ||
1633 | } | ||
1634 | module_init(bq2415x_init); | ||
1635 | |||
1636 | static void __exit bq2415x_exit(void) | ||
1637 | { | ||
1638 | i2c_del_driver(&bq2415x_driver); | ||
1639 | } | ||
1640 | module_exit(bq2415x_exit); | ||
1641 | |||
1642 | MODULE_AUTHOR("Pali Rohár <pali.rohar@gmail.com>"); | ||
1643 | MODULE_DESCRIPTION("bq2415x charger driver"); | ||
1644 | MODULE_LICENSE("GPL"); | ||
diff --git a/include/linux/power/bq2415x_charger.h b/include/linux/power/bq2415x_charger.h new file mode 100644 index 000000000000..fb6bf4d8aea8 --- /dev/null +++ b/include/linux/power/bq2415x_charger.h | |||
@@ -0,0 +1,90 @@ | |||
1 | /* | ||
2 | bq2415x_charger.h - bq2415x charger driver | ||
3 | Copyright (C) 2011-2012 Pali Rohár <pali.rohar@gmail.com> | ||
4 | |||
5 | This program is free software; you can redistribute it and/or modify | ||
6 | it under the terms of the GNU General Public License as published by | ||
7 | the Free Software Foundation; either version 2 of the License, or | ||
8 | (at your option) any later version. | ||
9 | |||
10 | This program is distributed in the hope that it will be useful, | ||
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | GNU General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU General Public License along | ||
16 | with this program; if not, write to the Free Software Foundation, Inc., | ||
17 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
18 | */ | ||
19 | |||
20 | #ifndef BQ2415X_CHARGER_H | ||
21 | #define BQ2415X_CHARGER_H | ||
22 | |||
23 | /* | ||
24 | This is platform data for bq2415x chip. It contains default board voltages | ||
25 | and currents which can be also later configured via sysfs. If value is -1 | ||
26 | then default chip value (specified in datasheet) will be used. | ||
27 | |||
28 | Value resistor_sense is needed for for configuring charge and termination | ||
29 | current. It it is less or equal to zero, configuring charge and termination | ||
30 | current will not be possible. | ||
31 | |||
32 | Function set_mode_hook is needed for automode (setting correct current limit | ||
33 | when charger is connected/disconnected or setting boost mode). When is NULL, | ||
34 | automode function is disabled. When is not NULL, it must have this prototype: | ||
35 | |||
36 | int (*set_mode_hook)( | ||
37 | void (*hook)(enum bq2415x_mode mode, void *data), | ||
38 | void *data) | ||
39 | |||
40 | hook is hook function (see below) and data is pointer to driver private data | ||
41 | |||
42 | bq2415x driver will call it as: | ||
43 | |||
44 | platform_data->set_mode_hook(bq2415x_hook_function, bq2415x_device); | ||
45 | |||
46 | Board/platform function set_mode_hook return non zero value when hook | ||
47 | function was successful registered. Platform code should call that hook | ||
48 | function (which get from pointer, with data) every time when charger was | ||
49 | connected/disconnected or require to enable boost mode. bq2415x driver then | ||
50 | will set correct current limit, enable/disable charger or boost mode. | ||
51 | |||
52 | Hook function has this prototype: | ||
53 | |||
54 | void hook(enum bq2415x_mode mode, void *data); | ||
55 | |||
56 | mode is bq2415x mode (charger or boost) | ||
57 | data is pointer to driver private data (which get from set_charger_type_hook) | ||
58 | |||
59 | When bq driver is being unloaded, it call function: | ||
60 | |||
61 | platform_data->set_mode_hook(NULL, NULL); | ||
62 | |||
63 | (hook function and driver private data are NULL) | ||
64 | |||
65 | After that board/platform code must not call driver hook function! It is | ||
66 | possible that pointer to hook function will not be valid and calling will | ||
67 | cause undefined result. | ||
68 | |||
69 | */ | ||
70 | |||
71 | /* Supported modes with maximal current limit */ | ||
72 | enum bq2415x_mode { | ||
73 | BQ2415X_MODE_NONE, /* unknown or no charger (100mA) */ | ||
74 | BQ2415X_MODE_HOST_CHARGER, /* usb host/hub charger (500mA) */ | ||
75 | BQ2415X_MODE_DEDICATED_CHARGER, /* dedicated charger (unlimited) */ | ||
76 | BQ2415X_MODE_BOOST, /* boost mode (charging disabled) */ | ||
77 | }; | ||
78 | |||
79 | struct bq2415x_platform_data { | ||
80 | int current_limit; /* mA */ | ||
81 | int weak_battery_voltage; /* mV */ | ||
82 | int battery_regulation_voltage; /* mV */ | ||
83 | int charge_current; /* mA */ | ||
84 | int termination_current; /* mA */ | ||
85 | int resistor_sense; /* m ohm */ | ||
86 | int (*set_mode_hook)(void (*hook)(enum bq2415x_mode mode, void *data), | ||
87 | void *data); | ||
88 | }; | ||
89 | |||
90 | #endif | ||