Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /* Copyright (c) 2014, Sony Mobile Communications Inc.
0003  *
0004  * This driver is for the multi-block Switch-Mode Battery Charger and Boost
0005  * (SMBB) hardware, found in Qualcomm PM8941 PMICs.  The charger is an
0006  * integrated, single-cell lithium-ion battery charger.
0007  *
0008  * Sub-components:
0009  *  - Charger core
0010  *  - Buck
0011  *  - DC charge-path
0012  *  - USB charge-path
0013  *  - Battery interface
0014  *  - Boost (not implemented)
0015  *  - Misc
0016  *  - HF-Buck
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) /* USB connection is valid */
0084 #define STATUS_DCIN_VALID   BIT(1) /* DC connection is valid */
0085 #define STATUS_BAT_HOT      BIT(2) /* Battery temp 1=Hot, 0=Cold */
0086 #define STATUS_BAT_OK       BIT(3) /* Battery temp OK */
0087 #define STATUS_BAT_PRESENT  BIT(4) /* Battery is present */
0088 #define STATUS_CHG_DONE     BIT(5) /* Charge cycle is complete */
0089 #define STATUS_CHG_TRKL     BIT(6) /* Trickle charging */
0090 #define STATUS_CHG_FAST     BIT(7) /* Fast charging */
0091 #define STATUS_CHG_GONE     BIT(8) /* No charger is connected */
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 /* everything is ok for charging, but we are not... */
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         /* this charger is a single-cell lithium-ion battery charger
0644         * only.  If you hook up some other technology, there will be
0645         * fireworks.
0646         */
0647         val->intval = POWER_SUPPLY_TECHNOLOGY_LION;
0648         break;
0649     case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN:
0650         val->intval = 3000000; /* single-cell li-ion low end */
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     /* The bootloader is supposed to set this... make sure anyway. */
0718     { SMBB_MISC_BOOT_DONE, BOOT_DONE, BOOT_DONE },
0719 
0720     /* Disable software timer */
0721     { SMBB_CHG_TCHG_MAX_EN, TCHG_MAX_EN, 0 },
0722 
0723     /* Clear and disable watchdog */
0724     { SMBB_CHG_WDOG_TIME, 0xff, 160 },
0725     { SMBB_CHG_WDOG_EN, WDOG_EN, 0 },
0726 
0727     /* Use charger based EoC detection */
0728     { SMBB_CHG_IBAT_TERM_CHG, IBAT_TERM_CHG_IEOC, IBAT_TERM_CHG_IEOC_CHG },
0729 
0730     /* Disable GSM PA load adjustment.
0731     * The PA signal is incorrectly connected on v2.
0732     */
0733     { SMBB_CHG_CFG, 0xff, 0x00, BIT(3) },
0734 
0735     /* Use VBAT (not VSYS) to compensate for IR drop during fast charging */
0736     { SMBB_BUCK_REG_MODE, BUCK_REG_MODE, BUCK_REG_MODE_VBAT },
0737 
0738     /* Enable battery temperature comparators */
0739     { SMBB_BAT_BTC_CTRL, BTC_CTRL_COMP_EN, BTC_CTRL_COMP_EN },
0740 
0741     /* Stop USB enumeration timer */
0742     { SMBB_USB_ENUM_TIMER_STOP, ENUM_TIMER_STOP, ENUM_TIMER_STOP },
0743 
0744 #if 0 /* FIXME supposedly only to disable hardware ARB termination */
0745     { SMBB_USB_SEC_ACCESS, SEC_ACCESS_MAGIC },
0746     { SMBB_USB_REV_BST, 0xff, REV_BST_CHG_GONE },
0747 #endif
0748 
0749     /* Stop USB enumeration timer, again */
0750     { SMBB_USB_ENUM_TIMER_STOP, ENUM_TIMER_STOP, ENUM_TIMER_STOP },
0751 
0752     /* Enable charging */
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      * otg regulator is used to control VBUS voltage direction
0949      * when USB switches between host and gadget mode
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     /* Set temperature range to [35%:70%] or [25%:80%] accordingly */
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");