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