1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* |
3 | * TI BQ25890 charger driver |
4 | * |
5 | * Copyright (C) 2015 Intel Corporation |
6 | */ |
7 | |
8 | #include <linux/module.h> |
9 | #include <linux/i2c.h> |
10 | #include <linux/power_supply.h> |
11 | #include <linux/power/bq25890_charger.h> |
12 | #include <linux/regmap.h> |
13 | #include <linux/regulator/driver.h> |
14 | #include <linux/types.h> |
15 | #include <linux/gpio/consumer.h> |
16 | #include <linux/interrupt.h> |
17 | #include <linux/delay.h> |
18 | #include <linux/usb/phy.h> |
19 | |
20 | #include <linux/acpi.h> |
21 | #include <linux/of.h> |
22 | |
23 | #define BQ25890_MANUFACTURER "Texas Instruments" |
24 | #define BQ25890_IRQ_PIN "bq25890_irq" |
25 | |
26 | #define BQ25890_ID 3 |
27 | #define BQ25895_ID 7 |
28 | #define BQ25896_ID 0 |
29 | |
30 | #define PUMP_EXPRESS_START_DELAY (5 * HZ) |
31 | #define PUMP_EXPRESS_MAX_TRIES 6 |
32 | #define PUMP_EXPRESS_VBUS_MARGIN_uV 1000000 |
33 | |
34 | enum bq25890_chip_version { |
35 | BQ25890, |
36 | BQ25892, |
37 | BQ25895, |
38 | BQ25896, |
39 | }; |
40 | |
41 | static const char *const bq25890_chip_name[] = { |
42 | "BQ25890" , |
43 | "BQ25892" , |
44 | "BQ25895" , |
45 | "BQ25896" , |
46 | }; |
47 | |
48 | enum bq25890_fields { |
49 | F_EN_HIZ, F_EN_ILIM, F_IINLIM, /* Reg00 */ |
50 | F_BHOT, F_BCOLD, F_VINDPM_OFS, /* Reg01 */ |
51 | F_CONV_START, F_CONV_RATE, F_BOOSTF, F_ICO_EN, |
52 | F_HVDCP_EN, F_MAXC_EN, F_FORCE_DPM, F_AUTO_DPDM_EN, /* Reg02 */ |
53 | F_BAT_LOAD_EN, F_WD_RST, F_OTG_CFG, F_CHG_CFG, F_SYSVMIN, |
54 | F_MIN_VBAT_SEL, /* Reg03 */ |
55 | F_PUMPX_EN, F_ICHG, /* Reg04 */ |
56 | F_IPRECHG, F_ITERM, /* Reg05 */ |
57 | F_VREG, F_BATLOWV, F_VRECHG, /* Reg06 */ |
58 | F_TERM_EN, F_STAT_DIS, F_WD, F_TMR_EN, F_CHG_TMR, |
59 | F_JEITA_ISET, /* Reg07 */ |
60 | F_BATCMP, F_VCLAMP, F_TREG, /* Reg08 */ |
61 | F_FORCE_ICO, F_TMR2X_EN, F_BATFET_DIS, F_JEITA_VSET, |
62 | F_BATFET_DLY, F_BATFET_RST_EN, F_PUMPX_UP, F_PUMPX_DN, /* Reg09 */ |
63 | F_BOOSTV, F_PFM_OTG_DIS, F_BOOSTI, /* Reg0A */ |
64 | F_VBUS_STAT, F_CHG_STAT, F_PG_STAT, F_SDP_STAT, F_0B_RSVD, |
65 | F_VSYS_STAT, /* Reg0B */ |
66 | F_WD_FAULT, F_BOOST_FAULT, F_CHG_FAULT, F_BAT_FAULT, |
67 | F_NTC_FAULT, /* Reg0C */ |
68 | F_FORCE_VINDPM, F_VINDPM, /* Reg0D */ |
69 | F_THERM_STAT, F_BATV, /* Reg0E */ |
70 | F_SYSV, /* Reg0F */ |
71 | F_TSPCT, /* Reg10 */ |
72 | F_VBUS_GD, F_VBUSV, /* Reg11 */ |
73 | F_ICHGR, /* Reg12 */ |
74 | F_VDPM_STAT, F_IDPM_STAT, F_IDPM_LIM, /* Reg13 */ |
75 | F_REG_RST, F_ICO_OPTIMIZED, F_PN, F_TS_PROFILE, F_DEV_REV, /* Reg14 */ |
76 | |
77 | F_MAX_FIELDS |
78 | }; |
79 | |
80 | /* initial field values, converted to register values */ |
81 | struct bq25890_init_data { |
82 | u8 ichg; /* charge current */ |
83 | u8 vreg; /* regulation voltage */ |
84 | u8 iterm; /* termination current */ |
85 | u8 iprechg; /* precharge current */ |
86 | u8 sysvmin; /* minimum system voltage limit */ |
87 | u8 boostv; /* boost regulation voltage */ |
88 | u8 boosti; /* boost current limit */ |
89 | u8 boostf; /* boost frequency */ |
90 | u8 ilim_en; /* enable ILIM pin */ |
91 | u8 treg; /* thermal regulation threshold */ |
92 | u8 rbatcomp; /* IBAT sense resistor value */ |
93 | u8 vclamp; /* IBAT compensation voltage limit */ |
94 | }; |
95 | |
96 | struct bq25890_state { |
97 | u8 online; |
98 | u8 hiz; |
99 | u8 chrg_status; |
100 | u8 chrg_fault; |
101 | u8 vsys_status; |
102 | u8 boost_fault; |
103 | u8 bat_fault; |
104 | u8 ntc_fault; |
105 | }; |
106 | |
107 | struct bq25890_device { |
108 | struct i2c_client *client; |
109 | struct device *dev; |
110 | struct power_supply *charger; |
111 | struct power_supply *secondary_chrg; |
112 | struct power_supply_desc desc; |
113 | char name[28]; /* "bq25890-charger-%d" */ |
114 | int id; |
115 | |
116 | struct usb_phy *usb_phy; |
117 | struct notifier_block usb_nb; |
118 | struct work_struct usb_work; |
119 | struct delayed_work pump_express_work; |
120 | unsigned long usb_event; |
121 | |
122 | struct regmap *rmap; |
123 | struct regmap_field *rmap_fields[F_MAX_FIELDS]; |
124 | |
125 | bool skip_reset; |
126 | bool read_back_init_data; |
127 | bool force_hiz; |
128 | u32 pump_express_vbus_max; |
129 | u32 iinlim_percentage; |
130 | enum bq25890_chip_version chip_version; |
131 | struct bq25890_init_data init_data; |
132 | struct bq25890_state state; |
133 | |
134 | struct mutex lock; /* protect state data */ |
135 | }; |
136 | |
137 | static DEFINE_IDR(bq25890_id); |
138 | static DEFINE_MUTEX(bq25890_id_mutex); |
139 | |
140 | static const struct regmap_range bq25890_readonly_reg_ranges[] = { |
141 | regmap_reg_range(0x0b, 0x0c), |
142 | regmap_reg_range(0x0e, 0x13), |
143 | }; |
144 | |
145 | static const struct regmap_access_table bq25890_writeable_regs = { |
146 | .no_ranges = bq25890_readonly_reg_ranges, |
147 | .n_no_ranges = ARRAY_SIZE(bq25890_readonly_reg_ranges), |
148 | }; |
149 | |
150 | static const struct regmap_range bq25890_volatile_reg_ranges[] = { |
151 | regmap_reg_range(0x00, 0x00), |
152 | regmap_reg_range(0x02, 0x02), |
153 | regmap_reg_range(0x09, 0x09), |
154 | regmap_reg_range(0x0b, 0x14), |
155 | }; |
156 | |
157 | static const struct regmap_access_table bq25890_volatile_regs = { |
158 | .yes_ranges = bq25890_volatile_reg_ranges, |
159 | .n_yes_ranges = ARRAY_SIZE(bq25890_volatile_reg_ranges), |
160 | }; |
161 | |
162 | static const struct regmap_config bq25890_regmap_config = { |
163 | .reg_bits = 8, |
164 | .val_bits = 8, |
165 | |
166 | .max_register = 0x14, |
167 | .cache_type = REGCACHE_RBTREE, |
168 | |
169 | .wr_table = &bq25890_writeable_regs, |
170 | .volatile_table = &bq25890_volatile_regs, |
171 | }; |
172 | |
173 | static const struct reg_field bq25890_reg_fields[] = { |
174 | /* REG00 */ |
175 | [F_EN_HIZ] = REG_FIELD(0x00, 7, 7), |
176 | [F_EN_ILIM] = REG_FIELD(0x00, 6, 6), |
177 | [F_IINLIM] = REG_FIELD(0x00, 0, 5), |
178 | /* REG01 */ |
179 | [F_BHOT] = REG_FIELD(0x01, 6, 7), |
180 | [F_BCOLD] = REG_FIELD(0x01, 5, 5), |
181 | [F_VINDPM_OFS] = REG_FIELD(0x01, 0, 4), |
182 | /* REG02 */ |
183 | [F_CONV_START] = REG_FIELD(0x02, 7, 7), |
184 | [F_CONV_RATE] = REG_FIELD(0x02, 6, 6), |
185 | [F_BOOSTF] = REG_FIELD(0x02, 5, 5), |
186 | [F_ICO_EN] = REG_FIELD(0x02, 4, 4), |
187 | [F_HVDCP_EN] = REG_FIELD(0x02, 3, 3), // reserved on BQ25896 |
188 | [F_MAXC_EN] = REG_FIELD(0x02, 2, 2), // reserved on BQ25896 |
189 | [F_FORCE_DPM] = REG_FIELD(0x02, 1, 1), |
190 | [F_AUTO_DPDM_EN] = REG_FIELD(0x02, 0, 0), |
191 | /* REG03 */ |
192 | [F_BAT_LOAD_EN] = REG_FIELD(0x03, 7, 7), |
193 | [F_WD_RST] = REG_FIELD(0x03, 6, 6), |
194 | [F_OTG_CFG] = REG_FIELD(0x03, 5, 5), |
195 | [F_CHG_CFG] = REG_FIELD(0x03, 4, 4), |
196 | [F_SYSVMIN] = REG_FIELD(0x03, 1, 3), |
197 | [F_MIN_VBAT_SEL] = REG_FIELD(0x03, 0, 0), // BQ25896 only |
198 | /* REG04 */ |
199 | [F_PUMPX_EN] = REG_FIELD(0x04, 7, 7), |
200 | [F_ICHG] = REG_FIELD(0x04, 0, 6), |
201 | /* REG05 */ |
202 | [F_IPRECHG] = REG_FIELD(0x05, 4, 7), |
203 | [F_ITERM] = REG_FIELD(0x05, 0, 3), |
204 | /* REG06 */ |
205 | [F_VREG] = REG_FIELD(0x06, 2, 7), |
206 | [F_BATLOWV] = REG_FIELD(0x06, 1, 1), |
207 | [F_VRECHG] = REG_FIELD(0x06, 0, 0), |
208 | /* REG07 */ |
209 | [F_TERM_EN] = REG_FIELD(0x07, 7, 7), |
210 | [F_STAT_DIS] = REG_FIELD(0x07, 6, 6), |
211 | [F_WD] = REG_FIELD(0x07, 4, 5), |
212 | [F_TMR_EN] = REG_FIELD(0x07, 3, 3), |
213 | [F_CHG_TMR] = REG_FIELD(0x07, 1, 2), |
214 | [F_JEITA_ISET] = REG_FIELD(0x07, 0, 0), // reserved on BQ25895 |
215 | /* REG08 */ |
216 | [F_BATCMP] = REG_FIELD(0x08, 5, 7), |
217 | [F_VCLAMP] = REG_FIELD(0x08, 2, 4), |
218 | [F_TREG] = REG_FIELD(0x08, 0, 1), |
219 | /* REG09 */ |
220 | [F_FORCE_ICO] = REG_FIELD(0x09, 7, 7), |
221 | [F_TMR2X_EN] = REG_FIELD(0x09, 6, 6), |
222 | [F_BATFET_DIS] = REG_FIELD(0x09, 5, 5), |
223 | [F_JEITA_VSET] = REG_FIELD(0x09, 4, 4), // reserved on BQ25895 |
224 | [F_BATFET_DLY] = REG_FIELD(0x09, 3, 3), |
225 | [F_BATFET_RST_EN] = REG_FIELD(0x09, 2, 2), |
226 | [F_PUMPX_UP] = REG_FIELD(0x09, 1, 1), |
227 | [F_PUMPX_DN] = REG_FIELD(0x09, 0, 0), |
228 | /* REG0A */ |
229 | [F_BOOSTV] = REG_FIELD(0x0A, 4, 7), |
230 | [F_BOOSTI] = REG_FIELD(0x0A, 0, 2), // reserved on BQ25895 |
231 | [F_PFM_OTG_DIS] = REG_FIELD(0x0A, 3, 3), // BQ25896 only |
232 | /* REG0B */ |
233 | [F_VBUS_STAT] = REG_FIELD(0x0B, 5, 7), |
234 | [F_CHG_STAT] = REG_FIELD(0x0B, 3, 4), |
235 | [F_PG_STAT] = REG_FIELD(0x0B, 2, 2), |
236 | [F_SDP_STAT] = REG_FIELD(0x0B, 1, 1), // reserved on BQ25896 |
237 | [F_VSYS_STAT] = REG_FIELD(0x0B, 0, 0), |
238 | /* REG0C */ |
239 | [F_WD_FAULT] = REG_FIELD(0x0C, 7, 7), |
240 | [F_BOOST_FAULT] = REG_FIELD(0x0C, 6, 6), |
241 | [F_CHG_FAULT] = REG_FIELD(0x0C, 4, 5), |
242 | [F_BAT_FAULT] = REG_FIELD(0x0C, 3, 3), |
243 | [F_NTC_FAULT] = REG_FIELD(0x0C, 0, 2), |
244 | /* REG0D */ |
245 | [F_FORCE_VINDPM] = REG_FIELD(0x0D, 7, 7), |
246 | [F_VINDPM] = REG_FIELD(0x0D, 0, 6), |
247 | /* REG0E */ |
248 | [F_THERM_STAT] = REG_FIELD(0x0E, 7, 7), |
249 | [F_BATV] = REG_FIELD(0x0E, 0, 6), |
250 | /* REG0F */ |
251 | [F_SYSV] = REG_FIELD(0x0F, 0, 6), |
252 | /* REG10 */ |
253 | [F_TSPCT] = REG_FIELD(0x10, 0, 6), |
254 | /* REG11 */ |
255 | [F_VBUS_GD] = REG_FIELD(0x11, 7, 7), |
256 | [F_VBUSV] = REG_FIELD(0x11, 0, 6), |
257 | /* REG12 */ |
258 | [F_ICHGR] = REG_FIELD(0x12, 0, 6), |
259 | /* REG13 */ |
260 | [F_VDPM_STAT] = REG_FIELD(0x13, 7, 7), |
261 | [F_IDPM_STAT] = REG_FIELD(0x13, 6, 6), |
262 | [F_IDPM_LIM] = REG_FIELD(0x13, 0, 5), |
263 | /* REG14 */ |
264 | [F_REG_RST] = REG_FIELD(0x14, 7, 7), |
265 | [F_ICO_OPTIMIZED] = REG_FIELD(0x14, 6, 6), |
266 | [F_PN] = REG_FIELD(0x14, 3, 5), |
267 | [F_TS_PROFILE] = REG_FIELD(0x14, 2, 2), |
268 | [F_DEV_REV] = REG_FIELD(0x14, 0, 1) |
269 | }; |
270 | |
271 | /* |
272 | * Most of the val -> idx conversions can be computed, given the minimum, |
273 | * maximum and the step between values. For the rest of conversions, we use |
274 | * lookup tables. |
275 | */ |
276 | enum bq25890_table_ids { |
277 | /* range tables */ |
278 | TBL_ICHG, |
279 | TBL_ITERM, |
280 | TBL_IINLIM, |
281 | TBL_VREG, |
282 | TBL_BOOSTV, |
283 | TBL_SYSVMIN, |
284 | TBL_VBUSV, |
285 | TBL_VBATCOMP, |
286 | TBL_RBATCOMP, |
287 | |
288 | /* lookup tables */ |
289 | TBL_TREG, |
290 | TBL_BOOSTI, |
291 | TBL_TSPCT, |
292 | }; |
293 | |
294 | /* Thermal Regulation Threshold lookup table, in degrees Celsius */ |
295 | static const u32 bq25890_treg_tbl[] = { 60, 80, 100, 120 }; |
296 | |
297 | #define BQ25890_TREG_TBL_SIZE ARRAY_SIZE(bq25890_treg_tbl) |
298 | |
299 | /* Boost mode current limit lookup table, in uA */ |
300 | static const u32 bq25890_boosti_tbl[] = { |
301 | 500000, 700000, 1100000, 1300000, 1600000, 1800000, 2100000, 2400000 |
302 | }; |
303 | |
304 | #define BQ25890_BOOSTI_TBL_SIZE ARRAY_SIZE(bq25890_boosti_tbl) |
305 | |
306 | /* NTC 10K temperature lookup table in tenths of a degree */ |
307 | static const u32 bq25890_tspct_tbl[] = { |
308 | 850, 840, 830, 820, 810, 800, 790, 780, |
309 | 770, 760, 750, 740, 730, 720, 710, 700, |
310 | 690, 685, 680, 675, 670, 660, 650, 645, |
311 | 640, 630, 620, 615, 610, 600, 590, 585, |
312 | 580, 570, 565, 560, 550, 540, 535, 530, |
313 | 520, 515, 510, 500, 495, 490, 480, 475, |
314 | 470, 460, 455, 450, 440, 435, 430, 425, |
315 | 420, 410, 405, 400, 390, 385, 380, 370, |
316 | 365, 360, 355, 350, 340, 335, 330, 320, |
317 | 310, 305, 300, 290, 285, 280, 275, 270, |
318 | 260, 250, 245, 240, 230, 225, 220, 210, |
319 | 205, 200, 190, 180, 175, 170, 160, 150, |
320 | 145, 140, 130, 120, 115, 110, 100, 90, |
321 | 80, 70, 60, 50, 40, 30, 20, 10, |
322 | 0, -10, -20, -30, -40, -60, -70, -80, |
323 | -90, -10, -120, -140, -150, -170, -190, -210, |
324 | }; |
325 | |
326 | #define BQ25890_TSPCT_TBL_SIZE ARRAY_SIZE(bq25890_tspct_tbl) |
327 | |
328 | struct bq25890_range { |
329 | u32 min; |
330 | u32 max; |
331 | u32 step; |
332 | }; |
333 | |
334 | struct bq25890_lookup { |
335 | const u32 *tbl; |
336 | u32 size; |
337 | }; |
338 | |
339 | static const union { |
340 | struct bq25890_range rt; |
341 | struct bq25890_lookup lt; |
342 | } bq25890_tables[] = { |
343 | /* range tables */ |
344 | /* TODO: BQ25896 has max ICHG 3008 mA */ |
345 | [TBL_ICHG] = { .rt = {0, 5056000, 64000} }, /* uA */ |
346 | [TBL_ITERM] = { .rt = {64000, 1024000, 64000} }, /* uA */ |
347 | [TBL_IINLIM] = { .rt = {100000, 3250000, 50000} }, /* uA */ |
348 | [TBL_VREG] = { .rt = {3840000, 4608000, 16000} }, /* uV */ |
349 | [TBL_BOOSTV] = { .rt = {4550000, 5510000, 64000} }, /* uV */ |
350 | [TBL_SYSVMIN] = { .rt = {3000000, 3700000, 100000} }, /* uV */ |
351 | [TBL_VBUSV] = { .rt = {2600000, 15300000, 100000} }, /* uV */ |
352 | [TBL_VBATCOMP] = { .rt = {0, 224000, 32000} }, /* uV */ |
353 | [TBL_RBATCOMP] = { .rt = {0, 140000, 20000} }, /* uOhm */ |
354 | |
355 | /* lookup tables */ |
356 | [TBL_TREG] = { .lt = {bq25890_treg_tbl, BQ25890_TREG_TBL_SIZE} }, |
357 | [TBL_BOOSTI] = { .lt = {bq25890_boosti_tbl, BQ25890_BOOSTI_TBL_SIZE} }, |
358 | [TBL_TSPCT] = { .lt = {bq25890_tspct_tbl, BQ25890_TSPCT_TBL_SIZE} } |
359 | }; |
360 | |
361 | static int bq25890_field_read(struct bq25890_device *bq, |
362 | enum bq25890_fields field_id) |
363 | { |
364 | int ret; |
365 | int val; |
366 | |
367 | ret = regmap_field_read(field: bq->rmap_fields[field_id], val: &val); |
368 | if (ret < 0) |
369 | return ret; |
370 | |
371 | return val; |
372 | } |
373 | |
374 | static int bq25890_field_write(struct bq25890_device *bq, |
375 | enum bq25890_fields field_id, u8 val) |
376 | { |
377 | return regmap_field_write(field: bq->rmap_fields[field_id], val); |
378 | } |
379 | |
380 | static u8 bq25890_find_idx(u32 value, enum bq25890_table_ids id) |
381 | { |
382 | u8 idx; |
383 | |
384 | if (id >= TBL_TREG) { |
385 | const u32 *tbl = bq25890_tables[id].lt.tbl; |
386 | u32 tbl_size = bq25890_tables[id].lt.size; |
387 | |
388 | for (idx = 1; idx < tbl_size && tbl[idx] <= value; idx++) |
389 | ; |
390 | } else { |
391 | const struct bq25890_range *rtbl = &bq25890_tables[id].rt; |
392 | u8 rtbl_size; |
393 | |
394 | rtbl_size = (rtbl->max - rtbl->min) / rtbl->step + 1; |
395 | |
396 | for (idx = 1; |
397 | idx < rtbl_size && (idx * rtbl->step + rtbl->min <= value); |
398 | idx++) |
399 | ; |
400 | } |
401 | |
402 | return idx - 1; |
403 | } |
404 | |
405 | static u32 bq25890_find_val(u8 idx, enum bq25890_table_ids id) |
406 | { |
407 | const struct bq25890_range *rtbl; |
408 | |
409 | /* lookup table? */ |
410 | if (id >= TBL_TREG) |
411 | return bq25890_tables[id].lt.tbl[idx]; |
412 | |
413 | /* range table */ |
414 | rtbl = &bq25890_tables[id].rt; |
415 | |
416 | return (rtbl->min + idx * rtbl->step); |
417 | } |
418 | |
419 | enum bq25890_status { |
420 | STATUS_NOT_CHARGING, |
421 | STATUS_PRE_CHARGING, |
422 | STATUS_FAST_CHARGING, |
423 | STATUS_TERMINATION_DONE, |
424 | }; |
425 | |
426 | enum bq25890_chrg_fault { |
427 | CHRG_FAULT_NORMAL, |
428 | CHRG_FAULT_INPUT, |
429 | CHRG_FAULT_THERMAL_SHUTDOWN, |
430 | CHRG_FAULT_TIMER_EXPIRED, |
431 | }; |
432 | |
433 | enum bq25890_ntc_fault { |
434 | NTC_FAULT_NORMAL = 0, |
435 | NTC_FAULT_WARM = 2, |
436 | NTC_FAULT_COOL = 3, |
437 | NTC_FAULT_COLD = 5, |
438 | NTC_FAULT_HOT = 6, |
439 | }; |
440 | |
441 | static bool bq25890_is_adc_property(enum power_supply_property psp) |
442 | { |
443 | switch (psp) { |
444 | case POWER_SUPPLY_PROP_VOLTAGE_NOW: |
445 | case POWER_SUPPLY_PROP_CURRENT_NOW: |
446 | case POWER_SUPPLY_PROP_TEMP: |
447 | return true; |
448 | |
449 | default: |
450 | return false; |
451 | } |
452 | } |
453 | |
454 | static irqreturn_t __bq25890_handle_irq(struct bq25890_device *bq); |
455 | |
456 | static int bq25890_get_vbus_voltage(struct bq25890_device *bq) |
457 | { |
458 | int ret; |
459 | |
460 | ret = bq25890_field_read(bq, field_id: F_VBUSV); |
461 | if (ret < 0) |
462 | return ret; |
463 | |
464 | return bq25890_find_val(idx: ret, id: TBL_VBUSV); |
465 | } |
466 | |
467 | static void bq25890_update_state(struct bq25890_device *bq, |
468 | enum power_supply_property psp, |
469 | struct bq25890_state *state) |
470 | { |
471 | bool do_adc_conv; |
472 | int ret; |
473 | |
474 | mutex_lock(&bq->lock); |
475 | /* update state in case we lost an interrupt */ |
476 | __bq25890_handle_irq(bq); |
477 | *state = bq->state; |
478 | do_adc_conv = (!state->online || state->hiz) && bq25890_is_adc_property(psp); |
479 | if (do_adc_conv) |
480 | bq25890_field_write(bq, field_id: F_CONV_START, val: 1); |
481 | mutex_unlock(lock: &bq->lock); |
482 | |
483 | if (do_adc_conv) |
484 | regmap_field_read_poll_timeout(bq->rmap_fields[F_CONV_START], |
485 | ret, !ret, 25000, 1000000); |
486 | } |
487 | |
488 | static int bq25890_power_supply_get_property(struct power_supply *psy, |
489 | enum power_supply_property psp, |
490 | union power_supply_propval *val) |
491 | { |
492 | struct bq25890_device *bq = power_supply_get_drvdata(psy); |
493 | struct bq25890_state state; |
494 | int ret; |
495 | |
496 | bq25890_update_state(bq, psp, state: &state); |
497 | |
498 | switch (psp) { |
499 | case POWER_SUPPLY_PROP_STATUS: |
500 | if (!state.online || state.hiz) |
501 | val->intval = POWER_SUPPLY_STATUS_DISCHARGING; |
502 | else if (state.chrg_status == STATUS_NOT_CHARGING) |
503 | val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING; |
504 | else if (state.chrg_status == STATUS_PRE_CHARGING || |
505 | state.chrg_status == STATUS_FAST_CHARGING) |
506 | val->intval = POWER_SUPPLY_STATUS_CHARGING; |
507 | else if (state.chrg_status == STATUS_TERMINATION_DONE) |
508 | val->intval = POWER_SUPPLY_STATUS_FULL; |
509 | else |
510 | val->intval = POWER_SUPPLY_STATUS_UNKNOWN; |
511 | |
512 | break; |
513 | |
514 | case POWER_SUPPLY_PROP_CHARGE_TYPE: |
515 | if (!state.online || state.hiz || |
516 | state.chrg_status == STATUS_NOT_CHARGING || |
517 | state.chrg_status == STATUS_TERMINATION_DONE) |
518 | val->intval = POWER_SUPPLY_CHARGE_TYPE_NONE; |
519 | else if (state.chrg_status == STATUS_PRE_CHARGING) |
520 | val->intval = POWER_SUPPLY_CHARGE_TYPE_STANDARD; |
521 | else if (state.chrg_status == STATUS_FAST_CHARGING) |
522 | val->intval = POWER_SUPPLY_CHARGE_TYPE_FAST; |
523 | else /* unreachable */ |
524 | val->intval = POWER_SUPPLY_CHARGE_TYPE_UNKNOWN; |
525 | break; |
526 | |
527 | case POWER_SUPPLY_PROP_MANUFACTURER: |
528 | val->strval = BQ25890_MANUFACTURER; |
529 | break; |
530 | |
531 | case POWER_SUPPLY_PROP_MODEL_NAME: |
532 | val->strval = bq25890_chip_name[bq->chip_version]; |
533 | break; |
534 | |
535 | case POWER_SUPPLY_PROP_ONLINE: |
536 | val->intval = state.online && !state.hiz; |
537 | break; |
538 | |
539 | case POWER_SUPPLY_PROP_HEALTH: |
540 | if (!state.chrg_fault && !state.bat_fault && !state.boost_fault) |
541 | val->intval = POWER_SUPPLY_HEALTH_GOOD; |
542 | else if (state.bat_fault) |
543 | val->intval = POWER_SUPPLY_HEALTH_OVERVOLTAGE; |
544 | else if (state.chrg_fault == CHRG_FAULT_TIMER_EXPIRED) |
545 | val->intval = POWER_SUPPLY_HEALTH_SAFETY_TIMER_EXPIRE; |
546 | else if (state.chrg_fault == CHRG_FAULT_THERMAL_SHUTDOWN) |
547 | val->intval = POWER_SUPPLY_HEALTH_OVERHEAT; |
548 | else |
549 | val->intval = POWER_SUPPLY_HEALTH_UNSPEC_FAILURE; |
550 | break; |
551 | |
552 | case POWER_SUPPLY_PROP_PRECHARGE_CURRENT: |
553 | val->intval = bq25890_find_val(idx: bq->init_data.iprechg, id: TBL_ITERM); |
554 | break; |
555 | |
556 | case POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT: |
557 | val->intval = bq25890_find_val(idx: bq->init_data.iterm, id: TBL_ITERM); |
558 | break; |
559 | |
560 | case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT: |
561 | ret = bq25890_field_read(bq, field_id: F_IINLIM); |
562 | if (ret < 0) |
563 | return ret; |
564 | |
565 | val->intval = bq25890_find_val(idx: ret, id: TBL_IINLIM); |
566 | break; |
567 | |
568 | case POWER_SUPPLY_PROP_CURRENT_NOW: /* I_BAT now */ |
569 | /* |
570 | * This is ADC-sampled immediate charge current supplied |
571 | * from charger to battery. The property name is confusing, |
572 | * for clarification refer to: |
573 | * Documentation/ABI/testing/sysfs-class-power |
574 | * /sys/class/power_supply/<supply_name>/current_now |
575 | */ |
576 | ret = bq25890_field_read(bq, field_id: F_ICHGR); /* read measured value */ |
577 | if (ret < 0) |
578 | return ret; |
579 | |
580 | /* converted_val = ADC_val * 50mA (table 10.3.19) */ |
581 | val->intval = ret * -50000; |
582 | break; |
583 | |
584 | case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT: /* I_BAT user limit */ |
585 | /* |
586 | * This is user-configured constant charge current supplied |
587 | * from charger to battery in first phase of charging, when |
588 | * battery voltage is below constant charge voltage. |
589 | * |
590 | * This value reflects the current hardware setting. |
591 | * |
592 | * The POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX is the |
593 | * maximum value of this property. |
594 | */ |
595 | ret = bq25890_field_read(bq, field_id: F_ICHG); |
596 | if (ret < 0) |
597 | return ret; |
598 | val->intval = bq25890_find_val(idx: ret, id: TBL_ICHG); |
599 | |
600 | /* When temperature is too low, charge current is decreased */ |
601 | if (bq->state.ntc_fault == NTC_FAULT_COOL) { |
602 | ret = bq25890_field_read(bq, field_id: F_JEITA_ISET); |
603 | if (ret < 0) |
604 | return ret; |
605 | |
606 | if (ret) |
607 | val->intval /= 5; |
608 | else |
609 | val->intval /= 2; |
610 | } |
611 | break; |
612 | |
613 | case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX: /* I_BAT max */ |
614 | /* |
615 | * This is maximum allowed constant charge current supplied |
616 | * from charger to battery in first phase of charging, when |
617 | * battery voltage is below constant charge voltage. |
618 | * |
619 | * This value is constant for each battery and set from DT. |
620 | */ |
621 | val->intval = bq25890_find_val(idx: bq->init_data.ichg, id: TBL_ICHG); |
622 | break; |
623 | |
624 | case POWER_SUPPLY_PROP_VOLTAGE_NOW: /* V_BAT now */ |
625 | /* |
626 | * This is ADC-sampled immediate charge voltage supplied |
627 | * from charger to battery. The property name is confusing, |
628 | * for clarification refer to: |
629 | * Documentation/ABI/testing/sysfs-class-power |
630 | * /sys/class/power_supply/<supply_name>/voltage_now |
631 | */ |
632 | ret = bq25890_field_read(bq, field_id: F_BATV); /* read measured value */ |
633 | if (ret < 0) |
634 | return ret; |
635 | |
636 | /* converted_val = 2.304V + ADC_val * 20mV (table 10.3.15) */ |
637 | val->intval = 2304000 + ret * 20000; |
638 | break; |
639 | |
640 | case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE: /* V_BAT user limit */ |
641 | /* |
642 | * This is user-configured constant charge voltage supplied |
643 | * from charger to battery in second phase of charging, when |
644 | * battery voltage reached constant charge voltage. |
645 | * |
646 | * This value reflects the current hardware setting. |
647 | * |
648 | * The POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX is the |
649 | * maximum value of this property. |
650 | */ |
651 | ret = bq25890_field_read(bq, field_id: F_VREG); |
652 | if (ret < 0) |
653 | return ret; |
654 | |
655 | val->intval = bq25890_find_val(idx: ret, id: TBL_VREG); |
656 | break; |
657 | |
658 | case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX: /* V_BAT max */ |
659 | /* |
660 | * This is maximum allowed constant charge voltage supplied |
661 | * from charger to battery in second phase of charging, when |
662 | * battery voltage reached constant charge voltage. |
663 | * |
664 | * This value is constant for each battery and set from DT. |
665 | */ |
666 | val->intval = bq25890_find_val(idx: bq->init_data.vreg, id: TBL_VREG); |
667 | break; |
668 | |
669 | case POWER_SUPPLY_PROP_TEMP: |
670 | ret = bq25890_field_read(bq, field_id: F_TSPCT); |
671 | if (ret < 0) |
672 | return ret; |
673 | |
674 | /* convert TS percentage into rough temperature */ |
675 | val->intval = bq25890_find_val(idx: ret, id: TBL_TSPCT); |
676 | break; |
677 | |
678 | default: |
679 | return -EINVAL; |
680 | } |
681 | |
682 | return 0; |
683 | } |
684 | |
685 | static int bq25890_power_supply_set_property(struct power_supply *psy, |
686 | enum power_supply_property psp, |
687 | const union power_supply_propval *val) |
688 | { |
689 | struct bq25890_device *bq = power_supply_get_drvdata(psy); |
690 | struct bq25890_state state; |
691 | int maxval, ret; |
692 | u8 lval; |
693 | |
694 | switch (psp) { |
695 | case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT: |
696 | maxval = bq25890_find_val(idx: bq->init_data.ichg, id: TBL_ICHG); |
697 | lval = bq25890_find_idx(min(val->intval, maxval), id: TBL_ICHG); |
698 | return bq25890_field_write(bq, field_id: F_ICHG, val: lval); |
699 | case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE: |
700 | maxval = bq25890_find_val(idx: bq->init_data.vreg, id: TBL_VREG); |
701 | lval = bq25890_find_idx(min(val->intval, maxval), id: TBL_VREG); |
702 | return bq25890_field_write(bq, field_id: F_VREG, val: lval); |
703 | case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT: |
704 | lval = bq25890_find_idx(value: val->intval, id: TBL_IINLIM); |
705 | return bq25890_field_write(bq, field_id: F_IINLIM, val: lval); |
706 | case POWER_SUPPLY_PROP_ONLINE: |
707 | ret = bq25890_field_write(bq, field_id: F_EN_HIZ, val: !val->intval); |
708 | if (!ret) |
709 | bq->force_hiz = !val->intval; |
710 | bq25890_update_state(bq, psp, state: &state); |
711 | return ret; |
712 | default: |
713 | return -EINVAL; |
714 | } |
715 | } |
716 | |
717 | static int bq25890_power_supply_property_is_writeable(struct power_supply *psy, |
718 | enum power_supply_property psp) |
719 | { |
720 | switch (psp) { |
721 | case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT: |
722 | case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE: |
723 | case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT: |
724 | case POWER_SUPPLY_PROP_ONLINE: |
725 | return true; |
726 | default: |
727 | return false; |
728 | } |
729 | } |
730 | |
731 | /* |
732 | * If there are multiple chargers the maximum current the external power-supply |
733 | * can deliver needs to be divided over the chargers. This is done according |
734 | * to the bq->iinlim_percentage setting. |
735 | */ |
736 | static int bq25890_charger_get_scaled_iinlim_regval(struct bq25890_device *bq, |
737 | int iinlim_ua) |
738 | { |
739 | iinlim_ua = iinlim_ua * bq->iinlim_percentage / 100; |
740 | return bq25890_find_idx(value: iinlim_ua, id: TBL_IINLIM); |
741 | } |
742 | |
743 | /* On the BQ25892 try to get charger-type info from our supplier */ |
744 | static void bq25890_charger_external_power_changed(struct power_supply *psy) |
745 | { |
746 | struct bq25890_device *bq = power_supply_get_drvdata(psy); |
747 | union power_supply_propval val; |
748 | int input_current_limit, ret; |
749 | |
750 | if (bq->chip_version != BQ25892) |
751 | return; |
752 | |
753 | ret = power_supply_get_property_from_supplier(psy, |
754 | psp: POWER_SUPPLY_PROP_USB_TYPE, |
755 | val: &val); |
756 | if (ret) |
757 | return; |
758 | |
759 | switch (val.intval) { |
760 | case POWER_SUPPLY_USB_TYPE_DCP: |
761 | input_current_limit = bq25890_charger_get_scaled_iinlim_regval(bq, iinlim_ua: 2000000); |
762 | if (bq->pump_express_vbus_max) { |
763 | queue_delayed_work(wq: system_power_efficient_wq, |
764 | dwork: &bq->pump_express_work, |
765 | PUMP_EXPRESS_START_DELAY); |
766 | } |
767 | break; |
768 | case POWER_SUPPLY_USB_TYPE_CDP: |
769 | case POWER_SUPPLY_USB_TYPE_ACA: |
770 | input_current_limit = bq25890_charger_get_scaled_iinlim_regval(bq, iinlim_ua: 1500000); |
771 | break; |
772 | case POWER_SUPPLY_USB_TYPE_SDP: |
773 | default: |
774 | input_current_limit = bq25890_charger_get_scaled_iinlim_regval(bq, iinlim_ua: 500000); |
775 | } |
776 | |
777 | bq25890_field_write(bq, field_id: F_IINLIM, val: input_current_limit); |
778 | power_supply_changed(psy); |
779 | } |
780 | |
781 | static int bq25890_get_chip_state(struct bq25890_device *bq, |
782 | struct bq25890_state *state) |
783 | { |
784 | int i, ret; |
785 | |
786 | struct { |
787 | enum bq25890_fields id; |
788 | u8 *data; |
789 | } state_fields[] = { |
790 | {F_CHG_STAT, &state->chrg_status}, |
791 | {F_PG_STAT, &state->online}, |
792 | {F_EN_HIZ, &state->hiz}, |
793 | {F_VSYS_STAT, &state->vsys_status}, |
794 | {F_BOOST_FAULT, &state->boost_fault}, |
795 | {F_BAT_FAULT, &state->bat_fault}, |
796 | {F_CHG_FAULT, &state->chrg_fault}, |
797 | {F_NTC_FAULT, &state->ntc_fault} |
798 | }; |
799 | |
800 | for (i = 0; i < ARRAY_SIZE(state_fields); i++) { |
801 | ret = bq25890_field_read(bq, field_id: state_fields[i].id); |
802 | if (ret < 0) |
803 | return ret; |
804 | |
805 | *state_fields[i].data = ret; |
806 | } |
807 | |
808 | dev_dbg(bq->dev, "S:CHG/PG/HIZ/VSYS=%d/%d/%d/%d, F:CHG/BOOST/BAT/NTC=%d/%d/%d/%d\n" , |
809 | state->chrg_status, state->online, |
810 | state->hiz, state->vsys_status, |
811 | state->chrg_fault, state->boost_fault, |
812 | state->bat_fault, state->ntc_fault); |
813 | |
814 | return 0; |
815 | } |
816 | |
817 | static irqreturn_t __bq25890_handle_irq(struct bq25890_device *bq) |
818 | { |
819 | bool adc_conv_rate, new_adc_conv_rate; |
820 | struct bq25890_state new_state; |
821 | int ret; |
822 | |
823 | ret = bq25890_get_chip_state(bq, state: &new_state); |
824 | if (ret < 0) |
825 | return IRQ_NONE; |
826 | |
827 | if (!memcmp(p: &bq->state, q: &new_state, size: sizeof(new_state))) |
828 | return IRQ_NONE; |
829 | |
830 | /* |
831 | * Restore HiZ bit in case it was set by user. The chip does not retain |
832 | * this bit on cable replug, hence the bit must be reset manually here. |
833 | */ |
834 | if (new_state.online && !bq->state.online && bq->force_hiz) { |
835 | ret = bq25890_field_write(bq, field_id: F_EN_HIZ, val: bq->force_hiz); |
836 | if (ret < 0) |
837 | goto error; |
838 | new_state.hiz = 1; |
839 | } |
840 | |
841 | /* Should period ADC sampling be enabled? */ |
842 | adc_conv_rate = bq->state.online && !bq->state.hiz; |
843 | new_adc_conv_rate = new_state.online && !new_state.hiz; |
844 | |
845 | if (new_adc_conv_rate != adc_conv_rate) { |
846 | ret = bq25890_field_write(bq, field_id: F_CONV_RATE, val: new_adc_conv_rate); |
847 | if (ret < 0) |
848 | goto error; |
849 | } |
850 | |
851 | bq->state = new_state; |
852 | power_supply_changed(psy: bq->charger); |
853 | |
854 | return IRQ_HANDLED; |
855 | error: |
856 | dev_err(bq->dev, "Error communicating with the chip: %pe\n" , |
857 | ERR_PTR(ret)); |
858 | return IRQ_HANDLED; |
859 | } |
860 | |
861 | static irqreturn_t bq25890_irq_handler_thread(int irq, void *private) |
862 | { |
863 | struct bq25890_device *bq = private; |
864 | irqreturn_t ret; |
865 | |
866 | mutex_lock(&bq->lock); |
867 | ret = __bq25890_handle_irq(bq); |
868 | mutex_unlock(lock: &bq->lock); |
869 | |
870 | return ret; |
871 | } |
872 | |
873 | static int bq25890_chip_reset(struct bq25890_device *bq) |
874 | { |
875 | int ret; |
876 | int rst_check_counter = 10; |
877 | |
878 | ret = bq25890_field_write(bq, field_id: F_REG_RST, val: 1); |
879 | if (ret < 0) |
880 | return ret; |
881 | |
882 | do { |
883 | ret = bq25890_field_read(bq, field_id: F_REG_RST); |
884 | if (ret < 0) |
885 | return ret; |
886 | |
887 | usleep_range(min: 5, max: 10); |
888 | } while (ret == 1 && --rst_check_counter); |
889 | |
890 | if (!rst_check_counter) |
891 | return -ETIMEDOUT; |
892 | |
893 | return 0; |
894 | } |
895 | |
896 | static int bq25890_rw_init_data(struct bq25890_device *bq) |
897 | { |
898 | bool write = !bq->read_back_init_data; |
899 | int ret; |
900 | int i; |
901 | |
902 | const struct { |
903 | enum bq25890_fields id; |
904 | u8 *value; |
905 | } init_data[] = { |
906 | {F_ICHG, &bq->init_data.ichg}, |
907 | {F_VREG, &bq->init_data.vreg}, |
908 | {F_ITERM, &bq->init_data.iterm}, |
909 | {F_IPRECHG, &bq->init_data.iprechg}, |
910 | {F_SYSVMIN, &bq->init_data.sysvmin}, |
911 | {F_BOOSTV, &bq->init_data.boostv}, |
912 | {F_BOOSTI, &bq->init_data.boosti}, |
913 | {F_BOOSTF, &bq->init_data.boostf}, |
914 | {F_EN_ILIM, &bq->init_data.ilim_en}, |
915 | {F_TREG, &bq->init_data.treg}, |
916 | {F_BATCMP, &bq->init_data.rbatcomp}, |
917 | {F_VCLAMP, &bq->init_data.vclamp}, |
918 | }; |
919 | |
920 | for (i = 0; i < ARRAY_SIZE(init_data); i++) { |
921 | if (write) { |
922 | ret = bq25890_field_write(bq, field_id: init_data[i].id, |
923 | val: *init_data[i].value); |
924 | } else { |
925 | ret = bq25890_field_read(bq, field_id: init_data[i].id); |
926 | if (ret >= 0) |
927 | *init_data[i].value = ret; |
928 | } |
929 | if (ret < 0) { |
930 | dev_dbg(bq->dev, "Accessing init data failed %d\n" , ret); |
931 | return ret; |
932 | } |
933 | } |
934 | |
935 | return 0; |
936 | } |
937 | |
938 | static int bq25890_hw_init(struct bq25890_device *bq) |
939 | { |
940 | int ret; |
941 | |
942 | if (!bq->skip_reset) { |
943 | ret = bq25890_chip_reset(bq); |
944 | if (ret < 0) { |
945 | dev_dbg(bq->dev, "Reset failed %d\n" , ret); |
946 | return ret; |
947 | } |
948 | } else { |
949 | /* |
950 | * Ensure charging is enabled, on some boards where the fw |
951 | * takes care of initalizition F_CHG_CFG is set to 0 before |
952 | * handing control over to the OS. |
953 | */ |
954 | ret = bq25890_field_write(bq, field_id: F_CHG_CFG, val: 1); |
955 | if (ret < 0) { |
956 | dev_dbg(bq->dev, "Enabling charging failed %d\n" , ret); |
957 | return ret; |
958 | } |
959 | } |
960 | |
961 | /* disable watchdog */ |
962 | ret = bq25890_field_write(bq, field_id: F_WD, val: 0); |
963 | if (ret < 0) { |
964 | dev_dbg(bq->dev, "Disabling watchdog failed %d\n" , ret); |
965 | return ret; |
966 | } |
967 | |
968 | /* initialize currents/voltages and other parameters */ |
969 | ret = bq25890_rw_init_data(bq); |
970 | if (ret) |
971 | return ret; |
972 | |
973 | ret = bq25890_get_chip_state(bq, state: &bq->state); |
974 | if (ret < 0) { |
975 | dev_dbg(bq->dev, "Get state failed %d\n" , ret); |
976 | return ret; |
977 | } |
978 | |
979 | /* Configure ADC for continuous conversions when charging */ |
980 | ret = bq25890_field_write(bq, field_id: F_CONV_RATE, val: bq->state.online && !bq->state.hiz); |
981 | if (ret < 0) { |
982 | dev_dbg(bq->dev, "Config ADC failed %d\n" , ret); |
983 | return ret; |
984 | } |
985 | |
986 | return 0; |
987 | } |
988 | |
989 | static const enum power_supply_property bq25890_power_supply_props[] = { |
990 | POWER_SUPPLY_PROP_MANUFACTURER, |
991 | POWER_SUPPLY_PROP_MODEL_NAME, |
992 | POWER_SUPPLY_PROP_STATUS, |
993 | POWER_SUPPLY_PROP_CHARGE_TYPE, |
994 | POWER_SUPPLY_PROP_ONLINE, |
995 | POWER_SUPPLY_PROP_HEALTH, |
996 | POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT, |
997 | POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX, |
998 | POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE, |
999 | POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX, |
1000 | POWER_SUPPLY_PROP_PRECHARGE_CURRENT, |
1001 | POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT, |
1002 | POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT, |
1003 | POWER_SUPPLY_PROP_VOLTAGE_NOW, |
1004 | POWER_SUPPLY_PROP_CURRENT_NOW, |
1005 | POWER_SUPPLY_PROP_TEMP, |
1006 | }; |
1007 | |
1008 | static char *bq25890_charger_supplied_to[] = { |
1009 | "main-battery" , |
1010 | }; |
1011 | |
1012 | static const struct power_supply_desc bq25890_power_supply_desc = { |
1013 | .type = POWER_SUPPLY_TYPE_USB, |
1014 | .properties = bq25890_power_supply_props, |
1015 | .num_properties = ARRAY_SIZE(bq25890_power_supply_props), |
1016 | .get_property = bq25890_power_supply_get_property, |
1017 | .set_property = bq25890_power_supply_set_property, |
1018 | .property_is_writeable = bq25890_power_supply_property_is_writeable, |
1019 | .external_power_changed = bq25890_charger_external_power_changed, |
1020 | }; |
1021 | |
1022 | static int bq25890_power_supply_init(struct bq25890_device *bq) |
1023 | { |
1024 | struct power_supply_config psy_cfg = { .drv_data = bq, }; |
1025 | |
1026 | /* Get ID for the device */ |
1027 | mutex_lock(&bq25890_id_mutex); |
1028 | bq->id = idr_alloc(&bq25890_id, ptr: bq, start: 0, end: 0, GFP_KERNEL); |
1029 | mutex_unlock(lock: &bq25890_id_mutex); |
1030 | if (bq->id < 0) |
1031 | return bq->id; |
1032 | |
1033 | snprintf(buf: bq->name, size: sizeof(bq->name), fmt: "bq25890-charger-%d" , bq->id); |
1034 | bq->desc = bq25890_power_supply_desc; |
1035 | bq->desc.name = bq->name; |
1036 | |
1037 | psy_cfg.supplied_to = bq25890_charger_supplied_to; |
1038 | psy_cfg.num_supplicants = ARRAY_SIZE(bq25890_charger_supplied_to); |
1039 | |
1040 | bq->charger = devm_power_supply_register(parent: bq->dev, desc: &bq->desc, cfg: &psy_cfg); |
1041 | |
1042 | return PTR_ERR_OR_ZERO(ptr: bq->charger); |
1043 | } |
1044 | |
1045 | static int bq25890_set_otg_cfg(struct bq25890_device *bq, u8 val) |
1046 | { |
1047 | int ret; |
1048 | |
1049 | ret = bq25890_field_write(bq, field_id: F_OTG_CFG, val); |
1050 | if (ret < 0) |
1051 | dev_err(bq->dev, "Error switching to boost/charger mode: %d\n" , ret); |
1052 | |
1053 | return ret; |
1054 | } |
1055 | |
1056 | static void bq25890_pump_express_work(struct work_struct *data) |
1057 | { |
1058 | struct bq25890_device *bq = |
1059 | container_of(data, struct bq25890_device, pump_express_work.work); |
1060 | union power_supply_propval value; |
1061 | int voltage, i, ret; |
1062 | |
1063 | dev_dbg(bq->dev, "Start to request input voltage increasing\n" ); |
1064 | |
1065 | /* If there is a second charger put in Hi-Z mode */ |
1066 | if (bq->secondary_chrg) { |
1067 | value.intval = 0; |
1068 | power_supply_set_property(psy: bq->secondary_chrg, psp: POWER_SUPPLY_PROP_ONLINE, val: &value); |
1069 | } |
1070 | |
1071 | /* Enable current pulse voltage control protocol */ |
1072 | ret = bq25890_field_write(bq, field_id: F_PUMPX_EN, val: 1); |
1073 | if (ret < 0) |
1074 | goto error_print; |
1075 | |
1076 | for (i = 0; i < PUMP_EXPRESS_MAX_TRIES; i++) { |
1077 | voltage = bq25890_get_vbus_voltage(bq); |
1078 | if (voltage < 0) |
1079 | goto error_print; |
1080 | dev_dbg(bq->dev, "input voltage = %d uV\n" , voltage); |
1081 | |
1082 | if ((voltage + PUMP_EXPRESS_VBUS_MARGIN_uV) > |
1083 | bq->pump_express_vbus_max) |
1084 | break; |
1085 | |
1086 | ret = bq25890_field_write(bq, field_id: F_PUMPX_UP, val: 1); |
1087 | if (ret < 0) |
1088 | goto error_print; |
1089 | |
1090 | /* Note a single PUMPX up pulse-sequence takes 2.1s */ |
1091 | ret = regmap_field_read_poll_timeout(bq->rmap_fields[F_PUMPX_UP], |
1092 | ret, !ret, 100000, 3000000); |
1093 | if (ret < 0) |
1094 | goto error_print; |
1095 | |
1096 | /* Make sure ADC has sampled Vbus before checking again */ |
1097 | msleep(msecs: 1000); |
1098 | } |
1099 | |
1100 | bq25890_field_write(bq, field_id: F_PUMPX_EN, val: 0); |
1101 | |
1102 | if (bq->secondary_chrg) { |
1103 | value.intval = 1; |
1104 | power_supply_set_property(psy: bq->secondary_chrg, psp: POWER_SUPPLY_PROP_ONLINE, val: &value); |
1105 | } |
1106 | |
1107 | dev_info(bq->dev, "Hi-voltage charging requested, input voltage is %d mV\n" , |
1108 | voltage); |
1109 | |
1110 | power_supply_changed(psy: bq->charger); |
1111 | |
1112 | return; |
1113 | error_print: |
1114 | bq25890_field_write(bq, field_id: F_PUMPX_EN, val: 0); |
1115 | dev_err(bq->dev, "Failed to request hi-voltage charging\n" ); |
1116 | } |
1117 | |
1118 | static void bq25890_usb_work(struct work_struct *data) |
1119 | { |
1120 | int ret; |
1121 | struct bq25890_device *bq = |
1122 | container_of(data, struct bq25890_device, usb_work); |
1123 | |
1124 | switch (bq->usb_event) { |
1125 | case USB_EVENT_ID: |
1126 | /* Enable boost mode */ |
1127 | bq25890_set_otg_cfg(bq, val: 1); |
1128 | break; |
1129 | |
1130 | case USB_EVENT_NONE: |
1131 | /* Disable boost mode */ |
1132 | ret = bq25890_set_otg_cfg(bq, val: 0); |
1133 | if (ret == 0) |
1134 | power_supply_changed(psy: bq->charger); |
1135 | break; |
1136 | } |
1137 | } |
1138 | |
1139 | static int bq25890_usb_notifier(struct notifier_block *nb, unsigned long val, |
1140 | void *priv) |
1141 | { |
1142 | struct bq25890_device *bq = |
1143 | container_of(nb, struct bq25890_device, usb_nb); |
1144 | |
1145 | bq->usb_event = val; |
1146 | queue_work(wq: system_power_efficient_wq, work: &bq->usb_work); |
1147 | |
1148 | return NOTIFY_OK; |
1149 | } |
1150 | |
1151 | #ifdef CONFIG_REGULATOR |
1152 | static int bq25890_vbus_enable(struct regulator_dev *rdev) |
1153 | { |
1154 | struct bq25890_device *bq = rdev_get_drvdata(rdev); |
1155 | union power_supply_propval val = { |
1156 | .intval = 0, |
1157 | }; |
1158 | |
1159 | /* |
1160 | * When enabling 5V boost / Vbus output, we need to put the secondary |
1161 | * charger in Hi-Z mode to avoid it trying to charge the secondary |
1162 | * battery from the 5V boost output. |
1163 | */ |
1164 | if (bq->secondary_chrg) |
1165 | power_supply_set_property(psy: bq->secondary_chrg, psp: POWER_SUPPLY_PROP_ONLINE, val: &val); |
1166 | |
1167 | return bq25890_set_otg_cfg(bq, val: 1); |
1168 | } |
1169 | |
1170 | static int bq25890_vbus_disable(struct regulator_dev *rdev) |
1171 | { |
1172 | struct bq25890_device *bq = rdev_get_drvdata(rdev); |
1173 | union power_supply_propval val = { |
1174 | .intval = 1, |
1175 | }; |
1176 | int ret; |
1177 | |
1178 | ret = bq25890_set_otg_cfg(bq, val: 0); |
1179 | if (ret) |
1180 | return ret; |
1181 | |
1182 | if (bq->secondary_chrg) |
1183 | power_supply_set_property(psy: bq->secondary_chrg, psp: POWER_SUPPLY_PROP_ONLINE, val: &val); |
1184 | |
1185 | return 0; |
1186 | } |
1187 | |
1188 | static int bq25890_vbus_is_enabled(struct regulator_dev *rdev) |
1189 | { |
1190 | struct bq25890_device *bq = rdev_get_drvdata(rdev); |
1191 | |
1192 | return bq25890_field_read(bq, field_id: F_OTG_CFG); |
1193 | } |
1194 | |
1195 | static int bq25890_vbus_get_voltage(struct regulator_dev *rdev) |
1196 | { |
1197 | struct bq25890_device *bq = rdev_get_drvdata(rdev); |
1198 | |
1199 | return bq25890_get_vbus_voltage(bq); |
1200 | } |
1201 | |
1202 | static int bq25890_vsys_get_voltage(struct regulator_dev *rdev) |
1203 | { |
1204 | struct bq25890_device *bq = rdev_get_drvdata(rdev); |
1205 | int ret; |
1206 | |
1207 | /* Should be some output voltage ? */ |
1208 | ret = bq25890_field_read(bq, field_id: F_SYSV); /* read measured value */ |
1209 | if (ret < 0) |
1210 | return ret; |
1211 | |
1212 | /* converted_val = 2.304V + ADC_val * 20mV (table 10.3.15) */ |
1213 | return 2304000 + ret * 20000; |
1214 | } |
1215 | |
1216 | static const struct regulator_ops bq25890_vbus_ops = { |
1217 | .enable = bq25890_vbus_enable, |
1218 | .disable = bq25890_vbus_disable, |
1219 | .is_enabled = bq25890_vbus_is_enabled, |
1220 | .get_voltage = bq25890_vbus_get_voltage, |
1221 | }; |
1222 | |
1223 | static const struct regulator_desc bq25890_vbus_desc = { |
1224 | .name = "usb_otg_vbus" , |
1225 | .of_match = "usb-otg-vbus" , |
1226 | .type = REGULATOR_VOLTAGE, |
1227 | .owner = THIS_MODULE, |
1228 | .ops = &bq25890_vbus_ops, |
1229 | }; |
1230 | |
1231 | static const struct regulator_ops bq25890_vsys_ops = { |
1232 | .get_voltage = bq25890_vsys_get_voltage, |
1233 | }; |
1234 | |
1235 | static const struct regulator_desc bq25890_vsys_desc = { |
1236 | .name = "vsys" , |
1237 | .of_match = "vsys" , |
1238 | .type = REGULATOR_VOLTAGE, |
1239 | .owner = THIS_MODULE, |
1240 | .ops = &bq25890_vsys_ops, |
1241 | }; |
1242 | |
1243 | static int bq25890_register_regulator(struct bq25890_device *bq) |
1244 | { |
1245 | struct bq25890_platform_data *pdata = dev_get_platdata(dev: bq->dev); |
1246 | struct regulator_config cfg = { |
1247 | .dev = bq->dev, |
1248 | .driver_data = bq, |
1249 | }; |
1250 | struct regulator_dev *reg; |
1251 | |
1252 | if (pdata) |
1253 | cfg.init_data = pdata->regulator_init_data; |
1254 | |
1255 | reg = devm_regulator_register(dev: bq->dev, regulator_desc: &bq25890_vbus_desc, config: &cfg); |
1256 | if (IS_ERR(ptr: reg)) { |
1257 | return dev_err_probe(dev: bq->dev, err: PTR_ERR(ptr: reg), |
1258 | fmt: "registering vbus regulator" ); |
1259 | } |
1260 | |
1261 | /* pdata->regulator_init_data is for vbus only */ |
1262 | cfg.init_data = NULL; |
1263 | reg = devm_regulator_register(dev: bq->dev, regulator_desc: &bq25890_vsys_desc, config: &cfg); |
1264 | if (IS_ERR(ptr: reg)) { |
1265 | return dev_err_probe(dev: bq->dev, err: PTR_ERR(ptr: reg), |
1266 | fmt: "registering vsys regulator" ); |
1267 | } |
1268 | |
1269 | return 0; |
1270 | } |
1271 | #else |
1272 | static inline int |
1273 | bq25890_register_regulator(struct bq25890_device *bq) |
1274 | { |
1275 | return 0; |
1276 | } |
1277 | #endif |
1278 | |
1279 | static int bq25890_get_chip_version(struct bq25890_device *bq) |
1280 | { |
1281 | int id, rev; |
1282 | |
1283 | id = bq25890_field_read(bq, field_id: F_PN); |
1284 | if (id < 0) { |
1285 | dev_err(bq->dev, "Cannot read chip ID: %d\n" , id); |
1286 | return id; |
1287 | } |
1288 | |
1289 | rev = bq25890_field_read(bq, field_id: F_DEV_REV); |
1290 | if (rev < 0) { |
1291 | dev_err(bq->dev, "Cannot read chip revision: %d\n" , rev); |
1292 | return rev; |
1293 | } |
1294 | |
1295 | switch (id) { |
1296 | case BQ25890_ID: |
1297 | bq->chip_version = BQ25890; |
1298 | break; |
1299 | |
1300 | /* BQ25892 and BQ25896 share same ID 0 */ |
1301 | case BQ25896_ID: |
1302 | switch (rev) { |
1303 | case 2: |
1304 | bq->chip_version = BQ25896; |
1305 | break; |
1306 | case 1: |
1307 | bq->chip_version = BQ25892; |
1308 | break; |
1309 | default: |
1310 | dev_err(bq->dev, |
1311 | "Unknown device revision %d, assume BQ25892\n" , |
1312 | rev); |
1313 | bq->chip_version = BQ25892; |
1314 | } |
1315 | break; |
1316 | |
1317 | case BQ25895_ID: |
1318 | bq->chip_version = BQ25895; |
1319 | break; |
1320 | |
1321 | default: |
1322 | dev_err(bq->dev, "Unknown chip ID %d\n" , id); |
1323 | return -ENODEV; |
1324 | } |
1325 | |
1326 | return 0; |
1327 | } |
1328 | |
1329 | static int bq25890_irq_probe(struct bq25890_device *bq) |
1330 | { |
1331 | struct gpio_desc *irq; |
1332 | |
1333 | irq = devm_gpiod_get(dev: bq->dev, BQ25890_IRQ_PIN, flags: GPIOD_IN); |
1334 | if (IS_ERR(ptr: irq)) |
1335 | return dev_err_probe(dev: bq->dev, err: PTR_ERR(ptr: irq), |
1336 | fmt: "Could not probe irq pin.\n" ); |
1337 | |
1338 | return gpiod_to_irq(desc: irq); |
1339 | } |
1340 | |
1341 | static int bq25890_fw_read_u32_props(struct bq25890_device *bq) |
1342 | { |
1343 | int ret; |
1344 | u32 property; |
1345 | int i; |
1346 | struct bq25890_init_data *init = &bq->init_data; |
1347 | struct { |
1348 | char *name; |
1349 | bool optional; |
1350 | enum bq25890_table_ids tbl_id; |
1351 | u8 *conv_data; /* holds converted value from given property */ |
1352 | } props[] = { |
1353 | /* required properties */ |
1354 | {"ti,charge-current" , false, TBL_ICHG, &init->ichg}, |
1355 | {"ti,battery-regulation-voltage" , false, TBL_VREG, &init->vreg}, |
1356 | {"ti,termination-current" , false, TBL_ITERM, &init->iterm}, |
1357 | {"ti,precharge-current" , false, TBL_ITERM, &init->iprechg}, |
1358 | {"ti,minimum-sys-voltage" , false, TBL_SYSVMIN, &init->sysvmin}, |
1359 | {"ti,boost-voltage" , false, TBL_BOOSTV, &init->boostv}, |
1360 | {"ti,boost-max-current" , false, TBL_BOOSTI, &init->boosti}, |
1361 | |
1362 | /* optional properties */ |
1363 | {"ti,thermal-regulation-threshold" , true, TBL_TREG, &init->treg}, |
1364 | {"ti,ibatcomp-micro-ohms" , true, TBL_RBATCOMP, &init->rbatcomp}, |
1365 | {"ti,ibatcomp-clamp-microvolt" , true, TBL_VBATCOMP, &init->vclamp}, |
1366 | }; |
1367 | |
1368 | /* initialize data for optional properties */ |
1369 | init->treg = 3; /* 120 degrees Celsius */ |
1370 | init->rbatcomp = init->vclamp = 0; /* IBAT compensation disabled */ |
1371 | |
1372 | for (i = 0; i < ARRAY_SIZE(props); i++) { |
1373 | ret = device_property_read_u32(dev: bq->dev, propname: props[i].name, |
1374 | val: &property); |
1375 | if (ret < 0) { |
1376 | if (props[i].optional) |
1377 | continue; |
1378 | |
1379 | dev_err(bq->dev, "Unable to read property %d %s\n" , ret, |
1380 | props[i].name); |
1381 | |
1382 | return ret; |
1383 | } |
1384 | |
1385 | *props[i].conv_data = bq25890_find_idx(value: property, |
1386 | id: props[i].tbl_id); |
1387 | } |
1388 | |
1389 | return 0; |
1390 | } |
1391 | |
1392 | static int bq25890_fw_probe(struct bq25890_device *bq) |
1393 | { |
1394 | int ret; |
1395 | struct bq25890_init_data *init = &bq->init_data; |
1396 | const char *str; |
1397 | u32 val; |
1398 | |
1399 | ret = device_property_read_string(dev: bq->dev, propname: "linux,secondary-charger-name" , val: &str); |
1400 | if (ret == 0) { |
1401 | bq->secondary_chrg = power_supply_get_by_name(name: str); |
1402 | if (!bq->secondary_chrg) |
1403 | return -EPROBE_DEFER; |
1404 | } |
1405 | |
1406 | /* Optional, left at 0 if property is not present */ |
1407 | device_property_read_u32(dev: bq->dev, propname: "linux,pump-express-vbus-max" , |
1408 | val: &bq->pump_express_vbus_max); |
1409 | |
1410 | ret = device_property_read_u32(dev: bq->dev, propname: "linux,iinlim-percentage" , val: &val); |
1411 | if (ret == 0) { |
1412 | if (val > 100) { |
1413 | dev_err(bq->dev, "Error linux,iinlim-percentage %u > 100\n" , val); |
1414 | return -EINVAL; |
1415 | } |
1416 | bq->iinlim_percentage = val; |
1417 | } else { |
1418 | bq->iinlim_percentage = 100; |
1419 | } |
1420 | |
1421 | bq->skip_reset = device_property_read_bool(dev: bq->dev, propname: "linux,skip-reset" ); |
1422 | bq->read_back_init_data = device_property_read_bool(dev: bq->dev, |
1423 | propname: "linux,read-back-settings" ); |
1424 | if (bq->read_back_init_data) |
1425 | return 0; |
1426 | |
1427 | ret = bq25890_fw_read_u32_props(bq); |
1428 | if (ret < 0) |
1429 | return ret; |
1430 | |
1431 | init->ilim_en = device_property_read_bool(dev: bq->dev, propname: "ti,use-ilim-pin" ); |
1432 | init->boostf = device_property_read_bool(dev: bq->dev, propname: "ti,boost-low-freq" ); |
1433 | |
1434 | return 0; |
1435 | } |
1436 | |
1437 | static void bq25890_non_devm_cleanup(void *data) |
1438 | { |
1439 | struct bq25890_device *bq = data; |
1440 | |
1441 | cancel_delayed_work_sync(dwork: &bq->pump_express_work); |
1442 | |
1443 | if (bq->id >= 0) { |
1444 | mutex_lock(&bq25890_id_mutex); |
1445 | idr_remove(&bq25890_id, id: bq->id); |
1446 | mutex_unlock(lock: &bq25890_id_mutex); |
1447 | } |
1448 | } |
1449 | |
1450 | static int bq25890_probe(struct i2c_client *client) |
1451 | { |
1452 | struct device *dev = &client->dev; |
1453 | struct bq25890_device *bq; |
1454 | int ret; |
1455 | |
1456 | bq = devm_kzalloc(dev, size: sizeof(*bq), GFP_KERNEL); |
1457 | if (!bq) |
1458 | return -ENOMEM; |
1459 | |
1460 | bq->client = client; |
1461 | bq->dev = dev; |
1462 | bq->id = -1; |
1463 | |
1464 | mutex_init(&bq->lock); |
1465 | INIT_DELAYED_WORK(&bq->pump_express_work, bq25890_pump_express_work); |
1466 | |
1467 | bq->rmap = devm_regmap_init_i2c(client, &bq25890_regmap_config); |
1468 | if (IS_ERR(ptr: bq->rmap)) |
1469 | return dev_err_probe(dev, err: PTR_ERR(ptr: bq->rmap), |
1470 | fmt: "failed to allocate register map\n" ); |
1471 | |
1472 | ret = devm_regmap_field_bulk_alloc(dev, regmap: bq->rmap, field: bq->rmap_fields, |
1473 | reg_field: bq25890_reg_fields, num_fields: F_MAX_FIELDS); |
1474 | if (ret) |
1475 | return ret; |
1476 | |
1477 | i2c_set_clientdata(client, data: bq); |
1478 | |
1479 | ret = bq25890_get_chip_version(bq); |
1480 | if (ret) { |
1481 | dev_err(dev, "Cannot read chip ID or unknown chip: %d\n" , ret); |
1482 | return ret; |
1483 | } |
1484 | |
1485 | ret = bq25890_fw_probe(bq); |
1486 | if (ret < 0) |
1487 | return dev_err_probe(dev, err: ret, fmt: "reading device properties\n" ); |
1488 | |
1489 | ret = bq25890_hw_init(bq); |
1490 | if (ret < 0) { |
1491 | dev_err(dev, "Cannot initialize the chip: %d\n" , ret); |
1492 | return ret; |
1493 | } |
1494 | |
1495 | if (client->irq <= 0) |
1496 | client->irq = bq25890_irq_probe(bq); |
1497 | |
1498 | if (client->irq < 0) { |
1499 | dev_err(dev, "No irq resource found.\n" ); |
1500 | return client->irq; |
1501 | } |
1502 | |
1503 | /* OTG reporting */ |
1504 | bq->usb_phy = devm_usb_get_phy(dev, type: USB_PHY_TYPE_USB2); |
1505 | |
1506 | /* |
1507 | * This must be before bq25890_power_supply_init(), so that it runs |
1508 | * after devm unregisters the power_supply. |
1509 | */ |
1510 | ret = devm_add_action_or_reset(dev, bq25890_non_devm_cleanup, bq); |
1511 | if (ret) |
1512 | return ret; |
1513 | |
1514 | ret = bq25890_register_regulator(bq); |
1515 | if (ret) |
1516 | return ret; |
1517 | |
1518 | ret = bq25890_power_supply_init(bq); |
1519 | if (ret < 0) |
1520 | return dev_err_probe(dev, err: ret, fmt: "registering power supply\n" ); |
1521 | |
1522 | ret = devm_request_threaded_irq(dev, irq: client->irq, NULL, |
1523 | thread_fn: bq25890_irq_handler_thread, |
1524 | IRQF_TRIGGER_FALLING | IRQF_ONESHOT, |
1525 | BQ25890_IRQ_PIN, dev_id: bq); |
1526 | if (ret) |
1527 | return ret; |
1528 | |
1529 | if (!IS_ERR_OR_NULL(ptr: bq->usb_phy)) { |
1530 | INIT_WORK(&bq->usb_work, bq25890_usb_work); |
1531 | bq->usb_nb.notifier_call = bq25890_usb_notifier; |
1532 | usb_register_notifier(x: bq->usb_phy, nb: &bq->usb_nb); |
1533 | } |
1534 | |
1535 | return 0; |
1536 | } |
1537 | |
1538 | static void bq25890_remove(struct i2c_client *client) |
1539 | { |
1540 | struct bq25890_device *bq = i2c_get_clientdata(client); |
1541 | |
1542 | if (!IS_ERR_OR_NULL(ptr: bq->usb_phy)) { |
1543 | usb_unregister_notifier(x: bq->usb_phy, nb: &bq->usb_nb); |
1544 | cancel_work_sync(work: &bq->usb_work); |
1545 | } |
1546 | |
1547 | if (!bq->skip_reset) { |
1548 | /* reset all registers to default values */ |
1549 | bq25890_chip_reset(bq); |
1550 | } |
1551 | } |
1552 | |
1553 | static void bq25890_shutdown(struct i2c_client *client) |
1554 | { |
1555 | struct bq25890_device *bq = i2c_get_clientdata(client); |
1556 | |
1557 | /* |
1558 | * TODO this if + return should probably be removed, but that would |
1559 | * introduce a function change for boards using the usb-phy framework. |
1560 | * This needs to be tested on such a board before making this change. |
1561 | */ |
1562 | if (!IS_ERR_OR_NULL(ptr: bq->usb_phy)) |
1563 | return; |
1564 | |
1565 | /* |
1566 | * Turn off the 5v Boost regulator which outputs Vbus to the device's |
1567 | * Micro-USB or Type-C USB port. Leaving this on drains power and |
1568 | * this avoids the PMIC on some device-models seeing this as Vbus |
1569 | * getting inserted after shutdown, causing the device to immediately |
1570 | * power-up again. |
1571 | */ |
1572 | bq25890_set_otg_cfg(bq, val: 0); |
1573 | } |
1574 | |
1575 | #ifdef CONFIG_PM_SLEEP |
1576 | static int bq25890_suspend(struct device *dev) |
1577 | { |
1578 | struct bq25890_device *bq = dev_get_drvdata(dev); |
1579 | |
1580 | /* |
1581 | * If charger is removed, while in suspend, make sure ADC is diabled |
1582 | * since it consumes slightly more power. |
1583 | */ |
1584 | return bq25890_field_write(bq, field_id: F_CONV_RATE, val: 0); |
1585 | } |
1586 | |
1587 | static int bq25890_resume(struct device *dev) |
1588 | { |
1589 | int ret; |
1590 | struct bq25890_device *bq = dev_get_drvdata(dev); |
1591 | |
1592 | mutex_lock(&bq->lock); |
1593 | |
1594 | ret = bq25890_get_chip_state(bq, state: &bq->state); |
1595 | if (ret < 0) |
1596 | goto unlock; |
1597 | |
1598 | /* Re-enable ADC only if charger is plugged in. */ |
1599 | if (bq->state.online) { |
1600 | ret = bq25890_field_write(bq, field_id: F_CONV_RATE, val: 1); |
1601 | if (ret < 0) |
1602 | goto unlock; |
1603 | } |
1604 | |
1605 | /* signal userspace, maybe state changed while suspended */ |
1606 | power_supply_changed(psy: bq->charger); |
1607 | |
1608 | unlock: |
1609 | mutex_unlock(lock: &bq->lock); |
1610 | |
1611 | return ret; |
1612 | } |
1613 | #endif |
1614 | |
1615 | static const struct dev_pm_ops bq25890_pm = { |
1616 | SET_SYSTEM_SLEEP_PM_OPS(bq25890_suspend, bq25890_resume) |
1617 | }; |
1618 | |
1619 | static const struct i2c_device_id bq25890_i2c_ids[] = { |
1620 | { "bq25890" , 0 }, |
1621 | { "bq25892" , 0 }, |
1622 | { "bq25895" , 0 }, |
1623 | { "bq25896" , 0 }, |
1624 | {}, |
1625 | }; |
1626 | MODULE_DEVICE_TABLE(i2c, bq25890_i2c_ids); |
1627 | |
1628 | static const struct of_device_id bq25890_of_match[] __maybe_unused = { |
1629 | { .compatible = "ti,bq25890" , }, |
1630 | { .compatible = "ti,bq25892" , }, |
1631 | { .compatible = "ti,bq25895" , }, |
1632 | { .compatible = "ti,bq25896" , }, |
1633 | { }, |
1634 | }; |
1635 | MODULE_DEVICE_TABLE(of, bq25890_of_match); |
1636 | |
1637 | #ifdef CONFIG_ACPI |
1638 | static const struct acpi_device_id bq25890_acpi_match[] = { |
1639 | {"BQ258900" , 0}, |
1640 | {}, |
1641 | }; |
1642 | MODULE_DEVICE_TABLE(acpi, bq25890_acpi_match); |
1643 | #endif |
1644 | |
1645 | static struct i2c_driver bq25890_driver = { |
1646 | .driver = { |
1647 | .name = "bq25890-charger" , |
1648 | .of_match_table = of_match_ptr(bq25890_of_match), |
1649 | .acpi_match_table = ACPI_PTR(bq25890_acpi_match), |
1650 | .pm = &bq25890_pm, |
1651 | }, |
1652 | .probe = bq25890_probe, |
1653 | .remove = bq25890_remove, |
1654 | .shutdown = bq25890_shutdown, |
1655 | .id_table = bq25890_i2c_ids, |
1656 | }; |
1657 | module_i2c_driver(bq25890_driver); |
1658 | |
1659 | MODULE_AUTHOR("Laurentiu Palcu <laurentiu.palcu@intel.com>" ); |
1660 | MODULE_DESCRIPTION("bq25890 charger driver" ); |
1661 | MODULE_LICENSE("GPL" ); |
1662 | |