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

Configure Feed

Select the types of activity you want to include in your feed.

power: supply: max77759: add charger driver

Add support for MAX77759 battery charger driver. This is a 4A 1-Cell
Li+/LiPoly dual input switch mode charger. While the device can support
USB & wireless charger inputs, this implementation only supports USB
input. This implementation supports both buck and boost modes.

Signed-off-by: Amit Sunil Dhamne <amitsd@google.com>
Reviewed-by: André Draszik <andre.draszik@linaro.org>
Link: https://patch.msgid.link/20260325-max77759-charger-v9-5-4486dd297adc@google.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Amit Sunil Dhamne and committed by
Greg Kroah-Hartman
70d7dd27 f23388d0

+792
+6
MAINTAINERS
··· 15708 15708 F: drivers/nvmem/max77759-nvmem.c 15709 15709 F: include/linux/mfd/max77759.h 15710 15710 15711 + MAXIM MAX77759 BATTERY CHARGER DRIVER 15712 + M: Amit Sunil Dhamne <amitsd@google.com> 15713 + L: linux-kernel@vger.kernel.org 15714 + S: Maintained 15715 + F: drivers/power/supply/max77759_charger.c 15716 + 15711 15717 MAXIM MAX77802 PMIC REGULATOR DEVICE DRIVER 15712 15718 M: Javier Martinez Canillas <javier@dowhile0.org> 15713 15719 L: linux-kernel@vger.kernel.org
+11
drivers/power/supply/Kconfig
··· 631 631 help 632 632 Say Y to enable support for the Maxim MAX77705 battery charger. 633 633 634 + config CHARGER_MAX77759 635 + tristate "Maxim MAX77759 battery charger driver" 636 + depends on MFD_MAX77759 && REGULATOR 637 + default MFD_MAX77759 638 + help 639 + Say M or Y here to enable the MAX77759 battery charger. MAX77759 640 + charger is a function of the MAX77759 PMIC. This is a dual input 641 + switch-mode charger. This driver supports buck and OTG boost modes. 642 + 643 + If built as a module, it will be called max77759_charger. 644 + 634 645 config CHARGER_MAX77976 635 646 tristate "Maxim MAX77976 battery charger driver" 636 647 depends on I2C
+1
drivers/power/supply/Makefile
··· 128 128 obj-$(CONFIG_BATTERY_UG3105) += ug3105_battery.o 129 129 obj-$(CONFIG_CHARGER_QCOM_SMB2) += qcom_smbx.o 130 130 obj-$(CONFIG_FUEL_GAUGE_MM8013) += mm8013.o 131 + obj-$(CONFIG_CHARGER_MAX77759) += max77759_charger.o
+774
drivers/power/supply/max77759_charger.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + /* 3 + * max77759_charger.c - Battery charger driver for MAX77759 charger device. 4 + * 5 + * Copyright 2025 Google LLC. 6 + */ 7 + 8 + #include <linux/bitfield.h> 9 + #include <linux/cleanup.h> 10 + #include <linux/device.h> 11 + #include <linux/devm-helpers.h> 12 + #include <linux/interrupt.h> 13 + #include <linux/irq.h> 14 + #include <linux/linear_range.h> 15 + #include <linux/mfd/max77759.h> 16 + #include <linux/module.h> 17 + #include <linux/mod_devicetable.h> 18 + #include <linux/mutex.h> 19 + #include <linux/of.h> 20 + #include <linux/platform_device.h> 21 + #include <linux/power_supply.h> 22 + #include <linux/regmap.h> 23 + #include <linux/regulator/driver.h> 24 + #include <linux/string_choices.h> 25 + #include <linux/workqueue.h> 26 + 27 + /* Default values for Fast Charge Current & Float Voltage */ 28 + #define CHG_CC_DEFAULT_UA 2266770 29 + #define CHG_FV_DEFAULT_MV 4300 30 + 31 + #define MAX_NUM_RETRIES 3 32 + #define PSY_WORK_RETRY_DELAY_MS 10 33 + 34 + #define FOREACH_IRQ(S) \ 35 + S(AICL), \ 36 + S(CHGIN), \ 37 + S(CHG), \ 38 + S(INLIM), \ 39 + S(BAT_OILO), \ 40 + S(CHG_STA_CC), \ 41 + S(CHG_STA_CV), \ 42 + S(CHG_STA_TO), \ 43 + S(CHG_STA_DONE) 44 + 45 + #define GENERATE_ENUM(e) e 46 + #define GENERATE_STRING(s) #s 47 + 48 + enum { 49 + FOREACH_IRQ(GENERATE_ENUM) 50 + }; 51 + 52 + static const char *const chgr_irqs_str[] = { 53 + FOREACH_IRQ(GENERATE_STRING) 54 + }; 55 + 56 + #define NUM_IRQS ARRAY_SIZE(chgr_irqs_str) 57 + 58 + /* Fast charge current limits (in uA) */ 59 + static const struct linear_range chgcc_limit_ranges[] = { 60 + LINEAR_RANGE(133330, 0x0, 0x2, 0), 61 + LINEAR_RANGE(200000, 0x3, 0x3C, 66670), 62 + }; 63 + 64 + /* Charge Termination Voltage Limits (in mV) */ 65 + static const struct linear_range chg_cv_prm_ranges[] = { 66 + LINEAR_RANGE(3800, 0x38, 0x39, 100), 67 + LINEAR_RANGE(4000, 0x0, 0x32, 10), 68 + }; 69 + 70 + /* USB input current limits (in uA) */ 71 + static const struct linear_range chgin_ilim_ranges[] = { 72 + LINEAR_RANGE(100000, 0x3, 0x7F, 25000), 73 + }; 74 + 75 + struct max77759_charger { 76 + struct device *dev; 77 + struct regmap *regmap; 78 + struct power_supply *psy; 79 + struct regulator_dev *chgin_otg_rdev; 80 + struct notifier_block nb; 81 + struct power_supply *tcpm_psy; 82 + struct delayed_work psy_work; 83 + struct mutex retry_lock; /* Protects psy_work_retry_cnt */ 84 + u32 psy_work_retry_cnt; 85 + int irqs[NUM_IRQS]; 86 + struct mutex lock; /* protects the state below */ 87 + enum max77759_chgr_mode mode; 88 + }; 89 + 90 + static inline int unlock_prot_regs(struct max77759_charger *chg, bool unlock) 91 + { 92 + return regmap_update_bits(chg->regmap, MAX77759_CHGR_REG_CHG_CNFG_06, 93 + MAX77759_CHGR_REG_CHG_CNFG_06_CHGPROT, unlock 94 + ? MAX77759_CHGR_REG_CHG_CNFG_06_CHGPROT : 0); 95 + } 96 + 97 + static int charger_input_valid(struct max77759_charger *chg) 98 + { 99 + u32 val; 100 + int ret; 101 + 102 + ret = regmap_read(chg->regmap, MAX77759_CHGR_REG_CHG_INT_OK, &val); 103 + if (ret) 104 + return ret; 105 + 106 + return (val & MAX77759_CHGR_REG_CHG_INT_CHG) && 107 + (val & MAX77759_CHGR_REG_CHG_INT_CHGIN); 108 + } 109 + 110 + static int get_online(struct max77759_charger *chg) 111 + { 112 + u32 val; 113 + int ret; 114 + 115 + ret = charger_input_valid(chg); 116 + if (ret <= 0) 117 + return ret; 118 + 119 + ret = regmap_read(chg->regmap, MAX77759_CHGR_REG_CHG_DETAILS_02, &val); 120 + if (ret) 121 + return ret; 122 + 123 + guard(mutex)(&chg->lock); 124 + 125 + return (val & MAX77759_CHGR_REG_CHG_DETAILS_02_CHGIN_STS) && 126 + (chg->mode == MAX77759_CHGR_MODE_CHG_BUCK_ON); 127 + } 128 + 129 + static int get_status(struct max77759_charger *chg) 130 + { 131 + u32 val; 132 + int ret; 133 + 134 + ret = regmap_read(chg->regmap, MAX77759_CHGR_REG_CHG_DETAILS_01, &val); 135 + if (ret) 136 + return ret; 137 + 138 + switch (FIELD_GET(MAX77759_CHGR_REG_CHG_DETAILS_01_CHG_DTLS, val)) { 139 + case MAX77759_CHGR_CHG_DTLS_PREQUAL: 140 + case MAX77759_CHGR_CHG_DTLS_CC: 141 + case MAX77759_CHGR_CHG_DTLS_CV: 142 + case MAX77759_CHGR_CHG_DTLS_TO: 143 + return POWER_SUPPLY_STATUS_CHARGING; 144 + case MAX77759_CHGR_CHG_DTLS_DONE: 145 + return POWER_SUPPLY_STATUS_FULL; 146 + case MAX77759_CHGR_CHG_DTLS_TIMER_FAULT: 147 + case MAX77759_CHGR_CHG_DTLS_SUSP_BATT_THM: 148 + case MAX77759_CHGR_CHG_DTLS_OFF_WDOG_TIMER: 149 + case MAX77759_CHGR_CHG_DTLS_SUSP_JEITA: 150 + return POWER_SUPPLY_STATUS_NOT_CHARGING; 151 + case MAX77759_CHGR_CHG_DTLS_OFF: 152 + return POWER_SUPPLY_STATUS_DISCHARGING; 153 + default: 154 + break; 155 + } 156 + 157 + return POWER_SUPPLY_STATUS_UNKNOWN; 158 + } 159 + 160 + static int get_charge_type(struct max77759_charger *chg) 161 + { 162 + u32 val; 163 + int ret; 164 + 165 + ret = regmap_read(chg->regmap, MAX77759_CHGR_REG_CHG_DETAILS_01, &val); 166 + if (ret) 167 + return ret; 168 + 169 + switch (FIELD_GET(MAX77759_CHGR_REG_CHG_DETAILS_01_CHG_DTLS, val)) { 170 + case MAX77759_CHGR_CHG_DTLS_PREQUAL: 171 + return POWER_SUPPLY_CHARGE_TYPE_TRICKLE; 172 + case MAX77759_CHGR_CHG_DTLS_CC: 173 + case MAX77759_CHGR_CHG_DTLS_CV: 174 + return POWER_SUPPLY_CHARGE_TYPE_FAST; 175 + case MAX77759_CHGR_CHG_DTLS_TO: 176 + return POWER_SUPPLY_CHARGE_TYPE_STANDARD; 177 + case MAX77759_CHGR_CHG_DTLS_DONE: 178 + case MAX77759_CHGR_CHG_DTLS_TIMER_FAULT: 179 + case MAX77759_CHGR_CHG_DTLS_SUSP_BATT_THM: 180 + case MAX77759_CHGR_CHG_DTLS_OFF_WDOG_TIMER: 181 + case MAX77759_CHGR_CHG_DTLS_SUSP_JEITA: 182 + case MAX77759_CHGR_CHG_DTLS_OFF: 183 + return POWER_SUPPLY_CHARGE_TYPE_NONE; 184 + default: 185 + break; 186 + } 187 + 188 + return POWER_SUPPLY_CHARGE_TYPE_UNKNOWN; 189 + } 190 + 191 + static int get_chg_health(struct max77759_charger *chg) 192 + { 193 + u32 val; 194 + int ret; 195 + 196 + ret = regmap_read(chg->regmap, MAX77759_CHGR_REG_CHG_DETAILS_00, &val); 197 + if (ret) 198 + return ret; 199 + 200 + switch (FIELD_GET(MAX77759_CHGR_REG_CHG_DETAILS_00_CHGIN_DTLS, val)) { 201 + case MAX77759_CHGR_CHGIN_DTLS_VBUS_UNDERVOLTAGE: 202 + case MAX77759_CHGR_CHGIN_DTLS_VBUS_MARGINAL_VOLTAGE: 203 + return POWER_SUPPLY_HEALTH_UNDERVOLTAGE; 204 + case MAX77759_CHGR_CHGIN_DTLS_VBUS_OVERVOLTAGE: 205 + return POWER_SUPPLY_HEALTH_OVERVOLTAGE; 206 + case MAX77759_CHGR_CHGIN_DTLS_VBUS_VALID: 207 + return POWER_SUPPLY_HEALTH_GOOD; 208 + default: 209 + break; 210 + } 211 + 212 + return POWER_SUPPLY_HEALTH_UNKNOWN; 213 + } 214 + 215 + static int get_batt_health(struct max77759_charger *chg) 216 + { 217 + u32 val; 218 + int ret; 219 + 220 + ret = regmap_read(chg->regmap, MAX77759_CHGR_REG_CHG_DETAILS_01, &val); 221 + if (ret) 222 + return ret; 223 + 224 + switch (FIELD_GET(MAX77759_CHGR_REG_CHG_DETAILS_01_BAT_DTLS, val)) { 225 + case MAX77759_CHGR_BAT_DTLS_NO_BATT_CHG_SUSP: 226 + return POWER_SUPPLY_HEALTH_NO_BATTERY; 227 + case MAX77759_CHGR_BAT_DTLS_DEAD_BATTERY: 228 + return POWER_SUPPLY_HEALTH_DEAD; 229 + case MAX77759_CHGR_BAT_DTLS_BAT_CHG_TIMER_FAULT: 230 + return POWER_SUPPLY_HEALTH_SAFETY_TIMER_EXPIRE; 231 + case MAX77759_CHGR_BAT_DTLS_BAT_OKAY: 232 + case MAX77759_CHGR_BAT_DTLS_BAT_ONLY_MODE: 233 + return POWER_SUPPLY_HEALTH_GOOD; 234 + case MAX77759_CHGR_BAT_DTLS_BAT_UNDERVOLTAGE: 235 + return POWER_SUPPLY_HEALTH_UNDERVOLTAGE; 236 + case MAX77759_CHGR_BAT_DTLS_BAT_OVERVOLTAGE: 237 + return POWER_SUPPLY_HEALTH_OVERVOLTAGE; 238 + case MAX77759_CHGR_BAT_DTLS_BAT_OVERCURRENT: 239 + return POWER_SUPPLY_HEALTH_OVERCURRENT; 240 + default: 241 + break; 242 + } 243 + 244 + return POWER_SUPPLY_HEALTH_UNKNOWN; 245 + } 246 + 247 + static int get_health(struct max77759_charger *chg) 248 + { 249 + int ret; 250 + 251 + ret = get_online(chg); 252 + if (ret < 0) 253 + return ret; 254 + 255 + if (ret) { 256 + ret = get_chg_health(chg); 257 + if (ret < 0 || ret != POWER_SUPPLY_HEALTH_GOOD) 258 + return ret; 259 + } 260 + 261 + return get_batt_health(chg); 262 + } 263 + 264 + static int get_fast_charge_current(struct max77759_charger *chg) 265 + { 266 + u32 regval, val; 267 + int ret; 268 + 269 + ret = regmap_read(chg->regmap, MAX77759_CHGR_REG_CHG_CNFG_02, &regval); 270 + if (ret) 271 + return ret; 272 + 273 + regval = FIELD_GET(MAX77759_CHGR_REG_CHG_CNFG_02_CHGCC, regval); 274 + ret = linear_range_get_value_array(chgcc_limit_ranges, 275 + ARRAY_SIZE(chgcc_limit_ranges), 276 + regval, &val); 277 + return ret ? ret : val; 278 + } 279 + 280 + static int set_fast_charge_current_limit(struct max77759_charger *chg, 281 + u32 cc_max_ua) 282 + { 283 + bool found; 284 + u32 regval; 285 + 286 + linear_range_get_selector_high_array(chgcc_limit_ranges, 287 + ARRAY_SIZE(chgcc_limit_ranges), 288 + cc_max_ua, &regval, &found); 289 + if (!found) 290 + return -EINVAL; 291 + 292 + return regmap_update_bits(chg->regmap, MAX77759_CHGR_REG_CHG_CNFG_02, 293 + MAX77759_CHGR_REG_CHG_CNFG_02_CHGCC, regval); 294 + } 295 + 296 + static int get_float_voltage(struct max77759_charger *chg) 297 + { 298 + u32 regval, val; 299 + int ret; 300 + 301 + ret = regmap_read(chg->regmap, MAX77759_CHGR_REG_CHG_CNFG_04, &regval); 302 + if (ret) 303 + return ret; 304 + 305 + regval = FIELD_GET(MAX77759_CHGR_REG_CHG_CNFG_04_CHG_CV_PRM, regval); 306 + ret = linear_range_get_value_array(chg_cv_prm_ranges, 307 + ARRAY_SIZE(chg_cv_prm_ranges), 308 + regval, &val); 309 + 310 + return ret ? ret : val; 311 + } 312 + 313 + static int set_float_voltage_limit(struct max77759_charger *chg, u32 fv_mv) 314 + { 315 + u32 regval; 316 + bool found; 317 + 318 + linear_range_get_selector_high_array(chg_cv_prm_ranges, 319 + ARRAY_SIZE(chg_cv_prm_ranges), 320 + fv_mv, &regval, &found); 321 + if (!found) 322 + return -EINVAL; 323 + 324 + return regmap_update_bits(chg->regmap, MAX77759_CHGR_REG_CHG_CNFG_04, 325 + MAX77759_CHGR_REG_CHG_CNFG_04_CHG_CV_PRM, 326 + regval); 327 + } 328 + 329 + static int get_input_current_limit(struct max77759_charger *chg) 330 + { 331 + u32 regval, val; 332 + int ret; 333 + 334 + ret = regmap_read(chg->regmap, MAX77759_CHGR_REG_CHG_CNFG_09, &regval); 335 + if (ret) 336 + return ret; 337 + 338 + regval = FIELD_GET(MAX77759_CHGR_REG_CHG_CNFG_09_CHGIN_ILIM, regval); 339 + regval = umax(regval, chgin_ilim_ranges[0].min_sel); 340 + 341 + ret = linear_range_get_value_array(chgin_ilim_ranges, 342 + ARRAY_SIZE(chgin_ilim_ranges), 343 + regval, &val); 344 + 345 + return ret ? ret : val; 346 + } 347 + 348 + static int set_input_current_limit(struct max77759_charger *chg, int ilim_ua) 349 + { 350 + u32 regval; 351 + 352 + if (ilim_ua < 0) 353 + return -EINVAL; 354 + 355 + linear_range_get_selector_within(chgin_ilim_ranges, ilim_ua, &regval); 356 + 357 + return regmap_update_bits(chg->regmap, MAX77759_CHGR_REG_CHG_CNFG_09, 358 + MAX77759_CHGR_REG_CHG_CNFG_09_CHGIN_ILIM, 359 + regval); 360 + } 361 + 362 + static const enum power_supply_property max77759_charger_props[] = { 363 + POWER_SUPPLY_PROP_ONLINE, 364 + POWER_SUPPLY_PROP_PRESENT, 365 + POWER_SUPPLY_PROP_STATUS, 366 + POWER_SUPPLY_PROP_CHARGE_TYPE, 367 + POWER_SUPPLY_PROP_HEALTH, 368 + POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX, 369 + POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX, 370 + POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT, 371 + }; 372 + 373 + static int max77759_charger_get_property(struct power_supply *psy, 374 + enum power_supply_property psp, 375 + union power_supply_propval *pval) 376 + { 377 + struct max77759_charger *chg = power_supply_get_drvdata(psy); 378 + int ret; 379 + 380 + switch (psp) { 381 + case POWER_SUPPLY_PROP_ONLINE: 382 + ret = get_online(chg); 383 + break; 384 + case POWER_SUPPLY_PROP_PRESENT: 385 + ret = charger_input_valid(chg); 386 + break; 387 + case POWER_SUPPLY_PROP_STATUS: 388 + ret = get_status(chg); 389 + break; 390 + case POWER_SUPPLY_PROP_CHARGE_TYPE: 391 + ret = get_charge_type(chg); 392 + break; 393 + case POWER_SUPPLY_PROP_HEALTH: 394 + ret = get_health(chg); 395 + break; 396 + case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX: 397 + ret = get_fast_charge_current(chg); 398 + break; 399 + case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX: 400 + ret = get_float_voltage(chg); 401 + break; 402 + case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT: 403 + ret = get_input_current_limit(chg); 404 + break; 405 + default: 406 + ret = -EINVAL; 407 + } 408 + 409 + pval->intval = ret; 410 + return ret < 0 ? ret : 0; 411 + } 412 + 413 + static const struct power_supply_desc max77759_charger_desc = { 414 + .name = "max77759-charger", 415 + .type = POWER_SUPPLY_TYPE_USB, 416 + .properties = max77759_charger_props, 417 + .num_properties = ARRAY_SIZE(max77759_charger_props), 418 + .get_property = max77759_charger_get_property, 419 + }; 420 + 421 + static int charger_set_mode(struct max77759_charger *chg, 422 + enum max77759_chgr_mode mode) 423 + { 424 + int ret; 425 + 426 + guard(mutex)(&chg->lock); 427 + 428 + if (chg->mode == mode) 429 + return 0; 430 + 431 + if ((mode == MAX77759_CHGR_MODE_CHG_BUCK_ON || 432 + mode == MAX77759_CHGR_MODE_OTG_BOOST_ON) && 433 + chg->mode != MAX77759_CHGR_MODE_OFF) { 434 + dev_err(chg->dev, "Invalid mode transition from %d to %d\n", 435 + chg->mode, mode); 436 + return -EINVAL; 437 + } 438 + 439 + ret = regmap_update_bits(chg->regmap, MAX77759_CHGR_REG_CHG_CNFG_00, 440 + MAX77759_CHGR_REG_CHG_CNFG_00_MODE, mode); 441 + if (ret) 442 + return ret; 443 + 444 + chg->mode = mode; 445 + return 0; 446 + } 447 + 448 + static int enable_chgin_otg(struct regulator_dev *rdev) 449 + { 450 + struct max77759_charger *chg = rdev_get_drvdata(rdev); 451 + 452 + return charger_set_mode(chg, MAX77759_CHGR_MODE_OTG_BOOST_ON); 453 + } 454 + 455 + static int disable_chgin_otg(struct regulator_dev *rdev) 456 + { 457 + struct max77759_charger *chg = rdev_get_drvdata(rdev); 458 + 459 + return charger_set_mode(chg, MAX77759_CHGR_MODE_OFF); 460 + } 461 + 462 + static int chgin_otg_status(struct regulator_dev *rdev) 463 + { 464 + struct max77759_charger *chg = rdev_get_drvdata(rdev); 465 + 466 + guard(mutex)(&chg->lock); 467 + 468 + return chg->mode == MAX77759_CHGR_MODE_OTG_BOOST_ON; 469 + } 470 + 471 + static const struct regulator_ops chgin_otg_reg_ops = { 472 + .enable = enable_chgin_otg, 473 + .disable = disable_chgin_otg, 474 + .is_enabled = chgin_otg_status, 475 + }; 476 + 477 + static const struct regulator_desc chgin_otg_reg_desc = { 478 + .name = "chgin-otg", 479 + .of_match = of_match_ptr("chgin-otg-regulator"), 480 + .owner = THIS_MODULE, 481 + .ops = &chgin_otg_reg_ops, 482 + .fixed_uV = 5000000, 483 + .n_voltages = 1, 484 + }; 485 + 486 + static irqreturn_t irq_handler(int irq, void *data) 487 + { 488 + struct max77759_charger *chg = data; 489 + 490 + power_supply_changed(chg->psy); 491 + 492 + return IRQ_HANDLED; 493 + } 494 + 495 + static irqreturn_t bat_oilo_irq_handler(int irq, void *data) 496 + { 497 + struct max77759_charger *chg = data; 498 + 499 + dev_warn_ratelimited(chg->dev, 500 + "Battery over-current threshold crossed\n"); 501 + 502 + return irq_handler(irq, data); 503 + } 504 + 505 + static int max77759_init_irqhandler(struct max77759_charger *chg) 506 + { 507 + struct device *dev = chg->dev; 508 + irq_handler_t thread_fn; 509 + char *name; 510 + int i, ret; 511 + 512 + for (i = 0; i < ARRAY_SIZE(chgr_irqs_str); i++) { 513 + ret = platform_get_irq_byname(to_platform_device(dev), 514 + chgr_irqs_str[i]); 515 + if (ret < 0) 516 + return dev_err_probe(dev, ret, 517 + "Failed to get irq resource for %s\n", 518 + chgr_irqs_str[i]); 519 + 520 + chg->irqs[i] = ret; 521 + name = devm_kasprintf(dev, GFP_KERNEL, "%s:%s", dev_name(dev), 522 + chgr_irqs_str[i]); 523 + if (!name) 524 + return dev_err_probe(dev, -ENOMEM, 525 + "Failed to allocate space for irqname: %s\n", 526 + chgr_irqs_str[i]); 527 + 528 + if (i == BAT_OILO) 529 + thread_fn = bat_oilo_irq_handler; 530 + else 531 + thread_fn = irq_handler; 532 + 533 + ret = devm_request_threaded_irq(dev, chg->irqs[i], NULL, 534 + thread_fn, 0, name, chg); 535 + if (ret) 536 + return dev_err_probe(dev, ret, 537 + "Unable to register irq handler for %s\n", 538 + chgr_irqs_str[i]); 539 + } 540 + 541 + return 0; 542 + } 543 + 544 + static int max77759_charger_init(struct max77759_charger *chg) 545 + { 546 + struct power_supply_battery_info *info; 547 + u32 regval, fast_chg_curr, fv; 548 + int ret; 549 + 550 + ret = regmap_read(chg->regmap, MAX77759_CHGR_REG_CHG_CNFG_00, &regval); 551 + if (ret) 552 + return ret; 553 + 554 + chg->mode = FIELD_GET(MAX77759_CHGR_REG_CHG_CNFG_00_MODE, regval); 555 + ret = charger_set_mode(chg, MAX77759_CHGR_MODE_OFF); 556 + if (ret) 557 + return ret; 558 + 559 + if (power_supply_get_battery_info(chg->psy, &info)) { 560 + fv = CHG_FV_DEFAULT_MV; 561 + fast_chg_curr = CHG_CC_DEFAULT_UA; 562 + } else { 563 + fv = info->constant_charge_voltage_max_uv / 1000; 564 + fast_chg_curr = info->constant_charge_current_max_ua; 565 + } 566 + 567 + ret = set_fast_charge_current_limit(chg, fast_chg_curr); 568 + if (ret) 569 + return ret; 570 + 571 + ret = set_float_voltage_limit(chg, fv); 572 + if (ret) 573 + return ret; 574 + 575 + ret = unlock_prot_regs(chg, true); 576 + if (ret) 577 + return ret; 578 + 579 + /* Disable wireless charging input */ 580 + ret = regmap_update_bits(chg->regmap, MAX77759_CHGR_REG_CHG_CNFG_12, 581 + MAX77759_CHGR_REG_CHG_CNFG_12_WCINSEL, 0); 582 + if (ret) 583 + goto relock; 584 + 585 + ret = regmap_update_bits(chg->regmap, MAX77759_CHGR_REG_CHG_CNFG_18, 586 + MAX77759_CHGR_REG_CHG_CNFG_18_WDTEN, 0); 587 + if (ret) 588 + goto relock; 589 + 590 + return unlock_prot_regs(chg, false); 591 + 592 + relock: 593 + (void)unlock_prot_regs(chg, false); 594 + return ret; 595 + } 596 + 597 + static void psy_work_item(struct work_struct *work) 598 + { 599 + struct max77759_charger *chg = 600 + container_of(work, struct max77759_charger, psy_work.work); 601 + union power_supply_propval current_limit, online; 602 + int ret; 603 + 604 + ret = power_supply_get_property(chg->tcpm_psy, 605 + POWER_SUPPLY_PROP_CURRENT_MAX, 606 + &current_limit); 607 + if (ret) { 608 + dev_err(chg->dev, 609 + "Failed to get CURRENT_MAX psy property, ret=%d\n", 610 + ret); 611 + goto err; 612 + } 613 + 614 + ret = power_supply_get_property(chg->tcpm_psy, POWER_SUPPLY_PROP_ONLINE, 615 + &online); 616 + if (ret) { 617 + dev_err(chg->dev, 618 + "Failed to get ONLINE psy property, ret=%d\n", 619 + ret); 620 + goto err; 621 + } 622 + 623 + if (online.intval && current_limit.intval) { 624 + ret = set_input_current_limit(chg, current_limit.intval); 625 + if (ret) { 626 + dev_err(chg->dev, 627 + "Unable to set current limit, ret=%d\n", ret); 628 + goto err; 629 + } 630 + 631 + charger_set_mode(chg, MAX77759_CHGR_MODE_CHG_BUCK_ON); 632 + } else { 633 + charger_set_mode(chg, MAX77759_CHGR_MODE_OFF); 634 + } 635 + 636 + scoped_guard(mutex, &chg->retry_lock) { 637 + if (chg->psy_work_retry_cnt) 638 + dev_dbg(chg->dev, 639 + "chg psy_work succeeded after %u tries\n", 640 + chg->psy_work_retry_cnt); 641 + chg->psy_work_retry_cnt = 0; 642 + } 643 + 644 + return; 645 + 646 + err: 647 + charger_set_mode(chg, MAX77759_CHGR_MODE_OFF); 648 + scoped_guard(mutex, &chg->retry_lock) { 649 + if (chg->psy_work_retry_cnt >= MAX_NUM_RETRIES) { 650 + dev_err(chg->dev, "chg psy work failed, giving up\n"); 651 + return; 652 + } 653 + 654 + ++chg->psy_work_retry_cnt; 655 + dev_dbg(chg->dev, "Retrying %u/%u chg psy_work\n", 656 + chg->psy_work_retry_cnt, MAX_NUM_RETRIES); 657 + schedule_delayed_work(&chg->psy_work, 658 + msecs_to_jiffies(PSY_WORK_RETRY_DELAY_MS)); 659 + } 660 + } 661 + 662 + static int psy_changed(struct notifier_block *nb, unsigned long evt, void *data) 663 + { 664 + struct max77759_charger *chg = container_of(nb, struct max77759_charger, 665 + nb); 666 + static const char *psy_name = "tcpm-source"; 667 + struct power_supply *psy = data; 668 + 669 + if (!strnstr(psy->desc->name, psy_name, strlen(psy_name)) || 670 + evt != PSY_EVENT_PROP_CHANGED) 671 + return NOTIFY_OK; 672 + 673 + chg->tcpm_psy = psy; 674 + scoped_guard(mutex, &chg->retry_lock) 675 + chg->psy_work_retry_cnt = 0; 676 + 677 + schedule_delayed_work(&chg->psy_work, 0); 678 + 679 + return NOTIFY_OK; 680 + } 681 + 682 + static void max_tcpci_unregister_psy_notifier(void *nb) 683 + { 684 + power_supply_unreg_notifier(nb); 685 + } 686 + 687 + static int max77759_charger_probe(struct platform_device *pdev) 688 + { 689 + struct regulator_config chgin_otg_reg_cfg; 690 + struct power_supply_config psy_cfg; 691 + struct device *dev = &pdev->dev; 692 + struct max77759_charger *chg; 693 + int ret; 694 + 695 + device_set_of_node_from_dev(dev, dev->parent); 696 + chg = devm_kzalloc(dev, sizeof(*chg), GFP_KERNEL); 697 + if (!chg) 698 + return -ENOMEM; 699 + 700 + platform_set_drvdata(pdev, chg); 701 + chg->dev = dev; 702 + chg->regmap = dev_get_regmap(dev->parent, "charger"); 703 + if (!chg->regmap) 704 + return dev_err_probe(dev, -ENODEV, "Missing regmap\n"); 705 + 706 + ret = devm_mutex_init(dev, &chg->lock); 707 + if (ret) 708 + return dev_err_probe(dev, ret, "Failed to initialize lock\n"); 709 + 710 + ret = devm_mutex_init(dev, &chg->retry_lock); 711 + if (ret) 712 + return dev_err_probe(dev, ret, 713 + "Failed to initialize retry_lock\n"); 714 + 715 + psy_cfg.fwnode = dev_fwnode(dev); 716 + psy_cfg.drv_data = chg; 717 + chg->psy = devm_power_supply_register(dev, &max77759_charger_desc, 718 + &psy_cfg); 719 + if (IS_ERR(chg->psy)) 720 + return dev_err_probe(dev, PTR_ERR(chg->psy), 721 + "Failed to register psy\n"); 722 + 723 + ret = max77759_charger_init(chg); 724 + if (ret) 725 + return dev_err_probe(dev, ret, 726 + "Failed to initialize max77759 charger\n"); 727 + 728 + chgin_otg_reg_cfg.dev = dev; 729 + chgin_otg_reg_cfg.driver_data = chg; 730 + chgin_otg_reg_cfg.of_node = dev_of_node(dev); 731 + chg->chgin_otg_rdev = devm_regulator_register(dev, &chgin_otg_reg_desc, 732 + &chgin_otg_reg_cfg); 733 + if (IS_ERR(chg->chgin_otg_rdev)) 734 + return dev_err_probe(dev, PTR_ERR(chg->chgin_otg_rdev), 735 + "Failed to register chgin otg regulator\n"); 736 + 737 + ret = devm_delayed_work_autocancel(dev, &chg->psy_work, psy_work_item); 738 + if (ret) 739 + return dev_err_probe(dev, ret, "Failed to initialize psy work\n"); 740 + 741 + chg->nb.notifier_call = psy_changed; 742 + ret = power_supply_reg_notifier(&chg->nb); 743 + if (ret) 744 + return dev_err_probe(dev, ret, 745 + "Unable to register psy notifier\n"); 746 + 747 + ret = devm_add_action_or_reset(dev, max_tcpci_unregister_psy_notifier, 748 + &chg->nb); 749 + if (ret) 750 + return dev_err_probe(dev, ret, 751 + "Failed to add devm action to unregister psy notifier\n"); 752 + 753 + return max77759_init_irqhandler(chg); 754 + } 755 + 756 + static const struct platform_device_id max77759_charger_id[] = { 757 + { .name = "max77759-charger", }, 758 + { } 759 + }; 760 + MODULE_DEVICE_TABLE(platform, max77759_charger_id); 761 + 762 + static struct platform_driver max77759_charger_driver = { 763 + .driver = { 764 + .name = "max77759-charger", 765 + .probe_type = PROBE_PREFER_ASYNCHRONOUS, 766 + }, 767 + .probe = max77759_charger_probe, 768 + .id_table = max77759_charger_id, 769 + }; 770 + module_platform_driver(max77759_charger_driver); 771 + 772 + MODULE_AUTHOR("Amit Sunil Dhamne <amitsd@google.com>"); 773 + MODULE_DESCRIPTION("Maxim MAX77759 charger driver"); 774 + MODULE_LICENSE("GPL");