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