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

power: supply: bq257xx: Add support for BQ257XX charger

Add support for the charger function of the BQ257XX. The device is
capable of charging batteries with a layout of 1 to 4 cells in
series.

Signed-off-by: Chris Morgan <macromorgan@hotmail.com>
Reviewed-by: Sebastian Reichel <sebastian.reichel@collabora.com>
Link: https://lore.kernel.org/r/20250904160530.66178-4-macroalpha82@gmail.com
Signed-off-by: Lee Jones <lee@kernel.org>

authored by

Chris Morgan and committed by
Lee Jones
1cc017b7 3b1bbfb5

+763
+7
drivers/power/supply/Kconfig
··· 767 767 rail, ADC for battery and system monitoring, and push-button 768 768 controller. 769 769 770 + config CHARGER_BQ257XX 771 + tristate "TI BQ257XX battery charger family" 772 + depends on MFD_BQ257XX 773 + help 774 + Say Y to enable support for the TI BQ257XX family of battery 775 + charging integrated circuits. 776 + 770 777 config CHARGER_BQ25890 771 778 tristate "TI BQ25890 battery charger driver" 772 779 depends on I2C
+1
drivers/power/supply/Makefile
··· 97 97 obj-$(CONFIG_CHARGER_BQ24257) += bq24257_charger.o 98 98 obj-$(CONFIG_CHARGER_BQ24735) += bq24735-charger.o 99 99 obj-$(CONFIG_CHARGER_BQ2515X) += bq2515x_charger.o 100 + obj-$(CONFIG_CHARGER_BQ257XX) += bq257xx_charger.o 100 101 obj-$(CONFIG_CHARGER_BQ25890) += bq25890_charger.o 101 102 obj-$(CONFIG_CHARGER_BQ25980) += bq25980_charger.o 102 103 obj-$(CONFIG_CHARGER_BQ256XX) += bq256xx_charger.o
+755
drivers/power/supply/bq257xx_charger.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * BQ257XX Battery Charger Driver 4 + * Copyright (C) 2025 Chris Morgan <macromorgan@hotmail.com> 5 + */ 6 + 7 + #include <linux/bitfield.h> 8 + #include <linux/i2c.h> 9 + #include <linux/interrupt.h> 10 + #include <linux/mfd/bq257xx.h> 11 + #include <linux/platform_device.h> 12 + #include <linux/power_supply.h> 13 + #include <linux/property.h> 14 + #include <linux/regmap.h> 15 + 16 + /* Forward declaration of driver data. */ 17 + struct bq257xx_chg; 18 + 19 + /** 20 + * struct bq257xx_chip_info - chip specific routines 21 + * @bq257xx_hw_init: init function for hw 22 + * @bq257xx_hw_shutdown: shutdown function for hw 23 + * @bq257xx_get_state: get and update state of hardware 24 + * @bq257xx_set_ichg: set maximum charge current (in uA) 25 + * @bq257xx_set_vbatreg: set maximum charge voltage (in uV) 26 + * @bq257xx_set_iindpm: set maximum input current (in uA) 27 + */ 28 + struct bq257xx_chip_info { 29 + int (*bq257xx_hw_init)(struct bq257xx_chg *pdata); 30 + void (*bq257xx_hw_shutdown)(struct bq257xx_chg *pdata); 31 + int (*bq257xx_get_state)(struct bq257xx_chg *pdata); 32 + int (*bq257xx_set_ichg)(struct bq257xx_chg *pdata, int ichg); 33 + int (*bq257xx_set_vbatreg)(struct bq257xx_chg *pdata, int vbatreg); 34 + int (*bq257xx_set_iindpm)(struct bq257xx_chg *pdata, int iindpm); 35 + }; 36 + 37 + /** 38 + * struct bq257xx_chg - driver data for charger 39 + * @chip: hw specific functions 40 + * @bq: parent MFD device 41 + * @charger: power supply device 42 + * @online: charger input is present 43 + * @fast_charge: charger is in fast charge mode 44 + * @pre_charge: charger is in pre-charge mode 45 + * @ov_fault: charger reports over voltage fault 46 + * @batoc_fault: charger reports battery over current fault 47 + * @oc_fault: charger reports over current fault 48 + * @usb_type: USB type reported from parent power supply 49 + * @supplied: Status of parent power supply 50 + * @iindpm_max: maximum input current limit (uA) 51 + * @vbat_max: maximum charge voltage (uV) 52 + * @ichg_max: maximum charge current (uA) 53 + * @vsys_min: minimum system voltage (uV) 54 + */ 55 + struct bq257xx_chg { 56 + const struct bq257xx_chip_info *chip; 57 + struct bq257xx_device *bq; 58 + struct power_supply *charger; 59 + bool online; 60 + bool fast_charge; 61 + bool pre_charge; 62 + bool ov_fault; 63 + bool batoc_fault; 64 + bool oc_fault; 65 + int usb_type; 66 + int supplied; 67 + u32 iindpm_max; 68 + u32 vbat_max; 69 + u32 ichg_max; 70 + u32 vsys_min; 71 + }; 72 + 73 + /** 74 + * bq25703_get_state() - Get the current state of the device 75 + * @pdata: driver platform data 76 + * 77 + * Get the current state of the charger. Check if the charger is 78 + * powered, what kind of charge state (if any) the device is in, 79 + * and if there are any active faults. 80 + * 81 + * Return: Returns 0 on success, or error on failure to read device. 82 + */ 83 + static int bq25703_get_state(struct bq257xx_chg *pdata) 84 + { 85 + unsigned int reg; 86 + int ret; 87 + 88 + ret = regmap_read(pdata->bq->regmap, BQ25703_CHARGER_STATUS, &reg); 89 + if (ret) 90 + return ret; 91 + 92 + pdata->online = reg & BQ25703_STS_AC_STAT; 93 + pdata->fast_charge = reg & BQ25703_STS_IN_FCHRG; 94 + pdata->pre_charge = reg & BQ25703_STS_IN_PCHRG; 95 + pdata->ov_fault = reg & BQ25703_STS_FAULT_ACOV; 96 + pdata->batoc_fault = reg & BQ25703_STS_FAULT_BATOC; 97 + pdata->oc_fault = reg & BQ25703_STS_FAULT_ACOC; 98 + 99 + return 0; 100 + } 101 + 102 + /** 103 + * bq25703_get_min_vsys() - Get the minimum system voltage 104 + * @pdata: driver platform data 105 + * @intval: value for minimum voltage 106 + * 107 + * Return: Returns 0 on success or error on failure to read. 108 + */ 109 + static int bq25703_get_min_vsys(struct bq257xx_chg *pdata, int *intval) 110 + { 111 + unsigned int reg; 112 + int ret; 113 + 114 + ret = regmap_read(pdata->bq->regmap, BQ25703_MIN_VSYS, 115 + &reg); 116 + if (ret) 117 + return ret; 118 + 119 + reg = FIELD_GET(BQ25703_MINVSYS_MASK, reg); 120 + *intval = (reg * BQ25703_MINVSYS_STEP_UV) + BQ25703_MINVSYS_MIN_UV; 121 + 122 + return ret; 123 + } 124 + 125 + /** 126 + * bq25703_set_min_vsys() - Set the minimum system voltage 127 + * @pdata: driver platform data 128 + * @vsys: voltage value to set in uV. 129 + * 130 + * This function takes a requested minimum system voltage value, clamps 131 + * it between the minimum supported value by the charger and a user 132 + * defined minimum system value, and then writes the value to the 133 + * appropriate register. 134 + * 135 + * Return: Returns 0 on success or error if an error occurs. 136 + */ 137 + static int bq25703_set_min_vsys(struct bq257xx_chg *pdata, int vsys) 138 + { 139 + unsigned int reg; 140 + int vsys_min = pdata->vsys_min; 141 + 142 + vsys = clamp(vsys, BQ25703_MINVSYS_MIN_UV, vsys_min); 143 + reg = ((vsys - BQ25703_MINVSYS_MIN_UV) / BQ25703_MINVSYS_STEP_UV); 144 + reg = FIELD_PREP(BQ25703_MINVSYS_MASK, reg); 145 + 146 + return regmap_write(pdata->bq->regmap, BQ25703_MIN_VSYS, 147 + reg); 148 + } 149 + 150 + /** 151 + * bq25703_get_cur() - Get the reported current from the battery 152 + * @pdata: driver platform data 153 + * @intval: value of reported battery current 154 + * 155 + * Read the reported current from the battery. Since value is always 156 + * positive set sign to negative if discharging. 157 + * 158 + * Return: Returns 0 on success or error if unable to read value. 159 + */ 160 + static int bq25703_get_cur(struct bq257xx_chg *pdata, int *intval) 161 + { 162 + unsigned int reg; 163 + int ret; 164 + 165 + ret = regmap_read(pdata->bq->regmap, BQ25703_ADCIBAT_CHG, &reg); 166 + if (ret < 0) 167 + return ret; 168 + 169 + if (pdata->online) 170 + *intval = FIELD_GET(BQ25703_ADCIBAT_CHG_MASK, reg) * 171 + BQ25703_ADCIBAT_CHG_STEP_UA; 172 + else 173 + *intval = -(FIELD_GET(BQ25703_ADCIBAT_DISCHG_MASK, reg) * 174 + BQ25703_ADCIBAT_DIS_STEP_UA); 175 + 176 + return ret; 177 + } 178 + 179 + /** 180 + * bq25703_get_ichg_cur() - Get the maximum reported charge current 181 + * @pdata: driver platform data 182 + * @intval: value of maximum reported charge current 183 + * 184 + * Get the maximum reported charge current from the battery. 185 + * 186 + * Return: Returns 0 on success or error if unable to read value. 187 + */ 188 + static int bq25703_get_ichg_cur(struct bq257xx_chg *pdata, int *intval) 189 + { 190 + unsigned int reg; 191 + int ret; 192 + 193 + ret = regmap_read(pdata->bq->regmap, BQ25703_CHARGE_CURRENT, &reg); 194 + if (ret) 195 + return ret; 196 + 197 + *intval = FIELD_GET(BQ25703_ICHG_MASK, reg) * BQ25703_ICHG_STEP_UA; 198 + 199 + return ret; 200 + } 201 + 202 + /** 203 + * bq25703_set_ichg_cur() - Set the maximum charge current 204 + * @pdata: driver platform data 205 + * @ichg: current value to set in uA. 206 + * 207 + * This function takes a requested maximum charge current value, clamps 208 + * it between the minimum supported value by the charger and a user 209 + * defined maximum charging value, and then writes the value to the 210 + * appropriate register. 211 + * 212 + * Return: Returns 0 on success or error if an error occurs. 213 + */ 214 + static int bq25703_set_ichg_cur(struct bq257xx_chg *pdata, int ichg) 215 + { 216 + unsigned int reg; 217 + int ichg_max = pdata->ichg_max; 218 + 219 + ichg = clamp(ichg, BQ25703_ICHG_MIN_UA, ichg_max); 220 + reg = FIELD_PREP(BQ25703_ICHG_MASK, (ichg / BQ25703_ICHG_STEP_UA)); 221 + 222 + return regmap_write(pdata->bq->regmap, BQ25703_CHARGE_CURRENT, 223 + reg); 224 + } 225 + 226 + /** 227 + * bq25703_get_chrg_volt() - Get the maximum set charge voltage 228 + * @pdata: driver platform data 229 + * @intval: maximum charge voltage value 230 + * 231 + * Return: Returns 0 on success or error if unable to read value. 232 + */ 233 + static int bq25703_get_chrg_volt(struct bq257xx_chg *pdata, int *intval) 234 + { 235 + unsigned int reg; 236 + int ret; 237 + 238 + ret = regmap_read(pdata->bq->regmap, BQ25703_MAX_CHARGE_VOLT, 239 + &reg); 240 + if (ret) 241 + return ret; 242 + 243 + *intval = FIELD_GET(BQ25703_MAX_CHARGE_VOLT_MASK, reg) * 244 + BQ25703_VBATREG_STEP_UV; 245 + 246 + return ret; 247 + } 248 + 249 + /** 250 + * bq25703_set_chrg_volt() - Set the maximum charge voltage 251 + * @pdata: driver platform data 252 + * @vbat: voltage value to set in uV. 253 + * 254 + * This function takes a requested maximum charge voltage value, clamps 255 + * it between the minimum supported value by the charger and a user 256 + * defined maximum charging value, and then writes the value to the 257 + * appropriate register. 258 + * 259 + * Return: Returns 0 on success or error if an error occurs. 260 + */ 261 + static int bq25703_set_chrg_volt(struct bq257xx_chg *pdata, int vbat) 262 + { 263 + unsigned int reg; 264 + int vbat_max = pdata->vbat_max; 265 + 266 + vbat = clamp(vbat, BQ25703_VBATREG_MIN_UV, vbat_max); 267 + 268 + reg = FIELD_PREP(BQ25703_MAX_CHARGE_VOLT_MASK, 269 + (vbat / BQ25703_VBATREG_STEP_UV)); 270 + 271 + return regmap_write(pdata->bq->regmap, BQ25703_MAX_CHARGE_VOLT, 272 + reg); 273 + } 274 + 275 + /** 276 + * bq25703_get_iindpm() - Get the maximum set input current 277 + * @pdata: driver platform data 278 + * @intval: maximum input current value 279 + * 280 + * Read the actual input current limit from the device into intval. 281 + * This can differ from the value programmed due to some autonomous 282 + * functions that may be enabled (but are not currently). This is why 283 + * there is a different register used. 284 + * 285 + * Return: Returns 0 on success or error if unable to read register 286 + * value. 287 + */ 288 + static int bq25703_get_iindpm(struct bq257xx_chg *pdata, int *intval) 289 + { 290 + unsigned int reg; 291 + int ret; 292 + 293 + ret = regmap_read(pdata->bq->regmap, BQ25703_IIN_DPM, &reg); 294 + if (ret) 295 + return ret; 296 + 297 + reg = FIELD_GET(BQ25703_IINDPM_MASK, reg); 298 + *intval = (reg * BQ25703_IINDPM_STEP_UA) + BQ25703_IINDPM_OFFSET_UA; 299 + 300 + return ret; 301 + } 302 + 303 + /** 304 + * bq25703_set_iindpm() - Set the maximum input current 305 + * @pdata: driver platform data 306 + * @iindpm: current value in uA. 307 + * 308 + * This function takes a requested maximum input current value, clamps 309 + * it between the minimum supported value by the charger and a user 310 + * defined maximum input value, and then writes the value to the 311 + * appropriate register. 312 + * 313 + * Return: Returns 0 on success or error if an error occurs. 314 + */ 315 + static int bq25703_set_iindpm(struct bq257xx_chg *pdata, int iindpm) 316 + { 317 + unsigned int reg; 318 + int iindpm_max = pdata->iindpm_max; 319 + 320 + iindpm = clamp(iindpm, BQ25703_IINDPM_MIN_UA, iindpm_max); 321 + 322 + reg = ((iindpm - BQ25703_IINDPM_OFFSET_UA) / BQ25703_IINDPM_STEP_UA); 323 + 324 + return regmap_write(pdata->bq->regmap, BQ25703_IIN_HOST, 325 + FIELD_PREP(BQ25703_IINDPM_MASK, reg)); 326 + } 327 + 328 + /** 329 + * bq25703_get_vbat() - Get the reported voltage from the battery 330 + * @pdata: driver platform data 331 + * @intval: value of reported battery voltage 332 + * 333 + * Read value of battery voltage into intval. 334 + * 335 + * Return: Returns 0 on success or error if unable to read value. 336 + */ 337 + static int bq25703_get_vbat(struct bq257xx_chg *pdata, int *intval) 338 + { 339 + unsigned int reg; 340 + int ret; 341 + 342 + ret = regmap_read(pdata->bq->regmap, BQ25703_ADCVSYSVBAT, &reg); 343 + if (ret) 344 + return ret; 345 + 346 + reg = FIELD_GET(BQ25703_ADCVBAT_MASK, reg); 347 + *intval = (reg * BQ25703_ADCVSYSVBAT_STEP) + BQ25703_ADCVSYSVBAT_OFFSET_UV; 348 + 349 + return ret; 350 + } 351 + 352 + /** 353 + * bq25703_hw_init() - Set all the required registers to init the charger 354 + * @pdata: driver platform data 355 + * 356 + * Initialize the BQ25703 by first disabling the watchdog timer (which 357 + * shuts off the charger in the absence of periodic writes). Then, set 358 + * the charge current, charge voltage, minimum system voltage, and 359 + * input current limit. Disable low power mode to allow ADCs and 360 + * interrupts. Enable the ADC, start the ADC, set the ADC scale to 361 + * full, and enable each individual ADC channel. 362 + * 363 + * Return: Returns 0 on success or error code on error. 364 + */ 365 + static int bq25703_hw_init(struct bq257xx_chg *pdata) 366 + { 367 + struct regmap *regmap = pdata->bq->regmap; 368 + int ret = 0; 369 + 370 + regmap_update_bits(regmap, BQ25703_CHARGE_OPTION_0, 371 + BQ25703_WDTMR_ADJ_MASK, 372 + FIELD_PREP(BQ25703_WDTMR_ADJ_MASK, 373 + BQ25703_WDTMR_DISABLE)); 374 + 375 + ret = pdata->chip->bq257xx_set_ichg(pdata, pdata->ichg_max); 376 + if (ret) 377 + return ret; 378 + 379 + ret = pdata->chip->bq257xx_set_vbatreg(pdata, pdata->vbat_max); 380 + if (ret) 381 + return ret; 382 + 383 + ret = bq25703_set_min_vsys(pdata, pdata->vsys_min); 384 + if (ret) 385 + return ret; 386 + 387 + ret = pdata->chip->bq257xx_set_iindpm(pdata, pdata->iindpm_max); 388 + if (ret) 389 + return ret; 390 + 391 + /* Disable low power mode by writing 0 to the register. */ 392 + regmap_update_bits(regmap, BQ25703_CHARGE_OPTION_0, 393 + BQ25703_EN_LWPWR, 0); 394 + 395 + /* Enable the ADC. */ 396 + regmap_update_bits(regmap, BQ25703_ADC_OPTION, 397 + BQ25703_ADC_CONV_EN, BQ25703_ADC_CONV_EN); 398 + 399 + /* Start the ADC. */ 400 + regmap_update_bits(regmap, BQ25703_ADC_OPTION, 401 + BQ25703_ADC_START, BQ25703_ADC_START); 402 + 403 + /* Set the scale of the ADC. */ 404 + regmap_update_bits(regmap, BQ25703_ADC_OPTION, 405 + BQ25703_ADC_FULL_SCALE, BQ25703_ADC_FULL_SCALE); 406 + 407 + /* Enable each of the ADC channels available. */ 408 + regmap_update_bits(regmap, BQ25703_ADC_OPTION, 409 + BQ25703_ADC_CH_MASK, 410 + (BQ25703_ADC_CMPIN_EN | BQ25703_ADC_VBUS_EN | 411 + BQ25703_ADC_PSYS_EN | BQ25703_ADC_IIN_EN | 412 + BQ25703_ADC_IDCHG_EN | BQ25703_ADC_ICHG_EN | 413 + BQ25703_ADC_VSYS_EN | BQ25703_ADC_VBAT_EN)); 414 + 415 + return ret; 416 + } 417 + 418 + /** 419 + * bq25703_hw_shutdown() - Set registers for shutdown 420 + * @pdata: driver platform data 421 + * 422 + * Enable low power mode for the device while in shutdown. 423 + */ 424 + static void bq25703_hw_shutdown(struct bq257xx_chg *pdata) 425 + { 426 + regmap_update_bits(pdata->bq->regmap, BQ25703_CHARGE_OPTION_0, 427 + BQ25703_EN_LWPWR, BQ25703_EN_LWPWR); 428 + } 429 + 430 + static int bq257xx_set_charger_property(struct power_supply *psy, 431 + enum power_supply_property prop, 432 + const union power_supply_propval *val) 433 + { 434 + struct bq257xx_chg *pdata = power_supply_get_drvdata(psy); 435 + 436 + switch (prop) { 437 + case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT: 438 + return pdata->chip->bq257xx_set_iindpm(pdata, val->intval); 439 + 440 + case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX: 441 + return pdata->chip->bq257xx_set_vbatreg(pdata, val->intval); 442 + 443 + case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX: 444 + return pdata->chip->bq257xx_set_ichg(pdata, val->intval); 445 + 446 + default: 447 + break; 448 + } 449 + 450 + return -EINVAL; 451 + } 452 + 453 + static int bq257xx_get_charger_property(struct power_supply *psy, 454 + enum power_supply_property psp, 455 + union power_supply_propval *val) 456 + { 457 + struct bq257xx_chg *pdata = power_supply_get_drvdata(psy); 458 + int ret = 0; 459 + 460 + ret = pdata->chip->bq257xx_get_state(pdata); 461 + if (ret) 462 + return ret; 463 + 464 + switch (psp) { 465 + case POWER_SUPPLY_PROP_STATUS: 466 + if (!pdata->online) 467 + val->intval = POWER_SUPPLY_STATUS_DISCHARGING; 468 + else if (pdata->fast_charge || pdata->pre_charge) 469 + val->intval = POWER_SUPPLY_STATUS_CHARGING; 470 + else 471 + val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING; 472 + break; 473 + 474 + case POWER_SUPPLY_PROP_HEALTH: 475 + if (pdata->ov_fault || pdata->batoc_fault) 476 + val->intval = POWER_SUPPLY_HEALTH_OVERVOLTAGE; 477 + else if (pdata->oc_fault) 478 + val->intval = POWER_SUPPLY_HEALTH_OVERCURRENT; 479 + else 480 + val->intval = POWER_SUPPLY_HEALTH_GOOD; 481 + break; 482 + 483 + case POWER_SUPPLY_PROP_MANUFACTURER: 484 + val->strval = "Texas Instruments"; 485 + break; 486 + 487 + case POWER_SUPPLY_PROP_ONLINE: 488 + val->intval = pdata->online; 489 + break; 490 + 491 + case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT: 492 + return bq25703_get_iindpm(pdata, &val->intval); 493 + 494 + case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX: 495 + return bq25703_get_chrg_volt(pdata, &val->intval); 496 + 497 + case POWER_SUPPLY_PROP_CURRENT_NOW: 498 + return bq25703_get_cur(pdata, &val->intval); 499 + 500 + case POWER_SUPPLY_PROP_VOLTAGE_NOW: 501 + return bq25703_get_vbat(pdata, &val->intval); 502 + 503 + case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX: 504 + return bq25703_get_ichg_cur(pdata, &val->intval); 505 + 506 + case POWER_SUPPLY_PROP_VOLTAGE_MIN: 507 + return bq25703_get_min_vsys(pdata, &val->intval); 508 + 509 + case POWER_SUPPLY_PROP_USB_TYPE: 510 + val->intval = pdata->usb_type; 511 + break; 512 + 513 + default: 514 + return -EINVAL; 515 + } 516 + 517 + return ret; 518 + } 519 + 520 + static enum power_supply_property bq257xx_power_supply_props[] = { 521 + POWER_SUPPLY_PROP_MANUFACTURER, 522 + POWER_SUPPLY_PROP_STATUS, 523 + POWER_SUPPLY_PROP_ONLINE, 524 + POWER_SUPPLY_PROP_HEALTH, 525 + POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT, 526 + POWER_SUPPLY_PROP_CURRENT_NOW, 527 + POWER_SUPPLY_PROP_VOLTAGE_NOW, 528 + POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX, 529 + POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX, 530 + POWER_SUPPLY_PROP_VOLTAGE_MIN, 531 + POWER_SUPPLY_PROP_USB_TYPE, 532 + }; 533 + 534 + static int bq257xx_property_is_writeable(struct power_supply *psy, 535 + enum power_supply_property prop) 536 + { 537 + switch (prop) { 538 + case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX: 539 + case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX: 540 + case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT: 541 + return true; 542 + default: 543 + return false; 544 + } 545 + } 546 + 547 + /** 548 + * bq257xx_external_power_changed() - Handler for external power change 549 + * @psy: Power supply data 550 + * 551 + * When the external power into the charger is changed, check the USB 552 + * type so that it can be reported. Additionally, update the max input 553 + * current and max charging current to the value reported if it is a 554 + * USB PD charger, otherwise use the default value. Note that each time 555 + * a charger is removed the max charge current register is erased, so 556 + * it must be set again each time the input changes or the device will 557 + * not charge. 558 + */ 559 + static void bq257xx_external_power_changed(struct power_supply *psy) 560 + { 561 + struct bq257xx_chg *pdata = power_supply_get_drvdata(psy); 562 + union power_supply_propval val; 563 + int ret; 564 + int imax = pdata->iindpm_max; 565 + 566 + pdata->chip->bq257xx_get_state(pdata); 567 + 568 + pdata->supplied = power_supply_am_i_supplied(pdata->charger); 569 + if (pdata->supplied < 0) 570 + return; 571 + 572 + if (pdata->supplied == 0) 573 + goto out; 574 + 575 + ret = power_supply_get_property_from_supplier(psy, 576 + POWER_SUPPLY_PROP_USB_TYPE, 577 + &val); 578 + if (ret) 579 + return; 580 + 581 + pdata->usb_type = val.intval; 582 + 583 + if ((pdata->usb_type == POWER_SUPPLY_USB_TYPE_PD) || 584 + (pdata->usb_type == POWER_SUPPLY_USB_TYPE_PD_DRP) || 585 + (pdata->usb_type == POWER_SUPPLY_USB_TYPE_PD_PPS)) { 586 + ret = power_supply_get_property_from_supplier(psy, 587 + POWER_SUPPLY_PROP_CURRENT_MAX, 588 + &val); 589 + if (ret) 590 + return; 591 + 592 + if (val.intval) 593 + imax = val.intval; 594 + } 595 + 596 + if (pdata->supplied) { 597 + pdata->chip->bq257xx_set_ichg(pdata, pdata->ichg_max); 598 + pdata->chip->bq257xx_set_iindpm(pdata, imax); 599 + pdata->chip->bq257xx_set_vbatreg(pdata, pdata->vbat_max); 600 + } 601 + 602 + out: 603 + power_supply_changed(psy); 604 + } 605 + 606 + static irqreturn_t bq257xx_irq_handler_thread(int irq, void *private) 607 + { 608 + struct bq257xx_chg *pdata = private; 609 + 610 + bq257xx_external_power_changed(pdata->charger); 611 + return IRQ_HANDLED; 612 + } 613 + 614 + static const struct power_supply_desc bq257xx_power_supply_desc = { 615 + .name = "bq257xx-charger", 616 + .type = POWER_SUPPLY_TYPE_USB, 617 + .usb_types = BIT(POWER_SUPPLY_USB_TYPE_C) | 618 + BIT(POWER_SUPPLY_USB_TYPE_PD) | 619 + BIT(POWER_SUPPLY_USB_TYPE_PD_DRP) | 620 + BIT(POWER_SUPPLY_USB_TYPE_PD_PPS) | 621 + BIT(POWER_SUPPLY_USB_TYPE_UNKNOWN), 622 + .properties = bq257xx_power_supply_props, 623 + .num_properties = ARRAY_SIZE(bq257xx_power_supply_props), 624 + .get_property = bq257xx_get_charger_property, 625 + .set_property = bq257xx_set_charger_property, 626 + .property_is_writeable = bq257xx_property_is_writeable, 627 + .external_power_changed = bq257xx_external_power_changed, 628 + }; 629 + 630 + static const struct bq257xx_chip_info bq25703_chip_info = { 631 + .bq257xx_hw_init = &bq25703_hw_init, 632 + .bq257xx_hw_shutdown = &bq25703_hw_shutdown, 633 + .bq257xx_get_state = &bq25703_get_state, 634 + .bq257xx_set_ichg = &bq25703_set_ichg_cur, 635 + .bq257xx_set_vbatreg = &bq25703_set_chrg_volt, 636 + .bq257xx_set_iindpm = &bq25703_set_iindpm, 637 + }; 638 + 639 + /** 640 + * bq257xx_parse_dt() - Parse the device tree for required properties 641 + * @pdata: driver platform data 642 + * @psy_cfg: power supply config data 643 + * @dev: device struct 644 + * 645 + * Read the device tree to identify the minimum system voltage, the 646 + * maximum charge current, the maximum charge voltage, and the maximum 647 + * input current. 648 + * 649 + * Return: Returns 0 on success or error code on error. 650 + */ 651 + static int bq257xx_parse_dt(struct bq257xx_chg *pdata, 652 + struct power_supply_config *psy_cfg, struct device *dev) 653 + { 654 + struct power_supply_battery_info *bat_info; 655 + int ret; 656 + 657 + ret = power_supply_get_battery_info(pdata->charger, 658 + &bat_info); 659 + if (ret) 660 + return dev_err_probe(dev, ret, 661 + "Unable to get battery info\n"); 662 + 663 + if ((bat_info->voltage_min_design_uv <= 0) || 664 + (bat_info->constant_charge_voltage_max_uv <= 0) || 665 + (bat_info->constant_charge_current_max_ua <= 0)) 666 + return dev_err_probe(dev, -EINVAL, 667 + "Required bat info missing or invalid\n"); 668 + 669 + pdata->vsys_min = bat_info->voltage_min_design_uv; 670 + pdata->vbat_max = bat_info->constant_charge_voltage_max_uv; 671 + pdata->ichg_max = bat_info->constant_charge_current_max_ua; 672 + 673 + power_supply_put_battery_info(pdata->charger, bat_info); 674 + 675 + ret = device_property_read_u32(dev, 676 + "input-current-limit-microamp", 677 + &pdata->iindpm_max); 678 + if (ret) 679 + pdata->iindpm_max = BQ25703_IINDPM_DEFAULT_UA; 680 + 681 + return 0; 682 + } 683 + 684 + static int bq257xx_charger_probe(struct platform_device *pdev) 685 + { 686 + struct device *dev = &pdev->dev; 687 + struct bq257xx_device *bq = dev_get_drvdata(pdev->dev.parent); 688 + struct bq257xx_chg *pdata; 689 + struct power_supply_config psy_cfg = { }; 690 + int ret; 691 + 692 + device_set_of_node_from_dev(dev, pdev->dev.parent); 693 + 694 + pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); 695 + if (!pdata) 696 + return -ENOMEM; 697 + 698 + pdata->bq = bq; 699 + pdata->chip = &bq25703_chip_info; 700 + 701 + platform_set_drvdata(pdev, pdata); 702 + 703 + psy_cfg.drv_data = pdata; 704 + psy_cfg.fwnode = dev_fwnode(dev); 705 + 706 + pdata->charger = devm_power_supply_register(dev, 707 + &bq257xx_power_supply_desc, 708 + &psy_cfg); 709 + if (IS_ERR(pdata->charger)) 710 + return dev_err_probe(dev, PTR_ERR(pdata->charger), 711 + "Power supply register charger failed\n"); 712 + 713 + ret = bq257xx_parse_dt(pdata, &psy_cfg, dev); 714 + if (ret) 715 + return ret; 716 + 717 + ret = pdata->chip->bq257xx_hw_init(pdata); 718 + if (ret) 719 + return dev_err_probe(dev, ret, "Cannot initialize the charger\n"); 720 + 721 + platform_set_drvdata(pdev, pdata); 722 + 723 + if (bq->client->irq) { 724 + ret = devm_request_threaded_irq(dev, bq->client->irq, NULL, 725 + bq257xx_irq_handler_thread, 726 + IRQF_TRIGGER_RISING | 727 + IRQF_TRIGGER_FALLING | 728 + IRQF_ONESHOT, 729 + dev_name(&bq->client->dev), pdata); 730 + if (ret < 0) 731 + dev_err_probe(dev, ret, "Charger get irq failed\n"); 732 + } 733 + 734 + return ret; 735 + } 736 + 737 + static void bq257xx_charger_shutdown(struct platform_device *pdev) 738 + { 739 + struct bq257xx_chg *pdata = platform_get_drvdata(pdev); 740 + 741 + pdata->chip->bq257xx_hw_shutdown(pdata); 742 + } 743 + 744 + static struct platform_driver bq257xx_chg_driver = { 745 + .driver = { 746 + .name = "bq257xx-charger", 747 + }, 748 + .probe = bq257xx_charger_probe, 749 + .shutdown = bq257xx_charger_shutdown, 750 + }; 751 + module_platform_driver(bq257xx_chg_driver); 752 + 753 + MODULE_DESCRIPTION("bq257xx charger driver"); 754 + MODULE_AUTHOR("Chris Morgan <macromorgan@hotmail.com>"); 755 + MODULE_LICENSE("GPL");