linux/drivers/power/supply/axp20x_battery.c
<<
>>
Prefs
   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_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
  58struct axp20x_batt_ps;
  59
  60struct 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
  68struct 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
  80static 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, &reg);
  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
 109static 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, &reg);
 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
 138static 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, &reg);
 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
 167static 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
 183static 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        struct iio_channel *chan;
 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                                  &reg);
 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                                  &reg);
 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                                  &reg);
 265                if (ret)
 266                        return ret;
 267
 268                if (reg & AXP20X_PWR_STATUS_BAT_CHARGING)
 269                        chan = axp20x_batt->batt_chrg_i;
 270                else
 271                        chan = axp20x_batt->batt_dischrg_i;
 272
 273                ret = iio_read_channel_processed(chan, &val->intval);
 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                                  &reg);
 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, &reg);
 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, &reg);
 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, &current_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
 472        default:
 473                return -EINVAL;
 474        }
 475}
 476
 477static enum power_supply_property axp20x_battery_props[] = {
 478        POWER_SUPPLY_PROP_PRESENT,
 479        POWER_SUPPLY_PROP_ONLINE,
 480        POWER_SUPPLY_PROP_STATUS,
 481        POWER_SUPPLY_PROP_VOLTAGE_NOW,
 482        POWER_SUPPLY_PROP_CURRENT_NOW,
 483        POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT,
 484        POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX,
 485        POWER_SUPPLY_PROP_HEALTH,
 486        POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN,
 487        POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,
 488        POWER_SUPPLY_PROP_CAPACITY,
 489};
 490
 491static int axp20x_battery_prop_writeable(struct power_supply *psy,
 492                                         enum power_supply_property psp)
 493{
 494        return psp == POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN ||
 495               psp == POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN ||
 496               psp == POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT ||
 497               psp == POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX;
 498}
 499
 500static const struct power_supply_desc axp20x_batt_ps_desc = {
 501        .name = "axp20x-battery",
 502        .type = POWER_SUPPLY_TYPE_BATTERY,
 503        .properties = axp20x_battery_props,
 504        .num_properties = ARRAY_SIZE(axp20x_battery_props),
 505        .property_is_writeable = axp20x_battery_prop_writeable,
 506        .get_property = axp20x_battery_get_prop,
 507        .set_property = axp20x_battery_set_prop,
 508};
 509
 510static const struct axp_data axp209_data = {
 511        .ccc_scale = 100000,
 512        .ccc_offset = 300000,
 513        .get_max_voltage = axp20x_battery_get_max_voltage,
 514        .set_max_voltage = axp20x_battery_set_max_voltage,
 515};
 516
 517static const struct axp_data axp221_data = {
 518        .ccc_scale = 150000,
 519        .ccc_offset = 300000,
 520        .has_fg_valid = true,
 521        .get_max_voltage = axp22x_battery_get_max_voltage,
 522        .set_max_voltage = axp22x_battery_set_max_voltage,
 523};
 524
 525static const struct axp_data axp813_data = {
 526        .ccc_scale = 200000,
 527        .ccc_offset = 200000,
 528        .has_fg_valid = true,
 529        .get_max_voltage = axp813_battery_get_max_voltage,
 530        .set_max_voltage = axp20x_battery_set_max_voltage,
 531};
 532
 533static const struct of_device_id axp20x_battery_ps_id[] = {
 534        {
 535                .compatible = "x-powers,axp209-battery-power-supply",
 536                .data = (void *)&axp209_data,
 537        }, {
 538                .compatible = "x-powers,axp221-battery-power-supply",
 539                .data = (void *)&axp221_data,
 540        }, {
 541                .compatible = "x-powers,axp813-battery-power-supply",
 542                .data = (void *)&axp813_data,
 543        }, { /* sentinel */ },
 544};
 545MODULE_DEVICE_TABLE(of, axp20x_battery_ps_id);
 546
 547static int axp20x_power_probe(struct platform_device *pdev)
 548{
 549        struct axp20x_batt_ps *axp20x_batt;
 550        struct power_supply_config psy_cfg = {};
 551        struct power_supply_battery_info info;
 552        struct device *dev = &pdev->dev;
 553
 554        if (!of_device_is_available(pdev->dev.of_node))
 555                return -ENODEV;
 556
 557        axp20x_batt = devm_kzalloc(&pdev->dev, sizeof(*axp20x_batt),
 558                                   GFP_KERNEL);
 559        if (!axp20x_batt)
 560                return -ENOMEM;
 561
 562        axp20x_batt->dev = &pdev->dev;
 563
 564        axp20x_batt->batt_v = devm_iio_channel_get(&pdev->dev, "batt_v");
 565        if (IS_ERR(axp20x_batt->batt_v)) {
 566                if (PTR_ERR(axp20x_batt->batt_v) == -ENODEV)
 567                        return -EPROBE_DEFER;
 568                return PTR_ERR(axp20x_batt->batt_v);
 569        }
 570
 571        axp20x_batt->batt_chrg_i = devm_iio_channel_get(&pdev->dev,
 572                                                        "batt_chrg_i");
 573        if (IS_ERR(axp20x_batt->batt_chrg_i)) {
 574                if (PTR_ERR(axp20x_batt->batt_chrg_i) == -ENODEV)
 575                        return -EPROBE_DEFER;
 576                return PTR_ERR(axp20x_batt->batt_chrg_i);
 577        }
 578
 579        axp20x_batt->batt_dischrg_i = devm_iio_channel_get(&pdev->dev,
 580                                                           "batt_dischrg_i");
 581        if (IS_ERR(axp20x_batt->batt_dischrg_i)) {
 582                if (PTR_ERR(axp20x_batt->batt_dischrg_i) == -ENODEV)
 583                        return -EPROBE_DEFER;
 584                return PTR_ERR(axp20x_batt->batt_dischrg_i);
 585        }
 586
 587        axp20x_batt->regmap = dev_get_regmap(pdev->dev.parent, NULL);
 588        platform_set_drvdata(pdev, axp20x_batt);
 589
 590        psy_cfg.drv_data = axp20x_batt;
 591        psy_cfg.of_node = pdev->dev.of_node;
 592
 593        axp20x_batt->data = (struct axp_data *)of_device_get_match_data(dev);
 594
 595        axp20x_batt->batt = devm_power_supply_register(&pdev->dev,
 596                                                       &axp20x_batt_ps_desc,
 597                                                       &psy_cfg);
 598        if (IS_ERR(axp20x_batt->batt)) {
 599                dev_err(&pdev->dev, "failed to register power supply: %ld\n",
 600                        PTR_ERR(axp20x_batt->batt));
 601                return PTR_ERR(axp20x_batt->batt);
 602        }
 603
 604        if (!power_supply_get_battery_info(axp20x_batt->batt, &info)) {
 605                int vmin = info.voltage_min_design_uv;
 606                int ccc = info.constant_charge_current_max_ua;
 607
 608                if (vmin > 0 && axp20x_set_voltage_min_design(axp20x_batt,
 609                                                              vmin))
 610                        dev_err(&pdev->dev,
 611                                "couldn't set voltage_min_design\n");
 612
 613                /* Set max to unverified value to be able to set CCC */
 614                axp20x_batt->max_ccc = ccc;
 615
 616                if (ccc <= 0 || axp20x_set_constant_charge_current(axp20x_batt,
 617                                                                   ccc)) {
 618                        dev_err(&pdev->dev,
 619                                "couldn't set constant charge current from DT: fallback to minimum value\n");
 620                        ccc = 300000;
 621                        axp20x_batt->max_ccc = ccc;
 622                        axp20x_set_constant_charge_current(axp20x_batt, ccc);
 623                }
 624        }
 625
 626        /*
 627         * Update max CCC to a valid value if battery info is present or set it
 628         * to current register value by default.
 629         */
 630        axp20x_get_constant_charge_current(axp20x_batt,
 631                                           &axp20x_batt->max_ccc);
 632
 633        return 0;
 634}
 635
 636static struct platform_driver axp20x_batt_driver = {
 637        .probe    = axp20x_power_probe,
 638        .driver   = {
 639                .name  = "axp20x-battery-power-supply",
 640                .of_match_table = axp20x_battery_ps_id,
 641        },
 642};
 643
 644module_platform_driver(axp20x_batt_driver);
 645
 646MODULE_DESCRIPTION("Battery power supply driver for AXP20X and AXP22X PMICs");
 647MODULE_AUTHOR("Quentin Schulz <quentin.schulz@free-electrons.com>");
 648MODULE_LICENSE("GPL");
 649