1 /* 2 * Battery power supply driver for X-Powers AXP20X and AXP22X PMICs 3 * 4 * Copyright 2016 Free Electrons NextThing Co. 5 * Quentin Schulz <quentin.schulz@free-electrons.com> 6 * 7 * This driver is based on a previous upstreaming attempt by: 8 * Bruno Prémont <bonbons@linux-vserver.org> 9 * 10 * This file is subject to the terms and conditions of the GNU General 11 * Public License. See the file "COPYING" in the main directory of this 12 * archive for more details. 13 * 14 * This program is distributed in the hope that it will be useful, 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 * GNU General Public License for more details. 18 */ 19 20 #include <linux/err.h> 21 #include <linux/interrupt.h> 22 #include <linux/irq.h> 23 #include <linux/module.h> 24 #include <linux/of.h> 25 #include <linux/platform_device.h> 26 #include <linux/power_supply.h> 27 #include <linux/regmap.h> 28 #include <linux/slab.h> 29 #include <linux/time.h> 30 #include <linux/iio/iio.h> 31 #include <linux/iio/consumer.h> 32 #include <linux/mfd/axp20x.h> 33 34 #define AXP20X_PWR_STATUS_BAT_CHARGING BIT(2) 35 36 #define AXP20X_PWR_OP_BATT_PRESENT BIT(5) 37 #define AXP20X_PWR_OP_BATT_ACTIVATED BIT(3) 38 39 #define AXP209_FG_PERCENT GENMASK(6, 0) 40 #define AXP22X_FG_VALID BIT(7) 41 42 #define AXP20X_CHRG_CTRL1_ENABLE BIT(7) 43 #define AXP20X_CHRG_CTRL1_TGT_VOLT GENMASK(6, 5) 44 #define AXP20X_CHRG_CTRL1_TGT_4_1V (0 << 5) 45 #define AXP20X_CHRG_CTRL1_TGT_4_15V (1 << 5) 46 #define AXP20X_CHRG_CTRL1_TGT_4_2V (2 << 5) 47 #define AXP20X_CHRG_CTRL1_TGT_4_36V (3 << 5) 48 49 #define AXP22X_CHRG_CTRL1_TGT_4_22V (1 << 5) 50 #define AXP22X_CHRG_CTRL1_TGT_4_24V (3 << 5) 51 52 #define AXP813_CHRG_CTRL1_TGT_4_35V (3 << 5) 53 54 #define AXP20X_CHRG_CTRL1_TGT_CURR GENMASK(3, 0) 55 56 #define AXP20X_V_OFF_MASK GENMASK(2, 0) 57 58 struct axp20x_batt_ps; 59 60 struct axp_data { 61 int ccc_scale; 62 int ccc_offset; 63 bool has_fg_valid; 64 int (*get_max_voltage)(struct axp20x_batt_ps *batt, int *val); 65 int (*set_max_voltage)(struct axp20x_batt_ps *batt, int val); 66 }; 67 68 struct axp20x_batt_ps { 69 struct regmap *regmap; 70 struct power_supply *batt; 71 struct device *dev; 72 struct iio_channel *batt_chrg_i; 73 struct iio_channel *batt_dischrg_i; 74 struct iio_channel *batt_v; 75 /* Maximum constant charge current */ 76 unsigned int max_ccc; 77 const struct axp_data *data; 78 }; 79 80 static int axp20x_battery_get_max_voltage(struct axp20x_batt_ps *axp20x_batt, 81 int *val) 82 { 83 int ret, reg; 84 85 ret = regmap_read(axp20x_batt->regmap, AXP20X_CHRG_CTRL1, ®); 86 if (ret) 87 return ret; 88 89 switch (reg & AXP20X_CHRG_CTRL1_TGT_VOLT) { 90 case AXP20X_CHRG_CTRL1_TGT_4_1V: 91 *val = 4100000; 92 break; 93 case AXP20X_CHRG_CTRL1_TGT_4_15V: 94 *val = 4150000; 95 break; 96 case AXP20X_CHRG_CTRL1_TGT_4_2V: 97 *val = 4200000; 98 break; 99 case AXP20X_CHRG_CTRL1_TGT_4_36V: 100 *val = 4360000; 101 break; 102 default: 103 return -EINVAL; 104 } 105 106 return 0; 107 } 108 109 static int axp22x_battery_get_max_voltage(struct axp20x_batt_ps *axp20x_batt, 110 int *val) 111 { 112 int ret, reg; 113 114 ret = regmap_read(axp20x_batt->regmap, AXP20X_CHRG_CTRL1, ®); 115 if (ret) 116 return ret; 117 118 switch (reg & AXP20X_CHRG_CTRL1_TGT_VOLT) { 119 case AXP20X_CHRG_CTRL1_TGT_4_1V: 120 *val = 4100000; 121 break; 122 case AXP20X_CHRG_CTRL1_TGT_4_2V: 123 *val = 4200000; 124 break; 125 case AXP22X_CHRG_CTRL1_TGT_4_22V: 126 *val = 4220000; 127 break; 128 case AXP22X_CHRG_CTRL1_TGT_4_24V: 129 *val = 4240000; 130 break; 131 default: 132 return -EINVAL; 133 } 134 135 return 0; 136 } 137 138 static int axp813_battery_get_max_voltage(struct axp20x_batt_ps *axp20x_batt, 139 int *val) 140 { 141 int ret, reg; 142 143 ret = regmap_read(axp20x_batt->regmap, AXP20X_CHRG_CTRL1, ®); 144 if (ret) 145 return ret; 146 147 switch (reg & AXP20X_CHRG_CTRL1_TGT_VOLT) { 148 case AXP20X_CHRG_CTRL1_TGT_4_1V: 149 *val = 4100000; 150 break; 151 case AXP20X_CHRG_CTRL1_TGT_4_15V: 152 *val = 4150000; 153 break; 154 case AXP20X_CHRG_CTRL1_TGT_4_2V: 155 *val = 4200000; 156 break; 157 case AXP813_CHRG_CTRL1_TGT_4_35V: 158 *val = 4350000; 159 break; 160 default: 161 return -EINVAL; 162 } 163 164 return 0; 165 } 166 167 static int axp20x_get_constant_charge_current(struct axp20x_batt_ps *axp, 168 int *val) 169 { 170 int ret; 171 172 ret = regmap_read(axp->regmap, AXP20X_CHRG_CTRL1, val); 173 if (ret) 174 return ret; 175 176 *val &= AXP20X_CHRG_CTRL1_TGT_CURR; 177 178 *val = *val * axp->data->ccc_scale + axp->data->ccc_offset; 179 180 return 0; 181 } 182 183 static int axp20x_battery_get_prop(struct power_supply *psy, 184 enum power_supply_property psp, 185 union power_supply_propval *val) 186 { 187 struct axp20x_batt_ps *axp20x_batt = power_supply_get_drvdata(psy); 188 int ret = 0, reg, val1; 189 190 switch (psp) { 191 case POWER_SUPPLY_PROP_PRESENT: 192 case POWER_SUPPLY_PROP_ONLINE: 193 ret = regmap_read(axp20x_batt->regmap, AXP20X_PWR_OP_MODE, 194 ®); 195 if (ret) 196 return ret; 197 198 val->intval = !!(reg & AXP20X_PWR_OP_BATT_PRESENT); 199 break; 200 201 case POWER_SUPPLY_PROP_STATUS: 202 ret = regmap_read(axp20x_batt->regmap, AXP20X_PWR_INPUT_STATUS, 203 ®); 204 if (ret) 205 return ret; 206 207 if (reg & AXP20X_PWR_STATUS_BAT_CHARGING) { 208 val->intval = POWER_SUPPLY_STATUS_CHARGING; 209 return 0; 210 } 211 212 ret = iio_read_channel_processed(axp20x_batt->batt_dischrg_i, 213 &val1); 214 if (ret) 215 return ret; 216 217 if (val1) { 218 val->intval = POWER_SUPPLY_STATUS_DISCHARGING; 219 return 0; 220 } 221 222 ret = regmap_read(axp20x_batt->regmap, AXP20X_FG_RES, &val1); 223 if (ret) 224 return ret; 225 226 /* 227 * Fuel Gauge data takes 7 bits but the stored value seems to be 228 * directly the raw percentage without any scaling to 7 bits. 229 */ 230 if ((val1 & AXP209_FG_PERCENT) == 100) 231 val->intval = POWER_SUPPLY_STATUS_FULL; 232 else 233 val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING; 234 break; 235 236 case POWER_SUPPLY_PROP_HEALTH: 237 ret = regmap_read(axp20x_batt->regmap, AXP20X_PWR_OP_MODE, 238 &val1); 239 if (ret) 240 return ret; 241 242 if (val1 & AXP20X_PWR_OP_BATT_ACTIVATED) { 243 val->intval = POWER_SUPPLY_HEALTH_DEAD; 244 return 0; 245 } 246 247 val->intval = POWER_SUPPLY_HEALTH_GOOD; 248 break; 249 250 case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT: 251 ret = axp20x_get_constant_charge_current(axp20x_batt, 252 &val->intval); 253 if (ret) 254 return ret; 255 break; 256 257 case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX: 258 val->intval = axp20x_batt->max_ccc; 259 break; 260 261 case POWER_SUPPLY_PROP_CURRENT_NOW: 262 ret = regmap_read(axp20x_batt->regmap, AXP20X_PWR_INPUT_STATUS, 263 ®); 264 if (ret) 265 return ret; 266 267 if (reg & AXP20X_PWR_STATUS_BAT_CHARGING) { 268 ret = iio_read_channel_processed(axp20x_batt->batt_chrg_i, &val->intval); 269 } else { 270 ret = iio_read_channel_processed(axp20x_batt->batt_dischrg_i, &val1); 271 val->intval = -val1; 272 } 273 if (ret) 274 return ret; 275 276 /* IIO framework gives mA but Power Supply framework gives uA */ 277 val->intval *= 1000; 278 break; 279 280 case POWER_SUPPLY_PROP_CAPACITY: 281 /* When no battery is present, return capacity is 100% */ 282 ret = regmap_read(axp20x_batt->regmap, AXP20X_PWR_OP_MODE, 283 ®); 284 if (ret) 285 return ret; 286 287 if (!(reg & AXP20X_PWR_OP_BATT_PRESENT)) { 288 val->intval = 100; 289 return 0; 290 } 291 292 ret = regmap_read(axp20x_batt->regmap, AXP20X_FG_RES, ®); 293 if (ret) 294 return ret; 295 296 if (axp20x_batt->data->has_fg_valid && !(reg & AXP22X_FG_VALID)) 297 return -EINVAL; 298 299 /* 300 * Fuel Gauge data takes 7 bits but the stored value seems to be 301 * directly the raw percentage without any scaling to 7 bits. 302 */ 303 val->intval = reg & AXP209_FG_PERCENT; 304 break; 305 306 case POWER_SUPPLY_PROP_VOLTAGE_MAX: 307 return axp20x_batt->data->get_max_voltage(axp20x_batt, 308 &val->intval); 309 310 case POWER_SUPPLY_PROP_VOLTAGE_MIN: 311 ret = regmap_read(axp20x_batt->regmap, AXP20X_V_OFF, ®); 312 if (ret) 313 return ret; 314 315 val->intval = 2600000 + 100000 * (reg & AXP20X_V_OFF_MASK); 316 break; 317 318 case POWER_SUPPLY_PROP_VOLTAGE_NOW: 319 ret = iio_read_channel_processed(axp20x_batt->batt_v, 320 &val->intval); 321 if (ret) 322 return ret; 323 324 /* IIO framework gives mV but Power Supply framework gives uV */ 325 val->intval *= 1000; 326 break; 327 328 default: 329 return -EINVAL; 330 } 331 332 return 0; 333 } 334 335 static int axp22x_battery_set_max_voltage(struct axp20x_batt_ps *axp20x_batt, 336 int val) 337 { 338 switch (val) { 339 case 4100000: 340 val = AXP20X_CHRG_CTRL1_TGT_4_1V; 341 break; 342 343 case 4200000: 344 val = AXP20X_CHRG_CTRL1_TGT_4_2V; 345 break; 346 347 default: 348 /* 349 * AXP20x max voltage can be set to 4.36V and AXP22X max voltage 350 * can be set to 4.22V and 4.24V, but these voltages are too 351 * high for Lithium based batteries (AXP PMICs are supposed to 352 * be used with these kinds of battery). 353 */ 354 return -EINVAL; 355 } 356 357 return regmap_update_bits(axp20x_batt->regmap, AXP20X_CHRG_CTRL1, 358 AXP20X_CHRG_CTRL1_TGT_VOLT, val); 359 } 360 361 static int axp20x_battery_set_max_voltage(struct axp20x_batt_ps *axp20x_batt, 362 int val) 363 { 364 switch (val) { 365 case 4100000: 366 val = AXP20X_CHRG_CTRL1_TGT_4_1V; 367 break; 368 369 case 4150000: 370 val = AXP20X_CHRG_CTRL1_TGT_4_15V; 371 break; 372 373 case 4200000: 374 val = AXP20X_CHRG_CTRL1_TGT_4_2V; 375 break; 376 377 default: 378 /* 379 * AXP20x max voltage can be set to 4.36V and AXP22X max voltage 380 * can be set to 4.22V and 4.24V, but these voltages are too 381 * high for Lithium based batteries (AXP PMICs are supposed to 382 * be used with these kinds of battery). 383 */ 384 return -EINVAL; 385 } 386 387 return regmap_update_bits(axp20x_batt->regmap, AXP20X_CHRG_CTRL1, 388 AXP20X_CHRG_CTRL1_TGT_VOLT, val); 389 } 390 391 static int axp20x_set_constant_charge_current(struct axp20x_batt_ps *axp_batt, 392 int charge_current) 393 { 394 if (charge_current > axp_batt->max_ccc) 395 return -EINVAL; 396 397 charge_current = (charge_current - axp_batt->data->ccc_offset) / 398 axp_batt->data->ccc_scale; 399 400 if (charge_current > AXP20X_CHRG_CTRL1_TGT_CURR || charge_current < 0) 401 return -EINVAL; 402 403 return regmap_update_bits(axp_batt->regmap, AXP20X_CHRG_CTRL1, 404 AXP20X_CHRG_CTRL1_TGT_CURR, charge_current); 405 } 406 407 static int axp20x_set_max_constant_charge_current(struct axp20x_batt_ps *axp, 408 int charge_current) 409 { 410 bool lower_max = false; 411 412 charge_current = (charge_current - axp->data->ccc_offset) / 413 axp->data->ccc_scale; 414 415 if (charge_current > AXP20X_CHRG_CTRL1_TGT_CURR || charge_current < 0) 416 return -EINVAL; 417 418 charge_current = charge_current * axp->data->ccc_scale + 419 axp->data->ccc_offset; 420 421 if (charge_current > axp->max_ccc) 422 dev_warn(axp->dev, 423 "Setting max constant charge current higher than previously defined. Note that increasing the constant charge current may damage your battery.\n"); 424 else 425 lower_max = true; 426 427 axp->max_ccc = charge_current; 428 429 if (lower_max) { 430 int current_cc; 431 432 axp20x_get_constant_charge_current(axp, ¤t_cc); 433 if (current_cc > charge_current) 434 axp20x_set_constant_charge_current(axp, charge_current); 435 } 436 437 return 0; 438 } 439 static int axp20x_set_voltage_min_design(struct axp20x_batt_ps *axp_batt, 440 int min_voltage) 441 { 442 int val1 = (min_voltage - 2600000) / 100000; 443 444 if (val1 < 0 || val1 > AXP20X_V_OFF_MASK) 445 return -EINVAL; 446 447 return regmap_update_bits(axp_batt->regmap, AXP20X_V_OFF, 448 AXP20X_V_OFF_MASK, val1); 449 } 450 451 static int axp20x_battery_set_prop(struct power_supply *psy, 452 enum power_supply_property psp, 453 const union power_supply_propval *val) 454 { 455 struct axp20x_batt_ps *axp20x_batt = power_supply_get_drvdata(psy); 456 457 switch (psp) { 458 case POWER_SUPPLY_PROP_VOLTAGE_MIN: 459 return axp20x_set_voltage_min_design(axp20x_batt, val->intval); 460 461 case POWER_SUPPLY_PROP_VOLTAGE_MAX: 462 return axp20x_batt->data->set_max_voltage(axp20x_batt, val->intval); 463 464 case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT: 465 return axp20x_set_constant_charge_current(axp20x_batt, 466 val->intval); 467 case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX: 468 return axp20x_set_max_constant_charge_current(axp20x_batt, 469 val->intval); 470 case POWER_SUPPLY_PROP_STATUS: 471 switch (val->intval) { 472 case POWER_SUPPLY_STATUS_CHARGING: 473 return regmap_update_bits(axp20x_batt->regmap, AXP20X_CHRG_CTRL1, 474 AXP20X_CHRG_CTRL1_ENABLE, AXP20X_CHRG_CTRL1_ENABLE); 475 476 case POWER_SUPPLY_STATUS_DISCHARGING: 477 case POWER_SUPPLY_STATUS_NOT_CHARGING: 478 return regmap_update_bits(axp20x_batt->regmap, AXP20X_CHRG_CTRL1, 479 AXP20X_CHRG_CTRL1_ENABLE, 0); 480 } 481 fallthrough; 482 default: 483 return -EINVAL; 484 } 485 } 486 487 static enum power_supply_property axp20x_battery_props[] = { 488 POWER_SUPPLY_PROP_PRESENT, 489 POWER_SUPPLY_PROP_ONLINE, 490 POWER_SUPPLY_PROP_STATUS, 491 POWER_SUPPLY_PROP_VOLTAGE_NOW, 492 POWER_SUPPLY_PROP_CURRENT_NOW, 493 POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT, 494 POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX, 495 POWER_SUPPLY_PROP_HEALTH, 496 POWER_SUPPLY_PROP_VOLTAGE_MAX, 497 POWER_SUPPLY_PROP_VOLTAGE_MIN, 498 POWER_SUPPLY_PROP_CAPACITY, 499 }; 500 501 static int axp20x_battery_prop_writeable(struct power_supply *psy, 502 enum power_supply_property psp) 503 { 504 return psp == POWER_SUPPLY_PROP_STATUS || 505 psp == POWER_SUPPLY_PROP_VOLTAGE_MIN || 506 psp == POWER_SUPPLY_PROP_VOLTAGE_MAX || 507 psp == POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT || 508 psp == POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX; 509 } 510 511 static const struct power_supply_desc axp20x_batt_ps_desc = { 512 .name = "axp20x-battery", 513 .type = POWER_SUPPLY_TYPE_BATTERY, 514 .properties = axp20x_battery_props, 515 .num_properties = ARRAY_SIZE(axp20x_battery_props), 516 .property_is_writeable = axp20x_battery_prop_writeable, 517 .get_property = axp20x_battery_get_prop, 518 .set_property = axp20x_battery_set_prop, 519 }; 520 521 static const struct axp_data axp209_data = { 522 .ccc_scale = 100000, 523 .ccc_offset = 300000, 524 .get_max_voltage = axp20x_battery_get_max_voltage, 525 .set_max_voltage = axp20x_battery_set_max_voltage, 526 }; 527 528 static const struct axp_data axp221_data = { 529 .ccc_scale = 150000, 530 .ccc_offset = 300000, 531 .has_fg_valid = true, 532 .get_max_voltage = axp22x_battery_get_max_voltage, 533 .set_max_voltage = axp22x_battery_set_max_voltage, 534 }; 535 536 static const struct axp_data axp813_data = { 537 .ccc_scale = 200000, 538 .ccc_offset = 200000, 539 .has_fg_valid = true, 540 .get_max_voltage = axp813_battery_get_max_voltage, 541 .set_max_voltage = axp20x_battery_set_max_voltage, 542 }; 543 544 static const struct of_device_id axp20x_battery_ps_id[] = { 545 { 546 .compatible = "x-powers,axp209-battery-power-supply", 547 .data = (void *)&axp209_data, 548 }, { 549 .compatible = "x-powers,axp221-battery-power-supply", 550 .data = (void *)&axp221_data, 551 }, { 552 .compatible = "x-powers,axp813-battery-power-supply", 553 .data = (void *)&axp813_data, 554 }, { /* sentinel */ }, 555 }; 556 MODULE_DEVICE_TABLE(of, axp20x_battery_ps_id); 557 558 static int axp20x_power_probe(struct platform_device *pdev) 559 { 560 struct axp20x_batt_ps *axp20x_batt; 561 struct power_supply_config psy_cfg = {}; 562 struct power_supply_battery_info *info; 563 struct device *dev = &pdev->dev; 564 565 if (!of_device_is_available(pdev->dev.of_node)) 566 return -ENODEV; 567 568 axp20x_batt = devm_kzalloc(&pdev->dev, sizeof(*axp20x_batt), 569 GFP_KERNEL); 570 if (!axp20x_batt) 571 return -ENOMEM; 572 573 axp20x_batt->dev = &pdev->dev; 574 575 axp20x_batt->batt_v = devm_iio_channel_get(&pdev->dev, "batt_v"); 576 if (IS_ERR(axp20x_batt->batt_v)) { 577 if (PTR_ERR(axp20x_batt->batt_v) == -ENODEV) 578 return -EPROBE_DEFER; 579 return PTR_ERR(axp20x_batt->batt_v); 580 } 581 582 axp20x_batt->batt_chrg_i = devm_iio_channel_get(&pdev->dev, 583 "batt_chrg_i"); 584 if (IS_ERR(axp20x_batt->batt_chrg_i)) { 585 if (PTR_ERR(axp20x_batt->batt_chrg_i) == -ENODEV) 586 return -EPROBE_DEFER; 587 return PTR_ERR(axp20x_batt->batt_chrg_i); 588 } 589 590 axp20x_batt->batt_dischrg_i = devm_iio_channel_get(&pdev->dev, 591 "batt_dischrg_i"); 592 if (IS_ERR(axp20x_batt->batt_dischrg_i)) { 593 if (PTR_ERR(axp20x_batt->batt_dischrg_i) == -ENODEV) 594 return -EPROBE_DEFER; 595 return PTR_ERR(axp20x_batt->batt_dischrg_i); 596 } 597 598 axp20x_batt->regmap = dev_get_regmap(pdev->dev.parent, NULL); 599 platform_set_drvdata(pdev, axp20x_batt); 600 601 psy_cfg.drv_data = axp20x_batt; 602 psy_cfg.of_node = pdev->dev.of_node; 603 604 axp20x_batt->data = (struct axp_data *)of_device_get_match_data(dev); 605 606 axp20x_batt->batt = devm_power_supply_register(&pdev->dev, 607 &axp20x_batt_ps_desc, 608 &psy_cfg); 609 if (IS_ERR(axp20x_batt->batt)) { 610 dev_err(&pdev->dev, "failed to register power supply: %ld\n", 611 PTR_ERR(axp20x_batt->batt)); 612 return PTR_ERR(axp20x_batt->batt); 613 } 614 615 if (!power_supply_get_battery_info(axp20x_batt->batt, &info)) { 616 int vmin = info->voltage_min_design_uv; 617 int ccc = info->constant_charge_current_max_ua; 618 619 if (vmin > 0 && axp20x_set_voltage_min_design(axp20x_batt, 620 vmin)) 621 dev_err(&pdev->dev, 622 "couldn't set voltage_min_design\n"); 623 624 /* Set max to unverified value to be able to set CCC */ 625 axp20x_batt->max_ccc = ccc; 626 627 if (ccc <= 0 || axp20x_set_constant_charge_current(axp20x_batt, 628 ccc)) { 629 dev_err(&pdev->dev, 630 "couldn't set constant charge current from DT: fallback to minimum value\n"); 631 ccc = 300000; 632 axp20x_batt->max_ccc = ccc; 633 axp20x_set_constant_charge_current(axp20x_batt, ccc); 634 } 635 } 636 637 /* 638 * Update max CCC to a valid value if battery info is present or set it 639 * to current register value by default. 640 */ 641 axp20x_get_constant_charge_current(axp20x_batt, 642 &axp20x_batt->max_ccc); 643 644 return 0; 645 } 646 647 static struct platform_driver axp20x_batt_driver = { 648 .probe = axp20x_power_probe, 649 .driver = { 650 .name = "axp20x-battery-power-supply", 651 .of_match_table = axp20x_battery_ps_id, 652 }, 653 }; 654 655 module_platform_driver(axp20x_batt_driver); 656 657 MODULE_DESCRIPTION("Battery power supply driver for AXP20X and AXP22X PMICs"); 658 MODULE_AUTHOR("Quentin Schulz <quentin.schulz@free-electrons.com>"); 659 MODULE_LICENSE("GPL"); 660