Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

power_supply: Add support for TI BQ25890 charger chip

More details about the chip can be found here:
http://www.ti.com/product/bq25890

Signed-off-by: Laurentiu Palcu <laurentiu.palcu@intel.com>
Reviewed-by: Krzysztof Kozlowski <k.kozlowski@samsung.com>
Signed-off-by: Sebastian Reichel <sre@kernel.org>

authored by

Laurentiu Palcu and committed by
Sebastian Reichel
4aeae9cb 7e9f8a25

+1007
+7
drivers/power/Kconfig
··· 401 401 help 402 402 Say Y to enable support for the TI BQ24735 battery charger. 403 403 404 + config CHARGER_BQ25890 405 + tristate "TI BQ25890 battery charger driver" 406 + depends on I2C && GPIOLIB 407 + select REGMAP_I2C 408 + help 409 + Say Y to enable support for the TI BQ25890 battery charger. 410 + 404 411 config CHARGER_SMB347 405 412 tristate "Summit Microelectronics SMB347 Battery Charger" 406 413 depends on I2C
+1
drivers/power/Makefile
··· 60 60 obj-$(CONFIG_CHARGER_BQ24190) += bq24190_charger.o 61 61 obj-$(CONFIG_CHARGER_BQ24257) += bq24257_charger.o 62 62 obj-$(CONFIG_CHARGER_BQ24735) += bq24735-charger.o 63 + obj-$(CONFIG_CHARGER_BQ25890) += bq25890_charger.o 63 64 obj-$(CONFIG_POWER_AVS) += avs/ 64 65 obj-$(CONFIG_CHARGER_SMB347) += smb347-charger.o 65 66 obj-$(CONFIG_CHARGER_TPS65090) += tps65090-charger.o
+999
drivers/power/bq25890_charger.c
··· 1 + /* 2 + * TI BQ25890 charger driver 3 + * 4 + * 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 + */ 17 + 18 + #include <linux/module.h> 19 + #include <linux/i2c.h> 20 + #include <linux/power_supply.h> 21 + #include <linux/regmap.h> 22 + #include <linux/types.h> 23 + #include <linux/gpio/consumer.h> 24 + #include <linux/interrupt.h> 25 + #include <linux/delay.h> 26 + #include <linux/usb/phy.h> 27 + 28 + #include <linux/acpi.h> 29 + #include <linux/of.h> 30 + 31 + #define BQ25890_MANUFACTURER "Texas Instruments" 32 + #define BQ25890_IRQ_PIN "bq25890_irq" 33 + 34 + #define BQ25890_ID 3 35 + 36 + enum bq25890_fields { 37 + F_EN_HIZ, F_EN_ILIM, F_IILIM, /* Reg00 */ 38 + F_BHOT, F_BCOLD, F_VINDPM_OFS, /* Reg01 */ 39 + F_CONV_START, F_CONV_RATE, F_BOOSTF, F_ICO_EN, 40 + 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 */ 42 + F_PUMPX_EN, F_ICHG, /* Reg04 */ 43 + F_IPRECHG, F_ITERM, /* Reg05 */ 44 + F_VREG, F_BATLOWV, F_VRECHG, /* Reg06 */ 45 + F_TERM_EN, F_STAT_DIS, F_WD, F_TMR_EN, F_CHG_TMR, 46 + F_JEITA_ISET, /* Reg07 */ 47 + F_BATCMP, F_VCLAMP, F_TREG, /* Reg08 */ 48 + F_FORCE_ICO, F_TMR2X_EN, F_BATFET_DIS, F_JEITA_VSET, 49 + 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 */ 52 + F_WD_FAULT, F_BOOST_FAULT, F_CHG_FAULT, F_BAT_FAULT, 53 + F_NTC_FAULT, /* Reg0C */ 54 + F_FORCE_VINDPM, F_VINDPM, /* Reg0D */ 55 + F_THERM_STAT, F_BATV, /* Reg0E */ 56 + F_SYSV, /* Reg0F */ 57 + F_TSPCT, /* Reg10 */ 58 + F_VBUS_GD, F_VBUSV, /* Reg11 */ 59 + F_ICHGR, /* Reg12 */ 60 + F_VDPM_STAT, F_IDPM_STAT, F_IDPM_LIM, /* Reg13 */ 61 + F_REG_RST, F_ICO_OPTIMIZED, F_PN, F_TS_PROFILE, F_DEV_REV, /* Reg14 */ 62 + 63 + F_MAX_FIELDS 64 + }; 65 + 66 + /* initial field values, converted to register values */ 67 + struct bq25890_init_data { 68 + u8 ichg; /* charge current */ 69 + u8 vreg; /* regulation voltage */ 70 + u8 iterm; /* termination current */ 71 + u8 iprechg; /* precharge current */ 72 + u8 sysvmin; /* minimum system voltage limit */ 73 + u8 boostv; /* boost regulation voltage */ 74 + u8 boosti; /* boost current limit */ 75 + u8 boostf; /* boost frequency */ 76 + u8 ilim_en; /* enable ILIM pin */ 77 + u8 treg; /* thermal regulation threshold */ 78 + }; 79 + 80 + struct bq25890_state { 81 + u8 online; 82 + u8 chrg_status; 83 + u8 chrg_fault; 84 + u8 vsys_status; 85 + u8 boost_fault; 86 + u8 bat_fault; 87 + }; 88 + 89 + struct bq25890_device { 90 + struct i2c_client *client; 91 + struct device *dev; 92 + struct power_supply *charger; 93 + 94 + struct usb_phy *usb_phy; 95 + struct notifier_block usb_nb; 96 + struct work_struct usb_work; 97 + unsigned long usb_event; 98 + 99 + struct regmap *rmap; 100 + struct regmap_field *rmap_fields[F_MAX_FIELDS]; 101 + 102 + u8 chip_id; 103 + struct bq25890_init_data init_data; 104 + struct bq25890_state state; 105 + 106 + struct mutex lock; /* protect state data */ 107 + }; 108 + 109 + static const struct regmap_range bq25890_readonly_reg_ranges[] = { 110 + regmap_reg_range(0x0b, 0x0c), 111 + regmap_reg_range(0x0e, 0x13), 112 + }; 113 + 114 + static const struct regmap_access_table bq25890_writeable_regs = { 115 + .no_ranges = bq25890_readonly_reg_ranges, 116 + .n_no_ranges = ARRAY_SIZE(bq25890_readonly_reg_ranges), 117 + }; 118 + 119 + static const struct regmap_range bq25890_volatile_reg_ranges[] = { 120 + regmap_reg_range(0x00, 0x00), 121 + regmap_reg_range(0x09, 0x09), 122 + regmap_reg_range(0x0b, 0x0c), 123 + regmap_reg_range(0x0e, 0x14), 124 + }; 125 + 126 + static const struct regmap_access_table bq25890_volatile_regs = { 127 + .yes_ranges = bq25890_volatile_reg_ranges, 128 + .n_yes_ranges = ARRAY_SIZE(bq25890_volatile_reg_ranges), 129 + }; 130 + 131 + static const struct regmap_config bq25890_regmap_config = { 132 + .reg_bits = 8, 133 + .val_bits = 8, 134 + 135 + .max_register = 0x14, 136 + .cache_type = REGCACHE_RBTREE, 137 + 138 + .wr_table = &bq25890_writeable_regs, 139 + .volatile_table = &bq25890_volatile_regs, 140 + }; 141 + 142 + static const struct reg_field bq25890_reg_fields[] = { 143 + /* REG00 */ 144 + [F_EN_HIZ] = REG_FIELD(0x00, 7, 7), 145 + [F_EN_ILIM] = REG_FIELD(0x00, 6, 6), 146 + [F_IILIM] = REG_FIELD(0x00, 0, 5), 147 + /* REG01 */ 148 + [F_BHOT] = REG_FIELD(0x01, 6, 7), 149 + [F_BCOLD] = REG_FIELD(0x01, 5, 5), 150 + [F_VINDPM_OFS] = REG_FIELD(0x01, 0, 4), 151 + /* REG02 */ 152 + [F_CONV_START] = REG_FIELD(0x02, 7, 7), 153 + [F_CONV_RATE] = REG_FIELD(0x02, 6, 6), 154 + [F_BOOSTF] = REG_FIELD(0x02, 5, 5), 155 + [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), 158 + [F_FORCE_DPM] = REG_FIELD(0x02, 1, 1), 159 + [F_AUTO_DPDM_EN] = REG_FIELD(0x02, 0, 0), 160 + /* REG03 */ 161 + [F_BAT_LOAD_EN] = REG_FIELD(0x03, 7, 7), 162 + [F_WD_RST] = REG_FIELD(0x03, 6, 6), 163 + [F_OTG_CFG] = REG_FIELD(0x03, 5, 5), 164 + [F_CHG_CFG] = REG_FIELD(0x03, 4, 4), 165 + [F_SYSVMIN] = REG_FIELD(0x03, 1, 3), 166 + /* REG04 */ 167 + [F_PUMPX_EN] = REG_FIELD(0x04, 7, 7), 168 + [F_ICHG] = REG_FIELD(0x04, 0, 6), 169 + /* REG05 */ 170 + [F_IPRECHG] = REG_FIELD(0x05, 4, 7), 171 + [F_ITERM] = REG_FIELD(0x05, 0, 3), 172 + /* REG06 */ 173 + [F_VREG] = REG_FIELD(0x06, 2, 7), 174 + [F_BATLOWV] = REG_FIELD(0x06, 1, 1), 175 + [F_VRECHG] = REG_FIELD(0x06, 0, 0), 176 + /* REG07 */ 177 + [F_TERM_EN] = REG_FIELD(0x07, 7, 7), 178 + [F_STAT_DIS] = REG_FIELD(0x07, 6, 6), 179 + [F_WD] = REG_FIELD(0x07, 4, 5), 180 + [F_TMR_EN] = REG_FIELD(0x07, 3, 3), 181 + [F_CHG_TMR] = REG_FIELD(0x07, 1, 2), 182 + [F_JEITA_ISET] = REG_FIELD(0x07, 0, 0), 183 + /* REG08 */ 184 + [F_BATCMP] = REG_FIELD(0x08, 6, 7), 185 + [F_VCLAMP] = REG_FIELD(0x08, 2, 4), 186 + [F_TREG] = REG_FIELD(0x08, 0, 1), 187 + /* REG09 */ 188 + [F_FORCE_ICO] = REG_FIELD(0x09, 7, 7), 189 + [F_TMR2X_EN] = REG_FIELD(0x09, 6, 6), 190 + [F_BATFET_DIS] = REG_FIELD(0x09, 5, 5), 191 + [F_JEITA_VSET] = REG_FIELD(0x09, 4, 4), 192 + [F_BATFET_DLY] = REG_FIELD(0x09, 3, 3), 193 + [F_BATFET_RST_EN] = REG_FIELD(0x09, 2, 2), 194 + [F_PUMPX_UP] = REG_FIELD(0x09, 1, 1), 195 + [F_PUMPX_DN] = REG_FIELD(0x09, 0, 0), 196 + /* REG0A */ 197 + [F_BOOSTV] = REG_FIELD(0x0A, 4, 7), 198 + [F_BOOSTI] = REG_FIELD(0x0A, 0, 2), 199 + /* REG0B */ 200 + [F_VBUS_STAT] = REG_FIELD(0x0B, 5, 7), 201 + [F_CHG_STAT] = REG_FIELD(0x0B, 3, 4), 202 + [F_PG_STAT] = REG_FIELD(0x0B, 2, 2), 203 + [F_SDP_STAT] = REG_FIELD(0x0B, 1, 1), 204 + [F_VSYS_STAT] = REG_FIELD(0x0B, 0, 0), 205 + /* REG0C */ 206 + [F_WD_FAULT] = REG_FIELD(0x0C, 7, 7), 207 + [F_BOOST_FAULT] = REG_FIELD(0x0C, 6, 6), 208 + [F_CHG_FAULT] = REG_FIELD(0x0C, 4, 5), 209 + [F_BAT_FAULT] = REG_FIELD(0x0C, 3, 3), 210 + [F_NTC_FAULT] = REG_FIELD(0x0C, 0, 2), 211 + /* REG0D */ 212 + [F_FORCE_VINDPM] = REG_FIELD(0x0D, 7, 7), 213 + [F_VINDPM] = REG_FIELD(0x0D, 0, 6), 214 + /* REG0E */ 215 + [F_THERM_STAT] = REG_FIELD(0x0E, 7, 7), 216 + [F_BATV] = REG_FIELD(0x0E, 0, 6), 217 + /* REG0F */ 218 + [F_SYSV] = REG_FIELD(0x0F, 0, 6), 219 + /* REG10 */ 220 + [F_TSPCT] = REG_FIELD(0x10, 0, 6), 221 + /* REG11 */ 222 + [F_VBUS_GD] = REG_FIELD(0x11, 7, 7), 223 + [F_VBUSV] = REG_FIELD(0x11, 0, 6), 224 + /* REG12 */ 225 + [F_ICHGR] = REG_FIELD(0x12, 0, 6), 226 + /* REG13 */ 227 + [F_VDPM_STAT] = REG_FIELD(0x13, 7, 7), 228 + [F_IDPM_STAT] = REG_FIELD(0x13, 6, 6), 229 + [F_IDPM_LIM] = REG_FIELD(0x13, 0, 5), 230 + /* REG14 */ 231 + [F_REG_RST] = REG_FIELD(0x14, 7, 7), 232 + [F_ICO_OPTIMIZED] = REG_FIELD(0x14, 6, 6), 233 + [F_PN] = REG_FIELD(0x14, 3, 5), 234 + [F_TS_PROFILE] = REG_FIELD(0x14, 2, 2), 235 + [F_DEV_REV] = REG_FIELD(0x14, 0, 1) 236 + }; 237 + 238 + /* 239 + * Most of the val -> idx conversions can be computed, given the minimum, 240 + * maximum and the step between values. For the rest of conversions, we use 241 + * lookup tables. 242 + */ 243 + enum bq25890_table_ids { 244 + /* range tables */ 245 + TBL_ICHG, 246 + TBL_ITERM, 247 + TBL_IPRECHG, 248 + TBL_VREG, 249 + TBL_BATCMP, 250 + TBL_VCLAMP, 251 + TBL_BOOSTV, 252 + TBL_SYSVMIN, 253 + 254 + /* lookup tables */ 255 + TBL_TREG, 256 + TBL_BOOSTI, 257 + }; 258 + 259 + /* Thermal Regulation Threshold lookup table, in degrees Celsius */ 260 + static const u32 bq25890_treg_tbl[] = { 60, 80, 100, 120 }; 261 + 262 + #define BQ25890_TREG_TBL_SIZE ARRAY_SIZE(bq25890_treg_tbl) 263 + 264 + /* Boost mode current limit lookup table, in uA */ 265 + static const u32 bq25890_boosti_tbl[] = { 266 + 500000, 700000, 1100000, 1300000, 1600000, 1800000, 2100000, 2400000 267 + }; 268 + 269 + #define BQ25890_BOOSTI_TBL_SIZE ARRAY_SIZE(bq25890_boosti_tbl) 270 + 271 + struct bq25890_range { 272 + u32 min; 273 + u32 max; 274 + u32 step; 275 + }; 276 + 277 + struct bq25890_lookup { 278 + const u32 *tbl; 279 + u32 size; 280 + }; 281 + 282 + static const union { 283 + struct bq25890_range rt; 284 + struct bq25890_lookup lt; 285 + } bq25890_tables[] = { 286 + /* range tables */ 287 + [TBL_ICHG] = { .rt = {0, 5056000, 64000} }, /* uA */ 288 + [TBL_ITERM] = { .rt = {64000, 1024000, 64000} }, /* uA */ 289 + [TBL_VREG] = { .rt = {3840000, 4608000, 16000} }, /* uV */ 290 + [TBL_BATCMP] = { .rt = {0, 140, 20} }, /* mOhm */ 291 + [TBL_VCLAMP] = { .rt = {0, 224000, 32000} }, /* uV */ 292 + [TBL_BOOSTV] = { .rt = {4550000, 5510000, 64000} }, /* uV */ 293 + [TBL_SYSVMIN] = { .rt = {3000000, 3700000, 100000} }, /* uV */ 294 + 295 + /* lookup tables */ 296 + [TBL_TREG] = { .lt = {bq25890_treg_tbl, BQ25890_TREG_TBL_SIZE} }, 297 + [TBL_BOOSTI] = { .lt = {bq25890_boosti_tbl, BQ25890_BOOSTI_TBL_SIZE} } 298 + }; 299 + 300 + static int bq25890_field_read(struct bq25890_device *bq, 301 + enum bq25890_fields field_id) 302 + { 303 + int ret; 304 + int val; 305 + 306 + ret = regmap_field_read(bq->rmap_fields[field_id], &val); 307 + if (ret < 0) 308 + return ret; 309 + 310 + return val; 311 + } 312 + 313 + static int bq25890_field_write(struct bq25890_device *bq, 314 + enum bq25890_fields field_id, u8 val) 315 + { 316 + return regmap_field_write(bq->rmap_fields[field_id], val); 317 + } 318 + 319 + static u8 bq25890_find_idx(u32 value, enum bq25890_table_ids id) 320 + { 321 + u8 idx; 322 + 323 + if (id >= TBL_TREG) { 324 + const u32 *tbl = bq25890_tables[id].lt.tbl; 325 + u32 tbl_size = bq25890_tables[id].lt.size; 326 + 327 + for (idx = 1; idx < tbl_size && tbl[idx] <= value; idx++) 328 + ; 329 + } else { 330 + const struct bq25890_range *rtbl = &bq25890_tables[id].rt; 331 + u8 rtbl_size; 332 + 333 + rtbl_size = (rtbl->max - rtbl->min) / rtbl->step + 1; 334 + 335 + for (idx = 1; 336 + idx < rtbl_size && (idx * rtbl->step + rtbl->min <= value); 337 + idx++) 338 + ; 339 + } 340 + 341 + return idx - 1; 342 + } 343 + 344 + static u32 bq25890_find_val(u8 idx, enum bq25890_table_ids id) 345 + { 346 + const struct bq25890_range *rtbl; 347 + 348 + /* lookup table? */ 349 + if (id >= TBL_TREG) 350 + return bq25890_tables[id].lt.tbl[idx]; 351 + 352 + /* range table */ 353 + rtbl = &bq25890_tables[id].rt; 354 + 355 + return (rtbl->min + idx * rtbl->step); 356 + } 357 + 358 + enum bq25890_status { 359 + STATUS_NOT_CHARGING, 360 + STATUS_PRE_CHARGING, 361 + STATUS_FAST_CHARGING, 362 + STATUS_TERMINATION_DONE, 363 + }; 364 + 365 + enum bq25890_chrg_fault { 366 + CHRG_FAULT_NORMAL, 367 + CHRG_FAULT_INPUT, 368 + CHRG_FAULT_THERMAL_SHUTDOWN, 369 + CHRG_FAULT_TIMER_EXPIRED, 370 + }; 371 + 372 + static int bq25890_power_supply_get_property(struct power_supply *psy, 373 + enum power_supply_property psp, 374 + union power_supply_propval *val) 375 + { 376 + int ret; 377 + struct bq25890_device *bq = power_supply_get_drvdata(psy); 378 + struct bq25890_state state; 379 + 380 + mutex_lock(&bq->lock); 381 + state = bq->state; 382 + mutex_unlock(&bq->lock); 383 + 384 + switch (psp) { 385 + case POWER_SUPPLY_PROP_STATUS: 386 + if (!state.online) 387 + val->intval = POWER_SUPPLY_STATUS_DISCHARGING; 388 + else if (state.chrg_status == STATUS_NOT_CHARGING) 389 + val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING; 390 + else if (state.chrg_status == STATUS_PRE_CHARGING || 391 + state.chrg_status == STATUS_FAST_CHARGING) 392 + val->intval = POWER_SUPPLY_STATUS_CHARGING; 393 + else if (state.chrg_status == STATUS_TERMINATION_DONE) 394 + val->intval = POWER_SUPPLY_STATUS_FULL; 395 + else 396 + val->intval = POWER_SUPPLY_STATUS_UNKNOWN; 397 + 398 + break; 399 + 400 + case POWER_SUPPLY_PROP_MANUFACTURER: 401 + val->strval = BQ25890_MANUFACTURER; 402 + break; 403 + 404 + case POWER_SUPPLY_PROP_ONLINE: 405 + val->intval = state.online; 406 + break; 407 + 408 + case POWER_SUPPLY_PROP_HEALTH: 409 + if (!state.chrg_fault && !state.bat_fault && !state.boost_fault) 410 + val->intval = POWER_SUPPLY_HEALTH_GOOD; 411 + else if (state.bat_fault) 412 + val->intval = POWER_SUPPLY_HEALTH_OVERVOLTAGE; 413 + else if (state.chrg_fault == CHRG_FAULT_TIMER_EXPIRED) 414 + val->intval = POWER_SUPPLY_HEALTH_SAFETY_TIMER_EXPIRE; 415 + else if (state.chrg_fault == CHRG_FAULT_THERMAL_SHUTDOWN) 416 + val->intval = POWER_SUPPLY_HEALTH_OVERHEAT; 417 + else 418 + val->intval = POWER_SUPPLY_HEALTH_UNSPEC_FAILURE; 419 + break; 420 + 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 + case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX: 431 + val->intval = bq25890_tables[TBL_ICHG].rt.max; 432 + break; 433 + 434 + case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE: 435 + if (!state.online) { 436 + val->intval = 0; 437 + break; 438 + } 439 + 440 + ret = bq25890_field_read(bq, F_BATV); /* read measured value */ 441 + if (ret < 0) 442 + return ret; 443 + 444 + /* converted_val = 2.304V + ADC_val * 20mV (table 10.3.15) */ 445 + val->intval = 2304000 + ret * 20000; 446 + break; 447 + 448 + case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX: 449 + val->intval = bq25890_tables[TBL_VREG].rt.max; 450 + break; 451 + 452 + case POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT: 453 + val->intval = bq25890_find_val(bq->init_data.iterm, TBL_ITERM); 454 + break; 455 + 456 + default: 457 + return -EINVAL; 458 + } 459 + 460 + return 0; 461 + } 462 + 463 + static int bq25890_get_chip_state(struct bq25890_device *bq, 464 + struct bq25890_state *state) 465 + { 466 + int i, ret; 467 + 468 + struct { 469 + enum bq25890_fields id; 470 + u8 *data; 471 + } state_fields[] = { 472 + {F_CHG_STAT, &state->chrg_status}, 473 + {F_PG_STAT, &state->online}, 474 + {F_VSYS_STAT, &state->vsys_status}, 475 + {F_BOOST_FAULT, &state->boost_fault}, 476 + {F_BAT_FAULT, &state->bat_fault}, 477 + {F_CHG_FAULT, &state->chrg_fault} 478 + }; 479 + 480 + for (i = 0; i < ARRAY_SIZE(state_fields); i++) { 481 + ret = bq25890_field_read(bq, state_fields[i].id); 482 + if (ret < 0) 483 + return ret; 484 + 485 + *state_fields[i].data = ret; 486 + } 487 + 488 + dev_dbg(bq->dev, "S:CHG/PG/VSYS=%d/%d/%d, F:CHG/BOOST/BAT=%d/%d/%d\n", 489 + state->chrg_status, state->online, state->vsys_status, 490 + state->chrg_fault, state->boost_fault, state->bat_fault); 491 + 492 + return 0; 493 + } 494 + 495 + static bool bq25890_state_changed(struct bq25890_device *bq, 496 + struct bq25890_state *new_state) 497 + { 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 + { 515 + int ret; 516 + struct bq25890_state old_state; 517 + 518 + mutex_lock(&bq->lock); 519 + old_state = bq->state; 520 + mutex_unlock(&bq->lock); 521 + 522 + if (!new_state->online) { /* power removed */ 523 + /* disable ADC */ 524 + ret = bq25890_field_write(bq, F_CONV_START, 0); 525 + if (ret < 0) 526 + goto error; 527 + } else if (!old_state.online) { /* power inserted */ 528 + /* enable ADC, to have control of charge current/voltage */ 529 + ret = bq25890_field_write(bq, F_CONV_START, 1); 530 + if (ret < 0) 531 + goto error; 532 + } 533 + 534 + return; 535 + 536 + error: 537 + dev_err(bq->dev, "Error communicating with the chip.\n"); 538 + } 539 + 540 + static irqreturn_t bq25890_irq_handler_thread(int irq, void *private) 541 + { 542 + 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); 554 + 555 + mutex_lock(&bq->lock); 556 + bq->state = state; 557 + mutex_unlock(&bq->lock); 558 + 559 + power_supply_changed(bq->charger); 560 + 561 + handled: 562 + return IRQ_HANDLED; 563 + } 564 + 565 + static int bq25890_chip_reset(struct bq25890_device *bq) 566 + { 567 + int ret; 568 + int rst_check_counter = 10; 569 + 570 + ret = bq25890_field_write(bq, F_REG_RST, 1); 571 + if (ret < 0) 572 + return ret; 573 + 574 + do { 575 + ret = bq25890_field_read(bq, F_REG_RST); 576 + if (ret < 0) 577 + return ret; 578 + 579 + usleep_range(5, 10); 580 + } while (ret == 1 && --rst_check_counter); 581 + 582 + if (!rst_check_counter) 583 + return -ETIMEDOUT; 584 + 585 + return 0; 586 + } 587 + 588 + static int bq25890_hw_init(struct bq25890_device *bq) 589 + { 590 + int ret; 591 + int i; 592 + struct bq25890_state state; 593 + 594 + const struct { 595 + enum bq25890_fields id; 596 + u32 value; 597 + } init_data[] = { 598 + {F_ICHG, bq->init_data.ichg}, 599 + {F_VREG, bq->init_data.vreg}, 600 + {F_ITERM, bq->init_data.iterm}, 601 + {F_IPRECHG, bq->init_data.iprechg}, 602 + {F_SYSVMIN, bq->init_data.sysvmin}, 603 + {F_BOOSTV, bq->init_data.boostv}, 604 + {F_BOOSTI, bq->init_data.boosti}, 605 + {F_BOOSTF, bq->init_data.boostf}, 606 + {F_EN_ILIM, bq->init_data.ilim_en}, 607 + {F_TREG, bq->init_data.treg} 608 + }; 609 + 610 + ret = bq25890_chip_reset(bq); 611 + if (ret < 0) 612 + return ret; 613 + 614 + /* disable watchdog */ 615 + ret = bq25890_field_write(bq, F_WD, 0); 616 + if (ret < 0) 617 + return ret; 618 + 619 + /* initialize currents/voltages and other parameters */ 620 + for (i = 0; i < ARRAY_SIZE(init_data); i++) { 621 + ret = bq25890_field_write(bq, init_data[i].id, 622 + init_data[i].value); 623 + if (ret < 0) 624 + return ret; 625 + } 626 + 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) 630 + return ret; 631 + 632 + ret = bq25890_get_chip_state(bq, &state); 633 + if (ret < 0) 634 + return ret; 635 + 636 + mutex_lock(&bq->lock); 637 + bq->state = state; 638 + mutex_unlock(&bq->lock); 639 + 640 + return 0; 641 + } 642 + 643 + static enum power_supply_property bq25890_power_supply_props[] = { 644 + POWER_SUPPLY_PROP_MANUFACTURER, 645 + POWER_SUPPLY_PROP_STATUS, 646 + POWER_SUPPLY_PROP_ONLINE, 647 + POWER_SUPPLY_PROP_HEALTH, 648 + POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT, 649 + POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX, 650 + POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE, 651 + POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX, 652 + POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT, 653 + }; 654 + 655 + static char *bq25890_charger_supplied_to[] = { 656 + "main-battery", 657 + }; 658 + 659 + static const struct power_supply_desc bq25890_power_supply_desc = { 660 + .name = "bq25890-charger", 661 + .type = POWER_SUPPLY_TYPE_USB, 662 + .properties = bq25890_power_supply_props, 663 + .num_properties = ARRAY_SIZE(bq25890_power_supply_props), 664 + .get_property = bq25890_power_supply_get_property, 665 + }; 666 + 667 + static int bq25890_power_supply_init(struct bq25890_device *bq) 668 + { 669 + struct power_supply_config psy_cfg = { .drv_data = bq, }; 670 + 671 + psy_cfg.supplied_to = bq25890_charger_supplied_to; 672 + psy_cfg.num_supplicants = ARRAY_SIZE(bq25890_charger_supplied_to); 673 + 674 + bq->charger = power_supply_register(bq->dev, &bq25890_power_supply_desc, 675 + &psy_cfg); 676 + 677 + return PTR_ERR_OR_ZERO(bq->charger); 678 + } 679 + 680 + static void bq25890_usb_work(struct work_struct *data) 681 + { 682 + int ret; 683 + struct bq25890_device *bq = 684 + container_of(data, struct bq25890_device, usb_work); 685 + 686 + switch (bq->usb_event) { 687 + case USB_EVENT_ID: 688 + /* Enable boost mode */ 689 + ret = bq25890_field_write(bq, F_OTG_CFG, 1); 690 + if (ret < 0) 691 + goto error; 692 + break; 693 + 694 + case USB_EVENT_NONE: 695 + /* Disable boost mode */ 696 + ret = bq25890_field_write(bq, F_OTG_CFG, 0); 697 + if (ret < 0) 698 + goto error; 699 + 700 + power_supply_changed(bq->charger); 701 + break; 702 + } 703 + 704 + return; 705 + 706 + error: 707 + dev_err(bq->dev, "Error switching to boost/charger mode.\n"); 708 + } 709 + 710 + static int bq25890_usb_notifier(struct notifier_block *nb, unsigned long val, 711 + void *priv) 712 + { 713 + struct bq25890_device *bq = 714 + container_of(nb, struct bq25890_device, usb_nb); 715 + 716 + bq->usb_event = val; 717 + queue_work(system_power_efficient_wq, &bq->usb_work); 718 + 719 + return NOTIFY_OK; 720 + } 721 + 722 + static int bq25890_irq_probe(struct bq25890_device *bq) 723 + { 724 + int ret; 725 + struct gpio_desc *irq; 726 + 727 + irq = devm_gpiod_get_index(bq->dev, BQ25890_IRQ_PIN, 0); 728 + if (IS_ERR(irq)) { 729 + dev_err(bq->dev, "Could not probe irq pin.\n"); 730 + return PTR_ERR(irq); 731 + } 732 + 733 + ret = gpiod_direction_input(irq); 734 + if (ret < 0) 735 + return ret; 736 + 737 + return gpiod_to_irq(irq); 738 + } 739 + 740 + static int bq25890_fw_read_u32_props(struct bq25890_device *bq) 741 + { 742 + int ret; 743 + u32 property; 744 + int i; 745 + struct bq25890_init_data *init = &bq->init_data; 746 + struct { 747 + char *name; 748 + bool optional; 749 + enum bq25890_table_ids tbl_id; 750 + u8 *conv_data; /* holds converted value from given property */ 751 + } props[] = { 752 + /* required properties */ 753 + {"ti,charge-current", false, TBL_ICHG, &init->ichg}, 754 + {"ti,battery-regulation-voltage", false, TBL_VREG, &init->vreg}, 755 + {"ti,termination-current", false, TBL_ITERM, &init->iterm}, 756 + {"ti,precharge-current", false, TBL_ITERM, &init->iprechg}, 757 + {"ti,minimum-sys-voltage", false, TBL_SYSVMIN, &init->sysvmin}, 758 + {"ti,boost-voltage", false, TBL_BOOSTV, &init->boostv}, 759 + {"ti,boost-max-current", false, TBL_BOOSTI, &init->boosti}, 760 + 761 + /* optional properties */ 762 + {"ti,thermal-regulation-threshold", true, TBL_TREG, &init->treg} 763 + }; 764 + 765 + /* initialize data for optional properties */ 766 + init->treg = 3; /* 120 degrees Celsius */ 767 + 768 + for (i = 0; i < ARRAY_SIZE(props); i++) { 769 + ret = device_property_read_u32(bq->dev, props[i].name, 770 + &property); 771 + if (ret < 0) { 772 + if (props[i].optional) 773 + continue; 774 + 775 + return ret; 776 + } 777 + 778 + *props[i].conv_data = bq25890_find_idx(property, 779 + props[i].tbl_id); 780 + } 781 + 782 + return 0; 783 + } 784 + 785 + static int bq25890_fw_probe(struct bq25890_device *bq) 786 + { 787 + int ret; 788 + struct bq25890_init_data *init = &bq->init_data; 789 + 790 + ret = bq25890_fw_read_u32_props(bq); 791 + if (ret < 0) 792 + return ret; 793 + 794 + init->ilim_en = device_property_read_bool(bq->dev, "ti,use-ilim-pin"); 795 + init->boostf = device_property_read_bool(bq->dev, "ti,boost-low-freq"); 796 + 797 + return 0; 798 + } 799 + 800 + static int bq25890_probe(struct i2c_client *client, 801 + const struct i2c_device_id *id) 802 + { 803 + struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); 804 + struct device *dev = &client->dev; 805 + struct bq25890_device *bq; 806 + int ret; 807 + int i; 808 + 809 + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { 810 + dev_err(dev, "No support for SMBUS_BYTE_DATA\n"); 811 + return -ENODEV; 812 + } 813 + 814 + bq = devm_kzalloc(dev, sizeof(*bq), GFP_KERNEL); 815 + if (!bq) 816 + return -ENOMEM; 817 + 818 + bq->client = client; 819 + bq->dev = dev; 820 + 821 + mutex_init(&bq->lock); 822 + 823 + bq->rmap = devm_regmap_init_i2c(client, &bq25890_regmap_config); 824 + if (IS_ERR(bq->rmap)) { 825 + dev_err(dev, "failed to allocate register map\n"); 826 + return PTR_ERR(bq->rmap); 827 + } 828 + 829 + for (i = 0; i < ARRAY_SIZE(bq25890_reg_fields); i++) { 830 + const struct reg_field *reg_fields = bq25890_reg_fields; 831 + 832 + bq->rmap_fields[i] = devm_regmap_field_alloc(dev, bq->rmap, 833 + reg_fields[i]); 834 + if (IS_ERR(bq->rmap_fields[i])) { 835 + dev_err(dev, "cannot allocate regmap field\n"); 836 + return PTR_ERR(bq->rmap_fields[i]); 837 + } 838 + } 839 + 840 + i2c_set_clientdata(client, bq); 841 + 842 + bq->chip_id = bq25890_field_read(bq, F_PN); 843 + if (bq->chip_id < 0) { 844 + dev_err(dev, "Cannot read chip ID.\n"); 845 + return ret; 846 + } 847 + 848 + if (bq->chip_id != BQ25890_ID) { 849 + dev_err(dev, "Chip with ID=%d, not supported!\n", bq->chip_id); 850 + return -ENODEV; 851 + } 852 + 853 + if (!dev->platform_data) { 854 + ret = bq25890_fw_probe(bq); 855 + if (ret < 0) { 856 + dev_err(dev, "Cannot read device properties.\n"); 857 + return ret; 858 + } 859 + } else { 860 + return -ENODEV; 861 + } 862 + 863 + ret = bq25890_hw_init(bq); 864 + if (ret < 0) { 865 + dev_err(dev, "Cannot initialize the chip.\n"); 866 + return ret; 867 + } 868 + 869 + if (client->irq <= 0) 870 + client->irq = bq25890_irq_probe(bq); 871 + 872 + if (client->irq < 0) { 873 + dev_err(dev, "No irq resource found.\n"); 874 + return client->irq; 875 + } 876 + 877 + /* OTG reporting */ 878 + bq->usb_phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB2); 879 + if (!IS_ERR_OR_NULL(bq->usb_phy)) { 880 + INIT_WORK(&bq->usb_work, bq25890_usb_work); 881 + bq->usb_nb.notifier_call = bq25890_usb_notifier; 882 + usb_register_notifier(bq->usb_phy, &bq->usb_nb); 883 + } 884 + 885 + ret = devm_request_threaded_irq(dev, client->irq, NULL, 886 + bq25890_irq_handler_thread, 887 + IRQF_TRIGGER_FALLING | IRQF_ONESHOT, 888 + BQ25890_IRQ_PIN, bq); 889 + if (ret) 890 + goto irq_fail; 891 + 892 + ret = bq25890_power_supply_init(bq); 893 + if (ret < 0) { 894 + dev_err(dev, "Failed to register power supply\n"); 895 + goto irq_fail; 896 + } 897 + 898 + return 0; 899 + 900 + irq_fail: 901 + if (!IS_ERR_OR_NULL(bq->usb_phy)) 902 + usb_unregister_notifier(bq->usb_phy, &bq->usb_nb); 903 + 904 + return ret; 905 + } 906 + 907 + static int bq25890_remove(struct i2c_client *client) 908 + { 909 + struct bq25890_device *bq = i2c_get_clientdata(client); 910 + 911 + power_supply_unregister(bq->charger); 912 + 913 + if (!IS_ERR_OR_NULL(bq->usb_phy)) 914 + usb_unregister_notifier(bq->usb_phy, &bq->usb_nb); 915 + 916 + /* reset all registers to default values */ 917 + bq25890_chip_reset(bq); 918 + 919 + return 0; 920 + } 921 + 922 + #ifdef CONFIG_PM_SLEEP 923 + static int bq25890_suspend(struct device *dev) 924 + { 925 + struct bq25890_device *bq = dev_get_drvdata(dev); 926 + 927 + /* 928 + * If charger is removed, while in suspend, make sure ADC is diabled 929 + * since it consumes slightly more power. 930 + */ 931 + return bq25890_field_write(bq, F_CONV_START, 0); 932 + } 933 + 934 + static int bq25890_resume(struct device *dev) 935 + { 936 + int ret; 937 + struct bq25890_state state; 938 + struct bq25890_device *bq = dev_get_drvdata(dev); 939 + 940 + ret = bq25890_get_chip_state(bq, &state); 941 + if (ret < 0) 942 + return ret; 943 + 944 + mutex_lock(&bq->lock); 945 + bq->state = state; 946 + mutex_unlock(&bq->lock); 947 + 948 + /* Re-enable ADC only if charger is plugged in. */ 949 + if (state.online) { 950 + ret = bq25890_field_write(bq, F_CONV_START, 1); 951 + if (ret < 0) 952 + return ret; 953 + } 954 + 955 + /* signal userspace, maybe state changed while suspended */ 956 + power_supply_changed(bq->charger); 957 + 958 + return 0; 959 + } 960 + #endif 961 + 962 + static const struct dev_pm_ops bq25890_pm = { 963 + SET_SYSTEM_SLEEP_PM_OPS(bq25890_suspend, bq25890_resume) 964 + }; 965 + 966 + static const struct i2c_device_id bq25890_i2c_ids[] = { 967 + { "bq25890", 0 }, 968 + {}, 969 + }; 970 + MODULE_DEVICE_TABLE(i2c, bq25890_i2c_ids); 971 + 972 + static const struct of_device_id bq25890_of_match[] = { 973 + { .compatible = "ti,bq25890", }, 974 + { }, 975 + }; 976 + MODULE_DEVICE_TABLE(of, bq25890_of_match); 977 + 978 + static const struct acpi_device_id bq25890_acpi_match[] = { 979 + {"BQ258900", 0}, 980 + {}, 981 + }; 982 + MODULE_DEVICE_TABLE(acpi, bq25890_acpi_match); 983 + 984 + static struct i2c_driver bq25890_driver = { 985 + .driver = { 986 + .name = "bq25890-charger", 987 + .of_match_table = of_match_ptr(bq25890_of_match), 988 + .acpi_match_table = ACPI_PTR(bq25890_acpi_match), 989 + .pm = &bq25890_pm, 990 + }, 991 + .probe = bq25890_probe, 992 + .remove = bq25890_remove, 993 + .id_table = bq25890_i2c_ids, 994 + }; 995 + module_i2c_driver(bq25890_driver); 996 + 997 + MODULE_AUTHOR("Laurentiu Palcu <laurentiu.palcu@intel.com>"); 998 + MODULE_DESCRIPTION("bq25890 charger driver"); 999 + MODULE_LICENSE("GPL");