linux/drivers/power/supply/qcom_smbb.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/* Copyright (c) 2014, Sony Mobile Communications Inc.
   3 *
   4 * This driver is for the multi-block Switch-Mode Battery Charger and Boost
   5 * (SMBB) hardware, found in Qualcomm PM8941 PMICs.  The charger is an
   6 * integrated, single-cell lithium-ion battery charger.
   7 *
   8 * Sub-components:
   9 *  - Charger core
  10 *  - Buck
  11 *  - DC charge-path
  12 *  - USB charge-path
  13 *  - Battery interface
  14 *  - Boost (not implemented)
  15 *  - Misc
  16 *  - HF-Buck
  17 */
  18
  19#include <linux/errno.h>
  20#include <linux/interrupt.h>
  21#include <linux/kernel.h>
  22#include <linux/module.h>
  23#include <linux/mutex.h>
  24#include <linux/of.h>
  25#include <linux/platform_device.h>
  26#include <linux/power_supply.h>
  27#include <linux/regmap.h>
  28#include <linux/slab.h>
  29#include <linux/extcon-provider.h>
  30#include <linux/regulator/driver.h>
  31
  32#define SMBB_CHG_VMAX           0x040
  33#define SMBB_CHG_VSAFE          0x041
  34#define SMBB_CHG_CFG            0x043
  35#define SMBB_CHG_IMAX           0x044
  36#define SMBB_CHG_ISAFE          0x045
  37#define SMBB_CHG_VIN_MIN        0x047
  38#define SMBB_CHG_CTRL           0x049
  39#define CTRL_EN                 BIT(7)
  40#define SMBB_CHG_VBAT_WEAK      0x052
  41#define SMBB_CHG_IBAT_TERM_CHG  0x05b
  42#define IBAT_TERM_CHG_IEOC      BIT(7)
  43#define IBAT_TERM_CHG_IEOC_BMS  BIT(7)
  44#define IBAT_TERM_CHG_IEOC_CHG  0
  45#define SMBB_CHG_VBAT_DET       0x05d
  46#define SMBB_CHG_TCHG_MAX_EN    0x060
  47#define TCHG_MAX_EN             BIT(7)
  48#define SMBB_CHG_WDOG_TIME      0x062
  49#define SMBB_CHG_WDOG_EN        0x065
  50#define WDOG_EN                 BIT(7)
  51
  52#define SMBB_BUCK_REG_MODE      0x174
  53#define BUCK_REG_MODE           BIT(0)
  54#define BUCK_REG_MODE_VBAT      BIT(0)
  55#define BUCK_REG_MODE_VSYS      0
  56
  57#define SMBB_BAT_PRES_STATUS    0x208
  58#define PRES_STATUS_BAT_PRES    BIT(7)
  59#define SMBB_BAT_TEMP_STATUS    0x209
  60#define TEMP_STATUS_OK          BIT(7)
  61#define TEMP_STATUS_HOT         BIT(6)
  62#define SMBB_BAT_BTC_CTRL       0x249
  63#define BTC_CTRL_COMP_EN        BIT(7)
  64#define BTC_CTRL_COLD_EXT       BIT(1)
  65#define BTC_CTRL_HOT_EXT_N      BIT(0)
  66
  67#define SMBB_USB_IMAX           0x344
  68#define SMBB_USB_OTG_CTL        0x348
  69#define OTG_CTL_EN              BIT(0)
  70#define SMBB_USB_ENUM_TIMER_STOP 0x34e
  71#define ENUM_TIMER_STOP         BIT(0)
  72#define SMBB_USB_SEC_ACCESS     0x3d0
  73#define SEC_ACCESS_MAGIC        0xa5
  74#define SMBB_USB_REV_BST        0x3ed
  75#define REV_BST_CHG_GONE        BIT(7)
  76
  77#define SMBB_DC_IMAX            0x444
  78
  79#define SMBB_MISC_REV2          0x601
  80#define SMBB_MISC_BOOT_DONE     0x642
  81#define BOOT_DONE               BIT(7)
  82
  83#define STATUS_USBIN_VALID      BIT(0) /* USB connection is valid */
  84#define STATUS_DCIN_VALID       BIT(1) /* DC connection is valid */
  85#define STATUS_BAT_HOT          BIT(2) /* Battery temp 1=Hot, 0=Cold */
  86#define STATUS_BAT_OK           BIT(3) /* Battery temp OK */
  87#define STATUS_BAT_PRESENT      BIT(4) /* Battery is present */
  88#define STATUS_CHG_DONE         BIT(5) /* Charge cycle is complete */
  89#define STATUS_CHG_TRKL         BIT(6) /* Trickle charging */
  90#define STATUS_CHG_FAST         BIT(7) /* Fast charging */
  91#define STATUS_CHG_GONE         BIT(8) /* No charger is connected */
  92
  93enum smbb_attr {
  94        ATTR_BAT_ISAFE,
  95        ATTR_BAT_IMAX,
  96        ATTR_USBIN_IMAX,
  97        ATTR_DCIN_IMAX,
  98        ATTR_BAT_VSAFE,
  99        ATTR_BAT_VMAX,
 100        ATTR_BAT_VMIN,
 101        ATTR_CHG_VDET,
 102        ATTR_VIN_MIN,
 103        _ATTR_CNT,
 104};
 105
 106struct smbb_charger {
 107        unsigned int revision;
 108        unsigned int addr;
 109        struct device *dev;
 110        struct extcon_dev *edev;
 111
 112        bool dc_disabled;
 113        bool jeita_ext_temp;
 114        unsigned long status;
 115        struct mutex statlock;
 116
 117        unsigned int attr[_ATTR_CNT];
 118
 119        struct power_supply *usb_psy;
 120        struct power_supply *dc_psy;
 121        struct power_supply *bat_psy;
 122        struct regmap *regmap;
 123
 124        struct regulator_desc otg_rdesc;
 125        struct regulator_dev *otg_reg;
 126};
 127
 128static const unsigned int smbb_usb_extcon_cable[] = {
 129        EXTCON_USB,
 130        EXTCON_NONE,
 131};
 132
 133static int smbb_vbat_weak_fn(unsigned int index)
 134{
 135        return 2100000 + index * 100000;
 136}
 137
 138static int smbb_vin_fn(unsigned int index)
 139{
 140        if (index > 42)
 141                return 5600000 + (index - 43) * 200000;
 142        return 3400000 + index * 50000;
 143}
 144
 145static int smbb_vmax_fn(unsigned int index)
 146{
 147        return 3240000 + index * 10000;
 148}
 149
 150static int smbb_vbat_det_fn(unsigned int index)
 151{
 152        return 3240000 + index * 20000;
 153}
 154
 155static int smbb_imax_fn(unsigned int index)
 156{
 157        if (index < 2)
 158                return 100000 + index * 50000;
 159        return index * 100000;
 160}
 161
 162static int smbb_bat_imax_fn(unsigned int index)
 163{
 164        return index * 50000;
 165}
 166
 167static unsigned int smbb_hw_lookup(unsigned int val, int (*fn)(unsigned int))
 168{
 169        unsigned int widx;
 170        unsigned int sel;
 171
 172        for (widx = sel = 0; (*fn)(widx) <= val; ++widx)
 173                sel = widx;
 174
 175        return sel;
 176}
 177
 178static const struct smbb_charger_attr {
 179        const char *name;
 180        unsigned int reg;
 181        unsigned int safe_reg;
 182        unsigned int max;
 183        unsigned int min;
 184        unsigned int fail_ok;
 185        int (*hw_fn)(unsigned int);
 186} smbb_charger_attrs[] = {
 187        [ATTR_BAT_ISAFE] = {
 188                .name = "qcom,fast-charge-safe-current",
 189                .reg = SMBB_CHG_ISAFE,
 190                .max = 3000000,
 191                .min = 200000,
 192                .hw_fn = smbb_bat_imax_fn,
 193                .fail_ok = 1,
 194        },
 195        [ATTR_BAT_IMAX] = {
 196                .name = "qcom,fast-charge-current-limit",
 197                .reg = SMBB_CHG_IMAX,
 198                .safe_reg = SMBB_CHG_ISAFE,
 199                .max = 3000000,
 200                .min = 200000,
 201                .hw_fn = smbb_bat_imax_fn,
 202        },
 203        [ATTR_DCIN_IMAX] = {
 204                .name = "qcom,dc-current-limit",
 205                .reg = SMBB_DC_IMAX,
 206                .max = 2500000,
 207                .min = 100000,
 208                .hw_fn = smbb_imax_fn,
 209        },
 210        [ATTR_BAT_VSAFE] = {
 211                .name = "qcom,fast-charge-safe-voltage",
 212                .reg = SMBB_CHG_VSAFE,
 213                .max = 5000000,
 214                .min = 3240000,
 215                .hw_fn = smbb_vmax_fn,
 216                .fail_ok = 1,
 217        },
 218        [ATTR_BAT_VMAX] = {
 219                .name = "qcom,fast-charge-high-threshold-voltage",
 220                .reg = SMBB_CHG_VMAX,
 221                .safe_reg = SMBB_CHG_VSAFE,
 222                .max = 5000000,
 223                .min = 3240000,
 224                .hw_fn = smbb_vmax_fn,
 225        },
 226        [ATTR_BAT_VMIN] = {
 227                .name = "qcom,fast-charge-low-threshold-voltage",
 228                .reg = SMBB_CHG_VBAT_WEAK,
 229                .max = 3600000,
 230                .min = 2100000,
 231                .hw_fn = smbb_vbat_weak_fn,
 232        },
 233        [ATTR_CHG_VDET] = {
 234                .name = "qcom,auto-recharge-threshold-voltage",
 235                .reg = SMBB_CHG_VBAT_DET,
 236                .max = 5000000,
 237                .min = 3240000,
 238                .hw_fn = smbb_vbat_det_fn,
 239        },
 240        [ATTR_VIN_MIN] = {
 241                .name = "qcom,minimum-input-voltage",
 242                .reg = SMBB_CHG_VIN_MIN,
 243                .max = 9600000,
 244                .min = 4200000,
 245                .hw_fn = smbb_vin_fn,
 246        },
 247        [ATTR_USBIN_IMAX] = {
 248                .name = "usb-charge-current-limit",
 249                .reg = SMBB_USB_IMAX,
 250                .max = 2500000,
 251                .min = 100000,
 252                .hw_fn = smbb_imax_fn,
 253        },
 254};
 255
 256static int smbb_charger_attr_write(struct smbb_charger *chg,
 257                enum smbb_attr which, unsigned int val)
 258{
 259        const struct smbb_charger_attr *prop;
 260        unsigned int wval;
 261        unsigned int out;
 262        int rc;
 263
 264        prop = &smbb_charger_attrs[which];
 265
 266        if (val > prop->max || val < prop->min) {
 267                dev_err(chg->dev, "value out of range for %s [%u:%u]\n",
 268                        prop->name, prop->min, prop->max);
 269                return -EINVAL;
 270        }
 271
 272        if (prop->safe_reg) {
 273                rc = regmap_read(chg->regmap,
 274                                chg->addr + prop->safe_reg, &wval);
 275                if (rc) {
 276                        dev_err(chg->dev,
 277                                "unable to read safe value for '%s'\n",
 278                                prop->name);
 279                        return rc;
 280                }
 281
 282                wval = prop->hw_fn(wval);
 283
 284                if (val > wval) {
 285                        dev_warn(chg->dev,
 286                                "%s above safe value, clamping at %u\n",
 287                                prop->name, wval);
 288                        val = wval;
 289                }
 290        }
 291
 292        wval = smbb_hw_lookup(val, prop->hw_fn);
 293
 294        rc = regmap_write(chg->regmap, chg->addr + prop->reg, wval);
 295        if (rc) {
 296                dev_err(chg->dev, "unable to update %s", prop->name);
 297                return rc;
 298        }
 299        out = prop->hw_fn(wval);
 300        if (out != val) {
 301                dev_warn(chg->dev,
 302                        "%s inaccurate, rounded to %u\n",
 303                        prop->name, out);
 304        }
 305
 306        dev_dbg(chg->dev, "%s <= %d\n", prop->name, out);
 307
 308        chg->attr[which] = out;
 309
 310        return 0;
 311}
 312
 313static int smbb_charger_attr_read(struct smbb_charger *chg,
 314                enum smbb_attr which)
 315{
 316        const struct smbb_charger_attr *prop;
 317        unsigned int val;
 318        int rc;
 319
 320        prop = &smbb_charger_attrs[which];
 321
 322        rc = regmap_read(chg->regmap, chg->addr + prop->reg, &val);
 323        if (rc) {
 324                dev_err(chg->dev, "failed to read %s\n", prop->name);
 325                return rc;
 326        }
 327        val = prop->hw_fn(val);
 328        dev_dbg(chg->dev, "%s => %d\n", prop->name, val);
 329
 330        chg->attr[which] = val;
 331
 332        return 0;
 333}
 334
 335static int smbb_charger_attr_parse(struct smbb_charger *chg,
 336                enum smbb_attr which)
 337{
 338        const struct smbb_charger_attr *prop;
 339        unsigned int val;
 340        int rc;
 341
 342        prop = &smbb_charger_attrs[which];
 343
 344        rc = of_property_read_u32(chg->dev->of_node, prop->name, &val);
 345        if (rc == 0) {
 346                rc = smbb_charger_attr_write(chg, which, val);
 347                if (!rc || !prop->fail_ok)
 348                        return rc;
 349        }
 350        return smbb_charger_attr_read(chg, which);
 351}
 352
 353static void smbb_set_line_flag(struct smbb_charger *chg, int irq, int flag)
 354{
 355        bool state;
 356        int ret;
 357
 358        ret = irq_get_irqchip_state(irq, IRQCHIP_STATE_LINE_LEVEL, &state);
 359        if (ret < 0) {
 360                dev_err(chg->dev, "failed to read irq line\n");
 361                return;
 362        }
 363
 364        mutex_lock(&chg->statlock);
 365        if (state)
 366                chg->status |= flag;
 367        else
 368                chg->status &= ~flag;
 369        mutex_unlock(&chg->statlock);
 370
 371        dev_dbg(chg->dev, "status = %03lx\n", chg->status);
 372}
 373
 374static irqreturn_t smbb_usb_valid_handler(int irq, void *_data)
 375{
 376        struct smbb_charger *chg = _data;
 377
 378        smbb_set_line_flag(chg, irq, STATUS_USBIN_VALID);
 379        extcon_set_state_sync(chg->edev, EXTCON_USB,
 380                                chg->status & STATUS_USBIN_VALID);
 381        power_supply_changed(chg->usb_psy);
 382
 383        return IRQ_HANDLED;
 384}
 385
 386static irqreturn_t smbb_dc_valid_handler(int irq, void *_data)
 387{
 388        struct smbb_charger *chg = _data;
 389
 390        smbb_set_line_flag(chg, irq, STATUS_DCIN_VALID);
 391        if (!chg->dc_disabled)
 392                power_supply_changed(chg->dc_psy);
 393
 394        return IRQ_HANDLED;
 395}
 396
 397static irqreturn_t smbb_bat_temp_handler(int irq, void *_data)
 398{
 399        struct smbb_charger *chg = _data;
 400        unsigned int val;
 401        int rc;
 402
 403        rc = regmap_read(chg->regmap, chg->addr + SMBB_BAT_TEMP_STATUS, &val);
 404        if (rc)
 405                return IRQ_HANDLED;
 406
 407        mutex_lock(&chg->statlock);
 408        if (val & TEMP_STATUS_OK) {
 409                chg->status |= STATUS_BAT_OK;
 410        } else {
 411                chg->status &= ~STATUS_BAT_OK;
 412                if (val & TEMP_STATUS_HOT)
 413                        chg->status |= STATUS_BAT_HOT;
 414        }
 415        mutex_unlock(&chg->statlock);
 416
 417        power_supply_changed(chg->bat_psy);
 418        return IRQ_HANDLED;
 419}
 420
 421static irqreturn_t smbb_bat_present_handler(int irq, void *_data)
 422{
 423        struct smbb_charger *chg = _data;
 424
 425        smbb_set_line_flag(chg, irq, STATUS_BAT_PRESENT);
 426        power_supply_changed(chg->bat_psy);
 427
 428        return IRQ_HANDLED;
 429}
 430
 431static irqreturn_t smbb_chg_done_handler(int irq, void *_data)
 432{
 433        struct smbb_charger *chg = _data;
 434
 435        smbb_set_line_flag(chg, irq, STATUS_CHG_DONE);
 436        power_supply_changed(chg->bat_psy);
 437
 438        return IRQ_HANDLED;
 439}
 440
 441static irqreturn_t smbb_chg_gone_handler(int irq, void *_data)
 442{
 443        struct smbb_charger *chg = _data;
 444
 445        smbb_set_line_flag(chg, irq, STATUS_CHG_GONE);
 446        power_supply_changed(chg->bat_psy);
 447        power_supply_changed(chg->usb_psy);
 448        if (!chg->dc_disabled)
 449                power_supply_changed(chg->dc_psy);
 450
 451        return IRQ_HANDLED;
 452}
 453
 454static irqreturn_t smbb_chg_fast_handler(int irq, void *_data)
 455{
 456        struct smbb_charger *chg = _data;
 457
 458        smbb_set_line_flag(chg, irq, STATUS_CHG_FAST);
 459        power_supply_changed(chg->bat_psy);
 460
 461        return IRQ_HANDLED;
 462}
 463
 464static irqreturn_t smbb_chg_trkl_handler(int irq, void *_data)
 465{
 466        struct smbb_charger *chg = _data;
 467
 468        smbb_set_line_flag(chg, irq, STATUS_CHG_TRKL);
 469        power_supply_changed(chg->bat_psy);
 470
 471        return IRQ_HANDLED;
 472}
 473
 474static const struct smbb_irq {
 475        const char *name;
 476        irqreturn_t (*handler)(int, void *);
 477} smbb_charger_irqs[] = {
 478        { "chg-done", smbb_chg_done_handler },
 479        { "chg-fast", smbb_chg_fast_handler },
 480        { "chg-trkl", smbb_chg_trkl_handler },
 481        { "bat-temp-ok", smbb_bat_temp_handler },
 482        { "bat-present", smbb_bat_present_handler },
 483        { "chg-gone", smbb_chg_gone_handler },
 484        { "usb-valid", smbb_usb_valid_handler },
 485        { "dc-valid", smbb_dc_valid_handler },
 486};
 487
 488static int smbb_usbin_get_property(struct power_supply *psy,
 489                enum power_supply_property psp,
 490                union power_supply_propval *val)
 491{
 492        struct smbb_charger *chg = power_supply_get_drvdata(psy);
 493        int rc = 0;
 494
 495        switch (psp) {
 496        case POWER_SUPPLY_PROP_ONLINE:
 497                mutex_lock(&chg->statlock);
 498                val->intval = !(chg->status & STATUS_CHG_GONE) &&
 499                                (chg->status & STATUS_USBIN_VALID);
 500                mutex_unlock(&chg->statlock);
 501                break;
 502        case POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT:
 503                val->intval = chg->attr[ATTR_USBIN_IMAX];
 504                break;
 505        case POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT_MAX:
 506                val->intval = 2500000;
 507                break;
 508        default:
 509                rc = -EINVAL;
 510                break;
 511        }
 512
 513        return rc;
 514}
 515
 516static int smbb_usbin_set_property(struct power_supply *psy,
 517                enum power_supply_property psp,
 518                const union power_supply_propval *val)
 519{
 520        struct smbb_charger *chg = power_supply_get_drvdata(psy);
 521        int rc;
 522
 523        switch (psp) {
 524        case POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT:
 525                rc = smbb_charger_attr_write(chg, ATTR_USBIN_IMAX,
 526                                val->intval);
 527                break;
 528        default:
 529                rc = -EINVAL;
 530                break;
 531        }
 532
 533        return rc;
 534}
 535
 536static int smbb_dcin_get_property(struct power_supply *psy,
 537                enum power_supply_property psp,
 538                union power_supply_propval *val)
 539{
 540        struct smbb_charger *chg = power_supply_get_drvdata(psy);
 541        int rc = 0;
 542
 543        switch (psp) {
 544        case POWER_SUPPLY_PROP_ONLINE:
 545                mutex_lock(&chg->statlock);
 546                val->intval = !(chg->status & STATUS_CHG_GONE) &&
 547                                (chg->status & STATUS_DCIN_VALID);
 548                mutex_unlock(&chg->statlock);
 549                break;
 550        case POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT:
 551                val->intval = chg->attr[ATTR_DCIN_IMAX];
 552                break;
 553        case POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT_MAX:
 554                val->intval = 2500000;
 555                break;
 556        default:
 557                rc = -EINVAL;
 558                break;
 559        }
 560
 561        return rc;
 562}
 563
 564static int smbb_dcin_set_property(struct power_supply *psy,
 565                enum power_supply_property psp,
 566                const union power_supply_propval *val)
 567{
 568        struct smbb_charger *chg = power_supply_get_drvdata(psy);
 569        int rc;
 570
 571        switch (psp) {
 572        case POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT:
 573                rc = smbb_charger_attr_write(chg, ATTR_DCIN_IMAX,
 574                                val->intval);
 575                break;
 576        default:
 577                rc = -EINVAL;
 578                break;
 579        }
 580
 581        return rc;
 582}
 583
 584static int smbb_charger_writable_property(struct power_supply *psy,
 585                enum power_supply_property psp)
 586{
 587        return psp == POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT;
 588}
 589
 590static int smbb_battery_get_property(struct power_supply *psy,
 591                enum power_supply_property psp,
 592                union power_supply_propval *val)
 593{
 594        struct smbb_charger *chg = power_supply_get_drvdata(psy);
 595        unsigned long status;
 596        int rc = 0;
 597
 598        mutex_lock(&chg->statlock);
 599        status = chg->status;
 600        mutex_unlock(&chg->statlock);
 601
 602        switch (psp) {
 603        case POWER_SUPPLY_PROP_STATUS:
 604                if (status & STATUS_CHG_GONE)
 605                        val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
 606                else if (!(status & (STATUS_DCIN_VALID | STATUS_USBIN_VALID)))
 607                        val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
 608                else if (status & STATUS_CHG_DONE)
 609                        val->intval = POWER_SUPPLY_STATUS_FULL;
 610                else if (!(status & STATUS_BAT_OK))
 611                        val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
 612                else if (status & (STATUS_CHG_FAST | STATUS_CHG_TRKL))
 613                        val->intval = POWER_SUPPLY_STATUS_CHARGING;
 614                else /* everything is ok for charging, but we are not... */
 615                        val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
 616                break;
 617        case POWER_SUPPLY_PROP_HEALTH:
 618                if (status & STATUS_BAT_OK)
 619                        val->intval = POWER_SUPPLY_HEALTH_GOOD;
 620                else if (status & STATUS_BAT_HOT)
 621                        val->intval = POWER_SUPPLY_HEALTH_OVERHEAT;
 622                else
 623                        val->intval = POWER_SUPPLY_HEALTH_COLD;
 624                break;
 625        case POWER_SUPPLY_PROP_CHARGE_TYPE:
 626                if (status & STATUS_CHG_FAST)
 627                        val->intval = POWER_SUPPLY_CHARGE_TYPE_FAST;
 628                else if (status & STATUS_CHG_TRKL)
 629                        val->intval = POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
 630                else
 631                        val->intval = POWER_SUPPLY_CHARGE_TYPE_NONE;
 632                break;
 633        case POWER_SUPPLY_PROP_PRESENT:
 634                val->intval = !!(status & STATUS_BAT_PRESENT);
 635                break;
 636        case POWER_SUPPLY_PROP_CURRENT_MAX:
 637                val->intval = chg->attr[ATTR_BAT_IMAX];
 638                break;
 639        case POWER_SUPPLY_PROP_VOLTAGE_MAX:
 640                val->intval = chg->attr[ATTR_BAT_VMAX];
 641                break;
 642        case POWER_SUPPLY_PROP_TECHNOLOGY:
 643                /* this charger is a single-cell lithium-ion battery charger
 644                * only.  If you hook up some other technology, there will be
 645                * fireworks.
 646                */
 647                val->intval = POWER_SUPPLY_TECHNOLOGY_LION;
 648                break;
 649        case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN:
 650                val->intval = 3000000; /* single-cell li-ion low end */
 651                break;
 652        default:
 653                rc = -EINVAL;
 654                break;
 655        }
 656
 657        return rc;
 658}
 659
 660static int smbb_battery_set_property(struct power_supply *psy,
 661                enum power_supply_property psp,
 662                const union power_supply_propval *val)
 663{
 664        struct smbb_charger *chg = power_supply_get_drvdata(psy);
 665        int rc;
 666
 667        switch (psp) {
 668        case POWER_SUPPLY_PROP_CURRENT_MAX:
 669                rc = smbb_charger_attr_write(chg, ATTR_BAT_IMAX, val->intval);
 670                break;
 671        case POWER_SUPPLY_PROP_VOLTAGE_MAX:
 672                rc = smbb_charger_attr_write(chg, ATTR_BAT_VMAX, val->intval);
 673                break;
 674        default:
 675                rc = -EINVAL;
 676                break;
 677        }
 678
 679        return rc;
 680}
 681
 682static int smbb_battery_writable_property(struct power_supply *psy,
 683                enum power_supply_property psp)
 684{
 685        switch (psp) {
 686        case POWER_SUPPLY_PROP_CURRENT_MAX:
 687        case POWER_SUPPLY_PROP_VOLTAGE_MAX:
 688                return 1;
 689        default:
 690                return 0;
 691        }
 692}
 693
 694static enum power_supply_property smbb_charger_properties[] = {
 695        POWER_SUPPLY_PROP_ONLINE,
 696        POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT,
 697        POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT_MAX,
 698};
 699
 700static enum power_supply_property smbb_battery_properties[] = {
 701        POWER_SUPPLY_PROP_STATUS,
 702        POWER_SUPPLY_PROP_HEALTH,
 703        POWER_SUPPLY_PROP_PRESENT,
 704        POWER_SUPPLY_PROP_CHARGE_TYPE,
 705        POWER_SUPPLY_PROP_CURRENT_MAX,
 706        POWER_SUPPLY_PROP_VOLTAGE_MAX,
 707        POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,
 708        POWER_SUPPLY_PROP_TECHNOLOGY,
 709};
 710
 711static const struct reg_off_mask_default {
 712        unsigned int offset;
 713        unsigned int mask;
 714        unsigned int value;
 715        unsigned int rev_mask;
 716} smbb_charger_setup[] = {
 717        /* The bootloader is supposed to set this... make sure anyway. */
 718        { SMBB_MISC_BOOT_DONE, BOOT_DONE, BOOT_DONE },
 719
 720        /* Disable software timer */
 721        { SMBB_CHG_TCHG_MAX_EN, TCHG_MAX_EN, 0 },
 722
 723        /* Clear and disable watchdog */
 724        { SMBB_CHG_WDOG_TIME, 0xff, 160 },
 725        { SMBB_CHG_WDOG_EN, WDOG_EN, 0 },
 726
 727        /* Use charger based EoC detection */
 728        { SMBB_CHG_IBAT_TERM_CHG, IBAT_TERM_CHG_IEOC, IBAT_TERM_CHG_IEOC_CHG },
 729
 730        /* Disable GSM PA load adjustment.
 731        * The PA signal is incorrectly connected on v2.
 732        */
 733        { SMBB_CHG_CFG, 0xff, 0x00, BIT(3) },
 734
 735        /* Use VBAT (not VSYS) to compensate for IR drop during fast charging */
 736        { SMBB_BUCK_REG_MODE, BUCK_REG_MODE, BUCK_REG_MODE_VBAT },
 737
 738        /* Enable battery temperature comparators */
 739        { SMBB_BAT_BTC_CTRL, BTC_CTRL_COMP_EN, BTC_CTRL_COMP_EN },
 740
 741        /* Stop USB enumeration timer */
 742        { SMBB_USB_ENUM_TIMER_STOP, ENUM_TIMER_STOP, ENUM_TIMER_STOP },
 743
 744#if 0 /* FIXME supposedly only to disable hardware ARB termination */
 745        { SMBB_USB_SEC_ACCESS, SEC_ACCESS_MAGIC },
 746        { SMBB_USB_REV_BST, 0xff, REV_BST_CHG_GONE },
 747#endif
 748
 749        /* Stop USB enumeration timer, again */
 750        { SMBB_USB_ENUM_TIMER_STOP, ENUM_TIMER_STOP, ENUM_TIMER_STOP },
 751
 752        /* Enable charging */
 753        { SMBB_CHG_CTRL, CTRL_EN, CTRL_EN },
 754};
 755
 756static char *smbb_bif[] = { "smbb-bif" };
 757
 758static const struct power_supply_desc bat_psy_desc = {
 759        .name = "smbb-bif",
 760        .type = POWER_SUPPLY_TYPE_BATTERY,
 761        .properties = smbb_battery_properties,
 762        .num_properties = ARRAY_SIZE(smbb_battery_properties),
 763        .get_property = smbb_battery_get_property,
 764        .set_property = smbb_battery_set_property,
 765        .property_is_writeable = smbb_battery_writable_property,
 766};
 767
 768static const struct power_supply_desc usb_psy_desc = {
 769        .name = "smbb-usbin",
 770        .type = POWER_SUPPLY_TYPE_USB,
 771        .properties = smbb_charger_properties,
 772        .num_properties = ARRAY_SIZE(smbb_charger_properties),
 773        .get_property = smbb_usbin_get_property,
 774        .set_property = smbb_usbin_set_property,
 775        .property_is_writeable = smbb_charger_writable_property,
 776};
 777
 778static const struct power_supply_desc dc_psy_desc = {
 779        .name = "smbb-dcin",
 780        .type = POWER_SUPPLY_TYPE_MAINS,
 781        .properties = smbb_charger_properties,
 782        .num_properties = ARRAY_SIZE(smbb_charger_properties),
 783        .get_property = smbb_dcin_get_property,
 784        .set_property = smbb_dcin_set_property,
 785        .property_is_writeable = smbb_charger_writable_property,
 786};
 787
 788static int smbb_chg_otg_enable(struct regulator_dev *rdev)
 789{
 790        struct smbb_charger *chg = rdev_get_drvdata(rdev);
 791        int rc;
 792
 793        rc = regmap_update_bits(chg->regmap, chg->addr + SMBB_USB_OTG_CTL,
 794                                OTG_CTL_EN, OTG_CTL_EN);
 795        if (rc)
 796                dev_err(chg->dev, "failed to update OTG_CTL\n");
 797        return rc;
 798}
 799
 800static int smbb_chg_otg_disable(struct regulator_dev *rdev)
 801{
 802        struct smbb_charger *chg = rdev_get_drvdata(rdev);
 803        int rc;
 804
 805        rc = regmap_update_bits(chg->regmap, chg->addr + SMBB_USB_OTG_CTL,
 806                                OTG_CTL_EN, 0);
 807        if (rc)
 808                dev_err(chg->dev, "failed to update OTG_CTL\n");
 809        return rc;
 810}
 811
 812static int smbb_chg_otg_is_enabled(struct regulator_dev *rdev)
 813{
 814        struct smbb_charger *chg = rdev_get_drvdata(rdev);
 815        unsigned int value = 0;
 816        int rc;
 817
 818        rc = regmap_read(chg->regmap, chg->addr + SMBB_USB_OTG_CTL, &value);
 819        if (rc)
 820                dev_err(chg->dev, "failed to read OTG_CTL\n");
 821
 822        return !!(value & OTG_CTL_EN);
 823}
 824
 825static const struct regulator_ops smbb_chg_otg_ops = {
 826        .enable = smbb_chg_otg_enable,
 827        .disable = smbb_chg_otg_disable,
 828        .is_enabled = smbb_chg_otg_is_enabled,
 829};
 830
 831static int smbb_charger_probe(struct platform_device *pdev)
 832{
 833        struct power_supply_config bat_cfg = {};
 834        struct power_supply_config usb_cfg = {};
 835        struct power_supply_config dc_cfg = {};
 836        struct smbb_charger *chg;
 837        struct regulator_config config = { };
 838        int rc, i;
 839
 840        chg = devm_kzalloc(&pdev->dev, sizeof(*chg), GFP_KERNEL);
 841        if (!chg)
 842                return -ENOMEM;
 843
 844        chg->dev = &pdev->dev;
 845        mutex_init(&chg->statlock);
 846
 847        chg->regmap = dev_get_regmap(pdev->dev.parent, NULL);
 848        if (!chg->regmap) {
 849                dev_err(&pdev->dev, "failed to locate regmap\n");
 850                return -ENODEV;
 851        }
 852
 853        rc = of_property_read_u32(pdev->dev.of_node, "reg", &chg->addr);
 854        if (rc) {
 855                dev_err(&pdev->dev, "missing or invalid 'reg' property\n");
 856                return rc;
 857        }
 858
 859        rc = regmap_read(chg->regmap, chg->addr + SMBB_MISC_REV2, &chg->revision);
 860        if (rc) {
 861                dev_err(&pdev->dev, "unable to read revision\n");
 862                return rc;
 863        }
 864
 865        chg->revision += 1;
 866        if (chg->revision != 2 && chg->revision != 3) {
 867                dev_err(&pdev->dev, "v1 hardware not supported\n");
 868                return -ENODEV;
 869        }
 870        dev_info(&pdev->dev, "Initializing SMBB rev %u", chg->revision);
 871
 872        chg->dc_disabled = of_property_read_bool(pdev->dev.of_node, "qcom,disable-dc");
 873
 874        for (i = 0; i < _ATTR_CNT; ++i) {
 875                rc = smbb_charger_attr_parse(chg, i);
 876                if (rc) {
 877                        dev_err(&pdev->dev, "failed to parse/apply settings\n");
 878                        return rc;
 879                }
 880        }
 881
 882        bat_cfg.drv_data = chg;
 883        bat_cfg.of_node = pdev->dev.of_node;
 884        chg->bat_psy = devm_power_supply_register(&pdev->dev,
 885                                                  &bat_psy_desc,
 886                                                  &bat_cfg);
 887        if (IS_ERR(chg->bat_psy)) {
 888                dev_err(&pdev->dev, "failed to register battery\n");
 889                return PTR_ERR(chg->bat_psy);
 890        }
 891
 892        usb_cfg.drv_data = chg;
 893        usb_cfg.supplied_to = smbb_bif;
 894        usb_cfg.num_supplicants = ARRAY_SIZE(smbb_bif);
 895        chg->usb_psy = devm_power_supply_register(&pdev->dev,
 896                                                  &usb_psy_desc,
 897                                                  &usb_cfg);
 898        if (IS_ERR(chg->usb_psy)) {
 899                dev_err(&pdev->dev, "failed to register USB power supply\n");
 900                return PTR_ERR(chg->usb_psy);
 901        }
 902
 903        chg->edev = devm_extcon_dev_allocate(&pdev->dev, smbb_usb_extcon_cable);
 904        if (IS_ERR(chg->edev)) {
 905                dev_err(&pdev->dev, "failed to allocate extcon device\n");
 906                return -ENOMEM;
 907        }
 908
 909        rc = devm_extcon_dev_register(&pdev->dev, chg->edev);
 910        if (rc < 0) {
 911                dev_err(&pdev->dev, "failed to register extcon device\n");
 912                return rc;
 913        }
 914
 915        if (!chg->dc_disabled) {
 916                dc_cfg.drv_data = chg;
 917                dc_cfg.supplied_to = smbb_bif;
 918                dc_cfg.num_supplicants = ARRAY_SIZE(smbb_bif);
 919                chg->dc_psy = devm_power_supply_register(&pdev->dev,
 920                                                         &dc_psy_desc,
 921                                                         &dc_cfg);
 922                if (IS_ERR(chg->dc_psy)) {
 923                        dev_err(&pdev->dev, "failed to register DC power supply\n");
 924                        return PTR_ERR(chg->dc_psy);
 925                }
 926        }
 927
 928        for (i = 0; i < ARRAY_SIZE(smbb_charger_irqs); ++i) {
 929                int irq;
 930
 931                irq = platform_get_irq_byname(pdev, smbb_charger_irqs[i].name);
 932                if (irq < 0) {
 933                        dev_err(&pdev->dev, "failed to get irq '%s'\n",
 934                                smbb_charger_irqs[i].name);
 935                        return irq;
 936                }
 937
 938                smbb_charger_irqs[i].handler(irq, chg);
 939
 940                rc = devm_request_threaded_irq(&pdev->dev, irq, NULL,
 941                                smbb_charger_irqs[i].handler, IRQF_ONESHOT,
 942                                smbb_charger_irqs[i].name, chg);
 943                if (rc) {
 944                        dev_err(&pdev->dev, "failed to request irq '%s'\n",
 945                                smbb_charger_irqs[i].name);
 946                        return rc;
 947                }
 948        }
 949
 950        /*
 951         * otg regulator is used to control VBUS voltage direction
 952         * when USB switches between host and gadget mode
 953         */
 954        chg->otg_rdesc.id = -1;
 955        chg->otg_rdesc.name = "otg-vbus";
 956        chg->otg_rdesc.ops = &smbb_chg_otg_ops;
 957        chg->otg_rdesc.owner = THIS_MODULE;
 958        chg->otg_rdesc.type = REGULATOR_VOLTAGE;
 959        chg->otg_rdesc.supply_name = "usb-otg-in";
 960        chg->otg_rdesc.of_match = "otg-vbus";
 961
 962        config.dev = &pdev->dev;
 963        config.driver_data = chg;
 964
 965        chg->otg_reg = devm_regulator_register(&pdev->dev, &chg->otg_rdesc,
 966                                               &config);
 967        if (IS_ERR(chg->otg_reg))
 968                return PTR_ERR(chg->otg_reg);
 969
 970        chg->jeita_ext_temp = of_property_read_bool(pdev->dev.of_node,
 971                        "qcom,jeita-extended-temp-range");
 972
 973        /* Set temperature range to [35%:70%] or [25%:80%] accordingly */
 974        rc = regmap_update_bits(chg->regmap, chg->addr + SMBB_BAT_BTC_CTRL,
 975                        BTC_CTRL_COLD_EXT | BTC_CTRL_HOT_EXT_N,
 976                        chg->jeita_ext_temp ?
 977                                BTC_CTRL_COLD_EXT :
 978                                BTC_CTRL_HOT_EXT_N);
 979        if (rc) {
 980                dev_err(&pdev->dev,
 981                        "unable to set %s temperature range\n",
 982                        chg->jeita_ext_temp ? "JEITA extended" : "normal");
 983                return rc;
 984        }
 985
 986        for (i = 0; i < ARRAY_SIZE(smbb_charger_setup); ++i) {
 987                const struct reg_off_mask_default *r = &smbb_charger_setup[i];
 988
 989                if (r->rev_mask & BIT(chg->revision))
 990                        continue;
 991
 992                rc = regmap_update_bits(chg->regmap, chg->addr + r->offset,
 993                                r->mask, r->value);
 994                if (rc) {
 995                        dev_err(&pdev->dev,
 996                                "unable to initializing charging, bailing\n");
 997                        return rc;
 998                }
 999        }
1000
1001        platform_set_drvdata(pdev, chg);
1002
1003        return 0;
1004}
1005
1006static int smbb_charger_remove(struct platform_device *pdev)
1007{
1008        struct smbb_charger *chg;
1009
1010        chg = platform_get_drvdata(pdev);
1011
1012        regmap_update_bits(chg->regmap, chg->addr + SMBB_CHG_CTRL, CTRL_EN, 0);
1013
1014        return 0;
1015}
1016
1017static const struct of_device_id smbb_charger_id_table[] = {
1018        { .compatible = "qcom,pm8941-charger" },
1019        { }
1020};
1021MODULE_DEVICE_TABLE(of, smbb_charger_id_table);
1022
1023static struct platform_driver smbb_charger_driver = {
1024        .probe    = smbb_charger_probe,
1025        .remove  = smbb_charger_remove,
1026        .driver  = {
1027                .name   = "qcom-smbb",
1028                .of_match_table = smbb_charger_id_table,
1029        },
1030};
1031module_platform_driver(smbb_charger_driver);
1032
1033MODULE_DESCRIPTION("Qualcomm Switch-Mode Battery Charger and Boost driver");
1034MODULE_LICENSE("GPL v2");
1035