.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
---|
1 | 2 | /* |
---|
2 | 3 | * TI BQ25890 charger driver |
---|
3 | 4 | * |
---|
4 | 5 | * Copyright (C) 2015 Intel Corporation |
---|
5 | | - * |
---|
6 | | - * This program is free software; you can redistribute it and/or modify |
---|
7 | | - * it under the terms of the GNU General Public License as published by |
---|
8 | | - * the Free Software Foundation; either version 2 of the License, or |
---|
9 | | - * (at your option) any later version. |
---|
10 | | - * |
---|
11 | | - * This program is distributed in the hope that it will be useful, |
---|
12 | | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
13 | | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
---|
14 | | - * GNU General Public License for more details. |
---|
15 | | - * |
---|
16 | 6 | */ |
---|
17 | 7 | |
---|
18 | 8 | #include <linux/module.h> |
---|
19 | 9 | #include <linux/i2c.h> |
---|
20 | 10 | #include <linux/power_supply.h> |
---|
21 | 11 | #include <linux/regmap.h> |
---|
| 12 | +#include <linux/regulator/driver.h> |
---|
22 | 13 | #include <linux/types.h> |
---|
23 | 14 | #include <linux/gpio/consumer.h> |
---|
24 | 15 | #include <linux/interrupt.h> |
---|
.. | .. |
---|
32 | 23 | #define BQ25890_IRQ_PIN "bq25890_irq" |
---|
33 | 24 | |
---|
34 | 25 | #define BQ25890_ID 3 |
---|
| 26 | +#define BQ25895_ID 7 |
---|
| 27 | +#define BQ25896_ID 0 |
---|
| 28 | +#define SY6970_ID 1 |
---|
| 29 | + |
---|
| 30 | +enum bq25890_chip_version { |
---|
| 31 | + BQ25890, |
---|
| 32 | + BQ25892, |
---|
| 33 | + BQ25895, |
---|
| 34 | + BQ25896, |
---|
| 35 | + SY6970, |
---|
| 36 | +}; |
---|
| 37 | + |
---|
| 38 | +static const char *const bq25890_chip_name[] = { |
---|
| 39 | + "BQ25890", |
---|
| 40 | + "BQ25892", |
---|
| 41 | + "BQ25895", |
---|
| 42 | + "BQ25896", |
---|
| 43 | + "SY6970", |
---|
| 44 | +}; |
---|
35 | 45 | |
---|
36 | 46 | enum bq25890_fields { |
---|
37 | 47 | F_EN_HIZ, F_EN_ILIM, F_IILIM, /* Reg00 */ |
---|
38 | 48 | F_BHOT, F_BCOLD, F_VINDPM_OFS, /* Reg01 */ |
---|
39 | 49 | F_CONV_START, F_CONV_RATE, F_BOOSTF, F_ICO_EN, |
---|
40 | 50 | F_HVDCP_EN, F_MAXC_EN, F_FORCE_DPM, F_AUTO_DPDM_EN, /* Reg02 */ |
---|
41 | | - F_BAT_LOAD_EN, F_WD_RST, F_OTG_CFG, F_CHG_CFG, F_SYSVMIN, /* Reg03 */ |
---|
| 51 | + F_BAT_LOAD_EN, F_WD_RST, F_OTG_CFG, F_CHG_CFG, F_SYSVMIN, |
---|
| 52 | + F_MIN_VBAT_SEL, /* Reg03 */ |
---|
42 | 53 | F_PUMPX_EN, F_ICHG, /* Reg04 */ |
---|
43 | 54 | F_IPRECHG, F_ITERM, /* Reg05 */ |
---|
44 | 55 | F_VREG, F_BATLOWV, F_VRECHG, /* Reg06 */ |
---|
.. | .. |
---|
47 | 58 | F_BATCMP, F_VCLAMP, F_TREG, /* Reg08 */ |
---|
48 | 59 | F_FORCE_ICO, F_TMR2X_EN, F_BATFET_DIS, F_JEITA_VSET, |
---|
49 | 60 | F_BATFET_DLY, F_BATFET_RST_EN, F_PUMPX_UP, F_PUMPX_DN, /* Reg09 */ |
---|
50 | | - F_BOOSTV, F_BOOSTI, /* Reg0A */ |
---|
51 | | - F_VBUS_STAT, F_CHG_STAT, F_PG_STAT, F_SDP_STAT, F_VSYS_STAT, /* Reg0B */ |
---|
| 61 | + F_BOOSTV, F_PFM_OTG_DIS, F_BOOSTI, /* Reg0A */ |
---|
| 62 | + F_VBUS_STAT, F_CHG_STAT, F_PG_STAT, F_SDP_STAT, F_0B_RSVD, |
---|
| 63 | + F_VSYS_STAT, /* Reg0B */ |
---|
52 | 64 | F_WD_FAULT, F_BOOST_FAULT, F_CHG_FAULT, F_BAT_FAULT, |
---|
53 | 65 | F_NTC_FAULT, /* Reg0C */ |
---|
54 | 66 | F_FORCE_VINDPM, F_VINDPM, /* Reg0D */ |
---|
.. | .. |
---|
75 | 87 | u8 boostf; /* boost frequency */ |
---|
76 | 88 | u8 ilim_en; /* enable ILIM pin */ |
---|
77 | 89 | u8 treg; /* thermal regulation threshold */ |
---|
| 90 | + u8 rbatcomp; /* IBAT sense resistor value */ |
---|
| 91 | + u8 vclamp; /* IBAT compensation voltage limit */ |
---|
78 | 92 | }; |
---|
79 | 93 | |
---|
80 | 94 | struct bq25890_state { |
---|
.. | .. |
---|
96 | 110 | struct work_struct usb_work; |
---|
97 | 111 | unsigned long usb_event; |
---|
98 | 112 | |
---|
| 113 | + struct gpio_desc *otg_mode_en_io; |
---|
| 114 | + struct regulator_dev *otg_vbus_reg; |
---|
99 | 115 | struct regmap *rmap; |
---|
100 | 116 | struct regmap_field *rmap_fields[F_MAX_FIELDS]; |
---|
101 | 117 | |
---|
102 | | - int chip_id; |
---|
| 118 | + enum bq25890_chip_version chip_version; |
---|
103 | 119 | struct bq25890_init_data init_data; |
---|
104 | 120 | struct bq25890_state state; |
---|
| 121 | + |
---|
| 122 | + struct workqueue_struct *charger_wq; |
---|
| 123 | + struct delayed_work pd_work; |
---|
| 124 | + struct notifier_block nb; |
---|
| 125 | + struct device_node *notify_node; |
---|
| 126 | + int pd_vol; |
---|
| 127 | + int pd_cur; |
---|
105 | 128 | |
---|
106 | 129 | struct mutex lock; /* protect state data */ |
---|
107 | 130 | }; |
---|
.. | .. |
---|
118 | 141 | |
---|
119 | 142 | static const struct regmap_range bq25890_volatile_reg_ranges[] = { |
---|
120 | 143 | regmap_reg_range(0x00, 0x00), |
---|
| 144 | + regmap_reg_range(0x02, 0x02), |
---|
121 | 145 | regmap_reg_range(0x09, 0x09), |
---|
122 | | - regmap_reg_range(0x0b, 0x0c), |
---|
123 | | - regmap_reg_range(0x0e, 0x14), |
---|
| 146 | + regmap_reg_range(0x0b, 0x14), |
---|
124 | 147 | }; |
---|
125 | 148 | |
---|
126 | 149 | static const struct regmap_access_table bq25890_volatile_regs = { |
---|
.. | .. |
---|
153 | 176 | [F_CONV_RATE] = REG_FIELD(0x02, 6, 6), |
---|
154 | 177 | [F_BOOSTF] = REG_FIELD(0x02, 5, 5), |
---|
155 | 178 | [F_ICO_EN] = REG_FIELD(0x02, 4, 4), |
---|
156 | | - [F_HVDCP_EN] = REG_FIELD(0x02, 3, 3), |
---|
157 | | - [F_MAXC_EN] = REG_FIELD(0x02, 2, 2), |
---|
| 179 | + [F_HVDCP_EN] = REG_FIELD(0x02, 3, 3), // reserved on BQ25896 |
---|
| 180 | + [F_MAXC_EN] = REG_FIELD(0x02, 2, 2), // reserved on BQ25896 |
---|
158 | 181 | [F_FORCE_DPM] = REG_FIELD(0x02, 1, 1), |
---|
159 | 182 | [F_AUTO_DPDM_EN] = REG_FIELD(0x02, 0, 0), |
---|
160 | 183 | /* REG03 */ |
---|
.. | .. |
---|
163 | 186 | [F_OTG_CFG] = REG_FIELD(0x03, 5, 5), |
---|
164 | 187 | [F_CHG_CFG] = REG_FIELD(0x03, 4, 4), |
---|
165 | 188 | [F_SYSVMIN] = REG_FIELD(0x03, 1, 3), |
---|
| 189 | + [F_MIN_VBAT_SEL] = REG_FIELD(0x03, 0, 0), // BQ25896 only |
---|
166 | 190 | /* REG04 */ |
---|
167 | 191 | [F_PUMPX_EN] = REG_FIELD(0x04, 7, 7), |
---|
168 | 192 | [F_ICHG] = REG_FIELD(0x04, 0, 6), |
---|
.. | .. |
---|
179 | 203 | [F_WD] = REG_FIELD(0x07, 4, 5), |
---|
180 | 204 | [F_TMR_EN] = REG_FIELD(0x07, 3, 3), |
---|
181 | 205 | [F_CHG_TMR] = REG_FIELD(0x07, 1, 2), |
---|
182 | | - [F_JEITA_ISET] = REG_FIELD(0x07, 0, 0), |
---|
| 206 | + [F_JEITA_ISET] = REG_FIELD(0x07, 0, 0), // reserved on BQ25895 |
---|
183 | 207 | /* REG08 */ |
---|
184 | | - [F_BATCMP] = REG_FIELD(0x08, 6, 7), |
---|
| 208 | + [F_BATCMP] = REG_FIELD(0x08, 5, 7), |
---|
185 | 209 | [F_VCLAMP] = REG_FIELD(0x08, 2, 4), |
---|
186 | 210 | [F_TREG] = REG_FIELD(0x08, 0, 1), |
---|
187 | 211 | /* REG09 */ |
---|
188 | 212 | [F_FORCE_ICO] = REG_FIELD(0x09, 7, 7), |
---|
189 | 213 | [F_TMR2X_EN] = REG_FIELD(0x09, 6, 6), |
---|
190 | 214 | [F_BATFET_DIS] = REG_FIELD(0x09, 5, 5), |
---|
191 | | - [F_JEITA_VSET] = REG_FIELD(0x09, 4, 4), |
---|
| 215 | + [F_JEITA_VSET] = REG_FIELD(0x09, 4, 4), // reserved on BQ25895 |
---|
192 | 216 | [F_BATFET_DLY] = REG_FIELD(0x09, 3, 3), |
---|
193 | 217 | [F_BATFET_RST_EN] = REG_FIELD(0x09, 2, 2), |
---|
194 | 218 | [F_PUMPX_UP] = REG_FIELD(0x09, 1, 1), |
---|
195 | 219 | [F_PUMPX_DN] = REG_FIELD(0x09, 0, 0), |
---|
196 | 220 | /* REG0A */ |
---|
197 | 221 | [F_BOOSTV] = REG_FIELD(0x0A, 4, 7), |
---|
198 | | - [F_BOOSTI] = REG_FIELD(0x0A, 0, 2), |
---|
| 222 | + [F_BOOSTI] = REG_FIELD(0x0A, 0, 2), // reserved on BQ25895 |
---|
| 223 | + [F_PFM_OTG_DIS] = REG_FIELD(0x0A, 3, 3), // BQ25896 only |
---|
199 | 224 | /* REG0B */ |
---|
200 | 225 | [F_VBUS_STAT] = REG_FIELD(0x0B, 5, 7), |
---|
201 | 226 | [F_CHG_STAT] = REG_FIELD(0x0B, 3, 4), |
---|
202 | 227 | [F_PG_STAT] = REG_FIELD(0x0B, 2, 2), |
---|
203 | | - [F_SDP_STAT] = REG_FIELD(0x0B, 1, 1), |
---|
| 228 | + [F_SDP_STAT] = REG_FIELD(0x0B, 1, 1), // reserved on BQ25896 |
---|
204 | 229 | [F_VSYS_STAT] = REG_FIELD(0x0B, 0, 0), |
---|
205 | 230 | /* REG0C */ |
---|
206 | 231 | [F_WD_FAULT] = REG_FIELD(0x0C, 7, 7), |
---|
.. | .. |
---|
244 | 269 | /* range tables */ |
---|
245 | 270 | TBL_ICHG, |
---|
246 | 271 | TBL_ITERM, |
---|
247 | | - TBL_IPRECHG, |
---|
| 272 | + TBL_IILIM, |
---|
248 | 273 | TBL_VREG, |
---|
249 | | - TBL_BATCMP, |
---|
250 | | - TBL_VCLAMP, |
---|
251 | 274 | TBL_BOOSTV, |
---|
252 | 275 | TBL_SYSVMIN, |
---|
| 276 | + TBL_VBATCOMP, |
---|
| 277 | + TBL_RBATCOMP, |
---|
| 278 | + TBL_VINDPM, |
---|
253 | 279 | |
---|
254 | 280 | /* lookup tables */ |
---|
255 | 281 | TBL_TREG, |
---|
.. | .. |
---|
284 | 310 | struct bq25890_lookup lt; |
---|
285 | 311 | } bq25890_tables[] = { |
---|
286 | 312 | /* range tables */ |
---|
| 313 | + /* TODO: BQ25896 has max ICHG 3008 mA */ |
---|
287 | 314 | [TBL_ICHG] = { .rt = {0, 5056000, 64000} }, /* uA */ |
---|
288 | 315 | [TBL_ITERM] = { .rt = {64000, 1024000, 64000} }, /* uA */ |
---|
| 316 | + [TBL_IILIM] = { .rt = {100000, 3250000, 50000} }, /* uA */ |
---|
289 | 317 | [TBL_VREG] = { .rt = {3840000, 4608000, 16000} }, /* uV */ |
---|
290 | | - [TBL_BATCMP] = { .rt = {0, 140, 20} }, /* mOhm */ |
---|
291 | | - [TBL_VCLAMP] = { .rt = {0, 224000, 32000} }, /* uV */ |
---|
292 | 318 | [TBL_BOOSTV] = { .rt = {4550000, 5510000, 64000} }, /* uV */ |
---|
293 | 319 | [TBL_SYSVMIN] = { .rt = {3000000, 3700000, 100000} }, /* uV */ |
---|
| 320 | + [TBL_VBATCOMP] ={ .rt = {0, 224000, 32000} }, /* uV */ |
---|
| 321 | + [TBL_RBATCOMP] ={ .rt = {0, 140000, 20000} }, /* uOhm */ |
---|
| 322 | + [TBL_VINDPM] = { .rt = {100000, 3100000, 100000} }, /* uV */ |
---|
294 | 323 | |
---|
295 | 324 | /* lookup tables */ |
---|
296 | 325 | [TBL_TREG] = { .lt = {bq25890_treg_tbl, BQ25890_TREG_TBL_SIZE} }, |
---|
.. | .. |
---|
369 | 398 | CHRG_FAULT_TIMER_EXPIRED, |
---|
370 | 399 | }; |
---|
371 | 400 | |
---|
| 401 | +static bool bq25890_is_adc_property(enum power_supply_property psp) |
---|
| 402 | +{ |
---|
| 403 | + switch (psp) { |
---|
| 404 | + case POWER_SUPPLY_PROP_VOLTAGE_NOW: |
---|
| 405 | + case POWER_SUPPLY_PROP_CURRENT_NOW: |
---|
| 406 | + return true; |
---|
| 407 | + |
---|
| 408 | + default: |
---|
| 409 | + return false; |
---|
| 410 | + } |
---|
| 411 | +} |
---|
| 412 | + |
---|
| 413 | +static irqreturn_t __bq25890_handle_irq(struct bq25890_device *bq); |
---|
| 414 | + |
---|
372 | 415 | static int bq25890_power_supply_get_property(struct power_supply *psy, |
---|
373 | 416 | enum power_supply_property psp, |
---|
374 | 417 | union power_supply_propval *val) |
---|
375 | 418 | { |
---|
376 | | - int ret; |
---|
377 | 419 | struct bq25890_device *bq = power_supply_get_drvdata(psy); |
---|
378 | 420 | struct bq25890_state state; |
---|
| 421 | + bool do_adc_conv; |
---|
| 422 | + int ret; |
---|
379 | 423 | |
---|
380 | 424 | mutex_lock(&bq->lock); |
---|
| 425 | + /* update state in case we lost an interrupt */ |
---|
| 426 | + __bq25890_handle_irq(bq); |
---|
381 | 427 | state = bq->state; |
---|
| 428 | + do_adc_conv = !state.online && bq25890_is_adc_property(psp); |
---|
| 429 | + if (do_adc_conv) |
---|
| 430 | + bq25890_field_write(bq, F_CONV_START, 1); |
---|
382 | 431 | mutex_unlock(&bq->lock); |
---|
| 432 | + |
---|
| 433 | + if (do_adc_conv) |
---|
| 434 | + regmap_field_read_poll_timeout(bq->rmap_fields[F_CONV_START], |
---|
| 435 | + ret, !ret, 25000, 1000000); |
---|
383 | 436 | |
---|
384 | 437 | switch (psp) { |
---|
385 | 438 | case POWER_SUPPLY_PROP_STATUS: |
---|
.. | .. |
---|
397 | 450 | |
---|
398 | 451 | break; |
---|
399 | 452 | |
---|
| 453 | + case POWER_SUPPLY_PROP_CHARGE_TYPE: |
---|
| 454 | + if (!state.online || state.chrg_status == STATUS_NOT_CHARGING || |
---|
| 455 | + state.chrg_status == STATUS_TERMINATION_DONE) |
---|
| 456 | + val->intval = POWER_SUPPLY_CHARGE_TYPE_NONE; |
---|
| 457 | + else if (state.chrg_status == STATUS_PRE_CHARGING) |
---|
| 458 | + val->intval = POWER_SUPPLY_CHARGE_TYPE_STANDARD; |
---|
| 459 | + else if (state.chrg_status == STATUS_FAST_CHARGING) |
---|
| 460 | + val->intval = POWER_SUPPLY_CHARGE_TYPE_FAST; |
---|
| 461 | + else /* unreachable */ |
---|
| 462 | + val->intval = POWER_SUPPLY_CHARGE_TYPE_UNKNOWN; |
---|
| 463 | + break; |
---|
| 464 | + |
---|
400 | 465 | case POWER_SUPPLY_PROP_MANUFACTURER: |
---|
401 | 466 | val->strval = BQ25890_MANUFACTURER; |
---|
| 467 | + break; |
---|
| 468 | + |
---|
| 469 | + case POWER_SUPPLY_PROP_MODEL_NAME: |
---|
| 470 | + val->strval = bq25890_chip_name[bq->chip_version]; |
---|
402 | 471 | break; |
---|
403 | 472 | |
---|
404 | 473 | case POWER_SUPPLY_PROP_ONLINE: |
---|
.. | .. |
---|
418 | 487 | val->intval = POWER_SUPPLY_HEALTH_UNSPEC_FAILURE; |
---|
419 | 488 | break; |
---|
420 | 489 | |
---|
421 | | - case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT: |
---|
422 | | - ret = bq25890_field_read(bq, F_ICHGR); /* read measured value */ |
---|
423 | | - if (ret < 0) |
---|
424 | | - return ret; |
---|
425 | | - |
---|
426 | | - /* converted_val = ADC_val * 50mA (table 10.3.19) */ |
---|
427 | | - val->intval = ret * 50000; |
---|
428 | | - break; |
---|
429 | | - |
---|
430 | 490 | case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX: |
---|
431 | | - val->intval = bq25890_tables[TBL_ICHG].rt.max; |
---|
| 491 | + val->intval = bq25890_find_val(bq->init_data.ichg, TBL_ICHG); |
---|
432 | 492 | break; |
---|
433 | 493 | |
---|
434 | 494 | case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE: |
---|
.. | .. |
---|
446 | 506 | break; |
---|
447 | 507 | |
---|
448 | 508 | case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX: |
---|
449 | | - val->intval = bq25890_tables[TBL_VREG].rt.max; |
---|
| 509 | + val->intval = bq25890_find_val(bq->init_data.vreg, TBL_VREG); |
---|
| 510 | + break; |
---|
| 511 | + |
---|
| 512 | + case POWER_SUPPLY_PROP_PRECHARGE_CURRENT: |
---|
| 513 | + val->intval = bq25890_find_val(bq->init_data.iprechg, TBL_ITERM); |
---|
450 | 514 | break; |
---|
451 | 515 | |
---|
452 | 516 | case POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT: |
---|
453 | 517 | val->intval = bq25890_find_val(bq->init_data.iterm, TBL_ITERM); |
---|
| 518 | + break; |
---|
| 519 | + |
---|
| 520 | + case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT: |
---|
| 521 | + ret = bq25890_field_read(bq, F_IILIM); |
---|
| 522 | + if (ret < 0) |
---|
| 523 | + return ret; |
---|
| 524 | + |
---|
| 525 | + val->intval = bq25890_find_val(ret, TBL_IILIM); |
---|
| 526 | + break; |
---|
| 527 | + |
---|
| 528 | + case POWER_SUPPLY_PROP_VOLTAGE_NOW: |
---|
| 529 | + ret = bq25890_field_read(bq, F_SYSV); /* read measured value */ |
---|
| 530 | + if (ret < 0) |
---|
| 531 | + return ret; |
---|
| 532 | + |
---|
| 533 | + /* converted_val = 2.304V + ADC_val * 20mV (table 10.3.15) */ |
---|
| 534 | + val->intval = 2304000 + ret * 20000; |
---|
| 535 | + break; |
---|
| 536 | + |
---|
| 537 | + case POWER_SUPPLY_PROP_CURRENT_NOW: |
---|
| 538 | + ret = bq25890_field_read(bq, F_ICHGR); /* read measured value */ |
---|
| 539 | + if (ret < 0) |
---|
| 540 | + return ret; |
---|
| 541 | + |
---|
| 542 | + /* converted_val = ADC_val * 50mA (table 10.3.19) */ |
---|
| 543 | + val->intval = ret * -50000; |
---|
454 | 544 | break; |
---|
455 | 545 | |
---|
456 | 546 | default: |
---|
.. | .. |
---|
492 | 582 | return 0; |
---|
493 | 583 | } |
---|
494 | 584 | |
---|
495 | | -static bool bq25890_state_changed(struct bq25890_device *bq, |
---|
496 | | - struct bq25890_state *new_state) |
---|
| 585 | +static irqreturn_t __bq25890_handle_irq(struct bq25890_device *bq) |
---|
497 | 586 | { |
---|
498 | | - struct bq25890_state old_state; |
---|
499 | | - |
---|
500 | | - mutex_lock(&bq->lock); |
---|
501 | | - old_state = bq->state; |
---|
502 | | - mutex_unlock(&bq->lock); |
---|
503 | | - |
---|
504 | | - return (old_state.chrg_status != new_state->chrg_status || |
---|
505 | | - old_state.chrg_fault != new_state->chrg_fault || |
---|
506 | | - old_state.online != new_state->online || |
---|
507 | | - old_state.bat_fault != new_state->bat_fault || |
---|
508 | | - old_state.boost_fault != new_state->boost_fault || |
---|
509 | | - old_state.vsys_status != new_state->vsys_status); |
---|
510 | | -} |
---|
511 | | - |
---|
512 | | -static void bq25890_handle_state_change(struct bq25890_device *bq, |
---|
513 | | - struct bq25890_state *new_state) |
---|
514 | | -{ |
---|
| 587 | + struct bq25890_state new_state; |
---|
515 | 588 | int ret; |
---|
516 | | - struct bq25890_state old_state; |
---|
517 | 589 | |
---|
518 | | - mutex_lock(&bq->lock); |
---|
519 | | - old_state = bq->state; |
---|
520 | | - mutex_unlock(&bq->lock); |
---|
| 590 | + ret = bq25890_get_chip_state(bq, &new_state); |
---|
| 591 | + if (ret < 0) |
---|
| 592 | + return IRQ_NONE; |
---|
521 | 593 | |
---|
522 | | - if (!new_state->online) { /* power removed */ |
---|
| 594 | + if (!memcmp(&bq->state, &new_state, sizeof(new_state))) |
---|
| 595 | + return IRQ_NONE; |
---|
| 596 | + |
---|
| 597 | + if (!new_state.online && bq->state.online) { /* power removed */ |
---|
523 | 598 | /* disable ADC */ |
---|
524 | 599 | ret = bq25890_field_write(bq, F_CONV_RATE, 0); |
---|
525 | 600 | if (ret < 0) |
---|
526 | 601 | goto error; |
---|
527 | | - } else if (!old_state.online) { /* power inserted */ |
---|
| 602 | + } else if (new_state.online && !bq->state.online) { /* power inserted */ |
---|
528 | 603 | /* enable ADC, to have control of charge current/voltage */ |
---|
529 | 604 | ret = bq25890_field_write(bq, F_CONV_RATE, 1); |
---|
530 | 605 | if (ret < 0) |
---|
531 | 606 | goto error; |
---|
532 | 607 | } |
---|
533 | 608 | |
---|
534 | | - return; |
---|
| 609 | + bq->state = new_state; |
---|
| 610 | + power_supply_changed(bq->charger); |
---|
535 | 611 | |
---|
| 612 | + return IRQ_HANDLED; |
---|
536 | 613 | error: |
---|
537 | | - dev_err(bq->dev, "Error communicating with the chip.\n"); |
---|
| 614 | + dev_err(bq->dev, "Error communicating with the chip: %pe\n", |
---|
| 615 | + ERR_PTR(ret)); |
---|
| 616 | + return IRQ_HANDLED; |
---|
538 | 617 | } |
---|
539 | 618 | |
---|
540 | 619 | static irqreturn_t bq25890_irq_handler_thread(int irq, void *private) |
---|
541 | 620 | { |
---|
542 | 621 | struct bq25890_device *bq = private; |
---|
543 | | - int ret; |
---|
544 | | - struct bq25890_state state; |
---|
545 | | - |
---|
546 | | - ret = bq25890_get_chip_state(bq, &state); |
---|
547 | | - if (ret < 0) |
---|
548 | | - goto handled; |
---|
549 | | - |
---|
550 | | - if (!bq25890_state_changed(bq, &state)) |
---|
551 | | - goto handled; |
---|
552 | | - |
---|
553 | | - bq25890_handle_state_change(bq, &state); |
---|
| 622 | + irqreturn_t ret; |
---|
554 | 623 | |
---|
555 | 624 | mutex_lock(&bq->lock); |
---|
556 | | - bq->state = state; |
---|
| 625 | + ret = __bq25890_handle_irq(bq); |
---|
557 | 626 | mutex_unlock(&bq->lock); |
---|
558 | 627 | |
---|
559 | | - power_supply_changed(bq->charger); |
---|
560 | | - |
---|
561 | | -handled: |
---|
562 | | - return IRQ_HANDLED; |
---|
| 628 | + return ret; |
---|
563 | 629 | } |
---|
564 | 630 | |
---|
565 | 631 | static int bq25890_chip_reset(struct bq25890_device *bq) |
---|
.. | .. |
---|
589 | 655 | { |
---|
590 | 656 | int ret; |
---|
591 | 657 | int i; |
---|
592 | | - struct bq25890_state state; |
---|
593 | 658 | |
---|
594 | 659 | const struct { |
---|
595 | 660 | enum bq25890_fields id; |
---|
.. | .. |
---|
604 | 669 | {F_BOOSTI, bq->init_data.boosti}, |
---|
605 | 670 | {F_BOOSTF, bq->init_data.boostf}, |
---|
606 | 671 | {F_EN_ILIM, bq->init_data.ilim_en}, |
---|
607 | | - {F_TREG, bq->init_data.treg} |
---|
| 672 | + {F_TREG, bq->init_data.treg}, |
---|
| 673 | + {F_BATCMP, bq->init_data.rbatcomp}, |
---|
| 674 | + {F_VCLAMP, bq->init_data.vclamp}, |
---|
608 | 675 | }; |
---|
609 | 676 | |
---|
610 | 677 | ret = bq25890_chip_reset(bq); |
---|
611 | | - if (ret < 0) |
---|
| 678 | + if (ret < 0) { |
---|
| 679 | + dev_dbg(bq->dev, "Reset failed %d\n", ret); |
---|
612 | 680 | return ret; |
---|
| 681 | + } |
---|
613 | 682 | |
---|
614 | 683 | /* disable watchdog */ |
---|
615 | 684 | ret = bq25890_field_write(bq, F_WD, 0); |
---|
616 | | - if (ret < 0) |
---|
| 685 | + if (ret < 0) { |
---|
| 686 | + dev_dbg(bq->dev, "Disabling watchdog failed %d\n", ret); |
---|
617 | 687 | return ret; |
---|
| 688 | + } |
---|
618 | 689 | |
---|
619 | 690 | /* initialize currents/voltages and other parameters */ |
---|
620 | 691 | for (i = 0; i < ARRAY_SIZE(init_data); i++) { |
---|
621 | 692 | ret = bq25890_field_write(bq, init_data[i].id, |
---|
622 | 693 | init_data[i].value); |
---|
623 | | - if (ret < 0) |
---|
| 694 | + if (ret < 0) { |
---|
| 695 | + dev_dbg(bq->dev, "Writing init data failed %d\n", ret); |
---|
624 | 696 | return ret; |
---|
| 697 | + } |
---|
625 | 698 | } |
---|
626 | 699 | |
---|
627 | | - /* Configure ADC for continuous conversions. This does not enable it. */ |
---|
628 | | - ret = bq25890_field_write(bq, F_CONV_RATE, 1); |
---|
629 | | - if (ret < 0) |
---|
| 700 | + /* Configure ADC for continuous conversions when charging */ |
---|
| 701 | + ret = bq25890_field_write(bq, F_CONV_RATE, !!bq->state.online); |
---|
| 702 | + if (ret < 0) { |
---|
| 703 | + dev_dbg(bq->dev, "Config ADC failed %d\n", ret); |
---|
630 | 704 | return ret; |
---|
| 705 | + } |
---|
631 | 706 | |
---|
632 | | - ret = bq25890_get_chip_state(bq, &state); |
---|
633 | | - if (ret < 0) |
---|
| 707 | + ret = bq25890_get_chip_state(bq, &bq->state); |
---|
| 708 | + if (ret < 0) { |
---|
| 709 | + dev_dbg(bq->dev, "Get state failed %d\n", ret); |
---|
634 | 710 | return ret; |
---|
635 | | - |
---|
636 | | - mutex_lock(&bq->lock); |
---|
637 | | - bq->state = state; |
---|
638 | | - mutex_unlock(&bq->lock); |
---|
| 711 | + } |
---|
639 | 712 | |
---|
640 | 713 | return 0; |
---|
641 | 714 | } |
---|
642 | 715 | |
---|
643 | | -static enum power_supply_property bq25890_power_supply_props[] = { |
---|
| 716 | +static const enum power_supply_property bq25890_power_supply_props[] = { |
---|
644 | 717 | POWER_SUPPLY_PROP_MANUFACTURER, |
---|
| 718 | + POWER_SUPPLY_PROP_MODEL_NAME, |
---|
645 | 719 | POWER_SUPPLY_PROP_STATUS, |
---|
| 720 | + POWER_SUPPLY_PROP_CHARGE_TYPE, |
---|
646 | 721 | POWER_SUPPLY_PROP_ONLINE, |
---|
647 | 722 | POWER_SUPPLY_PROP_HEALTH, |
---|
648 | | - POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT, |
---|
649 | 723 | POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX, |
---|
650 | 724 | POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE, |
---|
651 | 725 | POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX, |
---|
| 726 | + POWER_SUPPLY_PROP_PRECHARGE_CURRENT, |
---|
652 | 727 | POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT, |
---|
| 728 | + POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT, |
---|
| 729 | + POWER_SUPPLY_PROP_VOLTAGE_NOW, |
---|
| 730 | + POWER_SUPPLY_PROP_CURRENT_NOW, |
---|
653 | 731 | }; |
---|
654 | 732 | |
---|
655 | 733 | static char *bq25890_charger_supplied_to[] = { |
---|
.. | .. |
---|
670 | 748 | |
---|
671 | 749 | psy_cfg.supplied_to = bq25890_charger_supplied_to; |
---|
672 | 750 | psy_cfg.num_supplicants = ARRAY_SIZE(bq25890_charger_supplied_to); |
---|
| 751 | + psy_cfg.of_node = bq->dev->of_node; |
---|
673 | 752 | |
---|
674 | 753 | bq->charger = power_supply_register(bq->dev, &bq25890_power_supply_desc, |
---|
675 | 754 | &psy_cfg); |
---|
.. | .. |
---|
719 | 798 | return NOTIFY_OK; |
---|
720 | 799 | } |
---|
721 | 800 | |
---|
| 801 | +static int bq25890_get_chip_version(struct bq25890_device *bq) |
---|
| 802 | +{ |
---|
| 803 | + int id, rev; |
---|
| 804 | + |
---|
| 805 | + id = bq25890_field_read(bq, F_PN); |
---|
| 806 | + if (id < 0) { |
---|
| 807 | + dev_err(bq->dev, "Cannot read chip ID.\n"); |
---|
| 808 | + return id; |
---|
| 809 | + } |
---|
| 810 | + |
---|
| 811 | + rev = bq25890_field_read(bq, F_DEV_REV); |
---|
| 812 | + if (rev < 0) { |
---|
| 813 | + dev_err(bq->dev, "Cannot read chip revision.\n"); |
---|
| 814 | + return rev; |
---|
| 815 | + } |
---|
| 816 | + |
---|
| 817 | + switch (id) { |
---|
| 818 | + case BQ25890_ID: |
---|
| 819 | + bq->chip_version = BQ25890; |
---|
| 820 | + break; |
---|
| 821 | + |
---|
| 822 | + /* BQ25892 and BQ25896 share same ID 0 */ |
---|
| 823 | + case BQ25896_ID: |
---|
| 824 | + switch (rev) { |
---|
| 825 | + case 2: |
---|
| 826 | + bq->chip_version = BQ25896; |
---|
| 827 | + break; |
---|
| 828 | + case 1: |
---|
| 829 | + bq->chip_version = BQ25892; |
---|
| 830 | + break; |
---|
| 831 | + default: |
---|
| 832 | + dev_err(bq->dev, |
---|
| 833 | + "Unknown device revision %d, assume BQ25892\n", |
---|
| 834 | + rev); |
---|
| 835 | + bq->chip_version = BQ25892; |
---|
| 836 | + } |
---|
| 837 | + break; |
---|
| 838 | + |
---|
| 839 | + case BQ25895_ID: |
---|
| 840 | + bq->chip_version = BQ25895; |
---|
| 841 | + break; |
---|
| 842 | + |
---|
| 843 | + case SY6970_ID: |
---|
| 844 | + bq->chip_version = SY6970; |
---|
| 845 | + break; |
---|
| 846 | + |
---|
| 847 | + default: |
---|
| 848 | + dev_err(bq->dev, "Unknown chip ID %d\n", id); |
---|
| 849 | + return -ENODEV; |
---|
| 850 | + } |
---|
| 851 | + |
---|
| 852 | + return 0; |
---|
| 853 | +} |
---|
| 854 | + |
---|
722 | 855 | static int bq25890_irq_probe(struct bq25890_device *bq) |
---|
723 | 856 | { |
---|
724 | 857 | struct gpio_desc *irq; |
---|
.. | .. |
---|
754 | 887 | {"ti,boost-max-current", false, TBL_BOOSTI, &init->boosti}, |
---|
755 | 888 | |
---|
756 | 889 | /* optional properties */ |
---|
757 | | - {"ti,thermal-regulation-threshold", true, TBL_TREG, &init->treg} |
---|
| 890 | + {"ti,thermal-regulation-threshold", true, TBL_TREG, &init->treg}, |
---|
| 891 | + {"ti,ibatcomp-micro-ohms", true, TBL_RBATCOMP, &init->rbatcomp}, |
---|
| 892 | + {"ti,ibatcomp-clamp-microvolt", true, TBL_VBATCOMP, &init->vclamp}, |
---|
758 | 893 | }; |
---|
759 | 894 | |
---|
760 | 895 | /* initialize data for optional properties */ |
---|
761 | 896 | init->treg = 3; /* 120 degrees Celsius */ |
---|
| 897 | + init->rbatcomp = init->vclamp = 0; /* IBAT compensation disabled */ |
---|
762 | 898 | |
---|
763 | 899 | for (i = 0; i < ARRAY_SIZE(props); i++) { |
---|
764 | 900 | ret = device_property_read_u32(bq->dev, props[i].name, |
---|
.. | .. |
---|
766 | 902 | if (ret < 0) { |
---|
767 | 903 | if (props[i].optional) |
---|
768 | 904 | continue; |
---|
| 905 | + |
---|
| 906 | + dev_err(bq->dev, "Unable to read property %d %s\n", ret, |
---|
| 907 | + props[i].name); |
---|
769 | 908 | |
---|
770 | 909 | return ret; |
---|
771 | 910 | } |
---|
.. | .. |
---|
788 | 927 | |
---|
789 | 928 | init->ilim_en = device_property_read_bool(bq->dev, "ti,use-ilim-pin"); |
---|
790 | 929 | init->boostf = device_property_read_bool(bq->dev, "ti,boost-low-freq"); |
---|
| 930 | + bq->notify_node = of_parse_phandle(bq->dev->of_node, |
---|
| 931 | + "ti,usb-charger-detection", 0); |
---|
| 932 | + bq->otg_mode_en_io = devm_gpiod_get_optional(bq->dev, |
---|
| 933 | + "otg-mode-en", |
---|
| 934 | + GPIOD_IN); |
---|
| 935 | + if (!IS_ERR_OR_NULL(bq->otg_mode_en_io)) |
---|
| 936 | + gpiod_direction_output(bq->otg_mode_en_io, 0); |
---|
| 937 | + |
---|
| 938 | + return 0; |
---|
| 939 | +} |
---|
| 940 | + |
---|
| 941 | +static void bq25890_set_pd_param(struct bq25890_device *bq, int vol, int cur) |
---|
| 942 | +{ |
---|
| 943 | + int vindpm, iilim, ichg, vol_limit; |
---|
| 944 | + int i = 0; |
---|
| 945 | + |
---|
| 946 | + iilim = bq25890_find_idx(cur, TBL_IILIM); |
---|
| 947 | + ichg = bq25890_find_idx(cur, TBL_ICHG); |
---|
| 948 | + |
---|
| 949 | + vol_limit = vol; |
---|
| 950 | + if (vol < 5000000) |
---|
| 951 | + vol_limit = 5000000; |
---|
| 952 | + vol_limit = vol_limit - 1280000 - 3200000; |
---|
| 953 | + |
---|
| 954 | + if (vol > 6000000) |
---|
| 955 | + vol_limit /= 2; |
---|
| 956 | + vindpm = bq25890_find_idx(vol_limit, TBL_VINDPM); |
---|
| 957 | + |
---|
| 958 | + while (!bq25890_field_read(bq, F_PG_STAT) && i < 5) { |
---|
| 959 | + msleep(500); |
---|
| 960 | + i++; |
---|
| 961 | + } |
---|
| 962 | + |
---|
| 963 | + bq25890_field_write(bq, F_IILIM, iilim); |
---|
| 964 | + bq25890_field_write(bq, F_VINDPM_OFS, vindpm); |
---|
| 965 | + bq25890_field_write(bq, F_ICHG, ichg); |
---|
| 966 | + dev_info(bq->dev, "vol=%d cur=%d INPUT_CURRENT:%x, INPUT_VOLTAGE:%x, CHARGE_CURRENT:%x\n", |
---|
| 967 | + vol, cur, iilim, vindpm, ichg); |
---|
| 968 | + |
---|
| 969 | + bq25890_get_chip_state(bq, &bq->state); |
---|
| 970 | + power_supply_changed(bq->charger); |
---|
| 971 | +} |
---|
| 972 | + |
---|
| 973 | +static int bq25890_pd_notifier_call(struct notifier_block *nb, |
---|
| 974 | + unsigned long val, void *v) |
---|
| 975 | +{ |
---|
| 976 | + struct bq25890_device *bq = |
---|
| 977 | + container_of(nb, struct bq25890_device, nb); |
---|
| 978 | + struct power_supply *psy = v; |
---|
| 979 | + union power_supply_propval prop; |
---|
| 980 | + int ret; |
---|
| 981 | + |
---|
| 982 | + if (val != PSY_EVENT_PROP_CHANGED) |
---|
| 983 | + return NOTIFY_OK; |
---|
| 984 | + |
---|
| 985 | + /* Ignore event if it was not send by notify_node/notify_device */ |
---|
| 986 | + if (bq->notify_node) { |
---|
| 987 | + if (!psy->dev.parent || |
---|
| 988 | + psy->dev.parent->of_node != bq->notify_node) |
---|
| 989 | + return NOTIFY_OK; |
---|
| 990 | + } |
---|
| 991 | + |
---|
| 992 | + ret = power_supply_get_property(psy, POWER_SUPPLY_PROP_ONLINE, &prop); |
---|
| 993 | + if (ret != 0) |
---|
| 994 | + return NOTIFY_OK; |
---|
| 995 | + /* online=0: USB out */ |
---|
| 996 | + if (prop.intval == 0) { |
---|
| 997 | + bq->pd_cur = 450000; |
---|
| 998 | + bq->pd_vol = 5000000; |
---|
| 999 | + queue_delayed_work(bq->charger_wq, &bq->pd_work, |
---|
| 1000 | + msecs_to_jiffies(10)); |
---|
| 1001 | + return NOTIFY_OK; |
---|
| 1002 | + } |
---|
| 1003 | + |
---|
| 1004 | + ret = power_supply_get_property(psy, POWER_SUPPLY_PROP_CURRENT_NOW, &prop); |
---|
| 1005 | + if (ret != 0) |
---|
| 1006 | + return NOTIFY_OK; |
---|
| 1007 | + bq->pd_cur = prop.intval; |
---|
| 1008 | + if (bq->pd_cur > 0) { |
---|
| 1009 | + ret = power_supply_get_property(psy, POWER_SUPPLY_PROP_VOLTAGE_NOW, |
---|
| 1010 | + &prop); |
---|
| 1011 | + if (ret != 0) |
---|
| 1012 | + return NOTIFY_OK; |
---|
| 1013 | + bq->pd_vol = prop.intval; |
---|
| 1014 | + |
---|
| 1015 | + queue_delayed_work(bq->charger_wq, &bq->pd_work, |
---|
| 1016 | + msecs_to_jiffies(100)); |
---|
| 1017 | + } |
---|
| 1018 | + |
---|
| 1019 | + return NOTIFY_OK; |
---|
| 1020 | +} |
---|
| 1021 | + |
---|
| 1022 | +static void bq25890_pd_evt_worker(struct work_struct *work) |
---|
| 1023 | +{ |
---|
| 1024 | + struct bq25890_device *bq = container_of(work, |
---|
| 1025 | + struct bq25890_device, |
---|
| 1026 | + pd_work.work); |
---|
| 1027 | + |
---|
| 1028 | + bq25890_set_pd_param(bq, bq->pd_vol, bq->pd_cur); |
---|
| 1029 | +} |
---|
| 1030 | + |
---|
| 1031 | +static int bq25890_register_pd_psy(struct bq25890_device *bq) |
---|
| 1032 | +{ |
---|
| 1033 | + struct power_supply *notify_psy = NULL; |
---|
| 1034 | + union power_supply_propval prop; |
---|
| 1035 | + int ret; |
---|
| 1036 | + |
---|
| 1037 | + if (!bq->notify_node) |
---|
| 1038 | + return -EINVAL; |
---|
| 1039 | + |
---|
| 1040 | + bq->charger_wq = alloc_ordered_workqueue("%s", |
---|
| 1041 | + WQ_MEM_RECLAIM | |
---|
| 1042 | + WQ_FREEZABLE, |
---|
| 1043 | + "bq25890-charge-wq"); |
---|
| 1044 | + INIT_DELAYED_WORK(&bq->pd_work, |
---|
| 1045 | + bq25890_pd_evt_worker); |
---|
| 1046 | + |
---|
| 1047 | + bq->nb.notifier_call = bq25890_pd_notifier_call; |
---|
| 1048 | + ret = power_supply_reg_notifier(&bq->nb); |
---|
| 1049 | + if (ret) { |
---|
| 1050 | + dev_err(bq->dev, "failed to reg notifier: %d\n", ret); |
---|
| 1051 | + return ret; |
---|
| 1052 | + } |
---|
| 1053 | + |
---|
| 1054 | + bq25890_field_write(bq, F_AUTO_DPDM_EN, 0); |
---|
| 1055 | + if (bq->nb.notifier_call) { |
---|
| 1056 | + notify_psy = power_supply_get_by_phandle(bq->dev->of_node, |
---|
| 1057 | + "ti,usb-charger-detection"); |
---|
| 1058 | + if (IS_ERR_OR_NULL(notify_psy)) { |
---|
| 1059 | + dev_info(bq->dev, "bq25700 notify_psy is error\n"); |
---|
| 1060 | + notify_psy = NULL; |
---|
| 1061 | + } |
---|
| 1062 | + } |
---|
| 1063 | + |
---|
| 1064 | + if (notify_psy) { |
---|
| 1065 | + ret = power_supply_get_property(notify_psy, |
---|
| 1066 | + POWER_SUPPLY_PROP_CURRENT_MAX, |
---|
| 1067 | + &prop); |
---|
| 1068 | + if (ret != 0) |
---|
| 1069 | + return ret; |
---|
| 1070 | + bq->pd_cur = prop.intval; |
---|
| 1071 | + |
---|
| 1072 | + ret = power_supply_get_property(notify_psy, |
---|
| 1073 | + POWER_SUPPLY_PROP_VOLTAGE_MAX, |
---|
| 1074 | + &prop); |
---|
| 1075 | + if (ret != 0) |
---|
| 1076 | + return ret; |
---|
| 1077 | + bq->pd_vol = prop.intval; |
---|
| 1078 | + |
---|
| 1079 | + queue_delayed_work(bq->charger_wq, &bq->pd_work, |
---|
| 1080 | + msecs_to_jiffies(10)); |
---|
| 1081 | + } |
---|
| 1082 | + |
---|
| 1083 | + return 0; |
---|
| 1084 | +} |
---|
| 1085 | + |
---|
| 1086 | +static void bq25890_set_otg_vbus(struct bq25890_device *bq, bool enable) |
---|
| 1087 | +{ |
---|
| 1088 | + if (!IS_ERR_OR_NULL(bq->otg_mode_en_io)) |
---|
| 1089 | + gpiod_direction_output(bq->otg_mode_en_io, enable); |
---|
| 1090 | + bq25890_field_write(bq, F_OTG_CFG, enable); |
---|
| 1091 | +} |
---|
| 1092 | + |
---|
| 1093 | +static int bq25890_otg_vbus_enable(struct regulator_dev *dev) |
---|
| 1094 | +{ |
---|
| 1095 | + struct bq25890_device *bq = rdev_get_drvdata(dev); |
---|
| 1096 | + |
---|
| 1097 | + bq25890_set_otg_vbus(bq, true); |
---|
| 1098 | + |
---|
| 1099 | + return 0; |
---|
| 1100 | +} |
---|
| 1101 | + |
---|
| 1102 | +static int bq25890_otg_vbus_disable(struct regulator_dev *dev) |
---|
| 1103 | +{ |
---|
| 1104 | + struct bq25890_device *bq = rdev_get_drvdata(dev); |
---|
| 1105 | + |
---|
| 1106 | + bq25890_set_otg_vbus(bq, false); |
---|
| 1107 | + |
---|
| 1108 | + return 0; |
---|
| 1109 | +} |
---|
| 1110 | + |
---|
| 1111 | +static int bq25890_otg_vbus_is_enabled(struct regulator_dev *dev) |
---|
| 1112 | +{ |
---|
| 1113 | + struct bq25890_device *bq = rdev_get_drvdata(dev); |
---|
| 1114 | + u8 val; |
---|
| 1115 | + int gpio_status = 1; |
---|
| 1116 | + |
---|
| 1117 | + val = bq25890_field_read(bq, F_OTG_CFG); |
---|
| 1118 | + if (!IS_ERR_OR_NULL(bq->otg_mode_en_io)) |
---|
| 1119 | + gpio_status = gpiod_get_value(bq->otg_mode_en_io); |
---|
| 1120 | + |
---|
| 1121 | + return val && gpio_status ? 1 : 0; |
---|
| 1122 | +} |
---|
| 1123 | + |
---|
| 1124 | +static const struct regulator_ops bq25890_otg_vbus_ops = { |
---|
| 1125 | + .enable = bq25890_otg_vbus_enable, |
---|
| 1126 | + .disable = bq25890_otg_vbus_disable, |
---|
| 1127 | + .is_enabled = bq25890_otg_vbus_is_enabled, |
---|
| 1128 | +}; |
---|
| 1129 | + |
---|
| 1130 | +static const struct regulator_desc bq25890_otg_vbus_desc = { |
---|
| 1131 | + .name = "otg-vbus", |
---|
| 1132 | + .of_match = "otg-vbus", |
---|
| 1133 | + .regulators_node = of_match_ptr("regulators"), |
---|
| 1134 | + .owner = THIS_MODULE, |
---|
| 1135 | + .ops = &bq25890_otg_vbus_ops, |
---|
| 1136 | + .type = REGULATOR_VOLTAGE, |
---|
| 1137 | + .fixed_uV = 5000000, |
---|
| 1138 | + .n_voltages = 1, |
---|
| 1139 | +}; |
---|
| 1140 | + |
---|
| 1141 | +static int bq25890_register_otg_vbus_regulator(struct bq25890_device *bq) |
---|
| 1142 | +{ |
---|
| 1143 | + struct device_node *np; |
---|
| 1144 | + struct regulator_config config = { }; |
---|
| 1145 | + |
---|
| 1146 | + np = of_get_child_by_name(bq->dev->of_node, "regulators"); |
---|
| 1147 | + if (!np) { |
---|
| 1148 | + dev_warn(bq->dev, "cannot find regulators node\n"); |
---|
| 1149 | + return -ENXIO; |
---|
| 1150 | + } |
---|
| 1151 | + |
---|
| 1152 | + config.dev = bq->dev; |
---|
| 1153 | + config.driver_data = bq; |
---|
| 1154 | + |
---|
| 1155 | + bq->otg_vbus_reg = devm_regulator_register(bq->dev, |
---|
| 1156 | + &bq25890_otg_vbus_desc, |
---|
| 1157 | + &config); |
---|
| 1158 | + if (IS_ERR(bq->otg_vbus_reg)) |
---|
| 1159 | + return PTR_ERR(bq->otg_vbus_reg); |
---|
| 1160 | + |
---|
| 1161 | + return 0; |
---|
| 1162 | +} |
---|
| 1163 | + |
---|
| 1164 | +static int bq25890_otg_register(struct bq25890_device *bq) |
---|
| 1165 | +{ |
---|
| 1166 | + int ret; |
---|
| 1167 | + |
---|
| 1168 | + /* OTG reporting */ |
---|
| 1169 | + bq->usb_phy = devm_usb_get_phy(bq->dev, USB_PHY_TYPE_USB2); |
---|
| 1170 | + if (!IS_ERR_OR_NULL(bq->usb_phy)) { |
---|
| 1171 | + INIT_WORK(&bq->usb_work, bq25890_usb_work); |
---|
| 1172 | + bq->usb_nb.notifier_call = bq25890_usb_notifier; |
---|
| 1173 | + usb_register_notifier(bq->usb_phy, &bq->usb_nb); |
---|
| 1174 | + return 0; |
---|
| 1175 | + } |
---|
| 1176 | + |
---|
| 1177 | + ret = bq25890_register_otg_vbus_regulator(bq); |
---|
| 1178 | + if (ret < 0) { |
---|
| 1179 | + dev_warn(bq->dev, |
---|
| 1180 | + "Cannot register otg vbus regulator\n"); |
---|
| 1181 | + bq->otg_vbus_reg = NULL; |
---|
| 1182 | + |
---|
| 1183 | + return ret; |
---|
| 1184 | + } |
---|
791 | 1185 | |
---|
792 | 1186 | return 0; |
---|
793 | 1187 | } |
---|
.. | .. |
---|
795 | 1189 | static int bq25890_probe(struct i2c_client *client, |
---|
796 | 1190 | const struct i2c_device_id *id) |
---|
797 | 1191 | { |
---|
798 | | - struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); |
---|
799 | 1192 | struct device *dev = &client->dev; |
---|
800 | 1193 | struct bq25890_device *bq; |
---|
801 | 1194 | int ret; |
---|
802 | 1195 | int i; |
---|
803 | | - |
---|
804 | | - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { |
---|
805 | | - dev_err(dev, "No support for SMBUS_BYTE_DATA\n"); |
---|
806 | | - return -ENODEV; |
---|
807 | | - } |
---|
808 | 1196 | |
---|
809 | 1197 | bq = devm_kzalloc(dev, sizeof(*bq), GFP_KERNEL); |
---|
810 | 1198 | if (!bq) |
---|
.. | .. |
---|
834 | 1222 | |
---|
835 | 1223 | i2c_set_clientdata(client, bq); |
---|
836 | 1224 | |
---|
837 | | - bq->chip_id = bq25890_field_read(bq, F_PN); |
---|
838 | | - if (bq->chip_id < 0) { |
---|
839 | | - dev_err(dev, "Cannot read chip ID.\n"); |
---|
840 | | - return bq->chip_id; |
---|
841 | | - } |
---|
842 | | - |
---|
843 | | - if (bq->chip_id != BQ25890_ID) { |
---|
844 | | - dev_err(dev, "Chip with ID=%d, not supported!\n", bq->chip_id); |
---|
845 | | - return -ENODEV; |
---|
| 1225 | + ret = bq25890_get_chip_version(bq); |
---|
| 1226 | + if (ret) { |
---|
| 1227 | + dev_err(dev, "Cannot read chip ID or unknown chip.\n"); |
---|
| 1228 | + return ret; |
---|
846 | 1229 | } |
---|
847 | 1230 | |
---|
848 | 1231 | if (!dev->platform_data) { |
---|
.. | .. |
---|
869 | 1252 | return client->irq; |
---|
870 | 1253 | } |
---|
871 | 1254 | |
---|
872 | | - /* OTG reporting */ |
---|
873 | | - bq->usb_phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB2); |
---|
874 | | - if (!IS_ERR_OR_NULL(bq->usb_phy)) { |
---|
875 | | - INIT_WORK(&bq->usb_work, bq25890_usb_work); |
---|
876 | | - bq->usb_nb.notifier_call = bq25890_usb_notifier; |
---|
877 | | - usb_register_notifier(bq->usb_phy, &bq->usb_nb); |
---|
878 | | - } |
---|
| 1255 | + bq25890_otg_register(bq); |
---|
879 | 1256 | |
---|
880 | 1257 | ret = devm_request_threaded_irq(dev, client->irq, NULL, |
---|
881 | 1258 | bq25890_irq_handler_thread, |
---|
.. | .. |
---|
889 | 1266 | dev_err(dev, "Failed to register power supply\n"); |
---|
890 | 1267 | goto irq_fail; |
---|
891 | 1268 | } |
---|
| 1269 | + |
---|
| 1270 | + bq25890_register_pd_psy(bq); |
---|
892 | 1271 | |
---|
893 | 1272 | return 0; |
---|
894 | 1273 | |
---|
.. | .. |
---|
923 | 1302 | * If charger is removed, while in suspend, make sure ADC is diabled |
---|
924 | 1303 | * since it consumes slightly more power. |
---|
925 | 1304 | */ |
---|
926 | | - return bq25890_field_write(bq, F_CONV_START, 0); |
---|
| 1305 | + return bq25890_field_write(bq, F_CONV_RATE, 0); |
---|
927 | 1306 | } |
---|
928 | 1307 | |
---|
929 | 1308 | static int bq25890_resume(struct device *dev) |
---|
930 | 1309 | { |
---|
931 | 1310 | int ret; |
---|
932 | | - struct bq25890_state state; |
---|
933 | 1311 | struct bq25890_device *bq = dev_get_drvdata(dev); |
---|
934 | 1312 | |
---|
935 | | - ret = bq25890_get_chip_state(bq, &state); |
---|
936 | | - if (ret < 0) |
---|
937 | | - return ret; |
---|
938 | | - |
---|
939 | 1313 | mutex_lock(&bq->lock); |
---|
940 | | - bq->state = state; |
---|
941 | | - mutex_unlock(&bq->lock); |
---|
| 1314 | + |
---|
| 1315 | + ret = bq25890_get_chip_state(bq, &bq->state); |
---|
| 1316 | + if (ret < 0) |
---|
| 1317 | + goto unlock; |
---|
942 | 1318 | |
---|
943 | 1319 | /* Re-enable ADC only if charger is plugged in. */ |
---|
944 | | - if (state.online) { |
---|
945 | | - ret = bq25890_field_write(bq, F_CONV_START, 1); |
---|
| 1320 | + if (bq->state.online) { |
---|
| 1321 | + ret = bq25890_field_write(bq, F_CONV_RATE, 1); |
---|
946 | 1322 | if (ret < 0) |
---|
947 | | - return ret; |
---|
| 1323 | + goto unlock; |
---|
948 | 1324 | } |
---|
949 | 1325 | |
---|
950 | 1326 | /* signal userspace, maybe state changed while suspended */ |
---|
951 | 1327 | power_supply_changed(bq->charger); |
---|
952 | 1328 | |
---|
953 | | - return 0; |
---|
| 1329 | +unlock: |
---|
| 1330 | + mutex_unlock(&bq->lock); |
---|
| 1331 | + |
---|
| 1332 | + return ret; |
---|
954 | 1333 | } |
---|
955 | 1334 | #endif |
---|
956 | 1335 | |
---|
.. | .. |
---|
960 | 1339 | |
---|
961 | 1340 | static const struct i2c_device_id bq25890_i2c_ids[] = { |
---|
962 | 1341 | { "bq25890", 0 }, |
---|
| 1342 | + { "bq25892", 0 }, |
---|
| 1343 | + { "bq25895", 0 }, |
---|
| 1344 | + { "bq25896", 0 }, |
---|
| 1345 | + { "sy6970", 0 }, |
---|
963 | 1346 | {}, |
---|
964 | 1347 | }; |
---|
965 | 1348 | MODULE_DEVICE_TABLE(i2c, bq25890_i2c_ids); |
---|
966 | 1349 | |
---|
967 | 1350 | static const struct of_device_id bq25890_of_match[] = { |
---|
968 | 1351 | { .compatible = "ti,bq25890", }, |
---|
| 1352 | + { .compatible = "ti,bq25892", }, |
---|
| 1353 | + { .compatible = "ti,bq25895", }, |
---|
| 1354 | + { .compatible = "ti,bq25896", }, |
---|
| 1355 | + { .compatible = "sy,sy6970", }, |
---|
969 | 1356 | { }, |
---|
970 | 1357 | }; |
---|
971 | 1358 | MODULE_DEVICE_TABLE(of, bq25890_of_match); |
---|
972 | 1359 | |
---|
| 1360 | +#ifdef CONFIG_ACPI |
---|
973 | 1361 | static const struct acpi_device_id bq25890_acpi_match[] = { |
---|
974 | 1362 | {"BQ258900", 0}, |
---|
975 | 1363 | {}, |
---|
976 | 1364 | }; |
---|
977 | 1365 | MODULE_DEVICE_TABLE(acpi, bq25890_acpi_match); |
---|
| 1366 | +#endif |
---|
978 | 1367 | |
---|
979 | 1368 | static struct i2c_driver bq25890_driver = { |
---|
980 | 1369 | .driver = { |
---|