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

power: supply: max77976: add Maxim MAX77976 charger driver

Add support for the MAX77976 3.5/5.5A 1-Cell Li+ Battery Charger.

This is a simple implementation enough to be used as a simple battery
charger without OTG and boost.

Signed-off-by: Luca Ceresoli <luca@lucaceresoli.net>
Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.com>

authored by

Luca Ceresoli and committed by
Sebastian Reichel
715ecbc1 77d641ba

+523
+1
MAINTAINERS
··· 11584 11584 M: Luca Ceresoli <luca@lucaceresoli.net> 11585 11585 S: Supported 11586 11586 F: Documentation/devicetree/bindings/power/supply/maxim,max77976.yaml 11587 + F: drivers/power/supply/max77976_charger.c 11587 11588 11588 11589 MAXIM MUIC CHARGER DRIVERS FOR EXYNOS BASED BOARDS 11589 11590 M: Krzysztof Kozlowski <krzysztof.kozlowski@canonical.com>
+12
drivers/power/supply/Kconfig
··· 557 557 help 558 558 Say Y to enable support for the Maxim MAX77693 battery charger. 559 559 560 + config CHARGER_MAX77976 561 + tristate "Maxim MAX77976 battery charger driver" 562 + depends on I2C 563 + select REGMAP_I2C 564 + help 565 + The Maxim MAX77976 is a 19 Vin, 5.5A 1-Cell Li+ Battery Charger 566 + USB OTG support. It has an I2C interface for configuration. 567 + 568 + Say Y to enable support for the Maxim MAX77976 battery charger. 569 + This driver can also be built as a module. If so, the module will be 570 + called max77976_charger. 571 + 560 572 config CHARGER_MAX8997 561 573 tristate "Maxim MAX8997/MAX8966 PMIC battery charger driver" 562 574 depends on MFD_MAX8997 && REGULATOR_MAX8997
+1
drivers/power/supply/Makefile
··· 75 75 obj-$(CONFIG_CHARGER_DETECTOR_MAX14656) += max14656_charger_detector.o 76 76 obj-$(CONFIG_CHARGER_MAX77650) += max77650-charger.o 77 77 obj-$(CONFIG_CHARGER_MAX77693) += max77693_charger.o 78 + obj-$(CONFIG_CHARGER_MAX77976) += max77976_charger.o 78 79 obj-$(CONFIG_CHARGER_MAX8997) += max8997_charger.o 79 80 obj-$(CONFIG_CHARGER_MAX8998) += max8998_charger.o 80 81 obj-$(CONFIG_CHARGER_MP2629) += mp2629_charger.o
+509
drivers/power/supply/max77976_charger.c
··· 1 + // SPDX-License-Identifier: GPL-2.0+ 2 + /* 3 + * max77976_charger.c - Driver for the Maxim MAX77976 battery charger 4 + * 5 + * Copyright (C) 2021 Luca Ceresoli 6 + * Author: Luca Ceresoli <luca@lucaceresoli.net> 7 + */ 8 + 9 + #include <linux/i2c.h> 10 + #include <linux/module.h> 11 + #include <linux/power_supply.h> 12 + #include <linux/regmap.h> 13 + 14 + #define MAX77976_DRIVER_NAME "max77976-charger" 15 + #define MAX77976_CHIP_ID 0x76 16 + 17 + static const char *max77976_manufacturer = "Maxim Integrated"; 18 + static const char *max77976_model = "MAX77976"; 19 + 20 + /* -------------------------------------------------------------------------- 21 + * Register map 22 + */ 23 + 24 + #define MAX77976_REG_CHIP_ID 0x00 25 + #define MAX77976_REG_CHIP_REVISION 0x01 26 + #define MAX77976_REG_CHG_INT_OK 0x12 27 + #define MAX77976_REG_CHG_DETAILS_01 0x14 28 + #define MAX77976_REG_CHG_CNFG_00 0x16 29 + #define MAX77976_REG_CHG_CNFG_02 0x18 30 + #define MAX77976_REG_CHG_CNFG_06 0x1c 31 + #define MAX77976_REG_CHG_CNFG_09 0x1f 32 + 33 + /* CHG_DETAILS_01.CHG_DTLS values */ 34 + enum max77976_charging_state { 35 + MAX77976_CHARGING_PREQUALIFICATION = 0x0, 36 + MAX77976_CHARGING_FAST_CONST_CURRENT, 37 + MAX77976_CHARGING_FAST_CONST_VOLTAGE, 38 + MAX77976_CHARGING_TOP_OFF, 39 + MAX77976_CHARGING_DONE, 40 + MAX77976_CHARGING_RESERVED_05, 41 + MAX77976_CHARGING_TIMER_FAULT, 42 + MAX77976_CHARGING_SUSPENDED_QBATT_OFF, 43 + MAX77976_CHARGING_OFF, 44 + MAX77976_CHARGING_RESERVED_09, 45 + MAX77976_CHARGING_THERMAL_SHUTDOWN, 46 + MAX77976_CHARGING_WATCHDOG_EXPIRED, 47 + MAX77976_CHARGING_SUSPENDED_JEITA, 48 + MAX77976_CHARGING_SUSPENDED_THM_REMOVAL, 49 + MAX77976_CHARGING_SUSPENDED_PIN, 50 + MAX77976_CHARGING_RESERVED_0F, 51 + }; 52 + 53 + /* CHG_DETAILS_01.BAT_DTLS values */ 54 + enum max77976_battery_state { 55 + MAX77976_BATTERY_BATTERY_REMOVAL = 0x0, 56 + MAX77976_BATTERY_PREQUALIFICATION, 57 + MAX77976_BATTERY_TIMER_FAULT, 58 + MAX77976_BATTERY_REGULAR_VOLTAGE, 59 + MAX77976_BATTERY_LOW_VOLTAGE, 60 + MAX77976_BATTERY_OVERVOLTAGE, 61 + MAX77976_BATTERY_RESERVED, 62 + MAX77976_BATTERY_BATTERY_ONLY, // No valid adapter is present 63 + }; 64 + 65 + /* CHG_CNFG_00.MODE values */ 66 + enum max77976_mode { 67 + MAX77976_MODE_CHARGER_BUCK = 0x5, 68 + MAX77976_MODE_BOOST = 0x9, 69 + }; 70 + 71 + /* CHG_CNFG_02.CHG_CC: charge current limit, 100..5500 mA, 50 mA steps */ 72 + #define MAX77976_CHG_CC_STEP 50000U 73 + #define MAX77976_CHG_CC_MIN 100000U 74 + #define MAX77976_CHG_CC_MAX 5500000U 75 + 76 + /* CHG_CNFG_09.CHGIN_ILIM: input current limit, 100..3200 mA, 100 mA steps */ 77 + #define MAX77976_CHGIN_ILIM_STEP 100000U 78 + #define MAX77976_CHGIN_ILIM_MIN 100000U 79 + #define MAX77976_CHGIN_ILIM_MAX 3200000U 80 + 81 + enum max77976_field_idx { 82 + VERSION, REVISION, /* CHIP_REVISION */ 83 + CHGIN_OK, /* CHG_INT_OK */ 84 + BAT_DTLS, CHG_DTLS, /* CHG_DETAILS_01 */ 85 + MODE, /* CHG_CNFG_00 */ 86 + CHG_CC, /* CHG_CNFG_02 */ 87 + CHGPROT, /* CHG_CNFG_06 */ 88 + CHGIN_ILIM, /* CHG_CNFG_09 */ 89 + MAX77976_N_REGMAP_FIELDS 90 + }; 91 + 92 + static const struct reg_field max77976_reg_field[MAX77976_N_REGMAP_FIELDS] = { 93 + [VERSION] = REG_FIELD(MAX77976_REG_CHIP_REVISION, 4, 7), 94 + [REVISION] = REG_FIELD(MAX77976_REG_CHIP_REVISION, 0, 3), 95 + [CHGIN_OK] = REG_FIELD(MAX77976_REG_CHG_INT_OK, 6, 6), 96 + [CHG_DTLS] = REG_FIELD(MAX77976_REG_CHG_DETAILS_01, 0, 3), 97 + [BAT_DTLS] = REG_FIELD(MAX77976_REG_CHG_DETAILS_01, 4, 6), 98 + [MODE] = REG_FIELD(MAX77976_REG_CHG_CNFG_00, 0, 3), 99 + [CHG_CC] = REG_FIELD(MAX77976_REG_CHG_CNFG_02, 0, 6), 100 + [CHGPROT] = REG_FIELD(MAX77976_REG_CHG_CNFG_06, 2, 3), 101 + [CHGIN_ILIM] = REG_FIELD(MAX77976_REG_CHG_CNFG_09, 0, 5), 102 + }; 103 + 104 + static const struct regmap_config max77976_regmap_config = { 105 + .reg_bits = 8, 106 + .val_bits = 8, 107 + .max_register = 0x24, 108 + }; 109 + 110 + /* -------------------------------------------------------------------------- 111 + * Data structures 112 + */ 113 + 114 + struct max77976 { 115 + struct i2c_client *client; 116 + struct regmap *regmap; 117 + struct regmap_field *rfield[MAX77976_N_REGMAP_FIELDS]; 118 + }; 119 + 120 + /* -------------------------------------------------------------------------- 121 + * power_supply properties 122 + */ 123 + 124 + static int max77976_get_status(struct max77976 *chg, int *val) 125 + { 126 + unsigned int regval; 127 + int err; 128 + 129 + err = regmap_field_read(chg->rfield[CHG_DTLS], &regval); 130 + if (err < 0) 131 + return err; 132 + 133 + switch (regval) { 134 + case MAX77976_CHARGING_PREQUALIFICATION: 135 + case MAX77976_CHARGING_FAST_CONST_CURRENT: 136 + case MAX77976_CHARGING_FAST_CONST_VOLTAGE: 137 + case MAX77976_CHARGING_TOP_OFF: 138 + *val = POWER_SUPPLY_STATUS_CHARGING; 139 + break; 140 + case MAX77976_CHARGING_DONE: 141 + *val = POWER_SUPPLY_STATUS_FULL; 142 + break; 143 + case MAX77976_CHARGING_TIMER_FAULT: 144 + case MAX77976_CHARGING_SUSPENDED_QBATT_OFF: 145 + case MAX77976_CHARGING_SUSPENDED_JEITA: 146 + case MAX77976_CHARGING_SUSPENDED_THM_REMOVAL: 147 + case MAX77976_CHARGING_SUSPENDED_PIN: 148 + *val = POWER_SUPPLY_STATUS_NOT_CHARGING; 149 + break; 150 + case MAX77976_CHARGING_OFF: 151 + case MAX77976_CHARGING_THERMAL_SHUTDOWN: 152 + case MAX77976_CHARGING_WATCHDOG_EXPIRED: 153 + *val = POWER_SUPPLY_STATUS_DISCHARGING; 154 + break; 155 + default: 156 + *val = POWER_SUPPLY_STATUS_UNKNOWN; 157 + } 158 + 159 + return 0; 160 + } 161 + 162 + static int max77976_get_charge_type(struct max77976 *chg, int *val) 163 + { 164 + unsigned int regval; 165 + int err; 166 + 167 + err = regmap_field_read(chg->rfield[CHG_DTLS], &regval); 168 + if (err < 0) 169 + return err; 170 + 171 + switch (regval) { 172 + case MAX77976_CHARGING_PREQUALIFICATION: 173 + *val = POWER_SUPPLY_CHARGE_TYPE_TRICKLE; 174 + break; 175 + case MAX77976_CHARGING_FAST_CONST_CURRENT: 176 + case MAX77976_CHARGING_FAST_CONST_VOLTAGE: 177 + *val = POWER_SUPPLY_CHARGE_TYPE_FAST; 178 + break; 179 + case MAX77976_CHARGING_TOP_OFF: 180 + *val = POWER_SUPPLY_CHARGE_TYPE_STANDARD; 181 + break; 182 + case MAX77976_CHARGING_DONE: 183 + case MAX77976_CHARGING_TIMER_FAULT: 184 + case MAX77976_CHARGING_SUSPENDED_QBATT_OFF: 185 + case MAX77976_CHARGING_OFF: 186 + case MAX77976_CHARGING_THERMAL_SHUTDOWN: 187 + case MAX77976_CHARGING_WATCHDOG_EXPIRED: 188 + case MAX77976_CHARGING_SUSPENDED_JEITA: 189 + case MAX77976_CHARGING_SUSPENDED_THM_REMOVAL: 190 + case MAX77976_CHARGING_SUSPENDED_PIN: 191 + *val = POWER_SUPPLY_CHARGE_TYPE_NONE; 192 + break; 193 + default: 194 + *val = POWER_SUPPLY_CHARGE_TYPE_UNKNOWN; 195 + } 196 + 197 + return 0; 198 + } 199 + 200 + static int max77976_get_health(struct max77976 *chg, int *val) 201 + { 202 + unsigned int regval; 203 + int err; 204 + 205 + err = regmap_field_read(chg->rfield[BAT_DTLS], &regval); 206 + if (err < 0) 207 + return err; 208 + 209 + switch (regval) { 210 + case MAX77976_BATTERY_BATTERY_REMOVAL: 211 + *val = POWER_SUPPLY_HEALTH_NO_BATTERY; 212 + break; 213 + case MAX77976_BATTERY_LOW_VOLTAGE: 214 + case MAX77976_BATTERY_REGULAR_VOLTAGE: 215 + *val = POWER_SUPPLY_HEALTH_GOOD; 216 + break; 217 + case MAX77976_BATTERY_TIMER_FAULT: 218 + *val = POWER_SUPPLY_HEALTH_SAFETY_TIMER_EXPIRE; 219 + break; 220 + case MAX77976_BATTERY_OVERVOLTAGE: 221 + *val = POWER_SUPPLY_HEALTH_OVERVOLTAGE; 222 + break; 223 + case MAX77976_BATTERY_PREQUALIFICATION: 224 + case MAX77976_BATTERY_BATTERY_ONLY: 225 + *val = POWER_SUPPLY_HEALTH_UNKNOWN; 226 + break; 227 + default: 228 + *val = POWER_SUPPLY_HEALTH_UNKNOWN; 229 + } 230 + 231 + return 0; 232 + } 233 + 234 + static int max77976_get_online(struct max77976 *chg, int *val) 235 + { 236 + unsigned int regval; 237 + int err; 238 + 239 + err = regmap_field_read(chg->rfield[CHGIN_OK], &regval); 240 + if (err < 0) 241 + return err; 242 + 243 + *val = (regval ? 1 : 0); 244 + 245 + return 0; 246 + } 247 + 248 + static int max77976_get_integer(struct max77976 *chg, enum max77976_field_idx fidx, 249 + unsigned int clamp_min, unsigned int clamp_max, 250 + unsigned int mult, int *val) 251 + { 252 + unsigned int regval; 253 + int err; 254 + 255 + err = regmap_field_read(chg->rfield[fidx], &regval); 256 + if (err < 0) 257 + return err; 258 + 259 + *val = clamp_val(regval * mult, clamp_min, clamp_max); 260 + 261 + return 0; 262 + } 263 + 264 + static int max77976_set_integer(struct max77976 *chg, enum max77976_field_idx fidx, 265 + unsigned int clamp_min, unsigned int clamp_max, 266 + unsigned int div, int val) 267 + { 268 + unsigned int regval; 269 + 270 + regval = clamp_val(val, clamp_min, clamp_max) / div; 271 + 272 + return regmap_field_write(chg->rfield[fidx], regval); 273 + } 274 + 275 + static int max77976_get_property(struct power_supply *psy, 276 + enum power_supply_property psp, 277 + union power_supply_propval *val) 278 + { 279 + struct max77976 *chg = power_supply_get_drvdata(psy); 280 + int err = 0; 281 + 282 + switch (psp) { 283 + case POWER_SUPPLY_PROP_STATUS: 284 + err = max77976_get_status(chg, &val->intval); 285 + break; 286 + case POWER_SUPPLY_PROP_CHARGE_TYPE: 287 + err = max77976_get_charge_type(chg, &val->intval); 288 + break; 289 + case POWER_SUPPLY_PROP_HEALTH: 290 + err = max77976_get_health(chg, &val->intval); 291 + break; 292 + case POWER_SUPPLY_PROP_ONLINE: 293 + err = max77976_get_online(chg, &val->intval); 294 + break; 295 + case POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT_MAX: 296 + val->intval = MAX77976_CHG_CC_MAX; 297 + break; 298 + case POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT: 299 + err = max77976_get_integer(chg, CHG_CC, 300 + MAX77976_CHG_CC_MIN, 301 + MAX77976_CHG_CC_MAX, 302 + MAX77976_CHG_CC_STEP, 303 + &val->intval); 304 + break; 305 + case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT: 306 + err = max77976_get_integer(chg, CHGIN_ILIM, 307 + MAX77976_CHGIN_ILIM_MIN, 308 + MAX77976_CHGIN_ILIM_MAX, 309 + MAX77976_CHGIN_ILIM_STEP, 310 + &val->intval); 311 + break; 312 + case POWER_SUPPLY_PROP_MODEL_NAME: 313 + val->strval = max77976_model; 314 + break; 315 + case POWER_SUPPLY_PROP_MANUFACTURER: 316 + val->strval = max77976_manufacturer; 317 + break; 318 + default: 319 + err = -EINVAL; 320 + } 321 + 322 + return err; 323 + } 324 + 325 + static int max77976_set_property(struct power_supply *psy, 326 + enum power_supply_property psp, 327 + const union power_supply_propval *val) 328 + { 329 + struct max77976 *chg = power_supply_get_drvdata(psy); 330 + int err = 0; 331 + 332 + switch (psp) { 333 + case POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT: 334 + err = max77976_set_integer(chg, CHG_CC, 335 + MAX77976_CHG_CC_MIN, 336 + MAX77976_CHG_CC_MAX, 337 + MAX77976_CHG_CC_STEP, 338 + val->intval); 339 + break; 340 + case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT: 341 + err = max77976_set_integer(chg, CHGIN_ILIM, 342 + MAX77976_CHGIN_ILIM_MIN, 343 + MAX77976_CHGIN_ILIM_MAX, 344 + MAX77976_CHGIN_ILIM_STEP, 345 + val->intval); 346 + break; 347 + default: 348 + err = -EINVAL; 349 + } 350 + 351 + return err; 352 + }; 353 + 354 + static int max77976_property_is_writeable(struct power_supply *psy, 355 + enum power_supply_property psp) 356 + { 357 + switch (psp) { 358 + case POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT: 359 + case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT: 360 + return true; 361 + default: 362 + return false; 363 + } 364 + } 365 + 366 + static enum power_supply_property max77976_psy_props[] = { 367 + POWER_SUPPLY_PROP_STATUS, 368 + POWER_SUPPLY_PROP_CHARGE_TYPE, 369 + POWER_SUPPLY_PROP_HEALTH, 370 + POWER_SUPPLY_PROP_ONLINE, 371 + POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT, 372 + POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT_MAX, 373 + POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT, 374 + POWER_SUPPLY_PROP_MODEL_NAME, 375 + POWER_SUPPLY_PROP_MANUFACTURER, 376 + }; 377 + 378 + static const struct power_supply_desc max77976_psy_desc = { 379 + .name = MAX77976_DRIVER_NAME, 380 + .type = POWER_SUPPLY_TYPE_USB, 381 + .properties = max77976_psy_props, 382 + .num_properties = ARRAY_SIZE(max77976_psy_props), 383 + .get_property = max77976_get_property, 384 + .set_property = max77976_set_property, 385 + .property_is_writeable = max77976_property_is_writeable, 386 + }; 387 + 388 + /* -------------------------------------------------------------------------- 389 + * Entry point 390 + */ 391 + 392 + static int max77976_detect(struct max77976 *chg) 393 + { 394 + struct device *dev = &chg->client->dev; 395 + unsigned int id, ver, rev; 396 + int err; 397 + 398 + err = regmap_read(chg->regmap, MAX77976_REG_CHIP_ID, &id); 399 + if (err) 400 + return dev_err_probe(dev, err, "cannot read chip ID\n"); 401 + 402 + if (id != MAX77976_CHIP_ID) 403 + return dev_err_probe(dev, -ENXIO, "unknown model ID 0x%02x\n", id); 404 + 405 + err = regmap_field_read(chg->rfield[VERSION], &ver); 406 + if (!err) 407 + err = regmap_field_read(chg->rfield[REVISION], &rev); 408 + if (err) 409 + return dev_err_probe(dev, -ENXIO, "cannot read version/revision\n"); 410 + 411 + dev_info(dev, "detected model MAX779%02x ver %u rev %u", id, ver, rev); 412 + 413 + return 0; 414 + } 415 + 416 + static int max77976_configure(struct max77976 *chg) 417 + { 418 + struct device *dev = &chg->client->dev; 419 + int err; 420 + 421 + /* Magic value to unlock writing to some registers */ 422 + err = regmap_field_write(chg->rfield[CHGPROT], 0x3); 423 + if (err) 424 + goto err; 425 + 426 + /* 427 + * Mode 5 = Charger ON, OTG OFF, buck ON, boost OFF. 428 + * Other modes are not implemented by this driver. 429 + */ 430 + err = regmap_field_write(chg->rfield[MODE], MAX77976_MODE_CHARGER_BUCK); 431 + if (err) 432 + goto err; 433 + 434 + return 0; 435 + 436 + err: 437 + return dev_err_probe(dev, err, "error while configuring"); 438 + } 439 + 440 + static int max77976_probe(struct i2c_client *client) 441 + { 442 + struct device *dev = &client->dev; 443 + struct power_supply_config psy_cfg = {}; 444 + struct power_supply *psy; 445 + struct max77976 *chg; 446 + int err; 447 + int i; 448 + 449 + chg = devm_kzalloc(dev, sizeof(*chg), GFP_KERNEL); 450 + if (!chg) 451 + return -ENOMEM; 452 + 453 + i2c_set_clientdata(client, chg); 454 + psy_cfg.drv_data = chg; 455 + chg->client = client; 456 + 457 + chg->regmap = devm_regmap_init_i2c(client, &max77976_regmap_config); 458 + if (IS_ERR(chg->regmap)) 459 + return dev_err_probe(dev, PTR_ERR(chg->regmap), 460 + "cannot allocate regmap\n"); 461 + 462 + for (i = 0; i < MAX77976_N_REGMAP_FIELDS; i++) { 463 + chg->rfield[i] = devm_regmap_field_alloc(dev, chg->regmap, 464 + max77976_reg_field[i]); 465 + if (IS_ERR(chg->rfield[i])) 466 + return dev_err_probe(dev, PTR_ERR(chg->rfield[i]), 467 + "cannot allocate regmap field\n"); 468 + } 469 + 470 + err = max77976_detect(chg); 471 + if (err) 472 + return err; 473 + 474 + err = max77976_configure(chg); 475 + if (err) 476 + return err; 477 + 478 + psy = devm_power_supply_register_no_ws(dev, &max77976_psy_desc, &psy_cfg); 479 + if (IS_ERR(psy)) 480 + return dev_err_probe(dev, PTR_ERR(psy), "cannot register\n"); 481 + 482 + return 0; 483 + } 484 + 485 + static const struct i2c_device_id max77976_i2c_id[] = { 486 + { MAX77976_DRIVER_NAME, 0 }, 487 + { }, 488 + }; 489 + MODULE_DEVICE_TABLE(i2c, max77976_i2c_id); 490 + 491 + static const struct of_device_id max77976_of_id[] = { 492 + { .compatible = "maxim,max77976" }, 493 + { }, 494 + }; 495 + MODULE_DEVICE_TABLE(of, max77976_of_id); 496 + 497 + static struct i2c_driver max77976_driver = { 498 + .driver = { 499 + .name = MAX77976_DRIVER_NAME, 500 + .of_match_table = max77976_of_id, 501 + }, 502 + .probe_new = max77976_probe, 503 + .id_table = max77976_i2c_id, 504 + }; 505 + module_i2c_driver(max77976_driver); 506 + 507 + MODULE_AUTHOR("Luca Ceresoli <luca@lucaceresoli.net>"); 508 + MODULE_DESCRIPTION("Maxim MAX77976 charger driver"); 509 + MODULE_LICENSE("GPL v2");