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

power: supply: Add support for Maxim MAX8971 charger

The MAX8971 is a compact, high-frequency, high-efficiency switch-mode
charger for a one-cell lithium-ion (Li+) battery.

Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
Link: https://lore.kernel.org/r/20250430055114.11469-3-clamor95@gmail.com
Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.com>

authored by

Svyatoslav Ryhel and committed by
Sebastian Reichel
60cd40ee c5a0a64c

+810
+43
Documentation/ABI/testing/sysfs-class-power
··· 822 822 Each entry is a link to the device which registered the extension. 823 823 824 824 Access: Read 825 + 826 + What: /sys/class/power_supply/max8971-charger/fast_charge_timer 827 + Date: May 2025 828 + KernelVersion: 6.15.0 829 + Contact: Svyatoslav Ryhel <clamor95@gmail.com> 830 + Description: 831 + This entry shows and sets the maximum time the max8971 832 + charger operates in fast-charge mode. When the timer expires 833 + the device will terminate fast-charge mode (charging current 834 + will drop to 0 A) and will trigger interrupt. 835 + 836 + Valid values: 837 + 838 + - 4 - 10 (hours), step by 1 839 + - 0: disabled. 840 + 841 + What: /sys/class/power_supply/max8971-charger/top_off_threshold_current 842 + Date: May 2025 843 + KernelVersion: 6.15.0 844 + Contact: Svyatoslav Ryhel <clamor95@gmail.com> 845 + Description: 846 + This entry shows and sets the charging current threshold for 847 + entering top-off charging mode. When charging current in fast 848 + charge mode drops below this value, the charger will trigger 849 + interrupt and start top-off charging mode. 850 + 851 + Valid values: 852 + 853 + - 50000 - 200000 (microamps), step by 50000 (rounded down) 854 + 855 + What: /sys/class/power_supply/max8971-charger/top_off_timer 856 + Date: May 2025 857 + KernelVersion: 6.15.0 858 + Contact: Svyatoslav Ryhel <clamor95@gmail.com> 859 + Description: 860 + This entry shows and sets the maximum time the max8971 861 + charger operates in top-off charge mode. When the timer expires 862 + the device will terminate top-off charge mode (charging current 863 + will drop to 0 A) and will trigger interrupt. 864 + 865 + Valid values: 866 + 867 + - 0 - 70 (minutes), step by 10 (rounded down)
+14
drivers/power/supply/Kconfig
··· 617 617 This driver can also be built as a module. If so, the module will be 618 618 called max77976_charger. 619 619 620 + config CHARGER_MAX8971 621 + tristate "Maxim MAX8971 battery charger driver" 622 + depends on I2C 623 + select REGMAP_I2C 624 + help 625 + The MAX8971 is a compact, high-frequency, high-efficiency switch-mode 626 + charger for a one-cell lithium-ion (Li+) battery. It delivers up to 627 + 1.55A of current to the battery from inputs up to 7.5V and withstands 628 + transient inputs up to 22V. 629 + 630 + Say Y to enable support for the Maxim MAX8971 battery charger. 631 + This driver can also be built as a module. If so, the module will be 632 + called max8971_charger. 633 + 620 634 config CHARGER_MAX8997 621 635 tristate "Maxim MAX8997/MAX8966 PMIC battery charger driver" 622 636 depends on MFD_MAX8997 && REGULATOR_MAX8997
+1
drivers/power/supply/Makefile
··· 83 83 obj-$(CONFIG_CHARGER_MAX77693) += max77693_charger.o 84 84 obj-$(CONFIG_CHARGER_MAX77705) += max77705_charger.o 85 85 obj-$(CONFIG_CHARGER_MAX77976) += max77976_charger.o 86 + obj-$(CONFIG_CHARGER_MAX8971) += max8971_charger.o 86 87 obj-$(CONFIG_CHARGER_MAX8997) += max8997_charger.o 87 88 obj-$(CONFIG_CHARGER_MAX8998) += max8998_charger.o 88 89 obj-$(CONFIG_CHARGER_MP2629) += mp2629_charger.o
+752
drivers/power/supply/max8971_charger.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-or-later 2 + 3 + #include <linux/devm-helpers.h> 4 + #include <linux/delay.h> 5 + #include <linux/device.h> 6 + #include <linux/err.h> 7 + #include <linux/extcon.h> 8 + #include <linux/i2c.h> 9 + #include <linux/mod_devicetable.h> 10 + #include <linux/of_graph.h> 11 + #include <linux/property.h> 12 + #include <linux/interrupt.h> 13 + #include <linux/module.h> 14 + #include <linux/pm.h> 15 + #include <linux/power_supply.h> 16 + #include <linux/regmap.h> 17 + #include <linux/sysfs.h> 18 + #include <linux/types.h> 19 + 20 + #define MAX8971_REG_CHGINT 0x0f 21 + #define MAX8971_REG_CHG_RST BIT(0) 22 + #define MAX8971_REG_CHGINT_MASK 0x01 23 + #define MAX8971_AICL_MASK BIT(7) 24 + #define MAX8971_REG_CHG_STAT 0x02 25 + #define MAX8971_CHG_MASK BIT(3) 26 + #define MAX8971_REG_DETAILS1 0x03 27 + #define MAX8971_REG_DETAILS2 0x04 28 + #define MAX8971_REG_CHGCNTL1 0x05 29 + #define MAX8971_REG_FCHGCRNT 0x06 30 + #define MAX8971_REG_DCCRNT 0x07 31 + #define MAX8971_CHGRSTRT_MASK BIT(6) 32 + #define MAX8971_REG_TOPOFF 0x08 33 + #define MAX8971_REG_TEMPREG 0x09 34 + #define MAX8971_REG_PROTCMD 0x0a 35 + #define MAX8971_CHGPROT_LOCKED 0x00 36 + #define MAX8971_CHGPROT_UNLOCKED 0x03 37 + 38 + #define MAX8971_FCHGT_DEFAULT 2 39 + #define MAX8971_TOPOFFT_DEFAULT 3 40 + 41 + static const char *max8971_manufacturer = "Maxim Integrated"; 42 + static const char *max8971_model = "MAX8971"; 43 + 44 + enum max8971_charging_state { 45 + MAX8971_CHARGING_DEAD_BATTERY, 46 + MAX8971_CHARGING_PREQUALIFICATION, 47 + MAX8971_CHARGING_FAST_CONST_CURRENT, 48 + MAX8971_CHARGING_FAST_CONST_VOLTAGE, 49 + MAX8971_CHARGING_TOP_OFF, 50 + MAX8971_CHARGING_DONE, 51 + MAX8971_CHARGING_TIMER_FAULT, 52 + MAX8971_CHARGING_SUSPENDED_THERMAL, 53 + MAX8971_CHARGING_OFF, 54 + MAX8971_CHARGING_THERMAL_LOOP, 55 + }; 56 + 57 + enum max8971_health_state { 58 + MAX8971_HEALTH_UNKNOWN, 59 + MAX8971_HEALTH_COLD, 60 + MAX8971_HEALTH_COOL, 61 + MAX8971_HEALTH_WARM, 62 + MAX8971_HEALTH_HOT, 63 + MAX8971_HEALTH_OVERHEAT, 64 + }; 65 + 66 + /* Fast-Charge current limit, 250..1550 mA, 50 mA steps */ 67 + #define MAX8971_CHG_CC_STEP 50000U 68 + #define MAX8971_CHG_CC_MIN 250000U 69 + #define MAX8971_CHG_CC_MAX 1550000U 70 + 71 + /* Input current limit, 250..1500 mA, 25 mA steps */ 72 + #define MAX8971_DCILMT_STEP 25000U 73 + #define MAX8971_DCILMT_MIN 250000U 74 + #define MAX8971_DCILMT_MAX 1500000U 75 + 76 + enum max8971_field_idx { 77 + THM_DTLS, /* DETAILS1 */ 78 + BAT_DTLS, CHG_DTLS, /* DETAILS2 */ 79 + CHG_CC, FCHG_T, /* FCHGCRNT */ 80 + DCI_LMT, /* DCCRNT */ 81 + TOPOFF_T, TOPOFF_S, /* TOPOFF */ 82 + CPROT, /* PROTCMD */ 83 + MAX8971_N_REGMAP_FIELDS 84 + }; 85 + 86 + static const struct reg_field max8971_reg_field[MAX8971_N_REGMAP_FIELDS] = { 87 + [THM_DTLS] = REG_FIELD(MAX8971_REG_DETAILS1, 0, 2), 88 + [BAT_DTLS] = REG_FIELD(MAX8971_REG_DETAILS2, 4, 5), 89 + [CHG_DTLS] = REG_FIELD(MAX8971_REG_DETAILS2, 0, 3), 90 + [CHG_CC] = REG_FIELD(MAX8971_REG_FCHGCRNT, 0, 4), 91 + [FCHG_T] = REG_FIELD(MAX8971_REG_FCHGCRNT, 5, 7), 92 + [DCI_LMT] = REG_FIELD(MAX8971_REG_DCCRNT, 0, 5), 93 + [TOPOFF_T] = REG_FIELD(MAX8971_REG_TOPOFF, 5, 7), 94 + [TOPOFF_S] = REG_FIELD(MAX8971_REG_TOPOFF, 2, 3), 95 + [CPROT] = REG_FIELD(MAX8971_REG_PROTCMD, 2, 3), 96 + }; 97 + 98 + static const struct regmap_config max8971_regmap_config = { 99 + .reg_bits = 8, 100 + .val_bits = 8, 101 + .max_register = MAX8971_REG_CHGINT, 102 + }; 103 + 104 + struct max8971_data { 105 + struct device *dev; 106 + struct power_supply *psy_mains; 107 + 108 + struct extcon_dev *edev; 109 + struct notifier_block extcon_nb; 110 + struct delayed_work extcon_work; 111 + 112 + struct regmap *regmap; 113 + struct regmap_field *rfield[MAX8971_N_REGMAP_FIELDS]; 114 + 115 + enum power_supply_usb_type usb_type; 116 + 117 + u32 fchgt; 118 + u32 tofft; 119 + u32 toffs; 120 + 121 + bool present; 122 + }; 123 + 124 + static int max8971_get_status(struct max8971_data *priv, int *val) 125 + { 126 + u32 regval; 127 + int err; 128 + 129 + err = regmap_field_read(priv->rfield[CHG_DTLS], &regval); 130 + if (err) 131 + return err; 132 + 133 + switch (regval) { 134 + case MAX8971_CHARGING_DEAD_BATTERY: 135 + case MAX8971_CHARGING_PREQUALIFICATION: 136 + case MAX8971_CHARGING_FAST_CONST_CURRENT: 137 + case MAX8971_CHARGING_FAST_CONST_VOLTAGE: 138 + case MAX8971_CHARGING_TOP_OFF: 139 + case MAX8971_CHARGING_THERMAL_LOOP: 140 + *val = POWER_SUPPLY_STATUS_CHARGING; 141 + break; 142 + case MAX8971_CHARGING_DONE: 143 + *val = POWER_SUPPLY_STATUS_FULL; 144 + break; 145 + case MAX8971_CHARGING_TIMER_FAULT: 146 + *val = POWER_SUPPLY_STATUS_NOT_CHARGING; 147 + break; 148 + case MAX8971_CHARGING_OFF: 149 + case MAX8971_CHARGING_SUSPENDED_THERMAL: 150 + *val = POWER_SUPPLY_STATUS_DISCHARGING; 151 + break; 152 + default: 153 + *val = POWER_SUPPLY_STATUS_UNKNOWN; 154 + } 155 + 156 + return 0; 157 + } 158 + 159 + static int max8971_get_charge_type(struct max8971_data *priv, int *val) 160 + { 161 + u32 regval; 162 + int err; 163 + 164 + err = regmap_field_read(priv->rfield[CHG_DTLS], &regval); 165 + if (err) 166 + return err; 167 + 168 + switch (regval) { 169 + case MAX8971_CHARGING_DEAD_BATTERY: 170 + case MAX8971_CHARGING_PREQUALIFICATION: 171 + *val = POWER_SUPPLY_CHARGE_TYPE_TRICKLE; 172 + break; 173 + case MAX8971_CHARGING_FAST_CONST_CURRENT: 174 + case MAX8971_CHARGING_FAST_CONST_VOLTAGE: 175 + *val = POWER_SUPPLY_CHARGE_TYPE_FAST; 176 + break; 177 + case MAX8971_CHARGING_TOP_OFF: 178 + case MAX8971_CHARGING_THERMAL_LOOP: 179 + *val = POWER_SUPPLY_CHARGE_TYPE_STANDARD; 180 + break; 181 + case MAX8971_CHARGING_DONE: 182 + case MAX8971_CHARGING_TIMER_FAULT: 183 + case MAX8971_CHARGING_SUSPENDED_THERMAL: 184 + case MAX8971_CHARGING_OFF: 185 + *val = POWER_SUPPLY_CHARGE_TYPE_NONE; 186 + break; 187 + default: 188 + *val = POWER_SUPPLY_CHARGE_TYPE_UNKNOWN; 189 + } 190 + 191 + return 0; 192 + } 193 + 194 + static int max8971_get_health(struct max8971_data *priv, int *val) 195 + { 196 + u32 regval; 197 + int err; 198 + 199 + err = regmap_field_read(priv->rfield[THM_DTLS], &regval); 200 + if (err) 201 + return err; 202 + 203 + switch (regval) { 204 + case MAX8971_HEALTH_COLD: 205 + *val = POWER_SUPPLY_HEALTH_COLD; 206 + break; 207 + case MAX8971_HEALTH_COOL: 208 + *val = POWER_SUPPLY_HEALTH_COOL; 209 + break; 210 + case MAX8971_HEALTH_WARM: 211 + *val = POWER_SUPPLY_HEALTH_GOOD; 212 + break; 213 + case MAX8971_HEALTH_HOT: 214 + *val = POWER_SUPPLY_HEALTH_HOT; 215 + break; 216 + case MAX8971_HEALTH_OVERHEAT: 217 + *val = POWER_SUPPLY_HEALTH_OVERHEAT; 218 + break; 219 + case MAX8971_HEALTH_UNKNOWN: 220 + default: 221 + *val = POWER_SUPPLY_HEALTH_UNKNOWN; 222 + } 223 + 224 + return 0; 225 + } 226 + 227 + static int max8971_get_online(struct max8971_data *priv, int *val) 228 + { 229 + u32 regval; 230 + int err; 231 + 232 + err = regmap_read(priv->regmap, MAX8971_REG_CHG_STAT, &regval); 233 + if (err) 234 + return err; 235 + 236 + if (priv->present) 237 + /* CHG_OK bit is 0 when charger is online */ 238 + *val = !(regval & MAX8971_CHG_MASK); 239 + else 240 + *val = priv->present; 241 + 242 + return 0; 243 + } 244 + 245 + static int max8971_get_integer(struct max8971_data *priv, enum max8971_field_idx fidx, 246 + u32 clamp_min, u32 clamp_max, u32 mult, int *val) 247 + { 248 + u32 regval; 249 + int err; 250 + 251 + err = regmap_field_read(priv->rfield[fidx], &regval); 252 + if (err) 253 + return err; 254 + 255 + *val = clamp_val(regval * mult, clamp_min, clamp_max); 256 + 257 + return 0; 258 + } 259 + 260 + static int max8971_set_integer(struct max8971_data *priv, enum max8971_field_idx fidx, 261 + u32 clamp_min, u32 clamp_max, u32 div, int val) 262 + { 263 + u32 regval; 264 + 265 + regval = clamp_val(val, clamp_min, clamp_max) / div; 266 + 267 + return regmap_field_write(priv->rfield[fidx], regval); 268 + } 269 + 270 + static int max8971_get_property(struct power_supply *psy, enum power_supply_property psp, 271 + union power_supply_propval *val) 272 + { 273 + struct max8971_data *priv = power_supply_get_drvdata(psy); 274 + int err = 0; 275 + 276 + switch (psp) { 277 + case POWER_SUPPLY_PROP_STATUS: 278 + err = max8971_get_status(priv, &val->intval); 279 + break; 280 + case POWER_SUPPLY_PROP_CHARGE_TYPE: 281 + err = max8971_get_charge_type(priv, &val->intval); 282 + break; 283 + case POWER_SUPPLY_PROP_USB_TYPE: 284 + val->intval = priv->usb_type; 285 + break; 286 + case POWER_SUPPLY_PROP_HEALTH: 287 + err = max8971_get_health(priv, &val->intval); 288 + break; 289 + case POWER_SUPPLY_PROP_ONLINE: 290 + err = max8971_get_online(priv, &val->intval); 291 + break; 292 + case POWER_SUPPLY_PROP_PRESENT: 293 + val->intval = priv->present; 294 + break; 295 + case POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT_MAX: 296 + val->intval = MAX8971_CHG_CC_MAX; 297 + break; 298 + case POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT: 299 + err = max8971_get_integer(priv, CHG_CC, MAX8971_CHG_CC_MIN, MAX8971_CHG_CC_MAX, 300 + MAX8971_CHG_CC_STEP, &val->intval); 301 + break; 302 + case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT: 303 + err = max8971_get_integer(priv, DCI_LMT, MAX8971_DCILMT_MIN, MAX8971_DCILMT_MAX, 304 + MAX8971_DCILMT_STEP, &val->intval); 305 + break; 306 + case POWER_SUPPLY_PROP_MODEL_NAME: 307 + val->strval = max8971_model; 308 + break; 309 + case POWER_SUPPLY_PROP_MANUFACTURER: 310 + val->strval = max8971_manufacturer; 311 + break; 312 + default: 313 + err = -EINVAL; 314 + } 315 + 316 + return err; 317 + } 318 + 319 + static int max8971_set_property(struct power_supply *psy, enum power_supply_property psp, 320 + const union power_supply_propval *val) 321 + { 322 + struct max8971_data *priv = power_supply_get_drvdata(psy); 323 + int err = 0; 324 + 325 + switch (psp) { 326 + case POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT: 327 + err = max8971_set_integer(priv, CHG_CC, MAX8971_CHG_CC_MIN, MAX8971_CHG_CC_MAX, 328 + MAX8971_CHG_CC_STEP, val->intval); 329 + break; 330 + case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT: 331 + err = max8971_set_integer(priv, DCI_LMT, MAX8971_DCILMT_MIN, MAX8971_DCILMT_MAX, 332 + MAX8971_DCILMT_STEP, val->intval); 333 + break; 334 + default: 335 + err = -EINVAL; 336 + } 337 + 338 + return err; 339 + }; 340 + 341 + static int max8971_property_is_writeable(struct power_supply *psy, 342 + enum power_supply_property psp) 343 + { 344 + switch (psp) { 345 + case POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT: 346 + case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT: 347 + return true; 348 + default: 349 + return false; 350 + } 351 + } 352 + 353 + static enum power_supply_property max8971_properties[] = { 354 + POWER_SUPPLY_PROP_STATUS, 355 + POWER_SUPPLY_PROP_CHARGE_TYPE, 356 + POWER_SUPPLY_PROP_USB_TYPE, 357 + POWER_SUPPLY_PROP_HEALTH, 358 + POWER_SUPPLY_PROP_ONLINE, 359 + POWER_SUPPLY_PROP_PRESENT, 360 + POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT, 361 + POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT_MAX, 362 + POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT, 363 + POWER_SUPPLY_PROP_MODEL_NAME, 364 + POWER_SUPPLY_PROP_MANUFACTURER, 365 + }; 366 + 367 + static const struct power_supply_desc max8971_charger_desc = { 368 + .name = "max8971-charger", 369 + .type = POWER_SUPPLY_TYPE_USB, 370 + .usb_types = BIT(POWER_SUPPLY_USB_TYPE_UNKNOWN) | 371 + BIT(POWER_SUPPLY_USB_TYPE_SDP) | 372 + BIT(POWER_SUPPLY_USB_TYPE_DCP) | 373 + BIT(POWER_SUPPLY_USB_TYPE_CDP) | 374 + BIT(POWER_SUPPLY_USB_TYPE_ACA), 375 + .properties = max8971_properties, 376 + .num_properties = ARRAY_SIZE(max8971_properties), 377 + .get_property = max8971_get_property, 378 + .set_property = max8971_set_property, 379 + .property_is_writeable = max8971_property_is_writeable, 380 + }; 381 + 382 + static void max8971_update_config(struct max8971_data *priv) 383 + { 384 + regmap_field_write(priv->rfield[CPROT], MAX8971_CHGPROT_UNLOCKED); 385 + 386 + if (priv->fchgt != MAX8971_FCHGT_DEFAULT) 387 + regmap_field_write(priv->rfield[FCHG_T], priv->fchgt); 388 + 389 + regmap_write_bits(priv->regmap, MAX8971_REG_DCCRNT, MAX8971_CHGRSTRT_MASK, 390 + MAX8971_CHGRSTRT_MASK); 391 + 392 + if (priv->tofft != MAX8971_TOPOFFT_DEFAULT) 393 + regmap_field_write(priv->rfield[TOPOFF_T], priv->tofft); 394 + 395 + if (priv->toffs) 396 + regmap_field_write(priv->rfield[TOPOFF_S], priv->toffs); 397 + 398 + regmap_field_write(priv->rfield[CPROT], MAX8971_CHGPROT_LOCKED); 399 + } 400 + 401 + static ssize_t fast_charge_timer_show(struct device *dev, struct device_attribute *attr, 402 + char *buf) 403 + { 404 + struct power_supply *psy = to_power_supply(dev); 405 + struct max8971_data *priv = power_supply_get_drvdata(psy); 406 + u32 regval; 407 + int err; 408 + 409 + err = regmap_field_read(priv->rfield[FCHG_T], &regval); 410 + if (err) 411 + return err; 412 + 413 + switch (regval) { 414 + case 0x1 ... 0x7: 415 + /* Time is off by 3 hours comparing to value */ 416 + regval += 3; 417 + break; 418 + case 0x0: 419 + default: 420 + regval = 0; 421 + break; 422 + } 423 + 424 + return sysfs_emit(buf, "%u\n", regval); 425 + } 426 + 427 + static ssize_t fast_charge_timer_store(struct device *dev, struct device_attribute *attr, 428 + const char *buf, size_t count) 429 + { 430 + struct power_supply *psy = to_power_supply(dev); 431 + struct max8971_data *priv = power_supply_get_drvdata(psy); 432 + unsigned long hours; 433 + int val, err; 434 + 435 + err = kstrtoul(buf, 10, &hours); 436 + if (err) 437 + return err; 438 + 439 + val = hours - 3; 440 + if (val <= 0 || val > 7) 441 + priv->fchgt = 0; 442 + else 443 + priv->fchgt = val; 444 + 445 + max8971_update_config(priv); 446 + 447 + return count; 448 + } 449 + 450 + static ssize_t top_off_threshold_current_show(struct device *dev, 451 + struct device_attribute *attr, 452 + char *buf) 453 + { 454 + struct power_supply *psy = to_power_supply(dev); 455 + struct max8971_data *priv = power_supply_get_drvdata(psy); 456 + u32 regval, val; 457 + int err; 458 + 459 + err = regmap_field_read(priv->rfield[TOPOFF_S], &regval); 460 + if (err) 461 + return err; 462 + 463 + /* 50uA start with 50uA step */ 464 + val = regval * 50 + 50; 465 + val *= 1000; 466 + 467 + return sysfs_emit(buf, "%u\n", val); 468 + } 469 + 470 + static ssize_t top_off_threshold_current_store(struct device *dev, 471 + struct device_attribute *attr, 472 + const char *buf, size_t count) 473 + { 474 + struct power_supply *psy = to_power_supply(dev); 475 + struct max8971_data *priv = power_supply_get_drvdata(psy); 476 + unsigned long uamp; 477 + int err; 478 + 479 + err = kstrtoul(buf, 10, &uamp); 480 + if (err) 481 + return err; 482 + 483 + if (uamp < 50000 || uamp > 200000) 484 + return -EINVAL; 485 + 486 + priv->toffs = uamp / 50000 - 1; 487 + 488 + max8971_update_config(priv); 489 + 490 + return count; 491 + } 492 + 493 + static ssize_t top_off_timer_show(struct device *dev, struct device_attribute *attr, 494 + char *buf) 495 + { 496 + struct power_supply *psy = to_power_supply(dev); 497 + struct max8971_data *priv = power_supply_get_drvdata(psy); 498 + u32 regval; 499 + int err; 500 + 501 + err = regmap_field_read(priv->rfield[TOPOFF_T], &regval); 502 + if (err) 503 + return err; 504 + 505 + /* 10 min intervals */ 506 + regval *= 10; 507 + 508 + return sysfs_emit(buf, "%u\n", regval); 509 + } 510 + 511 + static ssize_t top_off_timer_store(struct device *dev, struct device_attribute *attr, 512 + const char *buf, size_t count) 513 + { 514 + struct power_supply *psy = to_power_supply(dev); 515 + struct max8971_data *priv = power_supply_get_drvdata(psy); 516 + unsigned long minutes; 517 + int err; 518 + 519 + err = kstrtoul(buf, 10, &minutes); 520 + if (err) 521 + return err; 522 + 523 + if (minutes > 70) 524 + return -EINVAL; 525 + 526 + priv->tofft = minutes / 10; 527 + 528 + max8971_update_config(priv); 529 + 530 + return count; 531 + } 532 + 533 + static DEVICE_ATTR_RW(fast_charge_timer); 534 + static DEVICE_ATTR_RW(top_off_threshold_current); 535 + static DEVICE_ATTR_RW(top_off_timer); 536 + 537 + static struct attribute *max8971_attrs[] = { 538 + &dev_attr_fast_charge_timer.attr, 539 + &dev_attr_top_off_threshold_current.attr, 540 + &dev_attr_top_off_timer.attr, 541 + NULL 542 + }; 543 + ATTRIBUTE_GROUPS(max8971); 544 + 545 + static void max8971_extcon_evt_worker(struct work_struct *work) 546 + { 547 + struct max8971_data *priv = 548 + container_of(work, struct max8971_data, extcon_work.work); 549 + struct device *dev = priv->dev; 550 + struct extcon_dev *edev = priv->edev; 551 + u32 chgcc, dcilmt; 552 + 553 + if (extcon_get_state(edev, EXTCON_CHG_USB_SDP) > 0) { 554 + dev_dbg(dev, "USB SDP charger is connected\n"); 555 + priv->usb_type = POWER_SUPPLY_USB_TYPE_SDP; 556 + chgcc = 500000; 557 + dcilmt = 500000; 558 + } else if (extcon_get_state(edev, EXTCON_USB) > 0) { 559 + dev_dbg(dev, "USB charger is connected\n"); 560 + priv->usb_type = POWER_SUPPLY_USB_TYPE_SDP; 561 + chgcc = 500000; 562 + dcilmt = 500000; 563 + } else if (extcon_get_state(edev, EXTCON_DISP_MHL) > 0) { 564 + dev_dbg(dev, "MHL plug is connected\n"); 565 + priv->usb_type = POWER_SUPPLY_USB_TYPE_SDP; 566 + chgcc = 500000; 567 + dcilmt = 500000; 568 + } else if (extcon_get_state(edev, EXTCON_CHG_USB_DCP) > 0) { 569 + dev_dbg(dev, "USB DCP charger is connected\n"); 570 + priv->usb_type = POWER_SUPPLY_USB_TYPE_DCP; 571 + chgcc = 900000; 572 + dcilmt = 1200000; 573 + } else if (extcon_get_state(edev, EXTCON_CHG_USB_FAST) > 0) { 574 + dev_dbg(dev, "USB FAST charger is connected\n"); 575 + priv->usb_type = POWER_SUPPLY_USB_TYPE_ACA; 576 + chgcc = 900000; 577 + dcilmt = 1200000; 578 + } else if (extcon_get_state(edev, EXTCON_CHG_USB_SLOW) > 0) { 579 + dev_dbg(dev, "USB SLOW charger is connected\n"); 580 + priv->usb_type = POWER_SUPPLY_USB_TYPE_ACA; 581 + chgcc = 900000; 582 + dcilmt = 1200000; 583 + } else if (extcon_get_state(edev, EXTCON_CHG_USB_CDP) > 0) { 584 + dev_dbg(dev, "USB CDP charger is connected\n"); 585 + priv->usb_type = POWER_SUPPLY_USB_TYPE_CDP; 586 + chgcc = 900000; 587 + dcilmt = 1200000; 588 + } else { 589 + dev_dbg(dev, "USB state is unknown\n"); 590 + priv->usb_type = POWER_SUPPLY_USB_TYPE_UNKNOWN; 591 + return; 592 + } 593 + 594 + regmap_field_write(priv->rfield[CPROT], MAX8971_CHGPROT_UNLOCKED); 595 + 596 + max8971_set_integer(priv, CHG_CC, MAX8971_CHG_CC_MIN, MAX8971_CHG_CC_MAX, 597 + MAX8971_CHG_CC_STEP, chgcc); 598 + max8971_set_integer(priv, DCI_LMT, MAX8971_DCILMT_MIN, MAX8971_DCILMT_MAX, 599 + MAX8971_DCILMT_STEP, dcilmt); 600 + 601 + regmap_field_write(priv->rfield[CPROT], MAX8971_CHGPROT_LOCKED); 602 + } 603 + 604 + static int extcon_get_charger_type(struct notifier_block *nb, 605 + unsigned long state, void *data) 606 + { 607 + struct max8971_data *priv = 608 + container_of(nb, struct max8971_data, extcon_nb); 609 + schedule_delayed_work(&priv->extcon_work, 0); 610 + 611 + return NOTIFY_OK; 612 + } 613 + 614 + static irqreturn_t max8971_interrupt(int irq, void *dev_id) 615 + { 616 + struct max8971_data *priv = dev_id; 617 + struct device *dev = priv->dev; 618 + int err, state; 619 + 620 + err = regmap_read(priv->regmap, MAX8971_REG_CHGINT, &state); 621 + if (err) 622 + dev_err(dev, "interrupt reg read failed %d\n", err); 623 + 624 + err = regmap_write_bits(priv->regmap, MAX8971_REG_CHGINT_MASK, 625 + MAX8971_AICL_MASK, MAX8971_AICL_MASK); 626 + if (err) 627 + dev_err(dev, "failed to mask IRQ\n"); 628 + 629 + /* set presence prop */ 630 + priv->present = state & MAX8971_REG_CHG_RST; 631 + 632 + /* on every plug chip resets to default */ 633 + if (priv->present) 634 + max8971_update_config(priv); 635 + 636 + /* update supply status */ 637 + power_supply_changed(priv->psy_mains); 638 + 639 + return IRQ_HANDLED; 640 + } 641 + 642 + static int max8971_probe(struct i2c_client *client) 643 + { 644 + struct device *dev = &client->dev; 645 + struct max8971_data *priv; 646 + struct device_node *extcon; 647 + struct power_supply_config cfg = { }; 648 + int err, i; 649 + 650 + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 651 + if (!priv) 652 + return -ENOMEM; 653 + 654 + priv->dev = dev; 655 + priv->usb_type = POWER_SUPPLY_USB_TYPE_UNKNOWN; 656 + 657 + i2c_set_clientdata(client, priv); 658 + 659 + priv->regmap = devm_regmap_init_i2c(client, &max8971_regmap_config); 660 + if (IS_ERR(priv->regmap)) 661 + return dev_err_probe(dev, PTR_ERR(priv->regmap), "cannot allocate regmap\n"); 662 + 663 + for (i = 0; i < MAX8971_N_REGMAP_FIELDS; i++) { 664 + priv->rfield[i] = devm_regmap_field_alloc(dev, priv->regmap, max8971_reg_field[i]); 665 + if (IS_ERR(priv->rfield[i])) 666 + return dev_err_probe(dev, PTR_ERR(priv->rfield[i]), 667 + "cannot allocate regmap field\n"); 668 + } 669 + 670 + cfg.attr_grp = max8971_groups; 671 + cfg.drv_data = priv; 672 + cfg.fwnode = dev_fwnode(dev); 673 + 674 + priv->psy_mains = devm_power_supply_register(dev, &max8971_charger_desc, &cfg); 675 + if (IS_ERR(priv->psy_mains)) 676 + return dev_err_probe(dev, PTR_ERR(priv->psy_mains), 677 + "failed to register mains supply\n"); 678 + 679 + err = regmap_write_bits(priv->regmap, MAX8971_REG_CHGINT_MASK, MAX8971_AICL_MASK, 680 + MAX8971_AICL_MASK); 681 + if (err) 682 + return dev_err_probe(dev, err, "failed to mask IRQ\n"); 683 + 684 + err = devm_request_threaded_irq(dev, client->irq, NULL, &max8971_interrupt, 685 + IRQF_ONESHOT | IRQF_SHARED, client->name, priv); 686 + if (err) 687 + return dev_err_probe(dev, err, "failed to register IRQ %d\n", client->irq); 688 + 689 + extcon = of_graph_get_remote_node(dev->of_node, -1, -1); 690 + if (!extcon) 691 + return 0; 692 + 693 + priv->edev = extcon_find_edev_by_node(extcon); 694 + of_node_put(extcon); 695 + if (IS_ERR(priv->edev)) 696 + return dev_err_probe(dev, PTR_ERR(priv->edev), "failed to find extcon\n"); 697 + 698 + err = devm_delayed_work_autocancel(dev, &priv->extcon_work, 699 + max8971_extcon_evt_worker); 700 + if (err) 701 + return dev_err_probe(dev, err, "failed to add extcon evt stop action\n"); 702 + 703 + priv->extcon_nb.notifier_call = extcon_get_charger_type; 704 + 705 + err = devm_extcon_register_notifier_all(dev, priv->edev, &priv->extcon_nb); 706 + if (err) 707 + return dev_err_probe(dev, err, "failed to register notifier\n"); 708 + 709 + /* Initial configuration work with 1 sec delay */ 710 + schedule_delayed_work(&priv->extcon_work, msecs_to_jiffies(1000)); 711 + 712 + return 0; 713 + } 714 + 715 + static int __maybe_unused max8971_resume(struct device *dev) 716 + { 717 + struct i2c_client *client = to_i2c_client(dev); 718 + struct max8971_data *priv = i2c_get_clientdata(client); 719 + 720 + irq_wake_thread(client->irq, priv); 721 + 722 + return 0; 723 + } 724 + 725 + static SIMPLE_DEV_PM_OPS(max8971_pm_ops, NULL, max8971_resume); 726 + 727 + static const struct of_device_id max8971_match_ids[] = { 728 + { .compatible = "maxim,max8971" }, 729 + { /* sentinel */ } 730 + }; 731 + MODULE_DEVICE_TABLE(of, max8971_match_ids); 732 + 733 + static const struct i2c_device_id max8971_i2c_id[] = { 734 + { "max8971" }, 735 + { } 736 + }; 737 + MODULE_DEVICE_TABLE(i2c, max8971_i2c_id); 738 + 739 + static struct i2c_driver max8971_driver = { 740 + .driver = { 741 + .name = "max8971-charger", 742 + .of_match_table = max8971_match_ids, 743 + .pm = &max8971_pm_ops, 744 + }, 745 + .probe = max8971_probe, 746 + .id_table = max8971_i2c_id, 747 + }; 748 + module_i2c_driver(max8971_driver); 749 + 750 + MODULE_AUTHOR("Svyatoslav Ryhel <clamor95@gmail.com>"); 751 + MODULE_DESCRIPTION("MAX8971 Charger Driver"); 752 + MODULE_LICENSE("GPL");