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