0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019 #include <linux/errno.h>
0020 #include <linux/interrupt.h>
0021 #include <linux/kernel.h>
0022 #include <linux/module.h>
0023 #include <linux/mutex.h>
0024 #include <linux/of.h>
0025 #include <linux/platform_device.h>
0026 #include <linux/power_supply.h>
0027 #include <linux/regmap.h>
0028 #include <linux/slab.h>
0029 #include <linux/extcon-provider.h>
0030 #include <linux/regulator/driver.h>
0031
0032 #define SMBB_CHG_VMAX 0x040
0033 #define SMBB_CHG_VSAFE 0x041
0034 #define SMBB_CHG_CFG 0x043
0035 #define SMBB_CHG_IMAX 0x044
0036 #define SMBB_CHG_ISAFE 0x045
0037 #define SMBB_CHG_VIN_MIN 0x047
0038 #define SMBB_CHG_CTRL 0x049
0039 #define CTRL_EN BIT(7)
0040 #define SMBB_CHG_VBAT_WEAK 0x052
0041 #define SMBB_CHG_IBAT_TERM_CHG 0x05b
0042 #define IBAT_TERM_CHG_IEOC BIT(7)
0043 #define IBAT_TERM_CHG_IEOC_BMS BIT(7)
0044 #define IBAT_TERM_CHG_IEOC_CHG 0
0045 #define SMBB_CHG_VBAT_DET 0x05d
0046 #define SMBB_CHG_TCHG_MAX_EN 0x060
0047 #define TCHG_MAX_EN BIT(7)
0048 #define SMBB_CHG_WDOG_TIME 0x062
0049 #define SMBB_CHG_WDOG_EN 0x065
0050 #define WDOG_EN BIT(7)
0051
0052 #define SMBB_BUCK_REG_MODE 0x174
0053 #define BUCK_REG_MODE BIT(0)
0054 #define BUCK_REG_MODE_VBAT BIT(0)
0055 #define BUCK_REG_MODE_VSYS 0
0056
0057 #define SMBB_BAT_PRES_STATUS 0x208
0058 #define PRES_STATUS_BAT_PRES BIT(7)
0059 #define SMBB_BAT_TEMP_STATUS 0x209
0060 #define TEMP_STATUS_OK BIT(7)
0061 #define TEMP_STATUS_HOT BIT(6)
0062 #define SMBB_BAT_BTC_CTRL 0x249
0063 #define BTC_CTRL_COMP_EN BIT(7)
0064 #define BTC_CTRL_COLD_EXT BIT(1)
0065 #define BTC_CTRL_HOT_EXT_N BIT(0)
0066
0067 #define SMBB_USB_IMAX 0x344
0068 #define SMBB_USB_OTG_CTL 0x348
0069 #define OTG_CTL_EN BIT(0)
0070 #define SMBB_USB_ENUM_TIMER_STOP 0x34e
0071 #define ENUM_TIMER_STOP BIT(0)
0072 #define SMBB_USB_SEC_ACCESS 0x3d0
0073 #define SEC_ACCESS_MAGIC 0xa5
0074 #define SMBB_USB_REV_BST 0x3ed
0075 #define REV_BST_CHG_GONE BIT(7)
0076
0077 #define SMBB_DC_IMAX 0x444
0078
0079 #define SMBB_MISC_REV2 0x601
0080 #define SMBB_MISC_BOOT_DONE 0x642
0081 #define BOOT_DONE BIT(7)
0082
0083 #define STATUS_USBIN_VALID BIT(0)
0084 #define STATUS_DCIN_VALID BIT(1)
0085 #define STATUS_BAT_HOT BIT(2)
0086 #define STATUS_BAT_OK BIT(3)
0087 #define STATUS_BAT_PRESENT BIT(4)
0088 #define STATUS_CHG_DONE BIT(5)
0089 #define STATUS_CHG_TRKL BIT(6)
0090 #define STATUS_CHG_FAST BIT(7)
0091 #define STATUS_CHG_GONE BIT(8)
0092
0093 enum smbb_attr {
0094 ATTR_BAT_ISAFE,
0095 ATTR_BAT_IMAX,
0096 ATTR_USBIN_IMAX,
0097 ATTR_DCIN_IMAX,
0098 ATTR_BAT_VSAFE,
0099 ATTR_BAT_VMAX,
0100 ATTR_BAT_VMIN,
0101 ATTR_CHG_VDET,
0102 ATTR_VIN_MIN,
0103 _ATTR_CNT,
0104 };
0105
0106 struct smbb_charger {
0107 unsigned int revision;
0108 unsigned int addr;
0109 struct device *dev;
0110 struct extcon_dev *edev;
0111
0112 bool dc_disabled;
0113 bool jeita_ext_temp;
0114 unsigned long status;
0115 struct mutex statlock;
0116
0117 unsigned int attr[_ATTR_CNT];
0118
0119 struct power_supply *usb_psy;
0120 struct power_supply *dc_psy;
0121 struct power_supply *bat_psy;
0122 struct regmap *regmap;
0123
0124 struct regulator_desc otg_rdesc;
0125 struct regulator_dev *otg_reg;
0126 };
0127
0128 static const unsigned int smbb_usb_extcon_cable[] = {
0129 EXTCON_USB,
0130 EXTCON_NONE,
0131 };
0132
0133 static int smbb_vbat_weak_fn(unsigned int index)
0134 {
0135 return 2100000 + index * 100000;
0136 }
0137
0138 static int smbb_vin_fn(unsigned int index)
0139 {
0140 if (index > 42)
0141 return 5600000 + (index - 43) * 200000;
0142 return 3400000 + index * 50000;
0143 }
0144
0145 static int smbb_vmax_fn(unsigned int index)
0146 {
0147 return 3240000 + index * 10000;
0148 }
0149
0150 static int smbb_vbat_det_fn(unsigned int index)
0151 {
0152 return 3240000 + index * 20000;
0153 }
0154
0155 static int smbb_imax_fn(unsigned int index)
0156 {
0157 if (index < 2)
0158 return 100000 + index * 50000;
0159 return index * 100000;
0160 }
0161
0162 static int smbb_bat_imax_fn(unsigned int index)
0163 {
0164 return index * 50000;
0165 }
0166
0167 static unsigned int smbb_hw_lookup(unsigned int val, int (*fn)(unsigned int))
0168 {
0169 unsigned int widx;
0170 unsigned int sel;
0171
0172 for (widx = sel = 0; (*fn)(widx) <= val; ++widx)
0173 sel = widx;
0174
0175 return sel;
0176 }
0177
0178 static const struct smbb_charger_attr {
0179 const char *name;
0180 unsigned int reg;
0181 unsigned int safe_reg;
0182 unsigned int max;
0183 unsigned int min;
0184 unsigned int fail_ok;
0185 int (*hw_fn)(unsigned int);
0186 } smbb_charger_attrs[] = {
0187 [ATTR_BAT_ISAFE] = {
0188 .name = "qcom,fast-charge-safe-current",
0189 .reg = SMBB_CHG_ISAFE,
0190 .max = 3000000,
0191 .min = 200000,
0192 .hw_fn = smbb_bat_imax_fn,
0193 .fail_ok = 1,
0194 },
0195 [ATTR_BAT_IMAX] = {
0196 .name = "qcom,fast-charge-current-limit",
0197 .reg = SMBB_CHG_IMAX,
0198 .safe_reg = SMBB_CHG_ISAFE,
0199 .max = 3000000,
0200 .min = 200000,
0201 .hw_fn = smbb_bat_imax_fn,
0202 },
0203 [ATTR_DCIN_IMAX] = {
0204 .name = "qcom,dc-current-limit",
0205 .reg = SMBB_DC_IMAX,
0206 .max = 2500000,
0207 .min = 100000,
0208 .hw_fn = smbb_imax_fn,
0209 },
0210 [ATTR_BAT_VSAFE] = {
0211 .name = "qcom,fast-charge-safe-voltage",
0212 .reg = SMBB_CHG_VSAFE,
0213 .max = 5000000,
0214 .min = 3240000,
0215 .hw_fn = smbb_vmax_fn,
0216 .fail_ok = 1,
0217 },
0218 [ATTR_BAT_VMAX] = {
0219 .name = "qcom,fast-charge-high-threshold-voltage",
0220 .reg = SMBB_CHG_VMAX,
0221 .safe_reg = SMBB_CHG_VSAFE,
0222 .max = 5000000,
0223 .min = 3240000,
0224 .hw_fn = smbb_vmax_fn,
0225 },
0226 [ATTR_BAT_VMIN] = {
0227 .name = "qcom,fast-charge-low-threshold-voltage",
0228 .reg = SMBB_CHG_VBAT_WEAK,
0229 .max = 3600000,
0230 .min = 2100000,
0231 .hw_fn = smbb_vbat_weak_fn,
0232 },
0233 [ATTR_CHG_VDET] = {
0234 .name = "qcom,auto-recharge-threshold-voltage",
0235 .reg = SMBB_CHG_VBAT_DET,
0236 .max = 5000000,
0237 .min = 3240000,
0238 .hw_fn = smbb_vbat_det_fn,
0239 },
0240 [ATTR_VIN_MIN] = {
0241 .name = "qcom,minimum-input-voltage",
0242 .reg = SMBB_CHG_VIN_MIN,
0243 .max = 9600000,
0244 .min = 4200000,
0245 .hw_fn = smbb_vin_fn,
0246 },
0247 [ATTR_USBIN_IMAX] = {
0248 .name = "usb-charge-current-limit",
0249 .reg = SMBB_USB_IMAX,
0250 .max = 2500000,
0251 .min = 100000,
0252 .hw_fn = smbb_imax_fn,
0253 },
0254 };
0255
0256 static int smbb_charger_attr_write(struct smbb_charger *chg,
0257 enum smbb_attr which, unsigned int val)
0258 {
0259 const struct smbb_charger_attr *prop;
0260 unsigned int wval;
0261 unsigned int out;
0262 int rc;
0263
0264 prop = &smbb_charger_attrs[which];
0265
0266 if (val > prop->max || val < prop->min) {
0267 dev_err(chg->dev, "value out of range for %s [%u:%u]\n",
0268 prop->name, prop->min, prop->max);
0269 return -EINVAL;
0270 }
0271
0272 if (prop->safe_reg) {
0273 rc = regmap_read(chg->regmap,
0274 chg->addr + prop->safe_reg, &wval);
0275 if (rc) {
0276 dev_err(chg->dev,
0277 "unable to read safe value for '%s'\n",
0278 prop->name);
0279 return rc;
0280 }
0281
0282 wval = prop->hw_fn(wval);
0283
0284 if (val > wval) {
0285 dev_warn(chg->dev,
0286 "%s above safe value, clamping at %u\n",
0287 prop->name, wval);
0288 val = wval;
0289 }
0290 }
0291
0292 wval = smbb_hw_lookup(val, prop->hw_fn);
0293
0294 rc = regmap_write(chg->regmap, chg->addr + prop->reg, wval);
0295 if (rc) {
0296 dev_err(chg->dev, "unable to update %s", prop->name);
0297 return rc;
0298 }
0299 out = prop->hw_fn(wval);
0300 if (out != val) {
0301 dev_warn(chg->dev,
0302 "%s inaccurate, rounded to %u\n",
0303 prop->name, out);
0304 }
0305
0306 dev_dbg(chg->dev, "%s <= %d\n", prop->name, out);
0307
0308 chg->attr[which] = out;
0309
0310 return 0;
0311 }
0312
0313 static int smbb_charger_attr_read(struct smbb_charger *chg,
0314 enum smbb_attr which)
0315 {
0316 const struct smbb_charger_attr *prop;
0317 unsigned int val;
0318 int rc;
0319
0320 prop = &smbb_charger_attrs[which];
0321
0322 rc = regmap_read(chg->regmap, chg->addr + prop->reg, &val);
0323 if (rc) {
0324 dev_err(chg->dev, "failed to read %s\n", prop->name);
0325 return rc;
0326 }
0327 val = prop->hw_fn(val);
0328 dev_dbg(chg->dev, "%s => %d\n", prop->name, val);
0329
0330 chg->attr[which] = val;
0331
0332 return 0;
0333 }
0334
0335 static int smbb_charger_attr_parse(struct smbb_charger *chg,
0336 enum smbb_attr which)
0337 {
0338 const struct smbb_charger_attr *prop;
0339 unsigned int val;
0340 int rc;
0341
0342 prop = &smbb_charger_attrs[which];
0343
0344 rc = of_property_read_u32(chg->dev->of_node, prop->name, &val);
0345 if (rc == 0) {
0346 rc = smbb_charger_attr_write(chg, which, val);
0347 if (!rc || !prop->fail_ok)
0348 return rc;
0349 }
0350 return smbb_charger_attr_read(chg, which);
0351 }
0352
0353 static void smbb_set_line_flag(struct smbb_charger *chg, int irq, int flag)
0354 {
0355 bool state;
0356 int ret;
0357
0358 ret = irq_get_irqchip_state(irq, IRQCHIP_STATE_LINE_LEVEL, &state);
0359 if (ret < 0) {
0360 dev_err(chg->dev, "failed to read irq line\n");
0361 return;
0362 }
0363
0364 mutex_lock(&chg->statlock);
0365 if (state)
0366 chg->status |= flag;
0367 else
0368 chg->status &= ~flag;
0369 mutex_unlock(&chg->statlock);
0370
0371 dev_dbg(chg->dev, "status = %03lx\n", chg->status);
0372 }
0373
0374 static irqreturn_t smbb_usb_valid_handler(int irq, void *_data)
0375 {
0376 struct smbb_charger *chg = _data;
0377
0378 smbb_set_line_flag(chg, irq, STATUS_USBIN_VALID);
0379 extcon_set_state_sync(chg->edev, EXTCON_USB,
0380 chg->status & STATUS_USBIN_VALID);
0381 power_supply_changed(chg->usb_psy);
0382
0383 return IRQ_HANDLED;
0384 }
0385
0386 static irqreturn_t smbb_dc_valid_handler(int irq, void *_data)
0387 {
0388 struct smbb_charger *chg = _data;
0389
0390 smbb_set_line_flag(chg, irq, STATUS_DCIN_VALID);
0391 if (!chg->dc_disabled)
0392 power_supply_changed(chg->dc_psy);
0393
0394 return IRQ_HANDLED;
0395 }
0396
0397 static irqreturn_t smbb_bat_temp_handler(int irq, void *_data)
0398 {
0399 struct smbb_charger *chg = _data;
0400 unsigned int val;
0401 int rc;
0402
0403 rc = regmap_read(chg->regmap, chg->addr + SMBB_BAT_TEMP_STATUS, &val);
0404 if (rc)
0405 return IRQ_HANDLED;
0406
0407 mutex_lock(&chg->statlock);
0408 if (val & TEMP_STATUS_OK) {
0409 chg->status |= STATUS_BAT_OK;
0410 } else {
0411 chg->status &= ~STATUS_BAT_OK;
0412 if (val & TEMP_STATUS_HOT)
0413 chg->status |= STATUS_BAT_HOT;
0414 }
0415 mutex_unlock(&chg->statlock);
0416
0417 power_supply_changed(chg->bat_psy);
0418 return IRQ_HANDLED;
0419 }
0420
0421 static irqreturn_t smbb_bat_present_handler(int irq, void *_data)
0422 {
0423 struct smbb_charger *chg = _data;
0424
0425 smbb_set_line_flag(chg, irq, STATUS_BAT_PRESENT);
0426 power_supply_changed(chg->bat_psy);
0427
0428 return IRQ_HANDLED;
0429 }
0430
0431 static irqreturn_t smbb_chg_done_handler(int irq, void *_data)
0432 {
0433 struct smbb_charger *chg = _data;
0434
0435 smbb_set_line_flag(chg, irq, STATUS_CHG_DONE);
0436 power_supply_changed(chg->bat_psy);
0437
0438 return IRQ_HANDLED;
0439 }
0440
0441 static irqreturn_t smbb_chg_gone_handler(int irq, void *_data)
0442 {
0443 struct smbb_charger *chg = _data;
0444
0445 smbb_set_line_flag(chg, irq, STATUS_CHG_GONE);
0446 power_supply_changed(chg->bat_psy);
0447 power_supply_changed(chg->usb_psy);
0448 if (!chg->dc_disabled)
0449 power_supply_changed(chg->dc_psy);
0450
0451 return IRQ_HANDLED;
0452 }
0453
0454 static irqreturn_t smbb_chg_fast_handler(int irq, void *_data)
0455 {
0456 struct smbb_charger *chg = _data;
0457
0458 smbb_set_line_flag(chg, irq, STATUS_CHG_FAST);
0459 power_supply_changed(chg->bat_psy);
0460
0461 return IRQ_HANDLED;
0462 }
0463
0464 static irqreturn_t smbb_chg_trkl_handler(int irq, void *_data)
0465 {
0466 struct smbb_charger *chg = _data;
0467
0468 smbb_set_line_flag(chg, irq, STATUS_CHG_TRKL);
0469 power_supply_changed(chg->bat_psy);
0470
0471 return IRQ_HANDLED;
0472 }
0473
0474 static const struct smbb_irq {
0475 const char *name;
0476 irqreturn_t (*handler)(int, void *);
0477 } smbb_charger_irqs[] = {
0478 { "chg-done", smbb_chg_done_handler },
0479 { "chg-fast", smbb_chg_fast_handler },
0480 { "chg-trkl", smbb_chg_trkl_handler },
0481 { "bat-temp-ok", smbb_bat_temp_handler },
0482 { "bat-present", smbb_bat_present_handler },
0483 { "chg-gone", smbb_chg_gone_handler },
0484 { "usb-valid", smbb_usb_valid_handler },
0485 { "dc-valid", smbb_dc_valid_handler },
0486 };
0487
0488 static int smbb_usbin_get_property(struct power_supply *psy,
0489 enum power_supply_property psp,
0490 union power_supply_propval *val)
0491 {
0492 struct smbb_charger *chg = power_supply_get_drvdata(psy);
0493 int rc = 0;
0494
0495 switch (psp) {
0496 case POWER_SUPPLY_PROP_ONLINE:
0497 mutex_lock(&chg->statlock);
0498 val->intval = !(chg->status & STATUS_CHG_GONE) &&
0499 (chg->status & STATUS_USBIN_VALID);
0500 mutex_unlock(&chg->statlock);
0501 break;
0502 case POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT:
0503 val->intval = chg->attr[ATTR_USBIN_IMAX];
0504 break;
0505 case POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT_MAX:
0506 val->intval = 2500000;
0507 break;
0508 default:
0509 rc = -EINVAL;
0510 break;
0511 }
0512
0513 return rc;
0514 }
0515
0516 static int smbb_usbin_set_property(struct power_supply *psy,
0517 enum power_supply_property psp,
0518 const union power_supply_propval *val)
0519 {
0520 struct smbb_charger *chg = power_supply_get_drvdata(psy);
0521 int rc;
0522
0523 switch (psp) {
0524 case POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT:
0525 rc = smbb_charger_attr_write(chg, ATTR_USBIN_IMAX,
0526 val->intval);
0527 break;
0528 default:
0529 rc = -EINVAL;
0530 break;
0531 }
0532
0533 return rc;
0534 }
0535
0536 static int smbb_dcin_get_property(struct power_supply *psy,
0537 enum power_supply_property psp,
0538 union power_supply_propval *val)
0539 {
0540 struct smbb_charger *chg = power_supply_get_drvdata(psy);
0541 int rc = 0;
0542
0543 switch (psp) {
0544 case POWER_SUPPLY_PROP_ONLINE:
0545 mutex_lock(&chg->statlock);
0546 val->intval = !(chg->status & STATUS_CHG_GONE) &&
0547 (chg->status & STATUS_DCIN_VALID);
0548 mutex_unlock(&chg->statlock);
0549 break;
0550 case POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT:
0551 val->intval = chg->attr[ATTR_DCIN_IMAX];
0552 break;
0553 case POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT_MAX:
0554 val->intval = 2500000;
0555 break;
0556 default:
0557 rc = -EINVAL;
0558 break;
0559 }
0560
0561 return rc;
0562 }
0563
0564 static int smbb_dcin_set_property(struct power_supply *psy,
0565 enum power_supply_property psp,
0566 const union power_supply_propval *val)
0567 {
0568 struct smbb_charger *chg = power_supply_get_drvdata(psy);
0569 int rc;
0570
0571 switch (psp) {
0572 case POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT:
0573 rc = smbb_charger_attr_write(chg, ATTR_DCIN_IMAX,
0574 val->intval);
0575 break;
0576 default:
0577 rc = -EINVAL;
0578 break;
0579 }
0580
0581 return rc;
0582 }
0583
0584 static int smbb_charger_writable_property(struct power_supply *psy,
0585 enum power_supply_property psp)
0586 {
0587 return psp == POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT;
0588 }
0589
0590 static int smbb_battery_get_property(struct power_supply *psy,
0591 enum power_supply_property psp,
0592 union power_supply_propval *val)
0593 {
0594 struct smbb_charger *chg = power_supply_get_drvdata(psy);
0595 unsigned long status;
0596 int rc = 0;
0597
0598 mutex_lock(&chg->statlock);
0599 status = chg->status;
0600 mutex_unlock(&chg->statlock);
0601
0602 switch (psp) {
0603 case POWER_SUPPLY_PROP_STATUS:
0604 if (status & STATUS_CHG_GONE)
0605 val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
0606 else if (!(status & (STATUS_DCIN_VALID | STATUS_USBIN_VALID)))
0607 val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
0608 else if (status & STATUS_CHG_DONE)
0609 val->intval = POWER_SUPPLY_STATUS_FULL;
0610 else if (!(status & STATUS_BAT_OK))
0611 val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
0612 else if (status & (STATUS_CHG_FAST | STATUS_CHG_TRKL))
0613 val->intval = POWER_SUPPLY_STATUS_CHARGING;
0614 else
0615 val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
0616 break;
0617 case POWER_SUPPLY_PROP_HEALTH:
0618 if (status & STATUS_BAT_OK)
0619 val->intval = POWER_SUPPLY_HEALTH_GOOD;
0620 else if (status & STATUS_BAT_HOT)
0621 val->intval = POWER_SUPPLY_HEALTH_OVERHEAT;
0622 else
0623 val->intval = POWER_SUPPLY_HEALTH_COLD;
0624 break;
0625 case POWER_SUPPLY_PROP_CHARGE_TYPE:
0626 if (status & STATUS_CHG_FAST)
0627 val->intval = POWER_SUPPLY_CHARGE_TYPE_FAST;
0628 else if (status & STATUS_CHG_TRKL)
0629 val->intval = POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
0630 else
0631 val->intval = POWER_SUPPLY_CHARGE_TYPE_NONE;
0632 break;
0633 case POWER_SUPPLY_PROP_PRESENT:
0634 val->intval = !!(status & STATUS_BAT_PRESENT);
0635 break;
0636 case POWER_SUPPLY_PROP_CURRENT_MAX:
0637 val->intval = chg->attr[ATTR_BAT_IMAX];
0638 break;
0639 case POWER_SUPPLY_PROP_VOLTAGE_MAX:
0640 val->intval = chg->attr[ATTR_BAT_VMAX];
0641 break;
0642 case POWER_SUPPLY_PROP_TECHNOLOGY:
0643
0644
0645
0646
0647 val->intval = POWER_SUPPLY_TECHNOLOGY_LION;
0648 break;
0649 case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN:
0650 val->intval = 3000000;
0651 break;
0652 default:
0653 rc = -EINVAL;
0654 break;
0655 }
0656
0657 return rc;
0658 }
0659
0660 static int smbb_battery_set_property(struct power_supply *psy,
0661 enum power_supply_property psp,
0662 const union power_supply_propval *val)
0663 {
0664 struct smbb_charger *chg = power_supply_get_drvdata(psy);
0665 int rc;
0666
0667 switch (psp) {
0668 case POWER_SUPPLY_PROP_CURRENT_MAX:
0669 rc = smbb_charger_attr_write(chg, ATTR_BAT_IMAX, val->intval);
0670 break;
0671 case POWER_SUPPLY_PROP_VOLTAGE_MAX:
0672 rc = smbb_charger_attr_write(chg, ATTR_BAT_VMAX, val->intval);
0673 break;
0674 default:
0675 rc = -EINVAL;
0676 break;
0677 }
0678
0679 return rc;
0680 }
0681
0682 static int smbb_battery_writable_property(struct power_supply *psy,
0683 enum power_supply_property psp)
0684 {
0685 switch (psp) {
0686 case POWER_SUPPLY_PROP_CURRENT_MAX:
0687 case POWER_SUPPLY_PROP_VOLTAGE_MAX:
0688 return 1;
0689 default:
0690 return 0;
0691 }
0692 }
0693
0694 static enum power_supply_property smbb_charger_properties[] = {
0695 POWER_SUPPLY_PROP_ONLINE,
0696 POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT,
0697 POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT_MAX,
0698 };
0699
0700 static enum power_supply_property smbb_battery_properties[] = {
0701 POWER_SUPPLY_PROP_STATUS,
0702 POWER_SUPPLY_PROP_HEALTH,
0703 POWER_SUPPLY_PROP_PRESENT,
0704 POWER_SUPPLY_PROP_CHARGE_TYPE,
0705 POWER_SUPPLY_PROP_CURRENT_MAX,
0706 POWER_SUPPLY_PROP_VOLTAGE_MAX,
0707 POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,
0708 POWER_SUPPLY_PROP_TECHNOLOGY,
0709 };
0710
0711 static const struct reg_off_mask_default {
0712 unsigned int offset;
0713 unsigned int mask;
0714 unsigned int value;
0715 unsigned int rev_mask;
0716 } smbb_charger_setup[] = {
0717
0718 { SMBB_MISC_BOOT_DONE, BOOT_DONE, BOOT_DONE },
0719
0720
0721 { SMBB_CHG_TCHG_MAX_EN, TCHG_MAX_EN, 0 },
0722
0723
0724 { SMBB_CHG_WDOG_TIME, 0xff, 160 },
0725 { SMBB_CHG_WDOG_EN, WDOG_EN, 0 },
0726
0727
0728 { SMBB_CHG_IBAT_TERM_CHG, IBAT_TERM_CHG_IEOC, IBAT_TERM_CHG_IEOC_CHG },
0729
0730
0731
0732
0733 { SMBB_CHG_CFG, 0xff, 0x00, BIT(3) },
0734
0735
0736 { SMBB_BUCK_REG_MODE, BUCK_REG_MODE, BUCK_REG_MODE_VBAT },
0737
0738
0739 { SMBB_BAT_BTC_CTRL, BTC_CTRL_COMP_EN, BTC_CTRL_COMP_EN },
0740
0741
0742 { SMBB_USB_ENUM_TIMER_STOP, ENUM_TIMER_STOP, ENUM_TIMER_STOP },
0743
0744 #if 0
0745 { SMBB_USB_SEC_ACCESS, SEC_ACCESS_MAGIC },
0746 { SMBB_USB_REV_BST, 0xff, REV_BST_CHG_GONE },
0747 #endif
0748
0749
0750 { SMBB_USB_ENUM_TIMER_STOP, ENUM_TIMER_STOP, ENUM_TIMER_STOP },
0751
0752
0753 { SMBB_CHG_CTRL, CTRL_EN, CTRL_EN },
0754 };
0755
0756 static char *smbb_bif[] = { "smbb-bif" };
0757
0758 static const struct power_supply_desc bat_psy_desc = {
0759 .name = "smbb-bif",
0760 .type = POWER_SUPPLY_TYPE_BATTERY,
0761 .properties = smbb_battery_properties,
0762 .num_properties = ARRAY_SIZE(smbb_battery_properties),
0763 .get_property = smbb_battery_get_property,
0764 .set_property = smbb_battery_set_property,
0765 .property_is_writeable = smbb_battery_writable_property,
0766 };
0767
0768 static const struct power_supply_desc usb_psy_desc = {
0769 .name = "smbb-usbin",
0770 .type = POWER_SUPPLY_TYPE_USB,
0771 .properties = smbb_charger_properties,
0772 .num_properties = ARRAY_SIZE(smbb_charger_properties),
0773 .get_property = smbb_usbin_get_property,
0774 .set_property = smbb_usbin_set_property,
0775 .property_is_writeable = smbb_charger_writable_property,
0776 };
0777
0778 static const struct power_supply_desc dc_psy_desc = {
0779 .name = "smbb-dcin",
0780 .type = POWER_SUPPLY_TYPE_MAINS,
0781 .properties = smbb_charger_properties,
0782 .num_properties = ARRAY_SIZE(smbb_charger_properties),
0783 .get_property = smbb_dcin_get_property,
0784 .set_property = smbb_dcin_set_property,
0785 .property_is_writeable = smbb_charger_writable_property,
0786 };
0787
0788 static int smbb_chg_otg_enable(struct regulator_dev *rdev)
0789 {
0790 struct smbb_charger *chg = rdev_get_drvdata(rdev);
0791 int rc;
0792
0793 rc = regmap_update_bits(chg->regmap, chg->addr + SMBB_USB_OTG_CTL,
0794 OTG_CTL_EN, OTG_CTL_EN);
0795 if (rc)
0796 dev_err(chg->dev, "failed to update OTG_CTL\n");
0797 return rc;
0798 }
0799
0800 static int smbb_chg_otg_disable(struct regulator_dev *rdev)
0801 {
0802 struct smbb_charger *chg = rdev_get_drvdata(rdev);
0803 int rc;
0804
0805 rc = regmap_update_bits(chg->regmap, chg->addr + SMBB_USB_OTG_CTL,
0806 OTG_CTL_EN, 0);
0807 if (rc)
0808 dev_err(chg->dev, "failed to update OTG_CTL\n");
0809 return rc;
0810 }
0811
0812 static int smbb_chg_otg_is_enabled(struct regulator_dev *rdev)
0813 {
0814 struct smbb_charger *chg = rdev_get_drvdata(rdev);
0815 unsigned int value = 0;
0816 int rc;
0817
0818 rc = regmap_read(chg->regmap, chg->addr + SMBB_USB_OTG_CTL, &value);
0819 if (rc)
0820 dev_err(chg->dev, "failed to read OTG_CTL\n");
0821
0822 return !!(value & OTG_CTL_EN);
0823 }
0824
0825 static const struct regulator_ops smbb_chg_otg_ops = {
0826 .enable = smbb_chg_otg_enable,
0827 .disable = smbb_chg_otg_disable,
0828 .is_enabled = smbb_chg_otg_is_enabled,
0829 };
0830
0831 static int smbb_charger_probe(struct platform_device *pdev)
0832 {
0833 struct power_supply_config bat_cfg = {};
0834 struct power_supply_config usb_cfg = {};
0835 struct power_supply_config dc_cfg = {};
0836 struct smbb_charger *chg;
0837 struct regulator_config config = { };
0838 int rc, i;
0839
0840 chg = devm_kzalloc(&pdev->dev, sizeof(*chg), GFP_KERNEL);
0841 if (!chg)
0842 return -ENOMEM;
0843
0844 chg->dev = &pdev->dev;
0845 mutex_init(&chg->statlock);
0846
0847 chg->regmap = dev_get_regmap(pdev->dev.parent, NULL);
0848 if (!chg->regmap) {
0849 dev_err(&pdev->dev, "failed to locate regmap\n");
0850 return -ENODEV;
0851 }
0852
0853 rc = of_property_read_u32(pdev->dev.of_node, "reg", &chg->addr);
0854 if (rc) {
0855 dev_err(&pdev->dev, "missing or invalid 'reg' property\n");
0856 return rc;
0857 }
0858
0859 rc = regmap_read(chg->regmap, chg->addr + SMBB_MISC_REV2, &chg->revision);
0860 if (rc) {
0861 dev_err(&pdev->dev, "unable to read revision\n");
0862 return rc;
0863 }
0864
0865 chg->revision += 1;
0866 if (chg->revision != 1 && chg->revision != 2 && chg->revision != 3) {
0867 dev_err(&pdev->dev, "v%d hardware not supported\n", chg->revision);
0868 return -ENODEV;
0869 }
0870 dev_info(&pdev->dev, "Initializing SMBB rev %u", chg->revision);
0871
0872 chg->dc_disabled = of_property_read_bool(pdev->dev.of_node, "qcom,disable-dc");
0873
0874 for (i = 0; i < _ATTR_CNT; ++i) {
0875 rc = smbb_charger_attr_parse(chg, i);
0876 if (rc) {
0877 dev_err(&pdev->dev, "failed to parse/apply settings\n");
0878 return rc;
0879 }
0880 }
0881
0882 bat_cfg.drv_data = chg;
0883 bat_cfg.of_node = pdev->dev.of_node;
0884 chg->bat_psy = devm_power_supply_register(&pdev->dev,
0885 &bat_psy_desc,
0886 &bat_cfg);
0887 if (IS_ERR(chg->bat_psy)) {
0888 dev_err(&pdev->dev, "failed to register battery\n");
0889 return PTR_ERR(chg->bat_psy);
0890 }
0891
0892 usb_cfg.drv_data = chg;
0893 usb_cfg.supplied_to = smbb_bif;
0894 usb_cfg.num_supplicants = ARRAY_SIZE(smbb_bif);
0895 chg->usb_psy = devm_power_supply_register(&pdev->dev,
0896 &usb_psy_desc,
0897 &usb_cfg);
0898 if (IS_ERR(chg->usb_psy)) {
0899 dev_err(&pdev->dev, "failed to register USB power supply\n");
0900 return PTR_ERR(chg->usb_psy);
0901 }
0902
0903 chg->edev = devm_extcon_dev_allocate(&pdev->dev, smbb_usb_extcon_cable);
0904 if (IS_ERR(chg->edev)) {
0905 dev_err(&pdev->dev, "failed to allocate extcon device\n");
0906 return -ENOMEM;
0907 }
0908
0909 rc = devm_extcon_dev_register(&pdev->dev, chg->edev);
0910 if (rc < 0) {
0911 dev_err(&pdev->dev, "failed to register extcon device\n");
0912 return rc;
0913 }
0914
0915 if (!chg->dc_disabled) {
0916 dc_cfg.drv_data = chg;
0917 dc_cfg.supplied_to = smbb_bif;
0918 dc_cfg.num_supplicants = ARRAY_SIZE(smbb_bif);
0919 chg->dc_psy = devm_power_supply_register(&pdev->dev,
0920 &dc_psy_desc,
0921 &dc_cfg);
0922 if (IS_ERR(chg->dc_psy)) {
0923 dev_err(&pdev->dev, "failed to register DC power supply\n");
0924 return PTR_ERR(chg->dc_psy);
0925 }
0926 }
0927
0928 for (i = 0; i < ARRAY_SIZE(smbb_charger_irqs); ++i) {
0929 int irq;
0930
0931 irq = platform_get_irq_byname(pdev, smbb_charger_irqs[i].name);
0932 if (irq < 0)
0933 return irq;
0934
0935 smbb_charger_irqs[i].handler(irq, chg);
0936
0937 rc = devm_request_threaded_irq(&pdev->dev, irq, NULL,
0938 smbb_charger_irqs[i].handler, IRQF_ONESHOT,
0939 smbb_charger_irqs[i].name, chg);
0940 if (rc) {
0941 dev_err(&pdev->dev, "failed to request irq '%s'\n",
0942 smbb_charger_irqs[i].name);
0943 return rc;
0944 }
0945 }
0946
0947
0948
0949
0950
0951 chg->otg_rdesc.id = -1;
0952 chg->otg_rdesc.name = "otg-vbus";
0953 chg->otg_rdesc.ops = &smbb_chg_otg_ops;
0954 chg->otg_rdesc.owner = THIS_MODULE;
0955 chg->otg_rdesc.type = REGULATOR_VOLTAGE;
0956 chg->otg_rdesc.supply_name = "usb-otg-in";
0957 chg->otg_rdesc.of_match = "otg-vbus";
0958
0959 config.dev = &pdev->dev;
0960 config.driver_data = chg;
0961
0962 chg->otg_reg = devm_regulator_register(&pdev->dev, &chg->otg_rdesc,
0963 &config);
0964 if (IS_ERR(chg->otg_reg))
0965 return PTR_ERR(chg->otg_reg);
0966
0967 chg->jeita_ext_temp = of_property_read_bool(pdev->dev.of_node,
0968 "qcom,jeita-extended-temp-range");
0969
0970
0971 rc = regmap_update_bits(chg->regmap, chg->addr + SMBB_BAT_BTC_CTRL,
0972 BTC_CTRL_COLD_EXT | BTC_CTRL_HOT_EXT_N,
0973 chg->jeita_ext_temp ?
0974 BTC_CTRL_COLD_EXT :
0975 BTC_CTRL_HOT_EXT_N);
0976 if (rc) {
0977 dev_err(&pdev->dev,
0978 "unable to set %s temperature range\n",
0979 chg->jeita_ext_temp ? "JEITA extended" : "normal");
0980 return rc;
0981 }
0982
0983 for (i = 0; i < ARRAY_SIZE(smbb_charger_setup); ++i) {
0984 const struct reg_off_mask_default *r = &smbb_charger_setup[i];
0985
0986 if (r->rev_mask & BIT(chg->revision))
0987 continue;
0988
0989 rc = regmap_update_bits(chg->regmap, chg->addr + r->offset,
0990 r->mask, r->value);
0991 if (rc) {
0992 dev_err(&pdev->dev,
0993 "unable to initializing charging, bailing\n");
0994 return rc;
0995 }
0996 }
0997
0998 platform_set_drvdata(pdev, chg);
0999
1000 return 0;
1001 }
1002
1003 static int smbb_charger_remove(struct platform_device *pdev)
1004 {
1005 struct smbb_charger *chg;
1006
1007 chg = platform_get_drvdata(pdev);
1008
1009 regmap_update_bits(chg->regmap, chg->addr + SMBB_CHG_CTRL, CTRL_EN, 0);
1010
1011 return 0;
1012 }
1013
1014 static const struct of_device_id smbb_charger_id_table[] = {
1015 { .compatible = "qcom,pm8226-charger" },
1016 { .compatible = "qcom,pm8941-charger" },
1017 { }
1018 };
1019 MODULE_DEVICE_TABLE(of, smbb_charger_id_table);
1020
1021 static struct platform_driver smbb_charger_driver = {
1022 .probe = smbb_charger_probe,
1023 .remove = smbb_charger_remove,
1024 .driver = {
1025 .name = "qcom-smbb",
1026 .of_match_table = smbb_charger_id_table,
1027 },
1028 };
1029 module_platform_driver(smbb_charger_driver);
1030
1031 MODULE_DESCRIPTION("Qualcomm Switch-Mode Battery Charger and Boost driver");
1032 MODULE_LICENSE("GPL v2");