root/drivers/power/supply/qcom_smbb.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. smbb_vbat_weak_fn
  2. smbb_vin_fn
  3. smbb_vmax_fn
  4. smbb_vbat_det_fn
  5. smbb_imax_fn
  6. smbb_bat_imax_fn
  7. smbb_hw_lookup
  8. smbb_charger_attr_write
  9. smbb_charger_attr_read
  10. smbb_charger_attr_parse
  11. smbb_set_line_flag
  12. smbb_usb_valid_handler
  13. smbb_dc_valid_handler
  14. smbb_bat_temp_handler
  15. smbb_bat_present_handler
  16. smbb_chg_done_handler
  17. smbb_chg_gone_handler
  18. smbb_chg_fast_handler
  19. smbb_chg_trkl_handler
  20. smbb_usbin_get_property
  21. smbb_usbin_set_property
  22. smbb_dcin_get_property
  23. smbb_dcin_set_property
  24. smbb_charger_writable_property
  25. smbb_battery_get_property
  26. smbb_battery_set_property
  27. smbb_battery_writable_property
  28. smbb_chg_otg_enable
  29. smbb_chg_otg_disable
  30. smbb_chg_otg_is_enabled
  31. smbb_charger_probe
  32. smbb_charger_remove

   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 
  93 enum 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 
 106 struct 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 
 128 static const unsigned int smbb_usb_extcon_cable[] = {
 129         EXTCON_USB,
 130         EXTCON_NONE,
 131 };
 132 
 133 static int smbb_vbat_weak_fn(unsigned int index)
 134 {
 135         return 2100000 + index * 100000;
 136 }
 137 
 138 static 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 
 145 static int smbb_vmax_fn(unsigned int index)
 146 {
 147         return 3240000 + index * 10000;
 148 }
 149 
 150 static int smbb_vbat_det_fn(unsigned int index)
 151 {
 152         return 3240000 + index * 20000;
 153 }
 154 
 155 static int smbb_imax_fn(unsigned int index)
 156 {
 157         if (index < 2)
 158                 return 100000 + index * 50000;
 159         return index * 100000;
 160 }
 161 
 162 static int smbb_bat_imax_fn(unsigned int index)
 163 {
 164         return index * 50000;
 165 }
 166 
 167 static 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 
 178 static 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 
 256 static 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 
 313 static 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 
 335 static 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 
 353 static 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 
 374 static 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 
 386 static 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 
 397 static 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 
 421 static 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 
 431 static 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 
 441 static 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 
 454 static 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 
 464 static 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 
 474 static 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 
 488 static 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 
 516 static 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 
 536 static 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 
 564 static 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 
 584 static 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 
 590 static 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 
 660 static 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 
 682 static 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 
 694 static 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 
 700 static 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 
 711 static 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 
 756 static char *smbb_bif[] = { "smbb-bif" };
 757 
 758 static 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 
 768 static 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 
 778 static 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 
 788 static 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 
 800 static 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 
 812 static 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 
 825 static 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 
 831 static 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 
1006 static 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 
1017 static const struct of_device_id smbb_charger_id_table[] = {
1018         { .compatible = "qcom,pm8941-charger" },
1019         { }
1020 };
1021 MODULE_DEVICE_TABLE(of, smbb_charger_id_table);
1022 
1023 static 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 };
1031 module_platform_driver(smbb_charger_driver);
1032 
1033 MODULE_DESCRIPTION("Qualcomm Switch-Mode Battery Charger and Boost driver");
1034 MODULE_LICENSE("GPL v2");

/* [<][>][^][v][top][bottom][index][help] */