Commit | Line | Data |
---|---|---|
7b38ebdf KK |
1 | // SPDX-License-Identifier: GPL-2.0+ |
2 | // | |
3 | // Fuel gauge driver for Maxim 17042 / 8966 / 8997 | |
4 | // Note that Maxim 8966 and 8997 are mfd and this is its subdevice. | |
5 | // | |
6 | // Copyright (C) 2011 Samsung Electronics | |
7 | // MyungJoo Ham <myungjoo.ham@samsung.com> | |
8 | // | |
9 | // This driver is based on max17040_battery.c | |
359ab9f5 | 10 | |
e2116202 | 11 | #include <linux/acpi.h> |
359ab9f5 | 12 | #include <linux/init.h> |
7e6d62db | 13 | #include <linux/module.h> |
359ab9f5 MH |
14 | #include <linux/slab.h> |
15 | #include <linux/i2c.h> | |
f3a71a6e | 16 | #include <linux/delay.h> |
e5f3872d | 17 | #include <linux/interrupt.h> |
48bc1774 | 18 | #include <linux/pm.h> |
359ab9f5 MH |
19 | #include <linux/mod_devicetable.h> |
20 | #include <linux/power_supply.h> | |
21 | #include <linux/power/max17042_battery.h> | |
3832246d | 22 | #include <linux/of.h> |
39e7213e | 23 | #include <linux/regmap.h> |
359ab9f5 | 24 | |
f3a71a6e RP |
25 | /* Status register bits */ |
26 | #define STATUS_POR_BIT (1 << 1) | |
27 | #define STATUS_BST_BIT (1 << 3) | |
28 | #define STATUS_VMN_BIT (1 << 8) | |
29 | #define STATUS_TMN_BIT (1 << 9) | |
30 | #define STATUS_SMN_BIT (1 << 10) | |
31 | #define STATUS_BI_BIT (1 << 11) | |
32 | #define STATUS_VMX_BIT (1 << 12) | |
33 | #define STATUS_TMX_BIT (1 << 13) | |
34 | #define STATUS_SMX_BIT (1 << 14) | |
35 | #define STATUS_BR_BIT (1 << 15) | |
36 | ||
e5f3872d RP |
37 | /* Interrupt mask bits */ |
38 | #define CONFIG_ALRT_BIT_ENBL (1 << 2) | |
5cdd4d7f RP |
39 | #define STATUS_INTR_SOCMIN_BIT (1 << 10) |
40 | #define STATUS_INTR_SOCMAX_BIT (1 << 14) | |
e5f3872d | 41 | |
f3a71a6e RP |
42 | #define VFSOC0_LOCK 0x0000 |
43 | #define VFSOC0_UNLOCK 0x0080 | |
44 | #define MODEL_UNLOCK1 0X0059 | |
45 | #define MODEL_UNLOCK2 0X00C4 | |
46 | #define MODEL_LOCK1 0X0000 | |
47 | #define MODEL_LOCK2 0X0000 | |
48 | ||
49 | #define dQ_ACC_DIV 0x4 | |
50 | #define dP_ACC_100 0x1900 | |
51 | #define dP_ACC_200 0x3200 | |
52 | ||
edd4ab05 RP |
53 | #define MAX17042_VMAX_TOLERANCE 50 /* 50 mV */ |
54 | ||
359ab9f5 MH |
55 | struct max17042_chip { |
56 | struct i2c_client *client; | |
39e7213e | 57 | struct regmap *regmap; |
297d716f | 58 | struct power_supply *battery; |
9a8422d2 | 59 | enum max170xx_chip_type chip_type; |
359ab9f5 | 60 | struct max17042_platform_data *pdata; |
f3a71a6e RP |
61 | struct work_struct work; |
62 | int init_complete; | |
359ab9f5 MH |
63 | }; |
64 | ||
359ab9f5 | 65 | static enum power_supply_property max17042_battery_props[] = { |
a9df22c0 | 66 | POWER_SUPPLY_PROP_STATUS, |
086ef502 | 67 | POWER_SUPPLY_PROP_PRESENT, |
ef7fcdae | 68 | POWER_SUPPLY_PROP_TECHNOLOGY, |
086ef502 DK |
69 | POWER_SUPPLY_PROP_CYCLE_COUNT, |
70 | POWER_SUPPLY_PROP_VOLTAGE_MAX, | |
7bfc9397 | 71 | POWER_SUPPLY_PROP_VOLTAGE_MIN, |
086ef502 | 72 | POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN, |
359ab9f5 MH |
73 | POWER_SUPPLY_PROP_VOLTAGE_NOW, |
74 | POWER_SUPPLY_PROP_VOLTAGE_AVG, | |
a2ebfe2f | 75 | POWER_SUPPLY_PROP_VOLTAGE_OCV, |
359ab9f5 | 76 | POWER_SUPPLY_PROP_CAPACITY, |
2e015412 | 77 | POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, |
086ef502 | 78 | POWER_SUPPLY_PROP_CHARGE_FULL, |
6d6b61ea | 79 | POWER_SUPPLY_PROP_CHARGE_NOW, |
5fc55bc8 | 80 | POWER_SUPPLY_PROP_CHARGE_COUNTER, |
5225371e | 81 | POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT, |
086ef502 | 82 | POWER_SUPPLY_PROP_TEMP, |
edd4ab05 RP |
83 | POWER_SUPPLY_PROP_TEMP_ALERT_MIN, |
84 | POWER_SUPPLY_PROP_TEMP_ALERT_MAX, | |
85 | POWER_SUPPLY_PROP_TEMP_MIN, | |
86 | POWER_SUPPLY_PROP_TEMP_MAX, | |
87 | POWER_SUPPLY_PROP_HEALTH, | |
adb69a3c | 88 | POWER_SUPPLY_PROP_SCOPE, |
4b0a56e6 SK |
89 | POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW, |
90 | // these two have to be at the end on the list | |
086ef502 DK |
91 | POWER_SUPPLY_PROP_CURRENT_NOW, |
92 | POWER_SUPPLY_PROP_CURRENT_AVG, | |
359ab9f5 MH |
93 | }; |
94 | ||
edd4ab05 RP |
95 | static int max17042_get_temperature(struct max17042_chip *chip, int *temp) |
96 | { | |
97 | int ret; | |
98 | u32 data; | |
99 | struct regmap *map = chip->regmap; | |
100 | ||
101 | ret = regmap_read(map, MAX17042_TEMP, &data); | |
102 | if (ret < 0) | |
103 | return ret; | |
104 | ||
c67c0693 | 105 | *temp = sign_extend32(data, 15); |
edd4ab05 RP |
106 | /* The value is converted into deci-centigrade scale */ |
107 | /* Units of LSB = 1 / 256 degree Celsius */ | |
108 | *temp = *temp * 10 / 256; | |
109 | return 0; | |
110 | } | |
111 | ||
a9df22c0 HG |
112 | static int max17042_get_status(struct max17042_chip *chip, int *status) |
113 | { | |
114 | int ret, charge_full, charge_now; | |
6e5ab19d HG |
115 | int avg_current; |
116 | u32 data; | |
a9df22c0 HG |
117 | |
118 | ret = power_supply_am_i_supplied(chip->battery); | |
119 | if (ret < 0) { | |
120 | *status = POWER_SUPPLY_STATUS_UNKNOWN; | |
121 | return 0; | |
122 | } | |
123 | if (ret == 0) { | |
124 | *status = POWER_SUPPLY_STATUS_DISCHARGING; | |
125 | return 0; | |
126 | } | |
127 | ||
128 | /* | |
129 | * The MAX170xx has builtin end-of-charge detection and will update | |
130 | * FullCAP to match RepCap when it detects end of charging. | |
131 | * | |
132 | * When this cycle the battery gets charged to a higher (calculated) | |
133 | * capacity then the previous cycle then FullCAP will get updated | |
37ad56aa | 134 | * continuously once end-of-charge detection kicks in, so allow the |
a9df22c0 HG |
135 | * 2 to differ a bit. |
136 | */ | |
137 | ||
138 | ret = regmap_read(chip->regmap, MAX17042_FullCAP, &charge_full); | |
139 | if (ret < 0) | |
140 | return ret; | |
141 | ||
142 | ret = regmap_read(chip->regmap, MAX17042_RepCap, &charge_now); | |
143 | if (ret < 0) | |
144 | return ret; | |
145 | ||
6e5ab19d | 146 | if ((charge_full - charge_now) <= MAX17042_FULL_THRESHOLD) { |
a9df22c0 | 147 | *status = POWER_SUPPLY_STATUS_FULL; |
6e5ab19d HG |
148 | return 0; |
149 | } | |
150 | ||
151 | /* | |
152 | * Even though we are supplied, we may still be discharging if the | |
153 | * supply is e.g. only delivering 5V 0.5A. Check current if available. | |
154 | */ | |
155 | if (!chip->pdata->enable_current_sense) { | |
a9df22c0 | 156 | *status = POWER_SUPPLY_STATUS_CHARGING; |
6e5ab19d HG |
157 | return 0; |
158 | } | |
159 | ||
160 | ret = regmap_read(chip->regmap, MAX17042_AvgCurrent, &data); | |
161 | if (ret < 0) | |
162 | return ret; | |
163 | ||
164 | avg_current = sign_extend32(data, 15); | |
165 | avg_current *= 1562500 / chip->pdata->r_sns; | |
166 | ||
167 | if (avg_current > 0) | |
168 | *status = POWER_SUPPLY_STATUS_CHARGING; | |
169 | else | |
170 | *status = POWER_SUPPLY_STATUS_DISCHARGING; | |
a9df22c0 HG |
171 | |
172 | return 0; | |
173 | } | |
174 | ||
edd4ab05 RP |
175 | static int max17042_get_battery_health(struct max17042_chip *chip, int *health) |
176 | { | |
177 | int temp, vavg, vbatt, ret; | |
178 | u32 val; | |
179 | ||
180 | ret = regmap_read(chip->regmap, MAX17042_AvgVCELL, &val); | |
181 | if (ret < 0) | |
182 | goto health_error; | |
183 | ||
184 | /* bits [0-3] unused */ | |
185 | vavg = val * 625 / 8; | |
186 | /* Convert to millivolts */ | |
187 | vavg /= 1000; | |
188 | ||
189 | ret = regmap_read(chip->regmap, MAX17042_VCELL, &val); | |
190 | if (ret < 0) | |
191 | goto health_error; | |
192 | ||
193 | /* bits [0-3] unused */ | |
194 | vbatt = val * 625 / 8; | |
195 | /* Convert to millivolts */ | |
196 | vbatt /= 1000; | |
197 | ||
198 | if (vavg < chip->pdata->vmin) { | |
199 | *health = POWER_SUPPLY_HEALTH_DEAD; | |
200 | goto out; | |
201 | } | |
202 | ||
203 | if (vbatt > chip->pdata->vmax + MAX17042_VMAX_TOLERANCE) { | |
204 | *health = POWER_SUPPLY_HEALTH_OVERVOLTAGE; | |
205 | goto out; | |
206 | } | |
207 | ||
208 | ret = max17042_get_temperature(chip, &temp); | |
209 | if (ret < 0) | |
210 | goto health_error; | |
211 | ||
91736213 | 212 | if (temp < chip->pdata->temp_min) { |
edd4ab05 RP |
213 | *health = POWER_SUPPLY_HEALTH_COLD; |
214 | goto out; | |
215 | } | |
216 | ||
91736213 | 217 | if (temp > chip->pdata->temp_max) { |
edd4ab05 RP |
218 | *health = POWER_SUPPLY_HEALTH_OVERHEAT; |
219 | goto out; | |
220 | } | |
221 | ||
222 | *health = POWER_SUPPLY_HEALTH_GOOD; | |
223 | ||
224 | out: | |
225 | return 0; | |
226 | ||
227 | health_error: | |
228 | return ret; | |
229 | } | |
230 | ||
359ab9f5 MH |
231 | static int max17042_get_property(struct power_supply *psy, |
232 | enum power_supply_property psp, | |
233 | union power_supply_propval *val) | |
234 | { | |
297d716f | 235 | struct max17042_chip *chip = power_supply_get_drvdata(psy); |
39e7213e | 236 | struct regmap *map = chip->regmap; |
60a1f6e4 | 237 | int ret; |
39e7213e | 238 | u32 data; |
d7d15fc6 | 239 | u64 data64; |
359ab9f5 | 240 | |
f3a71a6e RP |
241 | if (!chip->init_complete) |
242 | return -EAGAIN; | |
243 | ||
359ab9f5 | 244 | switch (psp) { |
a9df22c0 HG |
245 | case POWER_SUPPLY_PROP_STATUS: |
246 | ret = max17042_get_status(chip, &val->intval); | |
247 | if (ret < 0) | |
248 | return ret; | |
249 | break; | |
086ef502 | 250 | case POWER_SUPPLY_PROP_PRESENT: |
39e7213e | 251 | ret = regmap_read(map, MAX17042_STATUS, &data); |
60a1f6e4 RP |
252 | if (ret < 0) |
253 | return ret; | |
254 | ||
39e7213e | 255 | if (data & MAX17042_STATUS_BattAbsent) |
086ef502 DK |
256 | val->intval = 0; |
257 | else | |
258 | val->intval = 1; | |
259 | break; | |
ef7fcdae HG |
260 | case POWER_SUPPLY_PROP_TECHNOLOGY: |
261 | val->intval = POWER_SUPPLY_TECHNOLOGY_LION; | |
262 | break; | |
086ef502 | 263 | case POWER_SUPPLY_PROP_CYCLE_COUNT: |
39e7213e | 264 | ret = regmap_read(map, MAX17042_Cycles, &data); |
60a1f6e4 RP |
265 | if (ret < 0) |
266 | return ret; | |
267 | ||
39e7213e | 268 | val->intval = data; |
086ef502 DK |
269 | break; |
270 | case POWER_SUPPLY_PROP_VOLTAGE_MAX: | |
39e7213e | 271 | ret = regmap_read(map, MAX17042_MinMaxVolt, &data); |
60a1f6e4 RP |
272 | if (ret < 0) |
273 | return ret; | |
274 | ||
39e7213e | 275 | val->intval = data >> 8; |
086ef502 DK |
276 | val->intval *= 20000; /* Units of LSB = 20mV */ |
277 | break; | |
7bfc9397 HG |
278 | case POWER_SUPPLY_PROP_VOLTAGE_MIN: |
279 | ret = regmap_read(map, MAX17042_MinMaxVolt, &data); | |
280 | if (ret < 0) | |
281 | return ret; | |
282 | ||
283 | val->intval = (data & 0xff) * 20000; /* Units of 20mV */ | |
284 | break; | |
086ef502 | 285 | case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN: |
709c2c70 | 286 | if (chip->chip_type == MAXIM_DEVICE_TYPE_MAX17042) |
39e7213e | 287 | ret = regmap_read(map, MAX17042_V_empty, &data); |
bc90705b AAP |
288 | else if (chip->chip_type == MAXIM_DEVICE_TYPE_MAX17055) |
289 | ret = regmap_read(map, MAX17055_V_empty, &data); | |
9a8422d2 | 290 | else |
39e7213e | 291 | ret = regmap_read(map, MAX17047_V_empty, &data); |
60a1f6e4 RP |
292 | if (ret < 0) |
293 | return ret; | |
294 | ||
39e7213e | 295 | val->intval = data >> 7; |
086ef502 DK |
296 | val->intval *= 10000; /* Units of LSB = 10mV */ |
297 | break; | |
359ab9f5 | 298 | case POWER_SUPPLY_PROP_VOLTAGE_NOW: |
39e7213e | 299 | ret = regmap_read(map, MAX17042_VCELL, &data); |
60a1f6e4 RP |
300 | if (ret < 0) |
301 | return ret; | |
302 | ||
39e7213e | 303 | val->intval = data * 625 / 8; |
359ab9f5 MH |
304 | break; |
305 | case POWER_SUPPLY_PROP_VOLTAGE_AVG: | |
39e7213e | 306 | ret = regmap_read(map, MAX17042_AvgVCELL, &data); |
60a1f6e4 RP |
307 | if (ret < 0) |
308 | return ret; | |
309 | ||
39e7213e | 310 | val->intval = data * 625 / 8; |
a2ebfe2f RP |
311 | break; |
312 | case POWER_SUPPLY_PROP_VOLTAGE_OCV: | |
39e7213e | 313 | ret = regmap_read(map, MAX17042_OCVInternal, &data); |
a2ebfe2f RP |
314 | if (ret < 0) |
315 | return ret; | |
316 | ||
39e7213e | 317 | val->intval = data * 625 / 8; |
359ab9f5 MH |
318 | break; |
319 | case POWER_SUPPLY_PROP_CAPACITY: | |
39e7213e | 320 | ret = regmap_read(map, MAX17042_RepSOC, &data); |
60a1f6e4 RP |
321 | if (ret < 0) |
322 | return ret; | |
323 | ||
39e7213e | 324 | val->intval = data >> 8; |
359ab9f5 | 325 | break; |
2e015412 HG |
326 | case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN: |
327 | ret = regmap_read(map, MAX17042_DesignCap, &data); | |
328 | if (ret < 0) | |
329 | return ret; | |
330 | ||
331 | data64 = data * 5000000ll; | |
332 | do_div(data64, chip->pdata->r_sns); | |
333 | val->intval = data64; | |
334 | break; | |
086ef502 | 335 | case POWER_SUPPLY_PROP_CHARGE_FULL: |
39e7213e | 336 | ret = regmap_read(map, MAX17042_FullCAP, &data); |
60a1f6e4 RP |
337 | if (ret < 0) |
338 | return ret; | |
339 | ||
6d6b61ea HG |
340 | data64 = data * 5000000ll; |
341 | do_div(data64, chip->pdata->r_sns); | |
342 | val->intval = data64; | |
343 | break; | |
344 | case POWER_SUPPLY_PROP_CHARGE_NOW: | |
345 | ret = regmap_read(map, MAX17042_RepCap, &data); | |
346 | if (ret < 0) | |
347 | return ret; | |
348 | ||
d7d15fc6 HG |
349 | data64 = data * 5000000ll; |
350 | do_div(data64, chip->pdata->r_sns); | |
351 | val->intval = data64; | |
5fc55bc8 RP |
352 | break; |
353 | case POWER_SUPPLY_PROP_CHARGE_COUNTER: | |
39e7213e | 354 | ret = regmap_read(map, MAX17042_QH, &data); |
5fc55bc8 RP |
355 | if (ret < 0) |
356 | return ret; | |
357 | ||
6dcfa009 SK |
358 | data64 = sign_extend64(data, 15) * 5000000ll; |
359 | val->intval = div_s64(data64, chip->pdata->r_sns); | |
086ef502 DK |
360 | break; |
361 | case POWER_SUPPLY_PROP_TEMP: | |
edd4ab05 RP |
362 | ret = max17042_get_temperature(chip, &val->intval); |
363 | if (ret < 0) | |
364 | return ret; | |
365 | break; | |
366 | case POWER_SUPPLY_PROP_TEMP_ALERT_MIN: | |
367 | ret = regmap_read(map, MAX17042_TALRT_Th, &data); | |
368 | if (ret < 0) | |
369 | return ret; | |
370 | /* LSB is Alert Minimum. In deci-centigrade */ | |
2814913c | 371 | val->intval = sign_extend32(data & 0xff, 7) * 10; |
edd4ab05 RP |
372 | break; |
373 | case POWER_SUPPLY_PROP_TEMP_ALERT_MAX: | |
374 | ret = regmap_read(map, MAX17042_TALRT_Th, &data); | |
375 | if (ret < 0) | |
376 | return ret; | |
377 | /* MSB is Alert Maximum. In deci-centigrade */ | |
2814913c | 378 | val->intval = sign_extend32(data >> 8, 7) * 10; |
edd4ab05 RP |
379 | break; |
380 | case POWER_SUPPLY_PROP_TEMP_MIN: | |
381 | val->intval = chip->pdata->temp_min; | |
382 | break; | |
383 | case POWER_SUPPLY_PROP_TEMP_MAX: | |
384 | val->intval = chip->pdata->temp_max; | |
385 | break; | |
386 | case POWER_SUPPLY_PROP_HEALTH: | |
387 | ret = max17042_get_battery_health(chip, &val->intval); | |
60a1f6e4 RP |
388 | if (ret < 0) |
389 | return ret; | |
086ef502 | 390 | break; |
adb69a3c HG |
391 | case POWER_SUPPLY_PROP_SCOPE: |
392 | val->intval = POWER_SUPPLY_SCOPE_SYSTEM; | |
393 | break; | |
086ef502 DK |
394 | case POWER_SUPPLY_PROP_CURRENT_NOW: |
395 | if (chip->pdata->enable_current_sense) { | |
39e7213e | 396 | ret = regmap_read(map, MAX17042_Current, &data); |
60a1f6e4 RP |
397 | if (ret < 0) |
398 | return ret; | |
399 | ||
9e39ef14 SK |
400 | data64 = sign_extend64(data, 15) * 1562500ll; |
401 | val->intval = div_s64(data64, chip->pdata->r_sns); | |
086ef502 DK |
402 | } else { |
403 | return -EINVAL; | |
404 | } | |
405 | break; | |
406 | case POWER_SUPPLY_PROP_CURRENT_AVG: | |
407 | if (chip->pdata->enable_current_sense) { | |
39e7213e | 408 | ret = regmap_read(map, MAX17042_AvgCurrent, &data); |
60a1f6e4 RP |
409 | if (ret < 0) |
410 | return ret; | |
411 | ||
9e39ef14 SK |
412 | data64 = sign_extend64(data, 15) * 1562500ll; |
413 | val->intval = div_s64(data64, chip->pdata->r_sns); | |
086ef502 DK |
414 | } else { |
415 | return -EINVAL; | |
416 | } | |
417 | break; | |
5225371e SK |
418 | case POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT: |
419 | ret = regmap_read(map, MAX17042_ICHGTerm, &data); | |
420 | if (ret < 0) | |
421 | return ret; | |
422 | ||
423 | data64 = data * 1562500ll; | |
424 | val->intval = div_s64(data64, chip->pdata->r_sns); | |
425 | break; | |
21b01cc8 GN |
426 | case POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW: |
427 | ret = regmap_read(map, MAX17042_TTE, &data); | |
428 | if (ret < 0) | |
429 | return ret; | |
430 | ||
431 | val->intval = data * 5625 / 1000; | |
432 | break; | |
359ab9f5 MH |
433 | default: |
434 | return -EINVAL; | |
435 | } | |
436 | return 0; | |
437 | } | |
438 | ||
edd4ab05 RP |
439 | static int max17042_set_property(struct power_supply *psy, |
440 | enum power_supply_property psp, | |
441 | const union power_supply_propval *val) | |
442 | { | |
443 | struct max17042_chip *chip = power_supply_get_drvdata(psy); | |
444 | struct regmap *map = chip->regmap; | |
445 | int ret = 0; | |
446 | u32 data; | |
447 | int8_t temp; | |
448 | ||
449 | switch (psp) { | |
450 | case POWER_SUPPLY_PROP_TEMP_ALERT_MIN: | |
451 | ret = regmap_read(map, MAX17042_TALRT_Th, &data); | |
452 | if (ret < 0) | |
453 | return ret; | |
454 | ||
455 | /* Input in deci-centigrade, convert to centigrade */ | |
456 | temp = val->intval / 10; | |
457 | /* force min < max */ | |
458 | if (temp >= (int8_t)(data >> 8)) | |
459 | temp = (int8_t)(data >> 8) - 1; | |
460 | /* Write both MAX and MIN ALERT */ | |
461 | data = (data & 0xff00) + temp; | |
462 | ret = regmap_write(map, MAX17042_TALRT_Th, data); | |
463 | break; | |
464 | case POWER_SUPPLY_PROP_TEMP_ALERT_MAX: | |
465 | ret = regmap_read(map, MAX17042_TALRT_Th, &data); | |
466 | if (ret < 0) | |
467 | return ret; | |
468 | ||
469 | /* Input in Deci-Centigrade, convert to centigrade */ | |
470 | temp = val->intval / 10; | |
471 | /* force max > min */ | |
472 | if (temp <= (int8_t)(data & 0xff)) | |
473 | temp = (int8_t)(data & 0xff) + 1; | |
474 | /* Write both MAX and MIN ALERT */ | |
475 | data = (data & 0xff) + (temp << 8); | |
476 | ret = regmap_write(map, MAX17042_TALRT_Th, data); | |
477 | break; | |
478 | default: | |
479 | ret = -EINVAL; | |
480 | } | |
481 | ||
482 | return ret; | |
483 | } | |
484 | ||
485 | static int max17042_property_is_writeable(struct power_supply *psy, | |
486 | enum power_supply_property psp) | |
487 | { | |
488 | int ret; | |
489 | ||
490 | switch (psp) { | |
491 | case POWER_SUPPLY_PROP_TEMP_ALERT_MIN: | |
492 | case POWER_SUPPLY_PROP_TEMP_ALERT_MAX: | |
493 | ret = 1; | |
494 | break; | |
495 | default: | |
496 | ret = 0; | |
497 | } | |
498 | ||
499 | return ret; | |
500 | } | |
501 | ||
dcdddda8 HG |
502 | static void max17042_external_power_changed(struct power_supply *psy) |
503 | { | |
504 | power_supply_changed(psy); | |
505 | } | |
506 | ||
39e7213e | 507 | static int max17042_write_verify_reg(struct regmap *map, u8 reg, u32 value) |
f3a71a6e RP |
508 | { |
509 | int retries = 8; | |
510 | int ret; | |
39e7213e | 511 | u32 read_value; |
f3a71a6e RP |
512 | |
513 | do { | |
39e7213e JL |
514 | ret = regmap_write(map, reg, value); |
515 | regmap_read(map, reg, &read_value); | |
f3a71a6e RP |
516 | if (read_value != value) { |
517 | ret = -EIO; | |
518 | retries--; | |
519 | } | |
520 | } while (retries && read_value != value); | |
521 | ||
522 | if (ret < 0) | |
39e7213e | 523 | pr_err("%s: err %d\n", __func__, ret); |
f3a71a6e RP |
524 | |
525 | return ret; | |
526 | } | |
527 | ||
39e7213e JL |
528 | static inline void max17042_override_por(struct regmap *map, |
529 | u8 reg, u16 value) | |
f3a71a6e RP |
530 | { |
531 | if (value) | |
39e7213e | 532 | regmap_write(map, reg, value); |
f3a71a6e RP |
533 | } |
534 | ||
40badfa3 | 535 | static inline void max17042_unlock_model(struct max17042_chip *chip) |
f3a71a6e | 536 | { |
39e7213e | 537 | struct regmap *map = chip->regmap; |
bbaeeaaf | 538 | |
39e7213e JL |
539 | regmap_write(map, MAX17042_MLOCKReg1, MODEL_UNLOCK1); |
540 | regmap_write(map, MAX17042_MLOCKReg2, MODEL_UNLOCK2); | |
f3a71a6e RP |
541 | } |
542 | ||
40badfa3 | 543 | static inline void max17042_lock_model(struct max17042_chip *chip) |
f3a71a6e | 544 | { |
39e7213e JL |
545 | struct regmap *map = chip->regmap; |
546 | ||
547 | regmap_write(map, MAX17042_MLOCKReg1, MODEL_LOCK1); | |
548 | regmap_write(map, MAX17042_MLOCKReg2, MODEL_LOCK2); | |
f3a71a6e RP |
549 | } |
550 | ||
551 | static inline void max17042_write_model_data(struct max17042_chip *chip, | |
552 | u8 addr, int size) | |
553 | { | |
39e7213e | 554 | struct regmap *map = chip->regmap; |
f3a71a6e | 555 | int i; |
bbaeeaaf | 556 | |
f3a71a6e | 557 | for (i = 0; i < size; i++) |
39e7213e JL |
558 | regmap_write(map, addr + i, |
559 | chip->pdata->config_data->cell_char_tbl[i]); | |
f3a71a6e RP |
560 | } |
561 | ||
562 | static inline void max17042_read_model_data(struct max17042_chip *chip, | |
5381cfb6 | 563 | u8 addr, u16 *data, int size) |
f3a71a6e | 564 | { |
39e7213e | 565 | struct regmap *map = chip->regmap; |
f3a71a6e | 566 | int i; |
5381cfb6 | 567 | u32 tmp; |
f3a71a6e | 568 | |
5381cfb6 SVA |
569 | for (i = 0; i < size; i++) { |
570 | regmap_read(map, addr + i, &tmp); | |
571 | data[i] = (u16)tmp; | |
572 | } | |
f3a71a6e RP |
573 | } |
574 | ||
575 | static inline int max17042_model_data_compare(struct max17042_chip *chip, | |
576 | u16 *data1, u16 *data2, int size) | |
577 | { | |
578 | int i; | |
579 | ||
580 | if (memcmp(data1, data2, size)) { | |
581 | dev_err(&chip->client->dev, "%s compare failed\n", __func__); | |
582 | for (i = 0; i < size; i++) | |
583 | dev_info(&chip->client->dev, "0x%x, 0x%x", | |
584 | data1[i], data2[i]); | |
585 | dev_info(&chip->client->dev, "\n"); | |
586 | return -EINVAL; | |
587 | } | |
588 | return 0; | |
589 | } | |
590 | ||
591 | static int max17042_init_model(struct max17042_chip *chip) | |
592 | { | |
593 | int ret; | |
1ef3d8fb | 594 | int table_size = ARRAY_SIZE(chip->pdata->config_data->cell_char_tbl); |
5381cfb6 | 595 | u16 *temp_data; |
f3a71a6e | 596 | |
1ef3d8fb | 597 | temp_data = kcalloc(table_size, sizeof(*temp_data), GFP_KERNEL); |
f3a71a6e RP |
598 | if (!temp_data) |
599 | return -ENOMEM; | |
600 | ||
40badfa3 | 601 | max17042_unlock_model(chip); |
f3a71a6e RP |
602 | max17042_write_model_data(chip, MAX17042_MODELChrTbl, |
603 | table_size); | |
604 | max17042_read_model_data(chip, MAX17042_MODELChrTbl, temp_data, | |
605 | table_size); | |
606 | ||
607 | ret = max17042_model_data_compare( | |
608 | chip, | |
609 | chip->pdata->config_data->cell_char_tbl, | |
5381cfb6 | 610 | temp_data, |
f3a71a6e RP |
611 | table_size); |
612 | ||
40badfa3 | 613 | max17042_lock_model(chip); |
f3a71a6e RP |
614 | kfree(temp_data); |
615 | ||
616 | return ret; | |
617 | } | |
618 | ||
619 | static int max17042_verify_model_lock(struct max17042_chip *chip) | |
620 | { | |
621 | int i; | |
1ef3d8fb | 622 | int table_size = ARRAY_SIZE(chip->pdata->config_data->cell_char_tbl); |
5381cfb6 | 623 | u16 *temp_data; |
f3a71a6e RP |
624 | int ret = 0; |
625 | ||
1ef3d8fb | 626 | temp_data = kcalloc(table_size, sizeof(*temp_data), GFP_KERNEL); |
f3a71a6e RP |
627 | if (!temp_data) |
628 | return -ENOMEM; | |
629 | ||
630 | max17042_read_model_data(chip, MAX17042_MODELChrTbl, temp_data, | |
631 | table_size); | |
632 | for (i = 0; i < table_size; i++) | |
633 | if (temp_data[i]) | |
634 | ret = -EINVAL; | |
635 | ||
636 | kfree(temp_data); | |
637 | return ret; | |
638 | } | |
639 | ||
640 | static void max17042_write_config_regs(struct max17042_chip *chip) | |
641 | { | |
642 | struct max17042_config_data *config = chip->pdata->config_data; | |
39e7213e | 643 | struct regmap *map = chip->regmap; |
f3a71a6e | 644 | |
39e7213e JL |
645 | regmap_write(map, MAX17042_CONFIG, config->config); |
646 | regmap_write(map, MAX17042_LearnCFG, config->learn_cfg); | |
647 | regmap_write(map, MAX17042_FilterCFG, | |
f3a71a6e | 648 | config->filter_cfg); |
39e7213e | 649 | regmap_write(map, MAX17042_RelaxCFG, config->relax_cfg); |
709c2c70 | 650 | if (chip->chip_type == MAXIM_DEVICE_TYPE_MAX17047 || |
bc90705b AAP |
651 | chip->chip_type == MAXIM_DEVICE_TYPE_MAX17050 || |
652 | chip->chip_type == MAXIM_DEVICE_TYPE_MAX17055) | |
39e7213e | 653 | regmap_write(map, MAX17047_FullSOCThr, |
9a8422d2 | 654 | config->full_soc_thresh); |
f3a71a6e RP |
655 | } |
656 | ||
657 | static void max17042_write_custom_regs(struct max17042_chip *chip) | |
658 | { | |
659 | struct max17042_config_data *config = chip->pdata->config_data; | |
39e7213e | 660 | struct regmap *map = chip->regmap; |
f3a71a6e | 661 | |
39e7213e JL |
662 | max17042_write_verify_reg(map, MAX17042_RCOMP0, config->rcomp0); |
663 | max17042_write_verify_reg(map, MAX17042_TempCo, config->tcompc0); | |
664 | max17042_write_verify_reg(map, MAX17042_ICHGTerm, config->ichgt_term); | |
709c2c70 | 665 | if (chip->chip_type == MAXIM_DEVICE_TYPE_MAX17042) { |
39e7213e JL |
666 | regmap_write(map, MAX17042_EmptyTempCo, config->empty_tempco); |
667 | max17042_write_verify_reg(map, MAX17042_K_empty0, | |
9a8422d2 RP |
668 | config->kempty0); |
669 | } else { | |
39e7213e | 670 | max17042_write_verify_reg(map, MAX17047_QRTbl00, |
9a8422d2 | 671 | config->qrtbl00); |
39e7213e | 672 | max17042_write_verify_reg(map, MAX17047_QRTbl10, |
9a8422d2 | 673 | config->qrtbl10); |
39e7213e | 674 | max17042_write_verify_reg(map, MAX17047_QRTbl20, |
9a8422d2 | 675 | config->qrtbl20); |
39e7213e | 676 | max17042_write_verify_reg(map, MAX17047_QRTbl30, |
9a8422d2 RP |
677 | config->qrtbl30); |
678 | } | |
f3a71a6e RP |
679 | } |
680 | ||
681 | static void max17042_update_capacity_regs(struct max17042_chip *chip) | |
682 | { | |
683 | struct max17042_config_data *config = chip->pdata->config_data; | |
39e7213e | 684 | struct regmap *map = chip->regmap; |
f3a71a6e | 685 | |
39e7213e | 686 | max17042_write_verify_reg(map, MAX17042_FullCAP, |
f3a71a6e | 687 | config->fullcap); |
39e7213e JL |
688 | regmap_write(map, MAX17042_DesignCap, config->design_cap); |
689 | max17042_write_verify_reg(map, MAX17042_FullCAPNom, | |
f3a71a6e RP |
690 | config->fullcapnom); |
691 | } | |
692 | ||
693 | static void max17042_reset_vfsoc0_reg(struct max17042_chip *chip) | |
694 | { | |
39e7213e JL |
695 | unsigned int vfSoc; |
696 | struct regmap *map = chip->regmap; | |
f3a71a6e | 697 | |
39e7213e JL |
698 | regmap_read(map, MAX17042_VFSOC, &vfSoc); |
699 | regmap_write(map, MAX17042_VFSOC0Enable, VFSOC0_UNLOCK); | |
700 | max17042_write_verify_reg(map, MAX17042_VFSOC0, vfSoc); | |
701 | regmap_write(map, MAX17042_VFSOC0Enable, VFSOC0_LOCK); | |
f3a71a6e RP |
702 | } |
703 | ||
704 | static void max17042_load_new_capacity_params(struct max17042_chip *chip) | |
705 | { | |
39e7213e | 706 | u32 full_cap0, rep_cap, dq_acc, vfSoc; |
f3a71a6e RP |
707 | u32 rem_cap; |
708 | ||
709 | struct max17042_config_data *config = chip->pdata->config_data; | |
39e7213e | 710 | struct regmap *map = chip->regmap; |
f3a71a6e | 711 | |
39e7213e JL |
712 | regmap_read(map, MAX17042_FullCAP0, &full_cap0); |
713 | regmap_read(map, MAX17042_VFSOC, &vfSoc); | |
f3a71a6e RP |
714 | |
715 | /* fg_vfSoc needs to shifted by 8 bits to get the | |
716 | * perc in 1% accuracy, to get the right rem_cap multiply | |
717 | * full_cap0, fg_vfSoc and devide by 100 | |
718 | */ | |
719 | rem_cap = ((vfSoc >> 8) * full_cap0) / 100; | |
39e7213e | 720 | max17042_write_verify_reg(map, MAX17042_RemCap, rem_cap); |
f3a71a6e | 721 | |
39e7213e JL |
722 | rep_cap = rem_cap; |
723 | max17042_write_verify_reg(map, MAX17042_RepCap, rep_cap); | |
f3a71a6e RP |
724 | |
725 | /* Write dQ_acc to 200% of Capacity and dP_acc to 200% */ | |
726 | dq_acc = config->fullcap / dQ_ACC_DIV; | |
39e7213e JL |
727 | max17042_write_verify_reg(map, MAX17042_dQacc, dq_acc); |
728 | max17042_write_verify_reg(map, MAX17042_dPacc, dP_ACC_200); | |
f3a71a6e | 729 | |
39e7213e | 730 | max17042_write_verify_reg(map, MAX17042_FullCAP, |
f3a71a6e | 731 | config->fullcap); |
39e7213e | 732 | regmap_write(map, MAX17042_DesignCap, |
f3a71a6e | 733 | config->design_cap); |
39e7213e | 734 | max17042_write_verify_reg(map, MAX17042_FullCAPNom, |
f3a71a6e | 735 | config->fullcapnom); |
9a8422d2 | 736 | /* Update SOC register with new SOC */ |
39e7213e | 737 | regmap_write(map, MAX17042_RepSOC, vfSoc); |
f3a71a6e RP |
738 | } |
739 | ||
740 | /* | |
741 | * Block write all the override values coming from platform data. | |
37ad56aa | 742 | * This function MUST be called before the POR initialization procedure |
f3a71a6e RP |
743 | * specified by maxim. |
744 | */ | |
745 | static inline void max17042_override_por_values(struct max17042_chip *chip) | |
746 | { | |
39e7213e | 747 | struct regmap *map = chip->regmap; |
f3a71a6e RP |
748 | struct max17042_config_data *config = chip->pdata->config_data; |
749 | ||
39e7213e JL |
750 | max17042_override_por(map, MAX17042_TGAIN, config->tgain); |
751 | max17042_override_por(map, MAx17042_TOFF, config->toff); | |
752 | max17042_override_por(map, MAX17042_CGAIN, config->cgain); | |
753 | max17042_override_por(map, MAX17042_COFF, config->coff); | |
754 | ||
755 | max17042_override_por(map, MAX17042_VALRT_Th, config->valrt_thresh); | |
756 | max17042_override_por(map, MAX17042_TALRT_Th, config->talrt_thresh); | |
757 | max17042_override_por(map, MAX17042_SALRT_Th, | |
758 | config->soc_alrt_thresh); | |
759 | max17042_override_por(map, MAX17042_CONFIG, config->config); | |
760 | max17042_override_por(map, MAX17042_SHDNTIMER, config->shdntimer); | |
761 | ||
762 | max17042_override_por(map, MAX17042_DesignCap, config->design_cap); | |
763 | max17042_override_por(map, MAX17042_ICHGTerm, config->ichgt_term); | |
764 | ||
765 | max17042_override_por(map, MAX17042_AtRate, config->at_rate); | |
766 | max17042_override_por(map, MAX17042_LearnCFG, config->learn_cfg); | |
767 | max17042_override_por(map, MAX17042_FilterCFG, config->filter_cfg); | |
768 | max17042_override_por(map, MAX17042_RelaxCFG, config->relax_cfg); | |
769 | max17042_override_por(map, MAX17042_MiscCFG, config->misc_cfg); | |
770 | max17042_override_por(map, MAX17042_MaskSOC, config->masksoc); | |
771 | ||
772 | max17042_override_por(map, MAX17042_FullCAP, config->fullcap); | |
773 | max17042_override_por(map, MAX17042_FullCAPNom, config->fullcapnom); | |
709c2c70 | 774 | if (chip->chip_type == MAXIM_DEVICE_TYPE_MAX17042) |
39e7213e | 775 | max17042_override_por(map, MAX17042_SOC_empty, |
9a8422d2 | 776 | config->socempty); |
39e7213e JL |
777 | max17042_override_por(map, MAX17042_LAvg_empty, config->lavg_empty); |
778 | max17042_override_por(map, MAX17042_dQacc, config->dqacc); | |
779 | max17042_override_por(map, MAX17042_dPacc, config->dpacc); | |
f3a71a6e | 780 | |
709c2c70 | 781 | if (chip->chip_type == MAXIM_DEVICE_TYPE_MAX17042) |
39e7213e | 782 | max17042_override_por(map, MAX17042_V_empty, config->vempty); |
bc90705b AAP |
783 | if (chip->chip_type == MAXIM_DEVICE_TYPE_MAX17055) |
784 | max17042_override_por(map, MAX17055_V_empty, config->vempty); | |
9a8422d2 | 785 | else |
39e7213e JL |
786 | max17042_override_por(map, MAX17047_V_empty, config->vempty); |
787 | max17042_override_por(map, MAX17042_TempNom, config->temp_nom); | |
788 | max17042_override_por(map, MAX17042_TempLim, config->temp_lim); | |
789 | max17042_override_por(map, MAX17042_FCTC, config->fctc); | |
790 | max17042_override_por(map, MAX17042_RCOMP0, config->rcomp0); | |
791 | max17042_override_por(map, MAX17042_TempCo, config->tcompc0); | |
bc90705b AAP |
792 | if (chip->chip_type && |
793 | ((chip->chip_type == MAXIM_DEVICE_TYPE_MAX17042) || | |
794 | (chip->chip_type == MAXIM_DEVICE_TYPE_MAX17047) || | |
795 | (chip->chip_type == MAXIM_DEVICE_TYPE_MAX17050))) { | |
39e7213e JL |
796 | max17042_override_por(map, MAX17042_EmptyTempCo, |
797 | config->empty_tempco); | |
798 | max17042_override_por(map, MAX17042_K_empty0, | |
799 | config->kempty0); | |
9a8422d2 | 800 | } |
f3a71a6e RP |
801 | } |
802 | ||
803 | static int max17042_init_chip(struct max17042_chip *chip) | |
804 | { | |
39e7213e | 805 | struct regmap *map = chip->regmap; |
f3a71a6e | 806 | int ret; |
f3a71a6e RP |
807 | |
808 | max17042_override_por_values(chip); | |
809 | /* After Power up, the MAX17042 requires 500mS in order | |
810 | * to perform signal debouncing and initial SOC reporting | |
811 | */ | |
812 | msleep(500); | |
813 | ||
37ad56aa | 814 | /* Initialize configuration */ |
f3a71a6e RP |
815 | max17042_write_config_regs(chip); |
816 | ||
817 | /* write cell characterization data */ | |
818 | ret = max17042_init_model(chip); | |
819 | if (ret) { | |
820 | dev_err(&chip->client->dev, "%s init failed\n", | |
821 | __func__); | |
822 | return -EIO; | |
823 | } | |
a879f19f AC |
824 | |
825 | ret = max17042_verify_model_lock(chip); | |
f3a71a6e RP |
826 | if (ret) { |
827 | dev_err(&chip->client->dev, "%s lock verify failed\n", | |
828 | __func__); | |
829 | return -EIO; | |
830 | } | |
831 | /* write custom parameters */ | |
832 | max17042_write_custom_regs(chip); | |
833 | ||
834 | /* update capacity params */ | |
835 | max17042_update_capacity_regs(chip); | |
836 | ||
837 | /* delay must be atleast 350mS to allow VFSOC | |
838 | * to be calculated from the new configuration | |
839 | */ | |
840 | msleep(350); | |
841 | ||
842 | /* reset vfsoc0 reg */ | |
843 | max17042_reset_vfsoc0_reg(chip); | |
844 | ||
845 | /* load new capacity params */ | |
846 | max17042_load_new_capacity_params(chip); | |
847 | ||
848 | /* Init complete, Clear the POR bit */ | |
bc352686 | 849 | regmap_update_bits(map, MAX17042_STATUS, STATUS_POR_BIT, 0x0); |
f3a71a6e RP |
850 | return 0; |
851 | } | |
852 | ||
e5f3872d RP |
853 | static void max17042_set_soc_threshold(struct max17042_chip *chip, u16 off) |
854 | { | |
39e7213e JL |
855 | struct regmap *map = chip->regmap; |
856 | u32 soc, soc_tr; | |
e5f3872d | 857 | |
37ad56aa | 858 | /* program interrupt thresholds such that we should |
e5f3872d RP |
859 | * get interrupt for every 'off' perc change in the soc |
860 | */ | |
39e7213e JL |
861 | regmap_read(map, MAX17042_RepSOC, &soc); |
862 | soc >>= 8; | |
e5f3872d RP |
863 | soc_tr = (soc + off) << 8; |
864 | soc_tr |= (soc - off); | |
39e7213e | 865 | regmap_write(map, MAX17042_SALRT_Th, soc_tr); |
e5f3872d RP |
866 | } |
867 | ||
e5f3872d RP |
868 | static irqreturn_t max17042_thread_handler(int id, void *dev) |
869 | { | |
870 | struct max17042_chip *chip = dev; | |
39e7213e | 871 | u32 val; |
e5f3872d | 872 | |
39e7213e | 873 | regmap_read(chip->regmap, MAX17042_STATUS, &val); |
5cdd4d7f RP |
874 | if ((val & STATUS_INTR_SOCMIN_BIT) || |
875 | (val & STATUS_INTR_SOCMAX_BIT)) { | |
e5f3872d RP |
876 | dev_info(&chip->client->dev, "SOC threshold INTR\n"); |
877 | max17042_set_soc_threshold(chip, 1); | |
878 | } | |
879 | ||
297d716f | 880 | power_supply_changed(chip->battery); |
e5f3872d RP |
881 | return IRQ_HANDLED; |
882 | } | |
f3a71a6e RP |
883 | |
884 | static void max17042_init_worker(struct work_struct *work) | |
885 | { | |
886 | struct max17042_chip *chip = container_of(work, | |
887 | struct max17042_chip, work); | |
888 | int ret; | |
889 | ||
890 | /* Initialize registers according to values from the platform data */ | |
891 | if (chip->pdata->enable_por_init && chip->pdata->config_data) { | |
892 | ret = max17042_init_chip(chip); | |
893 | if (ret) | |
894 | return; | |
895 | } | |
896 | ||
897 | chip->init_complete = 1; | |
898 | } | |
899 | ||
3832246d KL |
900 | #ifdef CONFIG_OF |
901 | static struct max17042_platform_data * | |
2d7e6a83 | 902 | max17042_get_of_pdata(struct max17042_chip *chip) |
3832246d | 903 | { |
91736213 | 904 | struct device *dev = &chip->client->dev; |
3832246d KL |
905 | struct device_node *np = dev->of_node; |
906 | u32 prop; | |
907 | struct max17042_platform_data *pdata; | |
908 | ||
3832246d KL |
909 | pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); |
910 | if (!pdata) | |
911 | return NULL; | |
912 | ||
913 | /* | |
914 | * Require current sense resistor value to be specified for | |
915 | * current-sense functionality to be enabled at all. | |
916 | */ | |
917 | if (of_property_read_u32(np, "maxim,rsns-microohm", &prop) == 0) { | |
918 | pdata->r_sns = prop; | |
919 | pdata->enable_current_sense = true; | |
920 | } | |
921 | ||
a6e6b63e KK |
922 | if (of_property_read_s32(np, "maxim,cold-temp", &pdata->temp_min)) |
923 | pdata->temp_min = INT_MIN; | |
924 | if (of_property_read_s32(np, "maxim,over-heat-temp", &pdata->temp_max)) | |
925 | pdata->temp_max = INT_MAX; | |
926 | if (of_property_read_s32(np, "maxim,dead-volt", &pdata->vmin)) | |
927 | pdata->vmin = INT_MIN; | |
928 | if (of_property_read_s32(np, "maxim,over-volt", &pdata->vmax)) | |
929 | pdata->vmax = INT_MAX; | |
930 | ||
3832246d KL |
931 | return pdata; |
932 | } | |
2d7e6a83 HG |
933 | #endif |
934 | ||
91736213 HG |
935 | static struct max17042_reg_data max17047_default_pdata_init_regs[] = { |
936 | /* | |
937 | * Some firmwares do not set FullSOCThr, Enable End-of-Charge Detection | |
938 | * when the voltage FG reports 95%, as recommended in the datasheet. | |
939 | */ | |
940 | { MAX17047_FullSOCThr, MAX17042_BATTERY_FULL << 8 }, | |
941 | }; | |
942 | ||
3832246d | 943 | static struct max17042_platform_data * |
2d7e6a83 | 944 | max17042_get_default_pdata(struct max17042_chip *chip) |
3832246d | 945 | { |
91736213 HG |
946 | struct device *dev = &chip->client->dev; |
947 | struct max17042_platform_data *pdata; | |
948 | int ret, misc_cfg; | |
949 | ||
91736213 HG |
950 | /* |
951 | * The MAX17047 gets used on x86 where we might not have pdata, assume | |
952 | * the firmware will already have initialized the fuel-gauge and provide | |
953 | * default values for the non init bits to make things work. | |
954 | */ | |
955 | pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); | |
956 | if (!pdata) | |
957 | return pdata; | |
958 | ||
bc90705b AAP |
959 | if ((chip->chip_type == MAXIM_DEVICE_TYPE_MAX17047) || |
960 | (chip->chip_type == MAXIM_DEVICE_TYPE_MAX17050)) { | |
91736213 HG |
961 | pdata->init_data = max17047_default_pdata_init_regs; |
962 | pdata->num_init_data = | |
963 | ARRAY_SIZE(max17047_default_pdata_init_regs); | |
964 | } | |
965 | ||
966 | ret = regmap_read(chip->regmap, MAX17042_MiscCFG, &misc_cfg); | |
967 | if (ret < 0) | |
968 | return NULL; | |
969 | ||
970 | /* If bits 0-1 are set to 3 then only Voltage readings are used */ | |
971 | if ((misc_cfg & 0x3) == 0x3) | |
972 | pdata->enable_current_sense = false; | |
973 | else | |
974 | pdata->enable_current_sense = true; | |
975 | ||
976 | pdata->vmin = MAX17042_DEFAULT_VMIN; | |
977 | pdata->vmax = MAX17042_DEFAULT_VMAX; | |
978 | pdata->temp_min = MAX17042_DEFAULT_TEMP_MIN; | |
979 | pdata->temp_max = MAX17042_DEFAULT_TEMP_MAX; | |
980 | ||
981 | return pdata; | |
3832246d | 982 | } |
2d7e6a83 HG |
983 | |
984 | static struct max17042_platform_data * | |
985 | max17042_get_pdata(struct max17042_chip *chip) | |
986 | { | |
987 | struct device *dev = &chip->client->dev; | |
988 | ||
989 | #ifdef CONFIG_OF | |
990 | if (dev->of_node) | |
991 | return max17042_get_of_pdata(chip); | |
3832246d | 992 | #endif |
2d7e6a83 HG |
993 | if (dev->platform_data) |
994 | return dev->platform_data; | |
995 | ||
996 | return max17042_get_default_pdata(chip); | |
997 | } | |
3832246d | 998 | |
e0291285 | 999 | static const struct regmap_config max17042_regmap_config = { |
39e7213e JL |
1000 | .reg_bits = 8, |
1001 | .val_bits = 16, | |
1002 | .val_format_endian = REGMAP_ENDIAN_NATIVE, | |
1003 | }; | |
1004 | ||
297d716f KK |
1005 | static const struct power_supply_desc max17042_psy_desc = { |
1006 | .name = "max170xx_battery", | |
1007 | .type = POWER_SUPPLY_TYPE_BATTERY, | |
1008 | .get_property = max17042_get_property, | |
edd4ab05 RP |
1009 | .set_property = max17042_set_property, |
1010 | .property_is_writeable = max17042_property_is_writeable, | |
dcdddda8 | 1011 | .external_power_changed = max17042_external_power_changed, |
297d716f KK |
1012 | .properties = max17042_battery_props, |
1013 | .num_properties = ARRAY_SIZE(max17042_battery_props), | |
1014 | }; | |
1015 | ||
1016 | static const struct power_supply_desc max17042_no_current_sense_psy_desc = { | |
1017 | .name = "max170xx_battery", | |
1018 | .type = POWER_SUPPLY_TYPE_BATTERY, | |
1019 | .get_property = max17042_get_property, | |
edd4ab05 RP |
1020 | .set_property = max17042_set_property, |
1021 | .property_is_writeable = max17042_property_is_writeable, | |
297d716f KK |
1022 | .properties = max17042_battery_props, |
1023 | .num_properties = ARRAY_SIZE(max17042_battery_props) - 2, | |
1024 | }; | |
1025 | ||
bf592c56 SVA |
1026 | static void max17042_stop_work(void *data) |
1027 | { | |
1028 | struct max17042_chip *chip = data; | |
1029 | ||
1030 | cancel_work_sync(&chip->work); | |
1031 | } | |
1032 | ||
c8afa640 | 1033 | static int max17042_probe(struct i2c_client *client, |
359ab9f5 MH |
1034 | const struct i2c_device_id *id) |
1035 | { | |
dee2f3cf | 1036 | struct i2c_adapter *adapter = client->adapter; |
297d716f KK |
1037 | const struct power_supply_desc *max17042_desc = &max17042_psy_desc; |
1038 | struct power_supply_config psy_cfg = {}; | |
4f1e0cb7 | 1039 | const struct acpi_device_id *acpi_id = NULL; |
e2116202 | 1040 | struct device *dev = &client->dev; |
359ab9f5 MH |
1041 | struct max17042_chip *chip; |
1042 | int ret; | |
39e7213e JL |
1043 | int i; |
1044 | u32 val; | |
359ab9f5 MH |
1045 | |
1046 | if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA)) | |
1047 | return -EIO; | |
1048 | ||
2f3b4342 | 1049 | chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL); |
359ab9f5 MH |
1050 | if (!chip) |
1051 | return -ENOMEM; | |
1052 | ||
1053 | chip->client = client; | |
e2116202 HG |
1054 | if (id) { |
1055 | chip->chip_type = id->driver_data; | |
1056 | } else { | |
1057 | acpi_id = acpi_match_device(dev->driver->acpi_match_table, dev); | |
1058 | if (!acpi_id) | |
1059 | return -ENODEV; | |
1060 | ||
1061 | chip->chip_type = acpi_id->driver_data; | |
1062 | } | |
39e7213e JL |
1063 | chip->regmap = devm_regmap_init_i2c(client, &max17042_regmap_config); |
1064 | if (IS_ERR(chip->regmap)) { | |
1065 | dev_err(&client->dev, "Failed to initialize regmap\n"); | |
1066 | return -EINVAL; | |
1067 | } | |
1068 | ||
91736213 | 1069 | chip->pdata = max17042_get_pdata(chip); |
3832246d KL |
1070 | if (!chip->pdata) { |
1071 | dev_err(&client->dev, "no platform data provided\n"); | |
1072 | return -EINVAL; | |
1073 | } | |
359ab9f5 MH |
1074 | |
1075 | i2c_set_clientdata(client, chip); | |
297d716f | 1076 | psy_cfg.drv_data = chip; |
66ec32fc | 1077 | psy_cfg.of_node = dev->of_node; |
359ab9f5 | 1078 | |
086ef502 DK |
1079 | /* When current is not measured, |
1080 | * CURRENT_NOW and CURRENT_AVG properties should be invisible. */ | |
1081 | if (!chip->pdata->enable_current_sense) | |
297d716f | 1082 | max17042_desc = &max17042_no_current_sense_psy_desc; |
086ef502 | 1083 | |
4cfa892c PR |
1084 | if (chip->pdata->r_sns == 0) |
1085 | chip->pdata->r_sns = MAX17042_DEFAULT_SNS_RESISTOR; | |
1086 | ||
086ef502 | 1087 | if (chip->pdata->init_data) |
39e7213e JL |
1088 | for (i = 0; i < chip->pdata->num_init_data; i++) |
1089 | regmap_write(chip->regmap, | |
1090 | chip->pdata->init_data[i].addr, | |
1091 | chip->pdata->init_data[i].data); | |
086ef502 | 1092 | |
359ab9f5 | 1093 | if (!chip->pdata->enable_current_sense) { |
39e7213e JL |
1094 | regmap_write(chip->regmap, MAX17042_CGAIN, 0x0000); |
1095 | regmap_write(chip->regmap, MAX17042_MiscCFG, 0x0003); | |
1096 | regmap_write(chip->regmap, MAX17042_LearnCFG, 0x0007); | |
359ab9f5 MH |
1097 | } |
1098 | ||
50bddb99 VT |
1099 | chip->battery = devm_power_supply_register(&client->dev, max17042_desc, |
1100 | &psy_cfg); | |
297d716f | 1101 | if (IS_ERR(chip->battery)) { |
243e3527 | 1102 | dev_err(&client->dev, "failed: power supply register\n"); |
297d716f | 1103 | return PTR_ERR(chip->battery); |
243e3527 RP |
1104 | } |
1105 | ||
e5f3872d | 1106 | if (client->irq) { |
a865a155 HG |
1107 | unsigned int flags = IRQF_TRIGGER_FALLING | IRQF_ONESHOT; |
1108 | ||
1109 | /* | |
1110 | * On ACPI systems the IRQ may be handled by ACPI-event code, | |
1111 | * so we need to share (if the ACPI code is willing to share). | |
1112 | */ | |
1113 | if (acpi_id) | |
1114 | flags |= IRQF_SHARED | IRQF_PROBE_SHARED; | |
1115 | ||
50bddb99 VT |
1116 | ret = devm_request_threaded_irq(&client->dev, client->irq, |
1117 | NULL, | |
a865a155 | 1118 | max17042_thread_handler, flags, |
50bddb99 VT |
1119 | chip->battery->desc->name, |
1120 | chip); | |
e5f3872d | 1121 | if (!ret) { |
bc352686 KK |
1122 | regmap_update_bits(chip->regmap, MAX17042_CONFIG, |
1123 | CONFIG_ALRT_BIT_ENBL, | |
1124 | CONFIG_ALRT_BIT_ENBL); | |
e5f3872d | 1125 | max17042_set_soc_threshold(chip, 1); |
e5ba50bc RP |
1126 | } else { |
1127 | client->irq = 0; | |
a865a155 HG |
1128 | if (ret != -EBUSY) |
1129 | dev_err(&client->dev, "Failed to get IRQ\n"); | |
e5ba50bc | 1130 | } |
e5f3872d | 1131 | } |
a865a155 HG |
1132 | /* Not able to update the charge threshold when exceeded? -> disable */ |
1133 | if (!client->irq) | |
1134 | regmap_write(chip->regmap, MAX17042_SALRT_Th, 0xff00); | |
e5f3872d | 1135 | |
39e7213e JL |
1136 | regmap_read(chip->regmap, MAX17042_STATUS, &val); |
1137 | if (val & STATUS_POR_BIT) { | |
f3a71a6e | 1138 | INIT_WORK(&chip->work, max17042_init_worker); |
bf592c56 SVA |
1139 | ret = devm_add_action(&client->dev, max17042_stop_work, chip); |
1140 | if (ret) | |
1141 | return ret; | |
f3a71a6e RP |
1142 | schedule_work(&chip->work); |
1143 | } else { | |
1144 | chip->init_complete = 1; | |
1145 | } | |
1146 | ||
243e3527 | 1147 | return 0; |
359ab9f5 MH |
1148 | } |
1149 | ||
3d23c7f4 | 1150 | #ifdef CONFIG_PM_SLEEP |
48bc1774 RP |
1151 | static int max17042_suspend(struct device *dev) |
1152 | { | |
1153 | struct max17042_chip *chip = dev_get_drvdata(dev); | |
1154 | ||
48e41c70 AV |
1155 | /* |
1156 | * disable the irq and enable irq_wake | |
48bc1774 RP |
1157 | * capability to the interrupt line. |
1158 | */ | |
1159 | if (chip->client->irq) { | |
1160 | disable_irq(chip->client->irq); | |
1161 | enable_irq_wake(chip->client->irq); | |
1162 | } | |
1163 | ||
1164 | return 0; | |
1165 | } | |
1166 | ||
1167 | static int max17042_resume(struct device *dev) | |
1168 | { | |
1169 | struct max17042_chip *chip = dev_get_drvdata(dev); | |
1170 | ||
1171 | if (chip->client->irq) { | |
1172 | disable_irq_wake(chip->client->irq); | |
1173 | enable_irq(chip->client->irq); | |
1174 | /* re-program the SOC thresholds to 1% change */ | |
1175 | max17042_set_soc_threshold(chip, 1); | |
1176 | } | |
1177 | ||
1178 | return 0; | |
1179 | } | |
48bc1774 RP |
1180 | #endif |
1181 | ||
3d23c7f4 MB |
1182 | static SIMPLE_DEV_PM_OPS(max17042_pm_ops, max17042_suspend, |
1183 | max17042_resume); | |
1184 | ||
e2116202 HG |
1185 | #ifdef CONFIG_ACPI |
1186 | static const struct acpi_device_id max17042_acpi_match[] = { | |
1187 | { "MAX17047", MAXIM_DEVICE_TYPE_MAX17047 }, | |
1188 | { } | |
1189 | }; | |
1190 | MODULE_DEVICE_TABLE(acpi, max17042_acpi_match); | |
1191 | #endif | |
1192 | ||
3832246d KL |
1193 | #ifdef CONFIG_OF |
1194 | static const struct of_device_id max17042_dt_match[] = { | |
1195 | { .compatible = "maxim,max17042" }, | |
9a8422d2 RP |
1196 | { .compatible = "maxim,max17047" }, |
1197 | { .compatible = "maxim,max17050" }, | |
bc90705b | 1198 | { .compatible = "maxim,max17055" }, |
3832246d KL |
1199 | { }, |
1200 | }; | |
1201 | MODULE_DEVICE_TABLE(of, max17042_dt_match); | |
1202 | #endif | |
1203 | ||
359ab9f5 | 1204 | static const struct i2c_device_id max17042_id[] = { |
709c2c70 BS |
1205 | { "max17042", MAXIM_DEVICE_TYPE_MAX17042 }, |
1206 | { "max17047", MAXIM_DEVICE_TYPE_MAX17047 }, | |
1207 | { "max17050", MAXIM_DEVICE_TYPE_MAX17050 }, | |
bc90705b | 1208 | { "max17055", MAXIM_DEVICE_TYPE_MAX17055 }, |
359ab9f5 MH |
1209 | { } |
1210 | }; | |
1211 | MODULE_DEVICE_TABLE(i2c, max17042_id); | |
1212 | ||
1213 | static struct i2c_driver max17042_i2c_driver = { | |
1214 | .driver = { | |
1215 | .name = "max17042", | |
e2116202 | 1216 | .acpi_match_table = ACPI_PTR(max17042_acpi_match), |
3832246d | 1217 | .of_match_table = of_match_ptr(max17042_dt_match), |
3d23c7f4 | 1218 | .pm = &max17042_pm_ops, |
359ab9f5 MH |
1219 | }, |
1220 | .probe = max17042_probe, | |
359ab9f5 MH |
1221 | .id_table = max17042_id, |
1222 | }; | |
5ff92e7a | 1223 | module_i2c_driver(max17042_i2c_driver); |
359ab9f5 MH |
1224 | |
1225 | MODULE_AUTHOR("MyungJoo Ham <myungjoo.ham@samsung.com>"); | |
1226 | MODULE_DESCRIPTION("MAX17042 Fuel Gauge"); | |
1227 | MODULE_LICENSE("GPL"); |