linux/drivers/power/supply/axp288_charger.c
<<
>>
Prefs
   1/*
   2 * axp288_charger.c - X-power AXP288 PMIC Charger driver
   3 *
   4 * Copyright (C) 2014 Intel Corporation
   5 * Author: Ramakrishna Pallala <ramakrishna.pallala@intel.com>
   6 *
   7 * This program is free software; you can redistribute it and/or modify
   8 * it under the terms of the GNU General Public License version 2 as
   9 * published by the Free Software Foundation.
  10 *
  11 * This program is distributed in the hope that it will be useful,
  12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14 * GNU General Public License for more details.
  15 */
  16
  17#include <linux/module.h>
  18#include <linux/device.h>
  19#include <linux/regmap.h>
  20#include <linux/workqueue.h>
  21#include <linux/delay.h>
  22#include <linux/platform_device.h>
  23#include <linux/usb/otg.h>
  24#include <linux/notifier.h>
  25#include <linux/power_supply.h>
  26#include <linux/property.h>
  27#include <linux/mfd/axp20x.h>
  28#include <linux/extcon.h>
  29
  30#define PS_STAT_VBUS_TRIGGER            (1 << 0)
  31#define PS_STAT_BAT_CHRG_DIR            (1 << 2)
  32#define PS_STAT_VBAT_ABOVE_VHOLD        (1 << 3)
  33#define PS_STAT_VBUS_VALID              (1 << 4)
  34#define PS_STAT_VBUS_PRESENT            (1 << 5)
  35
  36#define CHRG_STAT_BAT_SAFE_MODE         (1 << 3)
  37#define CHRG_STAT_BAT_VALID             (1 << 4)
  38#define CHRG_STAT_BAT_PRESENT           (1 << 5)
  39#define CHRG_STAT_CHARGING              (1 << 6)
  40#define CHRG_STAT_PMIC_OTP              (1 << 7)
  41
  42#define VBUS_ISPOUT_CUR_LIM_MASK        0x03
  43#define VBUS_ISPOUT_CUR_LIM_BIT_POS     0
  44#define VBUS_ISPOUT_CUR_LIM_900MA       0x0     /* 900mA */
  45#define VBUS_ISPOUT_CUR_LIM_1500MA      0x1     /* 1500mA */
  46#define VBUS_ISPOUT_CUR_LIM_2000MA      0x2     /* 2000mA */
  47#define VBUS_ISPOUT_CUR_NO_LIM          0x3     /* 2500mA */
  48#define VBUS_ISPOUT_VHOLD_SET_MASK      0x31
  49#define VBUS_ISPOUT_VHOLD_SET_BIT_POS   0x3
  50#define VBUS_ISPOUT_VHOLD_SET_OFFSET    4000    /* 4000mV */
  51#define VBUS_ISPOUT_VHOLD_SET_LSB_RES   100     /* 100mV */
  52#define VBUS_ISPOUT_VHOLD_SET_4300MV    0x3     /* 4300mV */
  53#define VBUS_ISPOUT_VBUS_PATH_DIS       (1 << 7)
  54
  55#define CHRG_CCCV_CC_MASK               0xf             /* 4 bits */
  56#define CHRG_CCCV_CC_BIT_POS            0
  57#define CHRG_CCCV_CC_OFFSET             200             /* 200mA */
  58#define CHRG_CCCV_CC_LSB_RES            200             /* 200mA */
  59#define CHRG_CCCV_ITERM_20P             (1 << 4)        /* 20% of CC */
  60#define CHRG_CCCV_CV_MASK               0x60            /* 2 bits */
  61#define CHRG_CCCV_CV_BIT_POS            5
  62#define CHRG_CCCV_CV_4100MV             0x0             /* 4.10V */
  63#define CHRG_CCCV_CV_4150MV             0x1             /* 4.15V */
  64#define CHRG_CCCV_CV_4200MV             0x2             /* 4.20V */
  65#define CHRG_CCCV_CV_4350MV             0x3             /* 4.35V */
  66#define CHRG_CCCV_CHG_EN                (1 << 7)
  67
  68#define CNTL2_CC_TIMEOUT_MASK           0x3     /* 2 bits */
  69#define CNTL2_CC_TIMEOUT_OFFSET         6       /* 6 Hrs */
  70#define CNTL2_CC_TIMEOUT_LSB_RES        2       /* 2 Hrs */
  71#define CNTL2_CC_TIMEOUT_12HRS          0x3     /* 12 Hrs */
  72#define CNTL2_CHGLED_TYPEB              (1 << 4)
  73#define CNTL2_CHG_OUT_TURNON            (1 << 5)
  74#define CNTL2_PC_TIMEOUT_MASK           0xC0
  75#define CNTL2_PC_TIMEOUT_OFFSET         40      /* 40 mins */
  76#define CNTL2_PC_TIMEOUT_LSB_RES        10      /* 10 mins */
  77#define CNTL2_PC_TIMEOUT_70MINS         0x3
  78
  79#define CHRG_ILIM_TEMP_LOOP_EN          (1 << 3)
  80#define CHRG_VBUS_ILIM_MASK             0xf0
  81#define CHRG_VBUS_ILIM_BIT_POS          4
  82#define CHRG_VBUS_ILIM_100MA            0x0     /* 100mA */
  83#define CHRG_VBUS_ILIM_500MA            0x1     /* 500mA */
  84#define CHRG_VBUS_ILIM_900MA            0x2     /* 900mA */
  85#define CHRG_VBUS_ILIM_1500MA           0x3     /* 1500mA */
  86#define CHRG_VBUS_ILIM_2000MA           0x4     /* 2000mA */
  87#define CHRG_VBUS_ILIM_2500MA           0x5     /* 2500mA */
  88#define CHRG_VBUS_ILIM_3000MA           0x6     /* 3000mA */
  89
  90#define CHRG_VLTFC_0C                   0xA5    /* 0 DegC */
  91#define CHRG_VHTFC_45C                  0x1F    /* 45 DegC */
  92
  93#define FG_CNTL_OCV_ADJ_EN              (1 << 3)
  94
  95#define CV_4100MV                       4100    /* 4100mV */
  96#define CV_4150MV                       4150    /* 4150mV */
  97#define CV_4200MV                       4200    /* 4200mV */
  98#define CV_4350MV                       4350    /* 4350mV */
  99
 100#define CC_200MA                        200     /*  200mA */
 101#define CC_600MA                        600     /*  600mA */
 102#define CC_800MA                        800     /*  800mA */
 103#define CC_1000MA                       1000    /* 1000mA */
 104#define CC_1600MA                       1600    /* 1600mA */
 105#define CC_2000MA                       2000    /* 2000mA */
 106
 107#define ILIM_100MA                      100     /* 100mA */
 108#define ILIM_500MA                      500     /* 500mA */
 109#define ILIM_900MA                      900     /* 900mA */
 110#define ILIM_1500MA                     1500    /* 1500mA */
 111#define ILIM_2000MA                     2000    /* 2000mA */
 112#define ILIM_2500MA                     2500    /* 2500mA */
 113#define ILIM_3000MA                     3000    /* 3000mA */
 114
 115#define AXP288_EXTCON_DEV_NAME          "axp288_extcon"
 116#define USB_HOST_EXTCON_DEV_NAME        "INT3496:00"
 117
 118static const unsigned int cable_ids[] =
 119        { EXTCON_CHG_USB_SDP, EXTCON_CHG_USB_CDP, EXTCON_CHG_USB_DCP };
 120
 121enum {
 122        VBUS_OV_IRQ = 0,
 123        CHARGE_DONE_IRQ,
 124        CHARGE_CHARGING_IRQ,
 125        BAT_SAFE_QUIT_IRQ,
 126        BAT_SAFE_ENTER_IRQ,
 127        QCBTU_IRQ,
 128        CBTU_IRQ,
 129        QCBTO_IRQ,
 130        CBTO_IRQ,
 131        CHRG_INTR_END,
 132};
 133
 134struct axp288_chrg_info {
 135        struct platform_device *pdev;
 136        struct regmap *regmap;
 137        struct regmap_irq_chip_data *regmap_irqc;
 138        int irq[CHRG_INTR_END];
 139        struct power_supply *psy_usb;
 140        struct mutex lock;
 141
 142        /* OTG/Host mode */
 143        struct {
 144                struct work_struct work;
 145                struct extcon_dev *cable;
 146                struct notifier_block id_nb;
 147                bool id_short;
 148        } otg;
 149
 150        /* SDP/CDP/DCP USB charging cable notifications */
 151        struct {
 152                struct extcon_dev *edev;
 153                bool connected;
 154                enum power_supply_type chg_type;
 155                struct notifier_block nb[ARRAY_SIZE(cable_ids)];
 156                struct work_struct work;
 157        } cable;
 158
 159        int inlmt;
 160        int cc;
 161        int cv;
 162        int max_cc;
 163        int max_cv;
 164        int is_charger_enabled;
 165};
 166
 167static inline int axp288_charger_set_cc(struct axp288_chrg_info *info, int cc)
 168{
 169        u8 reg_val;
 170        int ret;
 171
 172        if (cc < CHRG_CCCV_CC_OFFSET)
 173                cc = CHRG_CCCV_CC_OFFSET;
 174        else if (cc > info->max_cc)
 175                cc = info->max_cc;
 176
 177        reg_val = (cc - CHRG_CCCV_CC_OFFSET) / CHRG_CCCV_CC_LSB_RES;
 178        cc = (reg_val * CHRG_CCCV_CC_LSB_RES) + CHRG_CCCV_CC_OFFSET;
 179        reg_val = reg_val << CHRG_CCCV_CC_BIT_POS;
 180
 181        ret = regmap_update_bits(info->regmap,
 182                                AXP20X_CHRG_CTRL1,
 183                                CHRG_CCCV_CC_MASK, reg_val);
 184        if (ret >= 0)
 185                info->cc = cc;
 186
 187        return ret;
 188}
 189
 190static inline int axp288_charger_set_cv(struct axp288_chrg_info *info, int cv)
 191{
 192        u8 reg_val;
 193        int ret;
 194
 195        if (cv <= CV_4100MV) {
 196                reg_val = CHRG_CCCV_CV_4100MV;
 197                cv = CV_4100MV;
 198        } else if (cv <= CV_4150MV) {
 199                reg_val = CHRG_CCCV_CV_4150MV;
 200                cv = CV_4150MV;
 201        } else if (cv <= CV_4200MV) {
 202                reg_val = CHRG_CCCV_CV_4200MV;
 203                cv = CV_4200MV;
 204        } else {
 205                reg_val = CHRG_CCCV_CV_4350MV;
 206                cv = CV_4350MV;
 207        }
 208
 209        reg_val = reg_val << CHRG_CCCV_CV_BIT_POS;
 210
 211        ret = regmap_update_bits(info->regmap,
 212                                AXP20X_CHRG_CTRL1,
 213                                CHRG_CCCV_CV_MASK, reg_val);
 214
 215        if (ret >= 0)
 216                info->cv = cv;
 217
 218        return ret;
 219}
 220
 221static inline int axp288_charger_set_vbus_inlmt(struct axp288_chrg_info *info,
 222                                           int inlmt)
 223{
 224        int ret;
 225        unsigned int val;
 226        u8 reg_val;
 227
 228        /* Read in limit register */
 229        ret = regmap_read(info->regmap, AXP20X_CHRG_BAK_CTRL, &val);
 230        if (ret < 0)
 231                goto set_inlmt_fail;
 232
 233        if (inlmt <= ILIM_100MA) {
 234                reg_val = CHRG_VBUS_ILIM_100MA;
 235                inlmt = ILIM_100MA;
 236        } else if (inlmt <= ILIM_500MA) {
 237                reg_val = CHRG_VBUS_ILIM_500MA;
 238                inlmt = ILIM_500MA;
 239        } else if (inlmt <= ILIM_900MA) {
 240                reg_val = CHRG_VBUS_ILIM_900MA;
 241                inlmt = ILIM_900MA;
 242        } else if (inlmt <= ILIM_1500MA) {
 243                reg_val = CHRG_VBUS_ILIM_1500MA;
 244                inlmt = ILIM_1500MA;
 245        } else if (inlmt <= ILIM_2000MA) {
 246                reg_val = CHRG_VBUS_ILIM_2000MA;
 247                inlmt = ILIM_2000MA;
 248        } else if (inlmt <= ILIM_2500MA) {
 249                reg_val = CHRG_VBUS_ILIM_2500MA;
 250                inlmt = ILIM_2500MA;
 251        } else {
 252                reg_val = CHRG_VBUS_ILIM_3000MA;
 253                inlmt = ILIM_3000MA;
 254        }
 255
 256        reg_val = (val & ~CHRG_VBUS_ILIM_MASK)
 257                        | (reg_val << CHRG_VBUS_ILIM_BIT_POS);
 258        ret = regmap_write(info->regmap, AXP20X_CHRG_BAK_CTRL, reg_val);
 259        if (ret >= 0)
 260                info->inlmt = inlmt;
 261        else
 262                dev_err(&info->pdev->dev, "charger BAK control %d\n", ret);
 263
 264
 265set_inlmt_fail:
 266        return ret;
 267}
 268
 269static int axp288_charger_vbus_path_select(struct axp288_chrg_info *info,
 270                                                                bool enable)
 271{
 272        int ret;
 273
 274        if (enable)
 275                ret = regmap_update_bits(info->regmap, AXP20X_VBUS_IPSOUT_MGMT,
 276                                        VBUS_ISPOUT_VBUS_PATH_DIS, 0);
 277        else
 278                ret = regmap_update_bits(info->regmap, AXP20X_VBUS_IPSOUT_MGMT,
 279                        VBUS_ISPOUT_VBUS_PATH_DIS, VBUS_ISPOUT_VBUS_PATH_DIS);
 280
 281        if (ret < 0)
 282                dev_err(&info->pdev->dev, "axp288 vbus path select %d\n", ret);
 283
 284
 285        return ret;
 286}
 287
 288static int axp288_charger_enable_charger(struct axp288_chrg_info *info,
 289                                                                bool enable)
 290{
 291        int ret;
 292
 293        if ((int)enable == info->is_charger_enabled)
 294                return 0;
 295
 296        if (enable)
 297                ret = regmap_update_bits(info->regmap, AXP20X_CHRG_CTRL1,
 298                                CHRG_CCCV_CHG_EN, CHRG_CCCV_CHG_EN);
 299        else
 300                ret = regmap_update_bits(info->regmap, AXP20X_CHRG_CTRL1,
 301                                CHRG_CCCV_CHG_EN, 0);
 302        if (ret < 0)
 303                dev_err(&info->pdev->dev, "axp288 enable charger %d\n", ret);
 304        else
 305                info->is_charger_enabled = enable;
 306
 307        return ret;
 308}
 309
 310static int axp288_charger_is_present(struct axp288_chrg_info *info)
 311{
 312        int ret, present = 0;
 313        unsigned int val;
 314
 315        ret = regmap_read(info->regmap, AXP20X_PWR_INPUT_STATUS, &val);
 316        if (ret < 0)
 317                return ret;
 318
 319        if (val & PS_STAT_VBUS_PRESENT)
 320                present = 1;
 321        return present;
 322}
 323
 324static int axp288_charger_is_online(struct axp288_chrg_info *info)
 325{
 326        int ret, online = 0;
 327        unsigned int val;
 328
 329        ret = regmap_read(info->regmap, AXP20X_PWR_INPUT_STATUS, &val);
 330        if (ret < 0)
 331                return ret;
 332
 333        if (val & PS_STAT_VBUS_VALID)
 334                online = 1;
 335        return online;
 336}
 337
 338static int axp288_get_charger_health(struct axp288_chrg_info *info)
 339{
 340        int ret, pwr_stat, chrg_stat;
 341        int health = POWER_SUPPLY_HEALTH_UNKNOWN;
 342        unsigned int val;
 343
 344        ret = regmap_read(info->regmap, AXP20X_PWR_INPUT_STATUS, &val);
 345        if ((ret < 0) || !(val & PS_STAT_VBUS_PRESENT))
 346                goto health_read_fail;
 347        else
 348                pwr_stat = val;
 349
 350        ret = regmap_read(info->regmap, AXP20X_PWR_OP_MODE, &val);
 351        if (ret < 0)
 352                goto health_read_fail;
 353        else
 354                chrg_stat = val;
 355
 356        if (!(pwr_stat & PS_STAT_VBUS_VALID))
 357                health = POWER_SUPPLY_HEALTH_DEAD;
 358        else if (chrg_stat & CHRG_STAT_PMIC_OTP)
 359                health = POWER_SUPPLY_HEALTH_OVERHEAT;
 360        else if (chrg_stat & CHRG_STAT_BAT_SAFE_MODE)
 361                health = POWER_SUPPLY_HEALTH_SAFETY_TIMER_EXPIRE;
 362        else
 363                health = POWER_SUPPLY_HEALTH_GOOD;
 364
 365health_read_fail:
 366        return health;
 367}
 368
 369static int axp288_charger_usb_set_property(struct power_supply *psy,
 370                                    enum power_supply_property psp,
 371                                    const union power_supply_propval *val)
 372{
 373        struct axp288_chrg_info *info = power_supply_get_drvdata(psy);
 374        int ret = 0;
 375        int scaled_val;
 376
 377        mutex_lock(&info->lock);
 378
 379        switch (psp) {
 380        case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:
 381                scaled_val = min(val->intval, info->max_cc);
 382                scaled_val = DIV_ROUND_CLOSEST(scaled_val, 1000);
 383                ret = axp288_charger_set_cc(info, scaled_val);
 384                if (ret < 0)
 385                        dev_warn(&info->pdev->dev, "set charge current failed\n");
 386                break;
 387        case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
 388                scaled_val = min(val->intval, info->max_cv);
 389                scaled_val = DIV_ROUND_CLOSEST(scaled_val, 1000);
 390                ret = axp288_charger_set_cv(info, scaled_val);
 391                if (ret < 0)
 392                        dev_warn(&info->pdev->dev, "set charge voltage failed\n");
 393                break;
 394        default:
 395                ret = -EINVAL;
 396        }
 397
 398        mutex_unlock(&info->lock);
 399        return ret;
 400}
 401
 402static int axp288_charger_usb_get_property(struct power_supply *psy,
 403                                    enum power_supply_property psp,
 404                                    union power_supply_propval *val)
 405{
 406        struct axp288_chrg_info *info = power_supply_get_drvdata(psy);
 407        int ret = 0;
 408
 409        mutex_lock(&info->lock);
 410
 411        switch (psp) {
 412        case POWER_SUPPLY_PROP_PRESENT:
 413                /* Check for OTG case first */
 414                if (info->otg.id_short) {
 415                        val->intval = 0;
 416                        break;
 417                }
 418                ret = axp288_charger_is_present(info);
 419                if (ret < 0)
 420                        goto psy_get_prop_fail;
 421                val->intval = ret;
 422                break;
 423        case POWER_SUPPLY_PROP_ONLINE:
 424                /* Check for OTG case first */
 425                if (info->otg.id_short) {
 426                        val->intval = 0;
 427                        break;
 428                }
 429                ret = axp288_charger_is_online(info);
 430                if (ret < 0)
 431                        goto psy_get_prop_fail;
 432                val->intval = ret;
 433                break;
 434        case POWER_SUPPLY_PROP_HEALTH:
 435                val->intval = axp288_get_charger_health(info);
 436                break;
 437        case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:
 438                val->intval = info->cc * 1000;
 439                break;
 440        case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX:
 441                val->intval = info->max_cc * 1000;
 442                break;
 443        case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
 444                val->intval = info->cv * 1000;
 445                break;
 446        case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX:
 447                val->intval = info->max_cv * 1000;
 448                break;
 449        case POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT:
 450                val->intval = info->inlmt * 1000;
 451                break;
 452        default:
 453                ret = -EINVAL;
 454                goto psy_get_prop_fail;
 455        }
 456
 457psy_get_prop_fail:
 458        mutex_unlock(&info->lock);
 459        return ret;
 460}
 461
 462static int axp288_charger_property_is_writeable(struct power_supply *psy,
 463                enum power_supply_property psp)
 464{
 465        int ret;
 466
 467        switch (psp) {
 468        case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:
 469        case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
 470                ret = 1;
 471                break;
 472        default:
 473                ret = 0;
 474        }
 475
 476        return ret;
 477}
 478
 479static enum power_supply_property axp288_usb_props[] = {
 480        POWER_SUPPLY_PROP_PRESENT,
 481        POWER_SUPPLY_PROP_ONLINE,
 482        POWER_SUPPLY_PROP_TYPE,
 483        POWER_SUPPLY_PROP_HEALTH,
 484        POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT,
 485        POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX,
 486        POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE,
 487        POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX,
 488        POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT,
 489};
 490
 491static const struct power_supply_desc axp288_charger_desc = {
 492        .name                   = "axp288_charger",
 493        .type                   = POWER_SUPPLY_TYPE_USB,
 494        .properties             = axp288_usb_props,
 495        .num_properties         = ARRAY_SIZE(axp288_usb_props),
 496        .get_property           = axp288_charger_usb_get_property,
 497        .set_property           = axp288_charger_usb_set_property,
 498        .property_is_writeable  = axp288_charger_property_is_writeable,
 499};
 500
 501static irqreturn_t axp288_charger_irq_thread_handler(int irq, void *dev)
 502{
 503        struct axp288_chrg_info *info = dev;
 504        int i;
 505
 506        for (i = 0; i < CHRG_INTR_END; i++) {
 507                if (info->irq[i] == irq)
 508                        break;
 509        }
 510
 511        if (i >= CHRG_INTR_END) {
 512                dev_warn(&info->pdev->dev, "spurious interrupt!!\n");
 513                return IRQ_NONE;
 514        }
 515
 516        switch (i) {
 517        case VBUS_OV_IRQ:
 518                dev_dbg(&info->pdev->dev, "VBUS Over Voltage INTR\n");
 519                break;
 520        case CHARGE_DONE_IRQ:
 521                dev_dbg(&info->pdev->dev, "Charging Done INTR\n");
 522                break;
 523        case CHARGE_CHARGING_IRQ:
 524                dev_dbg(&info->pdev->dev, "Start Charging IRQ\n");
 525                break;
 526        case BAT_SAFE_QUIT_IRQ:
 527                dev_dbg(&info->pdev->dev,
 528                        "Quit Safe Mode(restart timer) Charging IRQ\n");
 529                break;
 530        case BAT_SAFE_ENTER_IRQ:
 531                dev_dbg(&info->pdev->dev,
 532                        "Enter Safe Mode(timer expire) Charging IRQ\n");
 533                break;
 534        case QCBTU_IRQ:
 535                dev_dbg(&info->pdev->dev,
 536                        "Quit Battery Under Temperature(CHRG) INTR\n");
 537                break;
 538        case CBTU_IRQ:
 539                dev_dbg(&info->pdev->dev,
 540                        "Hit Battery Under Temperature(CHRG) INTR\n");
 541                break;
 542        case QCBTO_IRQ:
 543                dev_dbg(&info->pdev->dev,
 544                        "Quit Battery Over Temperature(CHRG) INTR\n");
 545                break;
 546        case CBTO_IRQ:
 547                dev_dbg(&info->pdev->dev,
 548                        "Hit Battery Over Temperature(CHRG) INTR\n");
 549                break;
 550        default:
 551                dev_warn(&info->pdev->dev, "Spurious Interrupt!!!\n");
 552                goto out;
 553        }
 554
 555        power_supply_changed(info->psy_usb);
 556out:
 557        return IRQ_HANDLED;
 558}
 559
 560static void axp288_charger_extcon_evt_worker(struct work_struct *work)
 561{
 562        struct axp288_chrg_info *info =
 563            container_of(work, struct axp288_chrg_info, cable.work);
 564        int ret, current_limit;
 565        struct extcon_dev *edev = info->cable.edev;
 566        bool old_connected = info->cable.connected;
 567        enum power_supply_type old_chg_type = info->cable.chg_type;
 568
 569        /* Determine cable/charger type */
 570        if (extcon_get_state(edev, EXTCON_CHG_USB_SDP) > 0) {
 571                dev_dbg(&info->pdev->dev, "USB SDP charger  is connected");
 572                info->cable.connected = true;
 573                info->cable.chg_type = POWER_SUPPLY_TYPE_USB;
 574        } else if (extcon_get_state(edev, EXTCON_CHG_USB_CDP) > 0) {
 575                dev_dbg(&info->pdev->dev, "USB CDP charger is connected");
 576                info->cable.connected = true;
 577                info->cable.chg_type = POWER_SUPPLY_TYPE_USB_CDP;
 578        } else if (extcon_get_state(edev, EXTCON_CHG_USB_DCP) > 0) {
 579                dev_dbg(&info->pdev->dev, "USB DCP charger is connected");
 580                info->cable.connected = true;
 581                info->cable.chg_type = POWER_SUPPLY_TYPE_USB_DCP;
 582        } else {
 583                if (old_connected)
 584                        dev_dbg(&info->pdev->dev, "USB charger disconnected");
 585                info->cable.connected = false;
 586                info->cable.chg_type = POWER_SUPPLY_TYPE_USB;
 587        }
 588
 589        /* Cable status changed */
 590        if (old_connected == info->cable.connected &&
 591            old_chg_type == info->cable.chg_type)
 592                return;
 593
 594        mutex_lock(&info->lock);
 595
 596        if (info->cable.connected) {
 597                axp288_charger_enable_charger(info, false);
 598
 599                switch (info->cable.chg_type) {
 600                case POWER_SUPPLY_TYPE_USB:
 601                        current_limit = ILIM_500MA;
 602                        break;
 603                case POWER_SUPPLY_TYPE_USB_CDP:
 604                        current_limit = ILIM_1500MA;
 605                        break;
 606                case POWER_SUPPLY_TYPE_USB_DCP:
 607                        current_limit = ILIM_2000MA;
 608                        break;
 609                default:
 610                        /* Unknown */
 611                        current_limit = 0;
 612                        break;
 613                }
 614
 615                /* Set vbus current limit first, then enable charger */
 616                ret = axp288_charger_set_vbus_inlmt(info, current_limit);
 617                if (ret == 0)
 618                        axp288_charger_enable_charger(info, true);
 619                else
 620                        dev_err(&info->pdev->dev,
 621                                "error setting current limit (%d)", ret);
 622        } else {
 623                axp288_charger_enable_charger(info, false);
 624        }
 625
 626        mutex_unlock(&info->lock);
 627
 628        power_supply_changed(info->psy_usb);
 629}
 630
 631/*
 632 * We need 3 copies of this, because there is no way to find out for which
 633 * cable id we are being called from the passed in arguments; and we must
 634 * have a separate nb for each extcon_register_notifier call.
 635 */
 636static int axp288_charger_handle_cable0_evt(struct notifier_block *nb,
 637                                            unsigned long event, void *param)
 638{
 639        struct axp288_chrg_info *info =
 640                container_of(nb, struct axp288_chrg_info, cable.nb[0]);
 641        schedule_work(&info->cable.work);
 642        return NOTIFY_OK;
 643}
 644
 645static int axp288_charger_handle_cable1_evt(struct notifier_block *nb,
 646                                            unsigned long event, void *param)
 647{
 648        struct axp288_chrg_info *info =
 649                container_of(nb, struct axp288_chrg_info, cable.nb[1]);
 650        schedule_work(&info->cable.work);
 651        return NOTIFY_OK;
 652}
 653
 654static int axp288_charger_handle_cable2_evt(struct notifier_block *nb,
 655                                            unsigned long event, void *param)
 656{
 657        struct axp288_chrg_info *info =
 658                container_of(nb, struct axp288_chrg_info, cable.nb[2]);
 659        schedule_work(&info->cable.work);
 660        return NOTIFY_OK;
 661}
 662
 663static void axp288_charger_otg_evt_worker(struct work_struct *work)
 664{
 665        struct axp288_chrg_info *info =
 666            container_of(work, struct axp288_chrg_info, otg.work);
 667        struct extcon_dev *edev = info->otg.cable;
 668        int ret, usb_host = extcon_get_state(edev, EXTCON_USB_HOST);
 669
 670        dev_dbg(&info->pdev->dev, "external connector USB-Host is %s\n",
 671                                usb_host ? "attached" : "detached");
 672
 673        /*
 674         * Set usb_id_short flag to avoid running charger detection logic
 675         * in case usb host.
 676         */
 677        info->otg.id_short = usb_host;
 678
 679        /* Disable VBUS path before enabling the 5V boost */
 680        ret = axp288_charger_vbus_path_select(info, !info->otg.id_short);
 681        if (ret < 0)
 682                dev_warn(&info->pdev->dev, "vbus path disable failed\n");
 683}
 684
 685static int axp288_charger_handle_otg_evt(struct notifier_block *nb,
 686                                   unsigned long event, void *param)
 687{
 688        struct axp288_chrg_info *info =
 689            container_of(nb, struct axp288_chrg_info, otg.id_nb);
 690
 691        schedule_work(&info->otg.work);
 692
 693        return NOTIFY_OK;
 694}
 695
 696static int charger_init_hw_regs(struct axp288_chrg_info *info)
 697{
 698        int ret, cc, cv;
 699        unsigned int val;
 700
 701        /* Program temperature thresholds */
 702        ret = regmap_write(info->regmap, AXP20X_V_LTF_CHRG, CHRG_VLTFC_0C);
 703        if (ret < 0) {
 704                dev_err(&info->pdev->dev, "register(%x) write error(%d)\n",
 705                                                        AXP20X_V_LTF_CHRG, ret);
 706                return ret;
 707        }
 708
 709        ret = regmap_write(info->regmap, AXP20X_V_HTF_CHRG, CHRG_VHTFC_45C);
 710        if (ret < 0) {
 711                dev_err(&info->pdev->dev, "register(%x) write error(%d)\n",
 712                                                        AXP20X_V_HTF_CHRG, ret);
 713                return ret;
 714        }
 715
 716        /* Do not turn-off charger o/p after charge cycle ends */
 717        ret = regmap_update_bits(info->regmap,
 718                                AXP20X_CHRG_CTRL2,
 719                                CNTL2_CHG_OUT_TURNON, CNTL2_CHG_OUT_TURNON);
 720        if (ret < 0) {
 721                dev_err(&info->pdev->dev, "register(%x) write error(%d)\n",
 722                                                AXP20X_CHRG_CTRL2, ret);
 723                return ret;
 724        }
 725
 726        /* Setup ending condition for charging to be 10% of I(chrg) */
 727        ret = regmap_update_bits(info->regmap,
 728                                AXP20X_CHRG_CTRL1,
 729                                CHRG_CCCV_ITERM_20P, 0);
 730        if (ret < 0) {
 731                dev_err(&info->pdev->dev, "register(%x) write error(%d)\n",
 732                                                AXP20X_CHRG_CTRL1, ret);
 733                return ret;
 734        }
 735
 736        /* Disable OCV-SOC curve calibration */
 737        ret = regmap_update_bits(info->regmap,
 738                                AXP20X_CC_CTRL,
 739                                FG_CNTL_OCV_ADJ_EN, 0);
 740        if (ret < 0) {
 741                dev_err(&info->pdev->dev, "register(%x) write error(%d)\n",
 742                                                AXP20X_CC_CTRL, ret);
 743                return ret;
 744        }
 745
 746        /* Read current charge voltage and current limit */
 747        ret = regmap_read(info->regmap, AXP20X_CHRG_CTRL1, &val);
 748        if (ret < 0) {
 749                dev_err(&info->pdev->dev, "register(%x) read error(%d)\n",
 750                        AXP20X_CHRG_CTRL1, ret);
 751                return ret;
 752        }
 753
 754        /* Determine charge voltage */
 755        cv = (val & CHRG_CCCV_CV_MASK) >> CHRG_CCCV_CV_BIT_POS;
 756        switch (cv) {
 757        case CHRG_CCCV_CV_4100MV:
 758                info->cv = CV_4100MV;
 759                break;
 760        case CHRG_CCCV_CV_4150MV:
 761                info->cv = CV_4150MV;
 762                break;
 763        case CHRG_CCCV_CV_4200MV:
 764                info->cv = CV_4200MV;
 765                break;
 766        case CHRG_CCCV_CV_4350MV:
 767                info->cv = CV_4350MV;
 768                break;
 769        }
 770
 771        /* Determine charge current limit */
 772        cc = (ret & CHRG_CCCV_CC_MASK) >> CHRG_CCCV_CC_BIT_POS;
 773        cc = (cc * CHRG_CCCV_CC_LSB_RES) + CHRG_CCCV_CC_OFFSET;
 774        info->cc = cc;
 775
 776        /*
 777         * Do not allow the user to configure higher settings then those
 778         * set by the firmware
 779         */
 780        info->max_cv = info->cv;
 781        info->max_cc = info->cc;
 782
 783        return 0;
 784}
 785
 786static int axp288_charger_probe(struct platform_device *pdev)
 787{
 788        int ret, i, pirq;
 789        struct axp288_chrg_info *info;
 790        struct device *dev = &pdev->dev;
 791        struct axp20x_dev *axp20x = dev_get_drvdata(pdev->dev.parent);
 792        struct power_supply_config charger_cfg = {};
 793        info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
 794        if (!info)
 795                return -ENOMEM;
 796
 797        info->pdev = pdev;
 798        info->regmap = axp20x->regmap;
 799        info->regmap_irqc = axp20x->regmap_irqc;
 800        info->cable.chg_type = -1;
 801        info->is_charger_enabled = -1;
 802
 803        info->cable.edev = extcon_get_extcon_dev(AXP288_EXTCON_DEV_NAME);
 804        if (info->cable.edev == NULL) {
 805                dev_dbg(&pdev->dev, "%s is not ready, probe deferred\n",
 806                        AXP288_EXTCON_DEV_NAME);
 807                return -EPROBE_DEFER;
 808        }
 809
 810        info->otg.cable = extcon_get_extcon_dev(USB_HOST_EXTCON_DEV_NAME);
 811        if (info->otg.cable == NULL) {
 812                dev_dbg(dev, "EXTCON_USB_HOST is not ready, probe deferred\n");
 813                return -EPROBE_DEFER;
 814        }
 815
 816        platform_set_drvdata(pdev, info);
 817        mutex_init(&info->lock);
 818
 819        ret = charger_init_hw_regs(info);
 820        if (ret)
 821                return ret;
 822
 823        /* Register with power supply class */
 824        charger_cfg.drv_data = info;
 825        info->psy_usb = devm_power_supply_register(dev, &axp288_charger_desc,
 826                                                   &charger_cfg);
 827        if (IS_ERR(info->psy_usb)) {
 828                ret = PTR_ERR(info->psy_usb);
 829                dev_err(dev, "failed to register power supply: %d\n", ret);
 830                return ret;
 831        }
 832
 833        /* Register for extcon notification */
 834        INIT_WORK(&info->cable.work, axp288_charger_extcon_evt_worker);
 835        info->cable.nb[0].notifier_call = axp288_charger_handle_cable0_evt;
 836        info->cable.nb[1].notifier_call = axp288_charger_handle_cable1_evt;
 837        info->cable.nb[2].notifier_call = axp288_charger_handle_cable2_evt;
 838        for (i = 0; i < ARRAY_SIZE(cable_ids); i++) {
 839                ret = devm_extcon_register_notifier(dev, info->cable.edev,
 840                                          cable_ids[i], &info->cable.nb[i]);
 841                if (ret) {
 842                        dev_err(dev, "failed to register extcon notifier for %u: %d\n",
 843                                cable_ids[i], ret);
 844                        return ret;
 845                }
 846        }
 847        schedule_work(&info->cable.work);
 848
 849        /* Register for OTG notification */
 850        INIT_WORK(&info->otg.work, axp288_charger_otg_evt_worker);
 851        info->otg.id_nb.notifier_call = axp288_charger_handle_otg_evt;
 852        ret = devm_extcon_register_notifier(&pdev->dev, info->otg.cable,
 853                                        EXTCON_USB_HOST, &info->otg.id_nb);
 854        if (ret) {
 855                dev_err(dev, "failed to register EXTCON_USB_HOST notifier\n");
 856                return ret;
 857        }
 858        schedule_work(&info->otg.work);
 859
 860        /* Register charger interrupts */
 861        for (i = 0; i < CHRG_INTR_END; i++) {
 862                pirq = platform_get_irq(info->pdev, i);
 863                info->irq[i] = regmap_irq_get_virq(info->regmap_irqc, pirq);
 864                if (info->irq[i] < 0) {
 865                        dev_warn(&info->pdev->dev,
 866                                "failed to get virtual interrupt=%d\n", pirq);
 867                        return info->irq[i];
 868                }
 869                ret = devm_request_threaded_irq(&info->pdev->dev, info->irq[i],
 870                                        NULL, axp288_charger_irq_thread_handler,
 871                                        IRQF_ONESHOT, info->pdev->name, info);
 872                if (ret) {
 873                        dev_err(&pdev->dev, "failed to request interrupt=%d\n",
 874                                                                info->irq[i]);
 875                        return ret;
 876                }
 877        }
 878
 879        return 0;
 880}
 881
 882static const struct platform_device_id axp288_charger_id_table[] = {
 883        { .name = "axp288_charger" },
 884        {},
 885};
 886MODULE_DEVICE_TABLE(platform, axp288_charger_id_table);
 887
 888static struct platform_driver axp288_charger_driver = {
 889        .probe = axp288_charger_probe,
 890        .id_table = axp288_charger_id_table,
 891        .driver = {
 892                .name = "axp288_charger",
 893        },
 894};
 895
 896module_platform_driver(axp288_charger_driver);
 897
 898MODULE_AUTHOR("Ramakrishna Pallala <ramakrishna.pallala@intel.com>");
 899MODULE_DESCRIPTION("X-power AXP288 Charger Driver");
 900MODULE_LICENSE("GPL v2");
 901