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