| .. | .. |
|---|
| 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 = { |
|---|