Commit | Line | Data |
---|---|---|
359ab9f5 MH |
1 | /* |
2 | * Fuel gauge driver for Maxim 17042 / 8966 / 8997 | |
3 | * Note that Maxim 8966 and 8997 are mfd and this is its subdevice. | |
4 | * | |
5 | * Copyright (C) 2011 Samsung Electronics | |
6 | * MyungJoo Ham <myungjoo.ham@samsung.com> | |
7 | * | |
8 | * This program is free software; you can redistribute it and/or modify | |
9 | * it under the terms of the GNU General Public License as published by | |
10 | * the Free Software Foundation; either version 2 of the License, or | |
11 | * (at your option) any later version. | |
12 | * | |
13 | * This program is distributed in the hope that it will be useful, | |
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
16 | * GNU General Public License for more details. | |
17 | * | |
18 | * You should have received a copy of the GNU General Public License | |
19 | * along with this program; if not, write to the Free Software | |
20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
21 | * | |
22 | * This driver is based on max17040_battery.c | |
23 | */ | |
24 | ||
25 | #include <linux/init.h> | |
7e6d62db | 26 | #include <linux/module.h> |
359ab9f5 MH |
27 | #include <linux/slab.h> |
28 | #include <linux/i2c.h> | |
f3a71a6e | 29 | #include <linux/delay.h> |
e5f3872d | 30 | #include <linux/interrupt.h> |
48bc1774 | 31 | #include <linux/pm.h> |
359ab9f5 MH |
32 | #include <linux/mod_devicetable.h> |
33 | #include <linux/power_supply.h> | |
34 | #include <linux/power/max17042_battery.h> | |
3832246d | 35 | #include <linux/of.h> |
39e7213e | 36 | #include <linux/regmap.h> |
359ab9f5 | 37 | |
f3a71a6e RP |
38 | /* Status register bits */ |
39 | #define STATUS_POR_BIT (1 << 1) | |
40 | #define STATUS_BST_BIT (1 << 3) | |
41 | #define STATUS_VMN_BIT (1 << 8) | |
42 | #define STATUS_TMN_BIT (1 << 9) | |
43 | #define STATUS_SMN_BIT (1 << 10) | |
44 | #define STATUS_BI_BIT (1 << 11) | |
45 | #define STATUS_VMX_BIT (1 << 12) | |
46 | #define STATUS_TMX_BIT (1 << 13) | |
47 | #define STATUS_SMX_BIT (1 << 14) | |
48 | #define STATUS_BR_BIT (1 << 15) | |
49 | ||
e5f3872d RP |
50 | /* Interrupt mask bits */ |
51 | #define CONFIG_ALRT_BIT_ENBL (1 << 2) | |
5cdd4d7f RP |
52 | #define STATUS_INTR_SOCMIN_BIT (1 << 10) |
53 | #define STATUS_INTR_SOCMAX_BIT (1 << 14) | |
e5f3872d | 54 | |
f3a71a6e RP |
55 | #define VFSOC0_LOCK 0x0000 |
56 | #define VFSOC0_UNLOCK 0x0080 | |
57 | #define MODEL_UNLOCK1 0X0059 | |
58 | #define MODEL_UNLOCK2 0X00C4 | |
59 | #define MODEL_LOCK1 0X0000 | |
60 | #define MODEL_LOCK2 0X0000 | |
61 | ||
62 | #define dQ_ACC_DIV 0x4 | |
63 | #define dP_ACC_100 0x1900 | |
64 | #define dP_ACC_200 0x3200 | |
65 | ||
edd4ab05 RP |
66 | #define MAX17042_VMAX_TOLERANCE 50 /* 50 mV */ |
67 | ||
359ab9f5 MH |
68 | struct max17042_chip { |
69 | struct i2c_client *client; | |
39e7213e | 70 | struct regmap *regmap; |
297d716f | 71 | struct power_supply *battery; |
9a8422d2 | 72 | enum max170xx_chip_type chip_type; |
359ab9f5 | 73 | struct max17042_platform_data *pdata; |
f3a71a6e RP |
74 | struct work_struct work; |
75 | int init_complete; | |
359ab9f5 MH |
76 | }; |
77 | ||
359ab9f5 | 78 | static enum power_supply_property max17042_battery_props[] = { |
086ef502 DK |
79 | POWER_SUPPLY_PROP_PRESENT, |
80 | POWER_SUPPLY_PROP_CYCLE_COUNT, | |
81 | POWER_SUPPLY_PROP_VOLTAGE_MAX, | |
82 | POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN, | |
359ab9f5 MH |
83 | POWER_SUPPLY_PROP_VOLTAGE_NOW, |
84 | POWER_SUPPLY_PROP_VOLTAGE_AVG, | |
a2ebfe2f | 85 | POWER_SUPPLY_PROP_VOLTAGE_OCV, |
359ab9f5 | 86 | POWER_SUPPLY_PROP_CAPACITY, |
086ef502 | 87 | POWER_SUPPLY_PROP_CHARGE_FULL, |
5fc55bc8 | 88 | POWER_SUPPLY_PROP_CHARGE_COUNTER, |
086ef502 | 89 | POWER_SUPPLY_PROP_TEMP, |
edd4ab05 RP |
90 | POWER_SUPPLY_PROP_TEMP_ALERT_MIN, |
91 | POWER_SUPPLY_PROP_TEMP_ALERT_MAX, | |
92 | POWER_SUPPLY_PROP_TEMP_MIN, | |
93 | POWER_SUPPLY_PROP_TEMP_MAX, | |
94 | POWER_SUPPLY_PROP_HEALTH, | |
086ef502 DK |
95 | POWER_SUPPLY_PROP_CURRENT_NOW, |
96 | POWER_SUPPLY_PROP_CURRENT_AVG, | |
359ab9f5 MH |
97 | }; |
98 | ||
edd4ab05 RP |
99 | static int max17042_get_temperature(struct max17042_chip *chip, int *temp) |
100 | { | |
101 | int ret; | |
102 | u32 data; | |
103 | struct regmap *map = chip->regmap; | |
104 | ||
105 | ret = regmap_read(map, MAX17042_TEMP, &data); | |
106 | if (ret < 0) | |
107 | return ret; | |
108 | ||
109 | *temp = data; | |
110 | /* The value is signed. */ | |
111 | if (*temp & 0x8000) { | |
112 | *temp = (0x7fff & ~*temp) + 1; | |
113 | *temp *= -1; | |
114 | } | |
115 | ||
116 | /* The value is converted into deci-centigrade scale */ | |
117 | /* Units of LSB = 1 / 256 degree Celsius */ | |
118 | *temp = *temp * 10 / 256; | |
119 | return 0; | |
120 | } | |
121 | ||
122 | static int max17042_get_battery_health(struct max17042_chip *chip, int *health) | |
123 | { | |
124 | int temp, vavg, vbatt, ret; | |
125 | u32 val; | |
126 | ||
127 | ret = regmap_read(chip->regmap, MAX17042_AvgVCELL, &val); | |
128 | if (ret < 0) | |
129 | goto health_error; | |
130 | ||
131 | /* bits [0-3] unused */ | |
132 | vavg = val * 625 / 8; | |
133 | /* Convert to millivolts */ | |
134 | vavg /= 1000; | |
135 | ||
136 | ret = regmap_read(chip->regmap, MAX17042_VCELL, &val); | |
137 | if (ret < 0) | |
138 | goto health_error; | |
139 | ||
140 | /* bits [0-3] unused */ | |
141 | vbatt = val * 625 / 8; | |
142 | /* Convert to millivolts */ | |
143 | vbatt /= 1000; | |
144 | ||
145 | if (vavg < chip->pdata->vmin) { | |
146 | *health = POWER_SUPPLY_HEALTH_DEAD; | |
147 | goto out; | |
148 | } | |
149 | ||
150 | if (vbatt > chip->pdata->vmax + MAX17042_VMAX_TOLERANCE) { | |
151 | *health = POWER_SUPPLY_HEALTH_OVERVOLTAGE; | |
152 | goto out; | |
153 | } | |
154 | ||
155 | ret = max17042_get_temperature(chip, &temp); | |
156 | if (ret < 0) | |
157 | goto health_error; | |
158 | ||
159 | if (temp <= chip->pdata->temp_min) { | |
160 | *health = POWER_SUPPLY_HEALTH_COLD; | |
161 | goto out; | |
162 | } | |
163 | ||
164 | if (temp >= chip->pdata->temp_max) { | |
165 | *health = POWER_SUPPLY_HEALTH_OVERHEAT; | |
166 | goto out; | |
167 | } | |
168 | ||
169 | *health = POWER_SUPPLY_HEALTH_GOOD; | |
170 | ||
171 | out: | |
172 | return 0; | |
173 | ||
174 | health_error: | |
175 | return ret; | |
176 | } | |
177 | ||
359ab9f5 MH |
178 | static int max17042_get_property(struct power_supply *psy, |
179 | enum power_supply_property psp, | |
180 | union power_supply_propval *val) | |
181 | { | |
297d716f | 182 | struct max17042_chip *chip = power_supply_get_drvdata(psy); |
39e7213e | 183 | struct regmap *map = chip->regmap; |
60a1f6e4 | 184 | int ret; |
39e7213e | 185 | u32 data; |
359ab9f5 | 186 | |
f3a71a6e RP |
187 | if (!chip->init_complete) |
188 | return -EAGAIN; | |
189 | ||
359ab9f5 | 190 | switch (psp) { |
086ef502 | 191 | case POWER_SUPPLY_PROP_PRESENT: |
39e7213e | 192 | ret = regmap_read(map, MAX17042_STATUS, &data); |
60a1f6e4 RP |
193 | if (ret < 0) |
194 | return ret; | |
195 | ||
39e7213e | 196 | if (data & MAX17042_STATUS_BattAbsent) |
086ef502 DK |
197 | val->intval = 0; |
198 | else | |
199 | val->intval = 1; | |
200 | break; | |
201 | case POWER_SUPPLY_PROP_CYCLE_COUNT: | |
39e7213e | 202 | ret = regmap_read(map, MAX17042_Cycles, &data); |
60a1f6e4 RP |
203 | if (ret < 0) |
204 | return ret; | |
205 | ||
39e7213e | 206 | val->intval = data; |
086ef502 DK |
207 | break; |
208 | case POWER_SUPPLY_PROP_VOLTAGE_MAX: | |
39e7213e | 209 | ret = regmap_read(map, MAX17042_MinMaxVolt, &data); |
60a1f6e4 RP |
210 | if (ret < 0) |
211 | return ret; | |
212 | ||
39e7213e | 213 | val->intval = data >> 8; |
086ef502 DK |
214 | val->intval *= 20000; /* Units of LSB = 20mV */ |
215 | break; | |
216 | case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN: | |
709c2c70 | 217 | if (chip->chip_type == MAXIM_DEVICE_TYPE_MAX17042) |
39e7213e | 218 | ret = regmap_read(map, MAX17042_V_empty, &data); |
9a8422d2 | 219 | else |
39e7213e | 220 | ret = regmap_read(map, MAX17047_V_empty, &data); |
60a1f6e4 RP |
221 | if (ret < 0) |
222 | return ret; | |
223 | ||
39e7213e | 224 | val->intval = data >> 7; |
086ef502 DK |
225 | val->intval *= 10000; /* Units of LSB = 10mV */ |
226 | break; | |
359ab9f5 | 227 | case POWER_SUPPLY_PROP_VOLTAGE_NOW: |
39e7213e | 228 | ret = regmap_read(map, MAX17042_VCELL, &data); |
60a1f6e4 RP |
229 | if (ret < 0) |
230 | return ret; | |
231 | ||
39e7213e | 232 | val->intval = data * 625 / 8; |
359ab9f5 MH |
233 | break; |
234 | case POWER_SUPPLY_PROP_VOLTAGE_AVG: | |
39e7213e | 235 | ret = regmap_read(map, MAX17042_AvgVCELL, &data); |
60a1f6e4 RP |
236 | if (ret < 0) |
237 | return ret; | |
238 | ||
39e7213e | 239 | val->intval = data * 625 / 8; |
a2ebfe2f RP |
240 | break; |
241 | case POWER_SUPPLY_PROP_VOLTAGE_OCV: | |
39e7213e | 242 | ret = regmap_read(map, MAX17042_OCVInternal, &data); |
a2ebfe2f RP |
243 | if (ret < 0) |
244 | return ret; | |
245 | ||
39e7213e | 246 | val->intval = data * 625 / 8; |
359ab9f5 MH |
247 | break; |
248 | case POWER_SUPPLY_PROP_CAPACITY: | |
39e7213e | 249 | ret = regmap_read(map, MAX17042_RepSOC, &data); |
60a1f6e4 RP |
250 | if (ret < 0) |
251 | return ret; | |
252 | ||
39e7213e | 253 | val->intval = data >> 8; |
359ab9f5 | 254 | break; |
086ef502 | 255 | case POWER_SUPPLY_PROP_CHARGE_FULL: |
39e7213e | 256 | ret = regmap_read(map, MAX17042_FullCAP, &data); |
60a1f6e4 RP |
257 | if (ret < 0) |
258 | return ret; | |
259 | ||
39e7213e | 260 | val->intval = data * 1000 / 2; |
5fc55bc8 RP |
261 | break; |
262 | case POWER_SUPPLY_PROP_CHARGE_COUNTER: | |
39e7213e | 263 | ret = regmap_read(map, MAX17042_QH, &data); |
5fc55bc8 RP |
264 | if (ret < 0) |
265 | return ret; | |
266 | ||
39e7213e | 267 | val->intval = data * 1000 / 2; |
086ef502 DK |
268 | break; |
269 | case POWER_SUPPLY_PROP_TEMP: | |
edd4ab05 RP |
270 | ret = max17042_get_temperature(chip, &val->intval); |
271 | if (ret < 0) | |
272 | return ret; | |
273 | break; | |
274 | case POWER_SUPPLY_PROP_TEMP_ALERT_MIN: | |
275 | ret = regmap_read(map, MAX17042_TALRT_Th, &data); | |
276 | if (ret < 0) | |
277 | return ret; | |
278 | /* LSB is Alert Minimum. In deci-centigrade */ | |
279 | val->intval = (data & 0xff) * 10; | |
280 | break; | |
281 | case POWER_SUPPLY_PROP_TEMP_ALERT_MAX: | |
282 | ret = regmap_read(map, MAX17042_TALRT_Th, &data); | |
283 | if (ret < 0) | |
284 | return ret; | |
285 | /* MSB is Alert Maximum. In deci-centigrade */ | |
286 | val->intval = (data >> 8) * 10; | |
287 | break; | |
288 | case POWER_SUPPLY_PROP_TEMP_MIN: | |
289 | val->intval = chip->pdata->temp_min; | |
290 | break; | |
291 | case POWER_SUPPLY_PROP_TEMP_MAX: | |
292 | val->intval = chip->pdata->temp_max; | |
293 | break; | |
294 | case POWER_SUPPLY_PROP_HEALTH: | |
295 | ret = max17042_get_battery_health(chip, &val->intval); | |
60a1f6e4 RP |
296 | if (ret < 0) |
297 | return ret; | |
086ef502 DK |
298 | break; |
299 | case POWER_SUPPLY_PROP_CURRENT_NOW: | |
300 | if (chip->pdata->enable_current_sense) { | |
39e7213e | 301 | ret = regmap_read(map, MAX17042_Current, &data); |
60a1f6e4 RP |
302 | if (ret < 0) |
303 | return ret; | |
304 | ||
39e7213e | 305 | val->intval = data; |
086ef502 DK |
306 | if (val->intval & 0x8000) { |
307 | /* Negative */ | |
308 | val->intval = ~val->intval & 0x7fff; | |
309 | val->intval++; | |
310 | val->intval *= -1; | |
311 | } | |
91d8b0d6 | 312 | val->intval *= 1562500 / chip->pdata->r_sns; |
086ef502 DK |
313 | } else { |
314 | return -EINVAL; | |
315 | } | |
316 | break; | |
317 | case POWER_SUPPLY_PROP_CURRENT_AVG: | |
318 | if (chip->pdata->enable_current_sense) { | |
39e7213e | 319 | ret = regmap_read(map, MAX17042_AvgCurrent, &data); |
60a1f6e4 RP |
320 | if (ret < 0) |
321 | return ret; | |
322 | ||
39e7213e | 323 | val->intval = data; |
086ef502 DK |
324 | if (val->intval & 0x8000) { |
325 | /* Negative */ | |
326 | val->intval = ~val->intval & 0x7fff; | |
327 | val->intval++; | |
328 | val->intval *= -1; | |
329 | } | |
330 | val->intval *= 1562500 / chip->pdata->r_sns; | |
331 | } else { | |
332 | return -EINVAL; | |
333 | } | |
334 | break; | |
359ab9f5 MH |
335 | default: |
336 | return -EINVAL; | |
337 | } | |
338 | return 0; | |
339 | } | |
340 | ||
edd4ab05 RP |
341 | static int max17042_set_property(struct power_supply *psy, |
342 | enum power_supply_property psp, | |
343 | const union power_supply_propval *val) | |
344 | { | |
345 | struct max17042_chip *chip = power_supply_get_drvdata(psy); | |
346 | struct regmap *map = chip->regmap; | |
347 | int ret = 0; | |
348 | u32 data; | |
349 | int8_t temp; | |
350 | ||
351 | switch (psp) { | |
352 | case POWER_SUPPLY_PROP_TEMP_ALERT_MIN: | |
353 | ret = regmap_read(map, MAX17042_TALRT_Th, &data); | |
354 | if (ret < 0) | |
355 | return ret; | |
356 | ||
357 | /* Input in deci-centigrade, convert to centigrade */ | |
358 | temp = val->intval / 10; | |
359 | /* force min < max */ | |
360 | if (temp >= (int8_t)(data >> 8)) | |
361 | temp = (int8_t)(data >> 8) - 1; | |
362 | /* Write both MAX and MIN ALERT */ | |
363 | data = (data & 0xff00) + temp; | |
364 | ret = regmap_write(map, MAX17042_TALRT_Th, data); | |
365 | break; | |
366 | case POWER_SUPPLY_PROP_TEMP_ALERT_MAX: | |
367 | ret = regmap_read(map, MAX17042_TALRT_Th, &data); | |
368 | if (ret < 0) | |
369 | return ret; | |
370 | ||
371 | /* Input in Deci-Centigrade, convert to centigrade */ | |
372 | temp = val->intval / 10; | |
373 | /* force max > min */ | |
374 | if (temp <= (int8_t)(data & 0xff)) | |
375 | temp = (int8_t)(data & 0xff) + 1; | |
376 | /* Write both MAX and MIN ALERT */ | |
377 | data = (data & 0xff) + (temp << 8); | |
378 | ret = regmap_write(map, MAX17042_TALRT_Th, data); | |
379 | break; | |
380 | default: | |
381 | ret = -EINVAL; | |
382 | } | |
383 | ||
384 | return ret; | |
385 | } | |
386 | ||
387 | static int max17042_property_is_writeable(struct power_supply *psy, | |
388 | enum power_supply_property psp) | |
389 | { | |
390 | int ret; | |
391 | ||
392 | switch (psp) { | |
393 | case POWER_SUPPLY_PROP_TEMP_ALERT_MIN: | |
394 | case POWER_SUPPLY_PROP_TEMP_ALERT_MAX: | |
395 | ret = 1; | |
396 | break; | |
397 | default: | |
398 | ret = 0; | |
399 | } | |
400 | ||
401 | return ret; | |
402 | } | |
403 | ||
39e7213e | 404 | static int max17042_write_verify_reg(struct regmap *map, u8 reg, u32 value) |
f3a71a6e RP |
405 | { |
406 | int retries = 8; | |
407 | int ret; | |
39e7213e | 408 | u32 read_value; |
f3a71a6e RP |
409 | |
410 | do { | |
39e7213e JL |
411 | ret = regmap_write(map, reg, value); |
412 | regmap_read(map, reg, &read_value); | |
f3a71a6e RP |
413 | if (read_value != value) { |
414 | ret = -EIO; | |
415 | retries--; | |
416 | } | |
417 | } while (retries && read_value != value); | |
418 | ||
419 | if (ret < 0) | |
39e7213e | 420 | pr_err("%s: err %d\n", __func__, ret); |
f3a71a6e RP |
421 | |
422 | return ret; | |
423 | } | |
424 | ||
39e7213e JL |
425 | static inline void max17042_override_por(struct regmap *map, |
426 | u8 reg, u16 value) | |
f3a71a6e RP |
427 | { |
428 | if (value) | |
39e7213e | 429 | regmap_write(map, reg, value); |
f3a71a6e RP |
430 | } |
431 | ||
432 | static inline void max10742_unlock_model(struct max17042_chip *chip) | |
433 | { | |
39e7213e | 434 | struct regmap *map = chip->regmap; |
bbaeeaaf | 435 | |
39e7213e JL |
436 | regmap_write(map, MAX17042_MLOCKReg1, MODEL_UNLOCK1); |
437 | regmap_write(map, MAX17042_MLOCKReg2, MODEL_UNLOCK2); | |
f3a71a6e RP |
438 | } |
439 | ||
440 | static inline void max10742_lock_model(struct max17042_chip *chip) | |
441 | { | |
39e7213e JL |
442 | struct regmap *map = chip->regmap; |
443 | ||
444 | regmap_write(map, MAX17042_MLOCKReg1, MODEL_LOCK1); | |
445 | regmap_write(map, MAX17042_MLOCKReg2, MODEL_LOCK2); | |
f3a71a6e RP |
446 | } |
447 | ||
448 | static inline void max17042_write_model_data(struct max17042_chip *chip, | |
449 | u8 addr, int size) | |
450 | { | |
39e7213e | 451 | struct regmap *map = chip->regmap; |
f3a71a6e | 452 | int i; |
bbaeeaaf | 453 | |
f3a71a6e | 454 | for (i = 0; i < size; i++) |
39e7213e JL |
455 | regmap_write(map, addr + i, |
456 | chip->pdata->config_data->cell_char_tbl[i]); | |
f3a71a6e RP |
457 | } |
458 | ||
459 | static inline void max17042_read_model_data(struct max17042_chip *chip, | |
5381cfb6 | 460 | u8 addr, u16 *data, int size) |
f3a71a6e | 461 | { |
39e7213e | 462 | struct regmap *map = chip->regmap; |
f3a71a6e | 463 | int i; |
5381cfb6 | 464 | u32 tmp; |
f3a71a6e | 465 | |
5381cfb6 SVA |
466 | for (i = 0; i < size; i++) { |
467 | regmap_read(map, addr + i, &tmp); | |
468 | data[i] = (u16)tmp; | |
469 | } | |
f3a71a6e RP |
470 | } |
471 | ||
472 | static inline int max17042_model_data_compare(struct max17042_chip *chip, | |
473 | u16 *data1, u16 *data2, int size) | |
474 | { | |
475 | int i; | |
476 | ||
477 | if (memcmp(data1, data2, size)) { | |
478 | dev_err(&chip->client->dev, "%s compare failed\n", __func__); | |
479 | for (i = 0; i < size; i++) | |
480 | dev_info(&chip->client->dev, "0x%x, 0x%x", | |
481 | data1[i], data2[i]); | |
482 | dev_info(&chip->client->dev, "\n"); | |
483 | return -EINVAL; | |
484 | } | |
485 | return 0; | |
486 | } | |
487 | ||
488 | static int max17042_init_model(struct max17042_chip *chip) | |
489 | { | |
490 | int ret; | |
1ef3d8fb | 491 | int table_size = ARRAY_SIZE(chip->pdata->config_data->cell_char_tbl); |
5381cfb6 | 492 | u16 *temp_data; |
f3a71a6e | 493 | |
1ef3d8fb | 494 | temp_data = kcalloc(table_size, sizeof(*temp_data), GFP_KERNEL); |
f3a71a6e RP |
495 | if (!temp_data) |
496 | return -ENOMEM; | |
497 | ||
498 | max10742_unlock_model(chip); | |
499 | max17042_write_model_data(chip, MAX17042_MODELChrTbl, | |
500 | table_size); | |
501 | max17042_read_model_data(chip, MAX17042_MODELChrTbl, temp_data, | |
502 | table_size); | |
503 | ||
504 | ret = max17042_model_data_compare( | |
505 | chip, | |
506 | chip->pdata->config_data->cell_char_tbl, | |
5381cfb6 | 507 | temp_data, |
f3a71a6e RP |
508 | table_size); |
509 | ||
510 | max10742_lock_model(chip); | |
511 | kfree(temp_data); | |
512 | ||
513 | return ret; | |
514 | } | |
515 | ||
516 | static int max17042_verify_model_lock(struct max17042_chip *chip) | |
517 | { | |
518 | int i; | |
1ef3d8fb | 519 | int table_size = ARRAY_SIZE(chip->pdata->config_data->cell_char_tbl); |
5381cfb6 | 520 | u16 *temp_data; |
f3a71a6e RP |
521 | int ret = 0; |
522 | ||
1ef3d8fb | 523 | temp_data = kcalloc(table_size, sizeof(*temp_data), GFP_KERNEL); |
f3a71a6e RP |
524 | if (!temp_data) |
525 | return -ENOMEM; | |
526 | ||
527 | max17042_read_model_data(chip, MAX17042_MODELChrTbl, temp_data, | |
528 | table_size); | |
529 | for (i = 0; i < table_size; i++) | |
530 | if (temp_data[i]) | |
531 | ret = -EINVAL; | |
532 | ||
533 | kfree(temp_data); | |
534 | return ret; | |
535 | } | |
536 | ||
537 | static void max17042_write_config_regs(struct max17042_chip *chip) | |
538 | { | |
539 | struct max17042_config_data *config = chip->pdata->config_data; | |
39e7213e | 540 | struct regmap *map = chip->regmap; |
f3a71a6e | 541 | |
39e7213e JL |
542 | regmap_write(map, MAX17042_CONFIG, config->config); |
543 | regmap_write(map, MAX17042_LearnCFG, config->learn_cfg); | |
544 | regmap_write(map, MAX17042_FilterCFG, | |
f3a71a6e | 545 | config->filter_cfg); |
39e7213e | 546 | regmap_write(map, MAX17042_RelaxCFG, config->relax_cfg); |
709c2c70 BS |
547 | if (chip->chip_type == MAXIM_DEVICE_TYPE_MAX17047 || |
548 | chip->chip_type == MAXIM_DEVICE_TYPE_MAX17050) | |
39e7213e | 549 | regmap_write(map, MAX17047_FullSOCThr, |
9a8422d2 | 550 | config->full_soc_thresh); |
f3a71a6e RP |
551 | } |
552 | ||
553 | static void max17042_write_custom_regs(struct max17042_chip *chip) | |
554 | { | |
555 | struct max17042_config_data *config = chip->pdata->config_data; | |
39e7213e | 556 | struct regmap *map = chip->regmap; |
f3a71a6e | 557 | |
39e7213e JL |
558 | max17042_write_verify_reg(map, MAX17042_RCOMP0, config->rcomp0); |
559 | max17042_write_verify_reg(map, MAX17042_TempCo, config->tcompc0); | |
560 | max17042_write_verify_reg(map, MAX17042_ICHGTerm, config->ichgt_term); | |
709c2c70 | 561 | if (chip->chip_type == MAXIM_DEVICE_TYPE_MAX17042) { |
39e7213e JL |
562 | regmap_write(map, MAX17042_EmptyTempCo, config->empty_tempco); |
563 | max17042_write_verify_reg(map, MAX17042_K_empty0, | |
9a8422d2 RP |
564 | config->kempty0); |
565 | } else { | |
39e7213e | 566 | max17042_write_verify_reg(map, MAX17047_QRTbl00, |
9a8422d2 | 567 | config->qrtbl00); |
39e7213e | 568 | max17042_write_verify_reg(map, MAX17047_QRTbl10, |
9a8422d2 | 569 | config->qrtbl10); |
39e7213e | 570 | max17042_write_verify_reg(map, MAX17047_QRTbl20, |
9a8422d2 | 571 | config->qrtbl20); |
39e7213e | 572 | max17042_write_verify_reg(map, MAX17047_QRTbl30, |
9a8422d2 RP |
573 | config->qrtbl30); |
574 | } | |
f3a71a6e RP |
575 | } |
576 | ||
577 | static void max17042_update_capacity_regs(struct max17042_chip *chip) | |
578 | { | |
579 | struct max17042_config_data *config = chip->pdata->config_data; | |
39e7213e | 580 | struct regmap *map = chip->regmap; |
f3a71a6e | 581 | |
39e7213e | 582 | max17042_write_verify_reg(map, MAX17042_FullCAP, |
f3a71a6e | 583 | config->fullcap); |
39e7213e JL |
584 | regmap_write(map, MAX17042_DesignCap, config->design_cap); |
585 | max17042_write_verify_reg(map, MAX17042_FullCAPNom, | |
f3a71a6e RP |
586 | config->fullcapnom); |
587 | } | |
588 | ||
589 | static void max17042_reset_vfsoc0_reg(struct max17042_chip *chip) | |
590 | { | |
39e7213e JL |
591 | unsigned int vfSoc; |
592 | struct regmap *map = chip->regmap; | |
f3a71a6e | 593 | |
39e7213e JL |
594 | regmap_read(map, MAX17042_VFSOC, &vfSoc); |
595 | regmap_write(map, MAX17042_VFSOC0Enable, VFSOC0_UNLOCK); | |
596 | max17042_write_verify_reg(map, MAX17042_VFSOC0, vfSoc); | |
597 | regmap_write(map, MAX17042_VFSOC0Enable, VFSOC0_LOCK); | |
f3a71a6e RP |
598 | } |
599 | ||
600 | static void max17042_load_new_capacity_params(struct max17042_chip *chip) | |
601 | { | |
39e7213e | 602 | u32 full_cap0, rep_cap, dq_acc, vfSoc; |
f3a71a6e RP |
603 | u32 rem_cap; |
604 | ||
605 | struct max17042_config_data *config = chip->pdata->config_data; | |
39e7213e | 606 | struct regmap *map = chip->regmap; |
f3a71a6e | 607 | |
39e7213e JL |
608 | regmap_read(map, MAX17042_FullCAP0, &full_cap0); |
609 | regmap_read(map, MAX17042_VFSOC, &vfSoc); | |
f3a71a6e RP |
610 | |
611 | /* fg_vfSoc needs to shifted by 8 bits to get the | |
612 | * perc in 1% accuracy, to get the right rem_cap multiply | |
613 | * full_cap0, fg_vfSoc and devide by 100 | |
614 | */ | |
615 | rem_cap = ((vfSoc >> 8) * full_cap0) / 100; | |
39e7213e | 616 | max17042_write_verify_reg(map, MAX17042_RemCap, rem_cap); |
f3a71a6e | 617 | |
39e7213e JL |
618 | rep_cap = rem_cap; |
619 | max17042_write_verify_reg(map, MAX17042_RepCap, rep_cap); | |
f3a71a6e RP |
620 | |
621 | /* Write dQ_acc to 200% of Capacity and dP_acc to 200% */ | |
622 | dq_acc = config->fullcap / dQ_ACC_DIV; | |
39e7213e JL |
623 | max17042_write_verify_reg(map, MAX17042_dQacc, dq_acc); |
624 | max17042_write_verify_reg(map, MAX17042_dPacc, dP_ACC_200); | |
f3a71a6e | 625 | |
39e7213e | 626 | max17042_write_verify_reg(map, MAX17042_FullCAP, |
f3a71a6e | 627 | config->fullcap); |
39e7213e | 628 | regmap_write(map, MAX17042_DesignCap, |
f3a71a6e | 629 | config->design_cap); |
39e7213e | 630 | max17042_write_verify_reg(map, MAX17042_FullCAPNom, |
f3a71a6e | 631 | config->fullcapnom); |
9a8422d2 | 632 | /* Update SOC register with new SOC */ |
39e7213e | 633 | regmap_write(map, MAX17042_RepSOC, vfSoc); |
f3a71a6e RP |
634 | } |
635 | ||
636 | /* | |
637 | * Block write all the override values coming from platform data. | |
638 | * This function MUST be called before the POR initialization proceedure | |
639 | * specified by maxim. | |
640 | */ | |
641 | static inline void max17042_override_por_values(struct max17042_chip *chip) | |
642 | { | |
39e7213e | 643 | struct regmap *map = chip->regmap; |
f3a71a6e RP |
644 | struct max17042_config_data *config = chip->pdata->config_data; |
645 | ||
39e7213e JL |
646 | max17042_override_por(map, MAX17042_TGAIN, config->tgain); |
647 | max17042_override_por(map, MAx17042_TOFF, config->toff); | |
648 | max17042_override_por(map, MAX17042_CGAIN, config->cgain); | |
649 | max17042_override_por(map, MAX17042_COFF, config->coff); | |
650 | ||
651 | max17042_override_por(map, MAX17042_VALRT_Th, config->valrt_thresh); | |
652 | max17042_override_por(map, MAX17042_TALRT_Th, config->talrt_thresh); | |
653 | max17042_override_por(map, MAX17042_SALRT_Th, | |
654 | config->soc_alrt_thresh); | |
655 | max17042_override_por(map, MAX17042_CONFIG, config->config); | |
656 | max17042_override_por(map, MAX17042_SHDNTIMER, config->shdntimer); | |
657 | ||
658 | max17042_override_por(map, MAX17042_DesignCap, config->design_cap); | |
659 | max17042_override_por(map, MAX17042_ICHGTerm, config->ichgt_term); | |
660 | ||
661 | max17042_override_por(map, MAX17042_AtRate, config->at_rate); | |
662 | max17042_override_por(map, MAX17042_LearnCFG, config->learn_cfg); | |
663 | max17042_override_por(map, MAX17042_FilterCFG, config->filter_cfg); | |
664 | max17042_override_por(map, MAX17042_RelaxCFG, config->relax_cfg); | |
665 | max17042_override_por(map, MAX17042_MiscCFG, config->misc_cfg); | |
666 | max17042_override_por(map, MAX17042_MaskSOC, config->masksoc); | |
667 | ||
668 | max17042_override_por(map, MAX17042_FullCAP, config->fullcap); | |
669 | max17042_override_por(map, MAX17042_FullCAPNom, config->fullcapnom); | |
709c2c70 | 670 | if (chip->chip_type == MAXIM_DEVICE_TYPE_MAX17042) |
39e7213e | 671 | max17042_override_por(map, MAX17042_SOC_empty, |
9a8422d2 | 672 | config->socempty); |
39e7213e JL |
673 | max17042_override_por(map, MAX17042_LAvg_empty, config->lavg_empty); |
674 | max17042_override_por(map, MAX17042_dQacc, config->dqacc); | |
675 | max17042_override_por(map, MAX17042_dPacc, config->dpacc); | |
f3a71a6e | 676 | |
709c2c70 | 677 | if (chip->chip_type == MAXIM_DEVICE_TYPE_MAX17042) |
39e7213e | 678 | max17042_override_por(map, MAX17042_V_empty, config->vempty); |
9a8422d2 | 679 | else |
39e7213e JL |
680 | max17042_override_por(map, MAX17047_V_empty, config->vempty); |
681 | max17042_override_por(map, MAX17042_TempNom, config->temp_nom); | |
682 | max17042_override_por(map, MAX17042_TempLim, config->temp_lim); | |
683 | max17042_override_por(map, MAX17042_FCTC, config->fctc); | |
684 | max17042_override_por(map, MAX17042_RCOMP0, config->rcomp0); | |
685 | max17042_override_por(map, MAX17042_TempCo, config->tcompc0); | |
9a8422d2 | 686 | if (chip->chip_type) { |
39e7213e JL |
687 | max17042_override_por(map, MAX17042_EmptyTempCo, |
688 | config->empty_tempco); | |
689 | max17042_override_por(map, MAX17042_K_empty0, | |
690 | config->kempty0); | |
9a8422d2 | 691 | } |
f3a71a6e RP |
692 | } |
693 | ||
694 | static int max17042_init_chip(struct max17042_chip *chip) | |
695 | { | |
39e7213e | 696 | struct regmap *map = chip->regmap; |
f3a71a6e | 697 | int ret; |
f3a71a6e RP |
698 | |
699 | max17042_override_por_values(chip); | |
700 | /* After Power up, the MAX17042 requires 500mS in order | |
701 | * to perform signal debouncing and initial SOC reporting | |
702 | */ | |
703 | msleep(500); | |
704 | ||
705 | /* Initialize configaration */ | |
706 | max17042_write_config_regs(chip); | |
707 | ||
708 | /* write cell characterization data */ | |
709 | ret = max17042_init_model(chip); | |
710 | if (ret) { | |
711 | dev_err(&chip->client->dev, "%s init failed\n", | |
712 | __func__); | |
713 | return -EIO; | |
714 | } | |
a879f19f AC |
715 | |
716 | ret = max17042_verify_model_lock(chip); | |
f3a71a6e RP |
717 | if (ret) { |
718 | dev_err(&chip->client->dev, "%s lock verify failed\n", | |
719 | __func__); | |
720 | return -EIO; | |
721 | } | |
722 | /* write custom parameters */ | |
723 | max17042_write_custom_regs(chip); | |
724 | ||
725 | /* update capacity params */ | |
726 | max17042_update_capacity_regs(chip); | |
727 | ||
728 | /* delay must be atleast 350mS to allow VFSOC | |
729 | * to be calculated from the new configuration | |
730 | */ | |
731 | msleep(350); | |
732 | ||
733 | /* reset vfsoc0 reg */ | |
734 | max17042_reset_vfsoc0_reg(chip); | |
735 | ||
736 | /* load new capacity params */ | |
737 | max17042_load_new_capacity_params(chip); | |
738 | ||
739 | /* Init complete, Clear the POR bit */ | |
bc352686 | 740 | regmap_update_bits(map, MAX17042_STATUS, STATUS_POR_BIT, 0x0); |
f3a71a6e RP |
741 | return 0; |
742 | } | |
743 | ||
e5f3872d RP |
744 | static void max17042_set_soc_threshold(struct max17042_chip *chip, u16 off) |
745 | { | |
39e7213e JL |
746 | struct regmap *map = chip->regmap; |
747 | u32 soc, soc_tr; | |
e5f3872d RP |
748 | |
749 | /* program interrupt thesholds such that we should | |
750 | * get interrupt for every 'off' perc change in the soc | |
751 | */ | |
39e7213e JL |
752 | regmap_read(map, MAX17042_RepSOC, &soc); |
753 | soc >>= 8; | |
e5f3872d RP |
754 | soc_tr = (soc + off) << 8; |
755 | soc_tr |= (soc - off); | |
39e7213e | 756 | regmap_write(map, MAX17042_SALRT_Th, soc_tr); |
e5f3872d RP |
757 | } |
758 | ||
e5f3872d RP |
759 | static irqreturn_t max17042_thread_handler(int id, void *dev) |
760 | { | |
761 | struct max17042_chip *chip = dev; | |
39e7213e | 762 | u32 val; |
e5f3872d | 763 | |
39e7213e | 764 | regmap_read(chip->regmap, MAX17042_STATUS, &val); |
5cdd4d7f RP |
765 | if ((val & STATUS_INTR_SOCMIN_BIT) || |
766 | (val & STATUS_INTR_SOCMAX_BIT)) { | |
e5f3872d RP |
767 | dev_info(&chip->client->dev, "SOC threshold INTR\n"); |
768 | max17042_set_soc_threshold(chip, 1); | |
769 | } | |
770 | ||
297d716f | 771 | power_supply_changed(chip->battery); |
e5f3872d RP |
772 | return IRQ_HANDLED; |
773 | } | |
f3a71a6e RP |
774 | |
775 | static void max17042_init_worker(struct work_struct *work) | |
776 | { | |
777 | struct max17042_chip *chip = container_of(work, | |
778 | struct max17042_chip, work); | |
779 | int ret; | |
780 | ||
781 | /* Initialize registers according to values from the platform data */ | |
782 | if (chip->pdata->enable_por_init && chip->pdata->config_data) { | |
783 | ret = max17042_init_chip(chip); | |
784 | if (ret) | |
785 | return; | |
786 | } | |
787 | ||
788 | chip->init_complete = 1; | |
789 | } | |
790 | ||
3832246d KL |
791 | #ifdef CONFIG_OF |
792 | static struct max17042_platform_data * | |
793 | max17042_get_pdata(struct device *dev) | |
794 | { | |
795 | struct device_node *np = dev->of_node; | |
796 | u32 prop; | |
797 | struct max17042_platform_data *pdata; | |
798 | ||
799 | if (!np) | |
800 | return dev->platform_data; | |
801 | ||
802 | pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); | |
803 | if (!pdata) | |
804 | return NULL; | |
805 | ||
806 | /* | |
807 | * Require current sense resistor value to be specified for | |
808 | * current-sense functionality to be enabled at all. | |
809 | */ | |
810 | if (of_property_read_u32(np, "maxim,rsns-microohm", &prop) == 0) { | |
811 | pdata->r_sns = prop; | |
812 | pdata->enable_current_sense = true; | |
813 | } | |
814 | ||
a6e6b63e KK |
815 | if (of_property_read_s32(np, "maxim,cold-temp", &pdata->temp_min)) |
816 | pdata->temp_min = INT_MIN; | |
817 | if (of_property_read_s32(np, "maxim,over-heat-temp", &pdata->temp_max)) | |
818 | pdata->temp_max = INT_MAX; | |
819 | if (of_property_read_s32(np, "maxim,dead-volt", &pdata->vmin)) | |
820 | pdata->vmin = INT_MIN; | |
821 | if (of_property_read_s32(np, "maxim,over-volt", &pdata->vmax)) | |
822 | pdata->vmax = INT_MAX; | |
823 | ||
3832246d KL |
824 | return pdata; |
825 | } | |
826 | #else | |
827 | static struct max17042_platform_data * | |
828 | max17042_get_pdata(struct device *dev) | |
829 | { | |
830 | return dev->platform_data; | |
831 | } | |
832 | #endif | |
833 | ||
e0291285 | 834 | static const struct regmap_config max17042_regmap_config = { |
39e7213e JL |
835 | .reg_bits = 8, |
836 | .val_bits = 16, | |
837 | .val_format_endian = REGMAP_ENDIAN_NATIVE, | |
838 | }; | |
839 | ||
297d716f KK |
840 | static const struct power_supply_desc max17042_psy_desc = { |
841 | .name = "max170xx_battery", | |
842 | .type = POWER_SUPPLY_TYPE_BATTERY, | |
843 | .get_property = max17042_get_property, | |
edd4ab05 RP |
844 | .set_property = max17042_set_property, |
845 | .property_is_writeable = max17042_property_is_writeable, | |
297d716f KK |
846 | .properties = max17042_battery_props, |
847 | .num_properties = ARRAY_SIZE(max17042_battery_props), | |
848 | }; | |
849 | ||
850 | static const struct power_supply_desc max17042_no_current_sense_psy_desc = { | |
851 | .name = "max170xx_battery", | |
852 | .type = POWER_SUPPLY_TYPE_BATTERY, | |
853 | .get_property = max17042_get_property, | |
edd4ab05 RP |
854 | .set_property = max17042_set_property, |
855 | .property_is_writeable = max17042_property_is_writeable, | |
297d716f KK |
856 | .properties = max17042_battery_props, |
857 | .num_properties = ARRAY_SIZE(max17042_battery_props) - 2, | |
858 | }; | |
859 | ||
c8afa640 | 860 | static int max17042_probe(struct i2c_client *client, |
359ab9f5 MH |
861 | const struct i2c_device_id *id) |
862 | { | |
863 | struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); | |
297d716f KK |
864 | const struct power_supply_desc *max17042_desc = &max17042_psy_desc; |
865 | struct power_supply_config psy_cfg = {}; | |
359ab9f5 MH |
866 | struct max17042_chip *chip; |
867 | int ret; | |
39e7213e JL |
868 | int i; |
869 | u32 val; | |
359ab9f5 MH |
870 | |
871 | if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA)) | |
872 | return -EIO; | |
873 | ||
2f3b4342 | 874 | chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL); |
359ab9f5 MH |
875 | if (!chip) |
876 | return -ENOMEM; | |
877 | ||
878 | chip->client = client; | |
39e7213e JL |
879 | chip->regmap = devm_regmap_init_i2c(client, &max17042_regmap_config); |
880 | if (IS_ERR(chip->regmap)) { | |
881 | dev_err(&client->dev, "Failed to initialize regmap\n"); | |
882 | return -EINVAL; | |
883 | } | |
884 | ||
3832246d KL |
885 | chip->pdata = max17042_get_pdata(&client->dev); |
886 | if (!chip->pdata) { | |
887 | dev_err(&client->dev, "no platform data provided\n"); | |
888 | return -EINVAL; | |
889 | } | |
359ab9f5 MH |
890 | |
891 | i2c_set_clientdata(client, chip); | |
709c2c70 | 892 | chip->chip_type = id->driver_data; |
297d716f | 893 | psy_cfg.drv_data = chip; |
359ab9f5 | 894 | |
086ef502 DK |
895 | /* When current is not measured, |
896 | * CURRENT_NOW and CURRENT_AVG properties should be invisible. */ | |
897 | if (!chip->pdata->enable_current_sense) | |
297d716f | 898 | max17042_desc = &max17042_no_current_sense_psy_desc; |
086ef502 | 899 | |
4cfa892c PR |
900 | if (chip->pdata->r_sns == 0) |
901 | chip->pdata->r_sns = MAX17042_DEFAULT_SNS_RESISTOR; | |
902 | ||
086ef502 | 903 | if (chip->pdata->init_data) |
39e7213e JL |
904 | for (i = 0; i < chip->pdata->num_init_data; i++) |
905 | regmap_write(chip->regmap, | |
906 | chip->pdata->init_data[i].addr, | |
907 | chip->pdata->init_data[i].data); | |
086ef502 | 908 | |
359ab9f5 | 909 | if (!chip->pdata->enable_current_sense) { |
39e7213e JL |
910 | regmap_write(chip->regmap, MAX17042_CGAIN, 0x0000); |
911 | regmap_write(chip->regmap, MAX17042_MiscCFG, 0x0003); | |
912 | regmap_write(chip->regmap, MAX17042_LearnCFG, 0x0007); | |
359ab9f5 MH |
913 | } |
914 | ||
50bddb99 VT |
915 | chip->battery = devm_power_supply_register(&client->dev, max17042_desc, |
916 | &psy_cfg); | |
297d716f | 917 | if (IS_ERR(chip->battery)) { |
243e3527 | 918 | dev_err(&client->dev, "failed: power supply register\n"); |
297d716f | 919 | return PTR_ERR(chip->battery); |
243e3527 RP |
920 | } |
921 | ||
e5f3872d | 922 | if (client->irq) { |
50bddb99 VT |
923 | ret = devm_request_threaded_irq(&client->dev, client->irq, |
924 | NULL, | |
925 | max17042_thread_handler, | |
926 | IRQF_TRIGGER_FALLING | | |
927 | IRQF_ONESHOT, | |
928 | chip->battery->desc->name, | |
929 | chip); | |
e5f3872d | 930 | if (!ret) { |
bc352686 KK |
931 | regmap_update_bits(chip->regmap, MAX17042_CONFIG, |
932 | CONFIG_ALRT_BIT_ENBL, | |
933 | CONFIG_ALRT_BIT_ENBL); | |
e5f3872d | 934 | max17042_set_soc_threshold(chip, 1); |
e5ba50bc RP |
935 | } else { |
936 | client->irq = 0; | |
e5f3872d RP |
937 | dev_err(&client->dev, "%s(): cannot get IRQ\n", |
938 | __func__); | |
e5ba50bc | 939 | } |
e5f3872d RP |
940 | } |
941 | ||
39e7213e JL |
942 | regmap_read(chip->regmap, MAX17042_STATUS, &val); |
943 | if (val & STATUS_POR_BIT) { | |
f3a71a6e RP |
944 | INIT_WORK(&chip->work, max17042_init_worker); |
945 | schedule_work(&chip->work); | |
946 | } else { | |
947 | chip->init_complete = 1; | |
948 | } | |
949 | ||
243e3527 | 950 | return 0; |
359ab9f5 MH |
951 | } |
952 | ||
3d23c7f4 | 953 | #ifdef CONFIG_PM_SLEEP |
48bc1774 RP |
954 | static int max17042_suspend(struct device *dev) |
955 | { | |
956 | struct max17042_chip *chip = dev_get_drvdata(dev); | |
957 | ||
48e41c70 AV |
958 | /* |
959 | * disable the irq and enable irq_wake | |
48bc1774 RP |
960 | * capability to the interrupt line. |
961 | */ | |
962 | if (chip->client->irq) { | |
963 | disable_irq(chip->client->irq); | |
964 | enable_irq_wake(chip->client->irq); | |
965 | } | |
966 | ||
967 | return 0; | |
968 | } | |
969 | ||
970 | static int max17042_resume(struct device *dev) | |
971 | { | |
972 | struct max17042_chip *chip = dev_get_drvdata(dev); | |
973 | ||
974 | if (chip->client->irq) { | |
975 | disable_irq_wake(chip->client->irq); | |
976 | enable_irq(chip->client->irq); | |
977 | /* re-program the SOC thresholds to 1% change */ | |
978 | max17042_set_soc_threshold(chip, 1); | |
979 | } | |
980 | ||
981 | return 0; | |
982 | } | |
48bc1774 RP |
983 | #endif |
984 | ||
3d23c7f4 MB |
985 | static SIMPLE_DEV_PM_OPS(max17042_pm_ops, max17042_suspend, |
986 | max17042_resume); | |
987 | ||
3832246d KL |
988 | #ifdef CONFIG_OF |
989 | static const struct of_device_id max17042_dt_match[] = { | |
990 | { .compatible = "maxim,max17042" }, | |
9a8422d2 RP |
991 | { .compatible = "maxim,max17047" }, |
992 | { .compatible = "maxim,max17050" }, | |
3832246d KL |
993 | { }, |
994 | }; | |
995 | MODULE_DEVICE_TABLE(of, max17042_dt_match); | |
996 | #endif | |
997 | ||
359ab9f5 | 998 | static const struct i2c_device_id max17042_id[] = { |
709c2c70 BS |
999 | { "max17042", MAXIM_DEVICE_TYPE_MAX17042 }, |
1000 | { "max17047", MAXIM_DEVICE_TYPE_MAX17047 }, | |
1001 | { "max17050", MAXIM_DEVICE_TYPE_MAX17050 }, | |
359ab9f5 MH |
1002 | { } |
1003 | }; | |
1004 | MODULE_DEVICE_TABLE(i2c, max17042_id); | |
1005 | ||
1006 | static struct i2c_driver max17042_i2c_driver = { | |
1007 | .driver = { | |
1008 | .name = "max17042", | |
3832246d | 1009 | .of_match_table = of_match_ptr(max17042_dt_match), |
3d23c7f4 | 1010 | .pm = &max17042_pm_ops, |
359ab9f5 MH |
1011 | }, |
1012 | .probe = max17042_probe, | |
359ab9f5 MH |
1013 | .id_table = max17042_id, |
1014 | }; | |
5ff92e7a | 1015 | module_i2c_driver(max17042_i2c_driver); |
359ab9f5 MH |
1016 | |
1017 | MODULE_AUTHOR("MyungJoo Ham <myungjoo.ham@samsung.com>"); | |
1018 | MODULE_DESCRIPTION("MAX17042 Fuel Gauge"); | |
1019 | MODULE_LICENSE("GPL"); |