1167 lines · c
1// SPDX-License-Identifier: GPL-2.02// BQ2515X Battery Charger Driver3// Copyright (C) 2020 Texas Instruments Incorporated - https://www.ti.com/4 5#include <linux/err.h>6#include <linux/i2c.h>7#include <linux/init.h>8#include <linux/kernel.h>9#include <linux/module.h>10#include <linux/gpio/consumer.h>11#include <linux/power_supply.h>12#include <linux/regmap.h>13#include <linux/types.h>14 15#define BQ2515X_MANUFACTURER "Texas Instruments"16 17#define BQ2515X_STAT0 0x0018#define BQ2515X_STAT1 0x0119#define BQ2515X_STAT2 0x0220#define BQ2515X_FLAG0 0x0321#define BQ2515X_FLAG1 0x0422#define BQ2515X_FLAG2 0x0523#define BQ2515X_FLAG3 0x0624#define BQ2515X_MASK0 0x0725#define BQ2515X_MASK1 0x0826#define BQ2515X_MASK2 0x0927#define BQ2515X_MASK3 0x0a28#define BQ2515X_VBAT_CTRL 0x1229#define BQ2515X_ICHG_CTRL 0x1330#define BQ2515X_PCHRGCTRL 0x1431#define BQ2515X_TERMCTRL 0x1532#define BQ2515X_BUVLO 0x1633#define BQ2515X_CHARGERCTRL0 0x1734#define BQ2515X_CHARGERCTRL1 0x1835#define BQ2515X_ILIMCTRL 0x1936#define BQ2515X_LDOCTRL 0x1d37#define BQ2515X_MRCTRL 0x3038#define BQ2515X_ICCTRL0 0x3539#define BQ2515X_ICCTRL1 0x3640#define BQ2515X_ICCTRL2 0x3741#define BQ2515X_ADCCTRL0 0x4042#define BQ2515X_ADCCTRL1 0x4143#define BQ2515X_ADC_VBAT_M 0x4244#define BQ2515X_ADC_VBAT_L 0x4345#define BQ2515X_ADC_TS_M 0x4446#define BQ2515X_ADC_TS_L 0x4547#define BQ2515X_ADC_ICHG_M 0x4648#define BQ2515X_ADC_ICHG_L 0x4749#define BQ2515X_ADC_ADCIN_M 0x4850#define BQ2515X_ADC_ADCIN_L 0x4951#define BQ2515X_ADC_VIN_M 0x4a52#define BQ2515X_ADC_VIN_L 0x4b53#define BQ2515X_ADC_PMID_M 0x4c54#define BQ2515X_ADC_PMID_L 0x4d55#define BQ2515X_ADC_IIN_M 0x4e56#define BQ2515X_ADC_IIN_L 0x4f57#define BQ2515X_ADC_COMP1_M 0x5258#define BQ2515X_ADC_COMP1_L 0X5359#define BQ2515X_ADC_COMP2_M 0X5460#define BQ2515X_ADC_COMP2_L 0x5561#define BQ2515X_ADC_COMP3_M 0x5662#define BQ2515X_ADC_COMP3_L 0x5763#define BQ2515X_ADC_READ_EN 0x5864#define BQ2515X_TS_FASTCHGCTRL 0x6165#define BQ2515X_TS_COLD 0x6266#define BQ2515X_TS_COOL 0x6367#define BQ2515X_TS_WARM 0x6468#define BQ2515X_TS_HOT 0x6569#define BQ2515X_DEVICE_ID 0x6f70 71#define BQ2515X_DEFAULT_ICHG_UA 1000072#define BQ25150_DEFAULT_ILIM_UA 10000073#define BQ25155_DEFAULT_ILIM_UA 50000074#define BQ2515X_DEFAULT_VBAT_REG_UV 420000075#define BQ2515X_DEFAULT_IPRECHARGE_UA 250076 77#define BQ2515X_DIVISOR 6553678#define BQ2515X_VBAT_BASE_VOLT 360000079#define BQ2515X_VBAT_REG_MAX 460000080#define BQ2515X_VBAT_REG_MIN 360000081#define BQ2515X_VBAT_STEP_UV 1000082#define BQ2515X_UV_FACTOR 100000083#define BQ2515X_VBAT_MULTIPLIER 684#define BQ2515X_ICHG_DIVISOR 5242985#define BQ2515X_ICHG_CURR_STEP_THRESH_UA 31875086#define BQ2515X_ICHG_MIN_UA 087#define BQ2515X_ICHG_MAX_UA 50000088#define BQ2515X_ICHG_RNG_1B0_UA 125089#define BQ2515X_ICHG_RNG_1B1_UA 250090#define BQ2515X_VLOWV_SEL_1B0_UV 300000091#define BQ2515X_VLOWV_SEL_1B1_UV 280000092#define BQ2515X_PRECHRG_ICHRG_RNGE_1875_UA 1875093#define BQ2515X_PRECHRG_ICHRG_RNGE_3750_UA 3750094#define BQ2515X_TWAKE2_MIN_US 170000095#define BQ2515X_TWAKE2_MAX_US 230000096 97#define BQ2515X_ILIM_150MA 0x298#define BQ2515X_ILIM_MASK 0x799#define BQ2515X_ILIM_MIN 50000100#define BQ2515X_ILIM_MAX 600000101#define BQ2515X_HEALTH_MASK 0xf102#define BQ2515X_ICHGRNG_MASK 0x80103#define BQ2515X_STAT0_MASK 0x0f104#define BQ2515X_STAT1_MASK 0x1f105#define BQ2515X_PRECHARGE_MASK 0x1f106 107#define BQ2515X_TS_HOT_STAT BIT(0)108#define BQ2515X_TS_WARM_STAT BIT(1)109#define BQ2515X_TS_COOL_STAT BIT(2)110#define BQ2515X_TS_COLD_STAT BIT(3)111#define BQ2515X_SAFETY_TIMER_EXP BIT(5)112 113#define BQ2515X_EN_VBAT_READ BIT(3)114#define BQ2515X_EN_ICHG_READ BIT(5)115 116#define BQ2515X_VIN_GOOD BIT(0)117#define BQ2515X_CHRG_DONE BIT(5)118#define BQ2515X_CV_CHRG_MODE BIT(6)119 120#define BQ2515X_VIN_OVP_FAULT_STAT BIT(7)121 122#define BQ2515X_WATCHDOG_DISABLE BIT(4)123 124#define BQ2515X_ICHARGE_RANGE BIT(7)125 126#define BQ2515X_VLOWV_SEL BIT(5)127 128#define BQ2515X_CHARGER_DISABLE BIT(0)129 130#define BQ2515X_HWRESET_14S_WD BIT(1)131 132static const int bq2515x_ilim_lvl_values[] = {133 50000, 100000, 150000, 200000, 300000, 400000, 500000, 600000134};135 136/**137 * struct bq2515x_init_data -138 * @ilim: input current limit139 * @ichg: fast charge current140 * @vbatreg: battery regulation voltage141 * @iprechg: precharge current142 */143struct bq2515x_init_data {144 int ilim;145 int ichg;146 int vbatreg;147 int iprechg;148};149 150/**151 * struct bq2515x_info -152 * @regmap_config: register map config153 * @ilim: input current limit154 */155struct bq2515x_info {156 const struct regmap_config *regmap_config;157 int ilim;158};159 160/**161 * struct bq2515x_device -162 * @mains: mains properties163 * @battery: battery properties164 * @regmap: register map structure165 * @dev: device structure166 *167 * @reset_gpio: manual reset (MR) pin168 * @powerdown_gpio: low power mode pin169 * @ac_detect_gpio: power good (PG) pin170 * @ce_gpio: charge enable (CE) pin171 *172 * @info: device info173 * @model_name: string value describing device model174 * @mains_online: boolean value indicating power supply online175 *176 * @init_data: charger initialization data structure177 */178struct bq2515x_device {179 struct power_supply *mains;180 struct power_supply *battery;181 struct regmap *regmap;182 struct device *dev;183 184 struct gpio_desc *reset_gpio;185 struct gpio_desc *powerdown_gpio;186 struct gpio_desc *ac_detect_gpio;187 struct gpio_desc *ce_gpio;188 189 const struct bq2515x_info *info;190 char model_name[I2C_NAME_SIZE];191 bool mains_online;192 193 struct bq2515x_init_data init_data;194};195 196static const struct reg_default bq25150_reg_defaults[] = {197 {BQ2515X_FLAG0, 0x0},198 {BQ2515X_FLAG1, 0x0},199 {BQ2515X_FLAG2, 0x0},200 {BQ2515X_FLAG3, 0x0},201 {BQ2515X_MASK0, 0x0},202 {BQ2515X_MASK1, 0x0},203 {BQ2515X_MASK2, 0x71},204 {BQ2515X_MASK3, 0x0},205 {BQ2515X_VBAT_CTRL, 0x3C},206 {BQ2515X_ICHG_CTRL, 0x8},207 {BQ2515X_PCHRGCTRL, 0x2},208 {BQ2515X_TERMCTRL, 0x14},209 {BQ2515X_BUVLO, 0x0},210 {BQ2515X_CHARGERCTRL0, 0x82},211 {BQ2515X_CHARGERCTRL1, 0x42},212 {BQ2515X_ILIMCTRL, 0x1},213 {BQ2515X_LDOCTRL, 0xB0},214 {BQ2515X_MRCTRL, 0x2A},215 {BQ2515X_ICCTRL0, 0x10},216 {BQ2515X_ICCTRL1, 0x0},217 {BQ2515X_ICCTRL2, 0x0},218 {BQ2515X_ADCCTRL0, 0x2},219 {BQ2515X_ADCCTRL1, 0x40},220 {BQ2515X_ADC_COMP1_M, 0x23},221 {BQ2515X_ADC_COMP1_L, 0x20},222 {BQ2515X_ADC_COMP2_M, 0x38},223 {BQ2515X_ADC_COMP2_L, 0x90},224 {BQ2515X_ADC_COMP3_M, 0x0},225 {BQ2515X_ADC_COMP3_L, 0x0},226 {BQ2515X_ADC_READ_EN, 0x0},227 {BQ2515X_TS_FASTCHGCTRL, 0x34},228 {BQ2515X_TS_COLD, 0x7C},229 {BQ2515X_TS_COOL, 0x6D},230 {BQ2515X_TS_WARM, 0x38},231 {BQ2515X_TS_HOT, 0x27},232 {BQ2515X_DEVICE_ID, 0x20},233};234 235static const struct reg_default bq25155_reg_defaults[] = {236 {BQ2515X_FLAG0, 0x0},237 {BQ2515X_FLAG1, 0x0},238 {BQ2515X_FLAG2, 0x0},239 {BQ2515X_FLAG3, 0x0},240 {BQ2515X_MASK0, 0x0},241 {BQ2515X_MASK1, 0x0},242 {BQ2515X_MASK2, 0x71},243 {BQ2515X_MASK3, 0x0},244 {BQ2515X_VBAT_CTRL, 0x3C},245 {BQ2515X_ICHG_CTRL, 0x8},246 {BQ2515X_PCHRGCTRL, 0x2},247 {BQ2515X_TERMCTRL, 0x14},248 {BQ2515X_BUVLO, 0x0},249 {BQ2515X_CHARGERCTRL0, 0x82},250 {BQ2515X_CHARGERCTRL1, 0xC2},251 {BQ2515X_ILIMCTRL, 0x6},252 {BQ2515X_LDOCTRL, 0xB0},253 {BQ2515X_MRCTRL, 0x2A},254 {BQ2515X_ICCTRL0, 0x10},255 {BQ2515X_ICCTRL1, 0x0},256 {BQ2515X_ICCTRL2, 0x40},257 {BQ2515X_ADCCTRL0, 0x2},258 {BQ2515X_ADCCTRL1, 0x40},259 {BQ2515X_ADC_COMP1_M, 0x23},260 {BQ2515X_ADC_COMP1_L, 0x20},261 {BQ2515X_ADC_COMP2_M, 0x38},262 {BQ2515X_ADC_COMP2_L, 0x90},263 {BQ2515X_ADC_COMP3_M, 0x0},264 {BQ2515X_ADC_COMP3_L, 0x0},265 {BQ2515X_ADC_READ_EN, 0x0},266 {BQ2515X_TS_FASTCHGCTRL, 0x34},267 {BQ2515X_TS_COLD, 0x7C},268 {BQ2515X_TS_COOL, 0x6D},269 {BQ2515X_TS_WARM, 0x38},270 {BQ2515X_TS_HOT, 0x27},271 {BQ2515X_DEVICE_ID, 0x35},272};273 274static int bq2515x_wake_up(struct bq2515x_device *bq2515x)275{276 int ret;277 int val;278 279 /* Read the STAT register if we can read it then the device is out280 * of ship mode. If the register cannot be read then attempt to wake281 * it up and enable the ADC.282 */283 ret = regmap_read(bq2515x->regmap, BQ2515X_STAT0, &val);284 if (ret)285 return ret;286 287 /* Need to toggle LP and bring device out of ship mode. The device288 * will exit the ship mode when the MR pin is held low for at least289 * t_WAKE2 as shown in section 8.3.7.1 of the datasheet.290 */291 gpiod_set_value_cansleep(bq2515x->powerdown_gpio, 0);292 293 gpiod_set_value_cansleep(bq2515x->reset_gpio, 0);294 usleep_range(BQ2515X_TWAKE2_MIN_US, BQ2515X_TWAKE2_MAX_US);295 gpiod_set_value_cansleep(bq2515x->reset_gpio, 1);296 297 return regmap_write(bq2515x->regmap, BQ2515X_ADC_READ_EN,298 (BQ2515X_EN_VBAT_READ | BQ2515X_EN_ICHG_READ));299}300 301static int bq2515x_update_ps_status(struct bq2515x_device *bq2515x)302{303 bool dc = false;304 unsigned int val;305 int ret;306 307 if (bq2515x->ac_detect_gpio)308 val = gpiod_get_value_cansleep(bq2515x->ac_detect_gpio);309 else {310 ret = regmap_read(bq2515x->regmap, BQ2515X_STAT0, &val);311 if (ret)312 return ret;313 }314 315 dc = val & BQ2515X_VIN_GOOD;316 317 ret = bq2515x->mains_online != dc;318 319 bq2515x->mains_online = dc;320 321 return ret;322}323 324static int bq2515x_disable_watchdog_timers(struct bq2515x_device *bq2515x)325{326 int ret;327 328 ret = regmap_update_bits(bq2515x->regmap, BQ2515X_CHARGERCTRL0,329 BQ2515X_WATCHDOG_DISABLE, BQ2515X_WATCHDOG_DISABLE);330 if (ret)331 return ret;332 333 return regmap_update_bits(bq2515x->regmap, BQ2515X_ICCTRL2,334 BQ2515X_HWRESET_14S_WD, 0);335}336 337static int bq2515x_get_battery_voltage_now(struct bq2515x_device *bq2515x)338{339 int ret;340 int vbat_msb;341 int vbat_lsb;342 uint32_t vbat_measurement;343 344 if (!bq2515x->mains_online)345 bq2515x_wake_up(bq2515x);346 347 ret = regmap_read(bq2515x->regmap, BQ2515X_ADC_VBAT_M, &vbat_msb);348 if (ret)349 return ret;350 351 ret = regmap_read(bq2515x->regmap, BQ2515X_ADC_VBAT_L, &vbat_lsb);352 if (ret)353 return ret;354 355 vbat_measurement = (vbat_msb << 8) | vbat_lsb;356 357 return vbat_measurement * (BQ2515X_UV_FACTOR / BQ2515X_DIVISOR) *358 BQ2515X_VBAT_MULTIPLIER;359}360 361static int bq2515x_get_battery_current_now(struct bq2515x_device *bq2515x)362{363 int ret;364 int ichg_msb;365 int ichg_lsb;366 uint32_t ichg_measurement;367 u16 ichg_multiplier = BQ2515X_ICHG_RNG_1B0_UA;368 unsigned int ichg_reg_code, reg_code;369 unsigned int icharge_range = 0, pchrgctrl;370 unsigned int buvlo, vlowv_sel, vlowv = BQ2515X_VLOWV_SEL_1B0_UV;371 372 if (!bq2515x->mains_online)373 return -ENODATA;374 375 ret = regmap_read(bq2515x->regmap, BQ2515X_ADC_ICHG_M, &ichg_msb);376 if (ret)377 return ret;378 379 ret = regmap_read(bq2515x->regmap, BQ2515X_ADC_ICHG_L, &ichg_lsb);380 if (ret)381 return ret;382 383 ichg_measurement = (ichg_msb << 8) | ichg_lsb;384 385 ret = regmap_read(bq2515x->regmap, BQ2515X_BUVLO, &buvlo);386 if (ret)387 return ret;388 389 vlowv_sel = buvlo & BQ2515X_VLOWV_SEL;390 391 if (vlowv_sel)392 vlowv = BQ2515X_VLOWV_SEL_1B1_UV;393 394 if (bq2515x_get_battery_voltage_now(bq2515x) < vlowv) {395 ret = regmap_read(bq2515x->regmap, BQ2515X_PCHRGCTRL,396 &pchrgctrl);397 if (ret)398 return ret;399 400 reg_code = pchrgctrl & BQ2515X_PRECHARGE_MASK;401 } else {402 ret = regmap_read(bq2515x->regmap, BQ2515X_ICHG_CTRL,403 &ichg_reg_code);404 if (ret)405 return ret;406 407 reg_code = ichg_reg_code;408 }409 410 ret = regmap_read(bq2515x->regmap, BQ2515X_PCHRGCTRL, &pchrgctrl);411 if (ret)412 return ret;413 414 icharge_range = pchrgctrl & BQ2515X_ICHARGE_RANGE;415 416 if (icharge_range)417 ichg_multiplier = BQ2515X_ICHG_RNG_1B1_UA;418 419 return reg_code * (ichg_multiplier * ichg_measurement /420 BQ2515X_ICHG_DIVISOR);421}422 423static bool bq2515x_get_charge_disable(struct bq2515x_device *bq2515x)424{425 int ret;426 int ce_pin;427 int icctrl2;428 int charger_disable;429 430 ce_pin = gpiod_get_value_cansleep(bq2515x->ce_gpio);431 432 ret = regmap_read(bq2515x->regmap, BQ2515X_ICCTRL2, &icctrl2);433 if (ret)434 return ret;435 436 charger_disable = icctrl2 & BQ2515X_CHARGER_DISABLE;437 438 if (charger_disable || ce_pin)439 return true;440 441 return false;442}443 444static int bq2515x_set_charge_disable(struct bq2515x_device *bq2515x, int val)445{446 gpiod_set_value_cansleep(bq2515x->ce_gpio, val);447 448 return regmap_update_bits(bq2515x->regmap, BQ2515X_ICCTRL2,449 BQ2515X_CHARGER_DISABLE, val);450}451 452static int bq2515x_get_const_charge_current(struct bq2515x_device *bq2515x)453{454 int ret;455 u16 ichg_multiplier = BQ2515X_ICHG_RNG_1B0_UA;456 unsigned int ichg_reg_code;457 unsigned int pchrgctrl;458 unsigned int icharge_range;459 460 ret = regmap_read(bq2515x->regmap, BQ2515X_ICHG_CTRL, &ichg_reg_code);461 if (ret)462 return ret;463 464 ret = regmap_read(bq2515x->regmap, BQ2515X_PCHRGCTRL, &pchrgctrl);465 if (ret)466 return ret;467 468 icharge_range = pchrgctrl & BQ2515X_ICHARGE_RANGE;469 470 if (icharge_range)471 ichg_multiplier = BQ2515X_ICHG_RNG_1B1_UA;472 473 return ichg_reg_code * ichg_multiplier;474}475 476static int bq2515x_set_const_charge_current(struct bq2515x_device *bq2515x,477 int val)478{479 int ret;480 unsigned int ichg_reg_code;481 u16 ichg_multiplier = BQ2515X_ICHG_RNG_1B0_UA;482 unsigned int icharge_range = 0;483 484 if (val > BQ2515X_ICHG_MAX_UA || val < BQ2515X_ICHG_MIN_UA)485 return -EINVAL;486 487 if (val > BQ2515X_ICHG_CURR_STEP_THRESH_UA) {488 ichg_multiplier = BQ2515X_ICHG_RNG_1B1_UA;489 icharge_range = BQ2515X_ICHARGE_RANGE;490 }491 492 bq2515x_set_charge_disable(bq2515x, 1);493 494 ret = regmap_update_bits(bq2515x->regmap, BQ2515X_PCHRGCTRL,495 BQ2515X_ICHARGE_RANGE, icharge_range);496 if (ret)497 return ret;498 499 ichg_reg_code = val / ichg_multiplier;500 501 ret = regmap_write(bq2515x->regmap, BQ2515X_ICHG_CTRL, ichg_reg_code);502 if (ret)503 return ret;504 505 return bq2515x_set_charge_disable(bq2515x, 0);506}507 508static int bq2515x_get_precharge_current(struct bq2515x_device *bq2515x)509{510 int ret;511 unsigned int pchrgctrl;512 unsigned int icharge_range;513 u16 precharge_multiplier = BQ2515X_ICHG_RNG_1B0_UA;514 unsigned int precharge_reg_code;515 516 ret = regmap_read(bq2515x->regmap, BQ2515X_PCHRGCTRL, &pchrgctrl);517 if (ret)518 return ret;519 520 icharge_range = pchrgctrl & BQ2515X_ICHARGE_RANGE;521 522 if (icharge_range)523 precharge_multiplier = BQ2515X_ICHG_RNG_1B1_UA;524 525 precharge_reg_code = pchrgctrl & BQ2515X_PRECHARGE_MASK;526 527 return precharge_reg_code * precharge_multiplier;528}529 530static int bq2515x_set_precharge_current(struct bq2515x_device *bq2515x,531 int val)532{533 int ret;534 unsigned int pchrgctrl;535 unsigned int icharge_range;536 unsigned int precharge_reg_code;537 unsigned int precharge_multiplier = BQ2515X_ICHG_RNG_1B0_UA;538 unsigned int precharge_max_ua = BQ2515X_PRECHRG_ICHRG_RNGE_1875_UA;539 540 ret = regmap_read(bq2515x->regmap, BQ2515X_PCHRGCTRL, &pchrgctrl);541 if (ret)542 return ret;543 544 icharge_range = pchrgctrl & BQ2515X_ICHARGE_RANGE;545 546 if (icharge_range) {547 precharge_max_ua = BQ2515X_PRECHRG_ICHRG_RNGE_3750_UA;548 precharge_multiplier = BQ2515X_ICHG_RNG_1B1_UA;549 } else {550 precharge_max_ua = BQ2515X_PRECHRG_ICHRG_RNGE_1875_UA;551 precharge_multiplier = BQ2515X_ICHG_RNG_1B0_UA;552 }553 if (val > precharge_max_ua || val < BQ2515X_ICHG_MIN_UA)554 return -EINVAL;555 556 precharge_reg_code = val / precharge_multiplier;557 558 ret = bq2515x_set_charge_disable(bq2515x, 1);559 if (ret)560 return ret;561 562 ret = regmap_update_bits(bq2515x->regmap, BQ2515X_PCHRGCTRL,563 BQ2515X_PRECHARGE_MASK, precharge_reg_code);564 if (ret)565 return ret;566 567 return bq2515x_set_charge_disable(bq2515x, 0);568}569 570static int bq2515x_charging_status(struct bq2515x_device *bq2515x,571 union power_supply_propval *val)572{573 bool status0_no_fault;574 bool status1_no_fault;575 bool ce_status;576 bool charge_done;577 unsigned int status;578 int ret;579 580 if (!bq2515x->mains_online) {581 val->intval = POWER_SUPPLY_STATUS_DISCHARGING;582 return 0;583 }584 585 ret = regmap_read(bq2515x->regmap, BQ2515X_STAT0, &status);586 if (ret)587 return ret;588 589 /*590 * The code block below is used to determine if any faults from the591 * STAT0 register are disbaling charging or if the charge has completed592 * according to the CHARGE_DONE_STAT bit.593 */594 if (((status & BQ2515X_STAT0_MASK) == true) &595 ((status & BQ2515X_CHRG_DONE) == false)) {596 status0_no_fault = true;597 charge_done = false;598 } else if (status & BQ2515X_CHRG_DONE) {599 charge_done = true;600 status0_no_fault = false;601 } else {602 status0_no_fault = false;603 charge_done = false;604 }605 606 ret = regmap_read(bq2515x->regmap, BQ2515X_STAT1, &status);607 if (ret)608 return ret;609 /*610 * The code block below is used to determine if any faults from the611 * STAT1 register are disbaling charging612 */613 if ((status & BQ2515X_STAT1_MASK) == false)614 status1_no_fault = true;615 else616 status1_no_fault = false;617 618 ce_status = (!bq2515x_get_charge_disable(bq2515x));619 620 /*621 * If there are no faults and charging is enabled, then status is622 * charging. Otherwise, if charging is complete, then status is full.623 * Otherwise, if a fault exists or charging is disabled, then status is624 * not charging625 */626 if (status0_no_fault & status1_no_fault & ce_status)627 val->intval = POWER_SUPPLY_STATUS_CHARGING;628 else if (charge_done)629 val->intval = POWER_SUPPLY_STATUS_FULL;630 else if (!(status0_no_fault & status1_no_fault & ce_status))631 val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;632 633 return 0;634}635 636static int bq2515x_get_batt_reg(struct bq2515x_device *bq2515x)637{638 int vbat_reg_code;639 int ret;640 641 ret = regmap_read(bq2515x->regmap, BQ2515X_VBAT_CTRL, &vbat_reg_code);642 if (ret)643 return ret;644 645 return BQ2515X_VBAT_BASE_VOLT + vbat_reg_code * BQ2515X_VBAT_STEP_UV;646}647 648static int bq2515x_set_batt_reg(struct bq2515x_device *bq2515x, int val)649{650 int vbat_reg_code;651 652 if (val > BQ2515X_VBAT_REG_MAX || val < BQ2515X_VBAT_REG_MIN)653 return -EINVAL;654 655 vbat_reg_code = (val - BQ2515X_VBAT_BASE_VOLT) / BQ2515X_VBAT_STEP_UV;656 657 return regmap_write(bq2515x->regmap, BQ2515X_VBAT_CTRL, vbat_reg_code);658}659 660static int bq2515x_get_ilim_lvl(struct bq2515x_device *bq2515x)661{662 int ret;663 int ilimctrl;664 665 ret = regmap_read(bq2515x->regmap, BQ2515X_ILIMCTRL, &ilimctrl);666 if (ret)667 return ret;668 669 return bq2515x_ilim_lvl_values[ilimctrl & BQ2515X_ILIM_MASK];670}671 672static int bq2515x_set_ilim_lvl(struct bq2515x_device *bq2515x, int val)673{674 int i = 0;675 unsigned int array_size = ARRAY_SIZE(bq2515x_ilim_lvl_values);676 677 for (i = array_size - 1; i > 0; i--) {678 if (val >= bq2515x_ilim_lvl_values[i])679 break;680 }681 return regmap_write(bq2515x->regmap, BQ2515X_ILIMCTRL, i);682}683 684static int bq2515x_power_supply_property_is_writeable(struct power_supply *psy,685 enum power_supply_property prop)686{687 switch (prop) {688 case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:689 case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:690 case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:691 case POWER_SUPPLY_PROP_PRECHARGE_CURRENT:692 return true;693 default:694 return false;695 }696}697 698static int bq2515x_charger_get_health(struct bq2515x_device *bq2515x,699 union power_supply_propval *val)700{701 int health = POWER_SUPPLY_HEALTH_GOOD;702 int ret;703 unsigned int stat1;704 unsigned int flag3;705 706 if (!bq2515x->mains_online)707 bq2515x_wake_up(bq2515x);708 709 ret = regmap_read(bq2515x->regmap, BQ2515X_FLAG3, &flag3);710 if (ret)711 return ret;712 713 ret = regmap_read(bq2515x->regmap, BQ2515X_STAT1, &stat1);714 if (ret)715 return ret;716 717 if (stat1 & BQ2515X_HEALTH_MASK) {718 switch (stat1 & BQ2515X_HEALTH_MASK) {719 case BQ2515X_TS_HOT_STAT:720 health = POWER_SUPPLY_HEALTH_HOT;721 break;722 case BQ2515X_TS_WARM_STAT:723 health = POWER_SUPPLY_HEALTH_WARM;724 break;725 case BQ2515X_TS_COOL_STAT:726 health = POWER_SUPPLY_HEALTH_COOL;727 break;728 case BQ2515X_TS_COLD_STAT:729 health = POWER_SUPPLY_HEALTH_COLD;730 break;731 default:732 health = POWER_SUPPLY_HEALTH_UNKNOWN;733 break;734 }735 }736 737 if (stat1 & BQ2515X_VIN_OVP_FAULT_STAT)738 health = POWER_SUPPLY_HEALTH_OVERVOLTAGE;739 740 if (flag3 & BQ2515X_SAFETY_TIMER_EXP)741 health = POWER_SUPPLY_HEALTH_SAFETY_TIMER_EXPIRE;742 743 val->intval = health;744 return 0;745}746 747static int bq2515x_mains_set_property(struct power_supply *psy,748 enum power_supply_property prop,749 const union power_supply_propval *val)750{751 struct bq2515x_device *bq2515x = power_supply_get_drvdata(psy);752 int ret;753 754 switch (prop) {755 case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:756 ret = bq2515x_set_batt_reg(bq2515x, val->intval);757 break;758 759 case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:760 ret = bq2515x_set_const_charge_current(bq2515x, val->intval);761 break;762 763 case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:764 ret = bq2515x_set_ilim_lvl(bq2515x, val->intval);765 break;766 767 case POWER_SUPPLY_PROP_PRECHARGE_CURRENT:768 ret = bq2515x_set_precharge_current(bq2515x, val->intval);769 break;770 771 default:772 return -EINVAL;773 }774 775 return ret;776}777 778static int bq2515x_mains_get_property(struct power_supply *psy,779 enum power_supply_property prop,780 union power_supply_propval *val)781{782 struct bq2515x_device *bq2515x = power_supply_get_drvdata(psy);783 int ret = 0;784 785 switch (prop) {786 787 case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:788 ret = bq2515x_get_const_charge_current(bq2515x);789 if (ret < 0)790 return ret;791 792 val->intval = ret;793 break;794 795 case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:796 ret = bq2515x_get_batt_reg(bq2515x);797 if (ret < 0)798 return ret;799 val->intval = ret;800 break;801 802 case POWER_SUPPLY_PROP_PRECHARGE_CURRENT:803 ret = bq2515x_get_precharge_current(bq2515x);804 if (ret < 0)805 return ret;806 val->intval = ret;807 break;808 809 case POWER_SUPPLY_PROP_ONLINE:810 val->intval = bq2515x->mains_online;811 break;812 813 case POWER_SUPPLY_PROP_HEALTH:814 ret = bq2515x_charger_get_health(bq2515x, val);815 if (ret)816 val->intval = POWER_SUPPLY_HEALTH_UNKNOWN;817 break;818 819 case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:820 ret = bq2515x_get_ilim_lvl(bq2515x);821 if (ret < 0)822 return ret;823 val->intval = ret;824 break;825 826 case POWER_SUPPLY_PROP_MODEL_NAME:827 val->strval = bq2515x->model_name;828 break;829 830 case POWER_SUPPLY_PROP_MANUFACTURER:831 val->strval = BQ2515X_MANUFACTURER;832 break;833 834 case POWER_SUPPLY_PROP_STATUS:835 ret = bq2515x_charging_status(bq2515x, val);836 if (ret)837 return ret;838 break;839 840 default:841 return -EINVAL;842 }843 844 return ret;845}846 847static int bq2515x_battery_get_property(struct power_supply *psy,848 enum power_supply_property prop,849 union power_supply_propval *val)850{851 struct bq2515x_device *bq2515x = power_supply_get_drvdata(psy);852 int ret;853 854 ret = bq2515x_update_ps_status(bq2515x);855 if (ret)856 return ret;857 858 switch (prop) {859 860 case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX:861 ret = bq2515x->init_data.vbatreg;862 if (ret < 0)863 return ret;864 val->intval = ret;865 break;866 867 case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX:868 ret = bq2515x->init_data.ichg;869 if (ret < 0)870 return ret;871 val->intval = ret;872 break;873 874 case POWER_SUPPLY_PROP_VOLTAGE_NOW:875 ret = bq2515x_get_battery_voltage_now(bq2515x);876 if (ret < 0)877 return ret;878 val->intval = ret;879 break;880 881 case POWER_SUPPLY_PROP_CURRENT_NOW:882 ret = bq2515x_get_battery_current_now(bq2515x);883 if (ret < 0)884 return ret;885 val->intval = ret;886 break;887 888 default:889 return -EINVAL;890 }891 return 0;892}893 894static const enum power_supply_property bq2515x_battery_properties[] = {895 POWER_SUPPLY_PROP_VOLTAGE_NOW,896 POWER_SUPPLY_PROP_CURRENT_NOW,897 POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX,898 POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX,899};900 901static const enum power_supply_property bq2515x_mains_properties[] = {902 POWER_SUPPLY_PROP_ONLINE,903 POWER_SUPPLY_PROP_STATUS,904 POWER_SUPPLY_PROP_HEALTH,905 POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT,906 POWER_SUPPLY_PROP_MODEL_NAME,907 POWER_SUPPLY_PROP_MANUFACTURER,908 POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE,909 POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT,910 POWER_SUPPLY_PROP_PRECHARGE_CURRENT,911};912 913static const struct power_supply_desc bq2515x_mains_desc = {914 .name = "bq2515x-mains",915 .type = POWER_SUPPLY_TYPE_MAINS,916 .get_property = bq2515x_mains_get_property,917 .set_property = bq2515x_mains_set_property,918 .properties = bq2515x_mains_properties,919 .num_properties = ARRAY_SIZE(bq2515x_mains_properties),920 .property_is_writeable = bq2515x_power_supply_property_is_writeable,921};922 923static const struct power_supply_desc bq2515x_battery_desc = {924 .name = "bq2515x-battery",925 .type = POWER_SUPPLY_TYPE_BATTERY,926 .get_property = bq2515x_battery_get_property,927 .properties = bq2515x_battery_properties,928 .num_properties = ARRAY_SIZE(bq2515x_battery_properties),929 .property_is_writeable = bq2515x_power_supply_property_is_writeable,930};931 932static int bq2515x_power_supply_register(struct bq2515x_device *bq2515x,933 struct device *dev, struct power_supply_config psy_cfg)934{935 bq2515x->mains = devm_power_supply_register(bq2515x->dev,936 &bq2515x_mains_desc,937 &psy_cfg);938 if (IS_ERR(bq2515x->mains))939 return -EINVAL;940 941 bq2515x->battery = devm_power_supply_register(bq2515x->dev,942 &bq2515x_battery_desc,943 &psy_cfg);944 if (IS_ERR(bq2515x->battery))945 return -EINVAL;946 947 return 0;948}949 950static int bq2515x_hw_init(struct bq2515x_device *bq2515x)951{952 int ret;953 struct power_supply_battery_info *bat_info;954 955 ret = bq2515x_disable_watchdog_timers(bq2515x);956 if (ret)957 return ret;958 959 if (bq2515x->init_data.ilim) {960 ret = bq2515x_set_ilim_lvl(bq2515x, bq2515x->init_data.ilim);961 if (ret)962 return ret;963 }964 965 ret = power_supply_get_battery_info(bq2515x->mains, &bat_info);966 if (ret) {967 dev_warn(bq2515x->dev, "battery info missing, default values will be applied\n");968 969 bq2515x->init_data.ichg = BQ2515X_DEFAULT_ICHG_UA;970 971 bq2515x->init_data.vbatreg = BQ2515X_DEFAULT_VBAT_REG_UV;972 973 bq2515x->init_data.iprechg = BQ2515X_DEFAULT_IPRECHARGE_UA;974 975 } else {976 bq2515x->init_data.ichg =977 bat_info->constant_charge_current_max_ua;978 979 bq2515x->init_data.vbatreg =980 bat_info->constant_charge_voltage_max_uv;981 982 bq2515x->init_data.iprechg =983 bat_info->precharge_current_ua;984 }985 986 ret = bq2515x_set_const_charge_current(bq2515x,987 bq2515x->init_data.ichg);988 if (ret)989 return ret;990 991 ret = bq2515x_set_batt_reg(bq2515x, bq2515x->init_data.vbatreg);992 if (ret)993 return ret;994 995 return bq2515x_set_precharge_current(bq2515x,996 bq2515x->init_data.iprechg);997}998 999static int bq2515x_read_properties(struct bq2515x_device *bq2515x)1000{1001 int ret;1002 1003 ret = device_property_read_u32(bq2515x->dev,1004 "input-current-limit-microamp",1005 &bq2515x->init_data.ilim);1006 if (ret)1007 bq2515x->init_data.ilim = bq2515x->info->ilim;1008 1009 bq2515x->ac_detect_gpio = devm_gpiod_get_optional(bq2515x->dev,1010 "ac-detect", GPIOD_IN);1011 if (IS_ERR(bq2515x->ac_detect_gpio)) {1012 ret = PTR_ERR(bq2515x->ac_detect_gpio);1013 dev_err(bq2515x->dev, "Failed to get ac detect");1014 return ret;1015 }1016 1017 bq2515x->reset_gpio = devm_gpiod_get_optional(bq2515x->dev,1018 "reset", GPIOD_OUT_LOW);1019 if (IS_ERR(bq2515x->reset_gpio)) {1020 ret = PTR_ERR(bq2515x->reset_gpio);1021 dev_err(bq2515x->dev, "Failed to get reset");1022 return ret;1023 }1024 1025 bq2515x->powerdown_gpio = devm_gpiod_get_optional(bq2515x->dev,1026 "powerdown", GPIOD_OUT_LOW);1027 if (IS_ERR(bq2515x->powerdown_gpio)) {1028 ret = PTR_ERR(bq2515x->powerdown_gpio);1029 dev_err(bq2515x->dev, "Failed to get powerdown");1030 return ret;1031 }1032 1033 bq2515x->ce_gpio = devm_gpiod_get_optional(bq2515x->dev,1034 "charge-enable",1035 GPIOD_OUT_LOW);1036 if (IS_ERR(bq2515x->ce_gpio)) {1037 ret = PTR_ERR(bq2515x->ce_gpio);1038 dev_err(bq2515x->dev, "Failed to get ce");1039 return ret;1040 }1041 1042 return 0;1043}1044 1045static bool bq2515x_volatile_register(struct device *dev, unsigned int reg)1046{1047 switch (reg) {1048 case BQ2515X_STAT0 ... BQ2515X_FLAG3:1049 case BQ2515X_ADC_VBAT_M ... BQ2515X_ADC_IIN_L:1050 return true;1051 default:1052 return false;1053 }1054}1055 1056static const struct regmap_config bq25150_regmap_config = {1057 .reg_bits = 8,1058 .val_bits = 8,1059 1060 .max_register = BQ2515X_DEVICE_ID,1061 .reg_defaults = bq25150_reg_defaults,1062 .num_reg_defaults = ARRAY_SIZE(bq25150_reg_defaults),1063 .cache_type = REGCACHE_RBTREE,1064 .volatile_reg = bq2515x_volatile_register,1065};1066 1067static const struct regmap_config bq25155_regmap_config = {1068 .reg_bits = 8,1069 .val_bits = 8,1070 1071 .max_register = BQ2515X_DEVICE_ID,1072 .reg_defaults = bq25155_reg_defaults,1073 .num_reg_defaults = ARRAY_SIZE(bq25155_reg_defaults),1074 .cache_type = REGCACHE_RBTREE,1075 .volatile_reg = bq2515x_volatile_register,1076};1077 1078static int bq2515x_probe(struct i2c_client *client)1079{1080 const struct i2c_device_id *id = i2c_client_get_device_id(client);1081 struct device *dev = &client->dev;1082 struct bq2515x_device *bq2515x;1083 struct power_supply_config charger_cfg = {};1084 int ret;1085 1086 bq2515x = devm_kzalloc(dev, sizeof(*bq2515x), GFP_KERNEL);1087 if (!bq2515x)1088 return -ENOMEM;1089 1090 bq2515x->dev = dev;1091 1092 strscpy(bq2515x->model_name, id->name, sizeof(bq2515x->model_name));1093 1094 bq2515x->info = i2c_get_match_data(client);1095 bq2515x->regmap = devm_regmap_init_i2c(client,1096 bq2515x->info->regmap_config);1097 if (IS_ERR(bq2515x->regmap)) {1098 dev_err(dev, "failed to allocate register map\n");1099 return PTR_ERR(bq2515x->regmap);1100 }1101 1102 i2c_set_clientdata(client, bq2515x);1103 1104 charger_cfg.drv_data = bq2515x;1105 charger_cfg.of_node = dev->of_node;1106 1107 ret = bq2515x_read_properties(bq2515x);1108 if (ret) {1109 dev_err(dev, "Failed to read device tree properties %d\n",1110 ret);1111 return ret;1112 }1113 1114 ret = bq2515x_power_supply_register(bq2515x, dev, charger_cfg);1115 if (ret) {1116 dev_err(dev, "failed to register power supply\n");1117 return ret;1118 }1119 1120 ret = bq2515x_hw_init(bq2515x);1121 if (ret) {1122 dev_err(dev, "Cannot initialize the chip\n");1123 return ret;1124 }1125 1126 return 0;1127}1128 1129static const struct bq2515x_info bq25150 = {1130 .regmap_config = &bq25150_regmap_config,1131 .ilim = BQ25150_DEFAULT_ILIM_UA,1132};1133 1134static const struct bq2515x_info bq25155 = {1135 .regmap_config = &bq25155_regmap_config,1136 .ilim = BQ25155_DEFAULT_ILIM_UA,1137};1138 1139static const struct i2c_device_id bq2515x_i2c_ids[] = {1140 { "bq25150", (kernel_ulong_t)&bq25150 },1141 { "bq25155", (kernel_ulong_t)&bq25155 },1142 {}1143};1144MODULE_DEVICE_TABLE(i2c, bq2515x_i2c_ids);1145 1146static const struct of_device_id bq2515x_of_match[] = {1147 { .compatible = "ti,bq25150", .data = &bq25150 },1148 { .compatible = "ti,bq25155", .data = &bq25155 },1149 {}1150};1151MODULE_DEVICE_TABLE(of, bq2515x_of_match);1152 1153static struct i2c_driver bq2515x_driver = {1154 .driver = {1155 .name = "bq2515x-charger",1156 .of_match_table = bq2515x_of_match,1157 },1158 .probe = bq2515x_probe,1159 .id_table = bq2515x_i2c_ids,1160};1161module_i2c_driver(bq2515x_driver);1162 1163MODULE_AUTHOR("Dan Murphy <dmurphy@ti.com>");1164MODULE_AUTHOR("Ricardo Rivera-Matos <r-rivera-matos@ti.com>");1165MODULE_DESCRIPTION("BQ2515X charger driver");1166MODULE_LICENSE("GPL v2");1167