static int __devinit smb349_hwinit(struct smb349_struct *smb349_chg) { int ret; ret = smb349_write_reg(smb349_chg->client, CMD_A_REG, VOLATILE_W_PERM_BIT); if (ret) { pr_err("Failed to set VOLATILE_W_PERM_BIT rc=%d\n", ret); return ret; } ret = smb349_masked_write(smb349_chg->client, CHG_CTRL_REG, CURR_TERM_END_CHG_BIT, CURR_TERM_END_CHG_BIT); if (ret) { pr_err("Failed to set CURR_TERM_END_CHG_BIT rc=%d\n", ret); return ret; } ret = chg_current_set(smb349_chg); if (ret) { pr_err("Failed to set FAST_CHG_CURRENT rc=%d\n", ret); return ret; } return 0; }
static int smb349_chg_otg_regulator_disable(struct regulator_dev *rdev) { int rc = 0; struct smb349_charger *chip = rdev_get_drvdata(rdev); rc = smb349_masked_write(chip, CMD_A_REG, CMD_A_OTG_ENABLE_BIT, 0); if (rc) dev_err(chip->dev, "Couldn't disable OTG mode rc=%d\n", rc); return rc; }
static int smb349_enable_volatile_writes(struct smb349_charger *chip) { int rc; rc = smb349_masked_write(chip, CMD_A_REG, CMD_A_VOLATILE_W_PERM_BIT, CMD_A_VOLATILE_W_PERM_BIT); if (rc) dev_err(chip->dev, "Couldn't write VOLATILE_W_PERM_BIT rc=%d\n", rc); return rc; }
static int smb349_float_voltage_set(struct smb349_charger *chip, int vfloat_mv) { u8 temp; if ((vfloat_mv < MIN_FLOAT_MV) || (vfloat_mv > MAX_FLOAT_MV)) { dev_err(chip->dev, "bad float voltage mv =%d asked to set\n", vfloat_mv); return -EINVAL; } temp = (vfloat_mv - MIN_FLOAT_MV) / VFLOAT_STEP_MV; return smb349_masked_write(chip, VFLOAT_REG, VFLOAT_MASK, temp); }
static int chg_current_set(struct smb349_struct *smb349_chg) { u8 temp; if ((smb349_chg->chg_current_ma < SMB349_FAST_CHG_MIN_MA) || (smb349_chg->chg_current_ma > SMB349_FAST_CHG_MAX_MA)) { pr_err("bad mA=%d asked to set\n", smb349_chg->chg_current_ma); return -EINVAL; } temp = (smb349_chg->chg_current_ma - SMB349_FAST_CHG_MIN_MA) / SMB349_FAST_CHG_STEP_MA; temp = temp << SMB349_FAST_CHG_SHIFT; pr_debug("fastchg limit=%d setting %02x\n", smb349_chg->chg_current_ma, temp); return smb349_masked_write(smb349_chg->client, CHG_CURRENT_REG, FAST_CHG_CURRENT_MASK, temp); }
static int smb349_charging(struct smb349_dual_charger *chip, int enable) { int rc = 0; dev_dbg(chip->dev, "%s: charging enable = %d\n", __func__, enable); if (chip->chg_present) { rc = smb349_masked_write(chip, CMD_A_REG, CMD_A_CHG_ENABLE_BIT, enable ? CMD_A_CHG_ENABLE_BIT : 0); if (rc) dev_err(chip->dev, "Couldn't enable = %d rc = %d\n", enable, rc); dev_dbg(chip->dev, "cradle psy changed\n"); power_supply_changed(&chip->cradle_psy); } chip->charging_disabled = !enable; return rc; }
static int smb349_charging(struct smb349_charger *chip, int enable) { int rc = 0; if (chip->chg_autonomous_mode) { dev_dbg(chip->dev, "%s: Charger in autonmous mode\n", __func__); return 0; } dev_dbg(chip->dev, "%s: charging enable = %d\n", __func__, enable); rc = smb349_masked_write(chip, CMD_A_REG, CMD_A_CHG_ENABLE_BIT, enable ? CMD_A_CHG_ENABLE_BIT : 0); if (rc) dev_err(chip->dev, "Couldn't enable = %d rc = %d\n", enable, rc); else chip->charging_disabled = !enable; return rc; }
static int smb349_fastchg_current_set(struct smb349_charger *chip) { u8 temp; if ((chip->fastchg_current_max_ma < SMB349_FAST_CHG_MIN_MA) || (chip->fastchg_current_max_ma > SMB349_FAST_CHG_MAX_MA)) { dev_dbg(chip->dev, "bad fastchg current mA=%d asked to set\n", chip->fastchg_current_max_ma); return -EINVAL; } temp = (chip->fastchg_current_max_ma - SMB349_FAST_CHG_MIN_MA) / SMB349_FAST_CHG_STEP_MA; temp = temp << SMB349_FAST_CHG_SHIFT; dev_dbg(chip->dev, "fastchg limit=%d setting %02x\n", chip->fastchg_current_max_ma, temp); return smb349_masked_write(chip, CHG_CURRENT_CTRL_REG, SMB_FAST_CHG_CURRENT_MASK, temp); }
static int smb349_set_usb_chg_current(struct smb349_charger *chip, int current_ma) { int i, rc = 0; u8 reg = 0, mask = 0; dev_dbg(chip->dev, "%s: USB current_ma = %d\n", __func__, current_ma); if (chip->chg_autonomous_mode) { dev_dbg(chip->dev, "%s: Charger in autonmous mode\n", __func__); return 0; } /* Only set suspend bit when chg present and current_ma = 2 */ if (current_ma == 2 && chip->chg_present) { rc = smb349_masked_write(chip, CMD_A_REG, CMD_A_CHG_SUSP_EN_MASK, CMD_A_CHG_SUSP_EN_BIT); if (rc < 0) dev_err(chip->dev, "Couldn't suspend rc = %d\n", rc); return rc; } if (current_ma <= 2) current_ma = USB2_MIN_CURRENT_MA; if (current_ma == USB2_MIN_CURRENT_MA) { /* USB 2.0 - 100mA */ reg &= ~CMD_B_CHG_USB3_ENABLE_BIT; reg &= ~CMD_B_CHG_USB_500_900_ENABLE_BIT; } else if (current_ma == USB2_MAX_CURRENT_MA) { /* USB 2.0 - 500mA */ reg &= ~CMD_B_CHG_USB3_ENABLE_BIT; reg |= CMD_B_CHG_USB_500_900_ENABLE_BIT; } else if (current_ma == USB3_MAX_CURRENT_MA) { /* USB 3.0 - 900mA */ reg |= CMD_B_CHG_USB3_ENABLE_BIT; reg |= CMD_B_CHG_USB_500_900_ENABLE_BIT; } else if (current_ma > USB2_MAX_CURRENT_MA) { /* HC mode - if none of the above */ reg |= CMD_B_CHG_HC_ENABLE_BIT; for (i = ARRAY_SIZE(chg_current) - 1; i >= 0; i--) { if (chg_current[i] <= current_ma) break; } if (i < 0) { dev_err(chip->dev, "Cannot find %dmA\n", current_ma); i = 0; } rc = smb349_masked_write(chip, CHG_CURRENT_CTRL_REG, AC_CHG_CURRENT_MASK, i); if (rc) dev_err(chip->dev, "Couldn't set input mA rc=%d\n", rc); } mask = CMD_B_CHG_HC_ENABLE_BIT | CMD_B_CHG_USB3_ENABLE_BIT | CMD_B_CHG_USB_500_900_ENABLE_BIT; rc = smb349_masked_write(chip, CMD_B_REG, mask, reg); if (rc < 0) dev_err(chip->dev, "Couldn't set charging mode rc = %d\n", rc); /* unset the susp bit here */ rc = smb349_masked_write(chip, CMD_A_REG, CMD_A_CHG_SUSP_EN_MASK, 0); if (rc < 0) dev_err(chip->dev, "Couldn't disable suspend rc = %d\n", rc); return rc; }
static int smb349_hw_init(struct smb349_charger *chip) { int rc; u8 reg = 0, mask = 0; /* * If the charger is pre-configured for autonomous operation, * do not apply additonal settings */ if (chip->chg_autonomous_mode) { dev_dbg(chip->dev, "Charger configured for autonomous mode\n"); return 0; } rc = smb349_read_reg(chip, CHG_REVISION_REG, ®); if (rc) { dev_err(chip->dev, "Couldn't read CHG_REVISION_REG rc=%d\n", rc); return rc; } /* * A4 silicon revision of SMB349 fails charger type detection * (apsd) due to interference on the D+/- lines by the USB phy. * Set the workaround flag to disable charger type reporting * for this revision. */ if ((reg & SMB349_REV_MASK) == SMB349_REV_A4) chip->workaround_flags |= WRKARND_APSD_FAIL; pr_debug("workaround_flags = %x\n", chip->workaround_flags); rc = smb349_enable_volatile_writes(chip); if (rc) { dev_err(chip->dev, "Couldn't configure volatile writes rc=%d\n", rc); return rc; } /* setup defaults for CHG_CNTRL_REG */ reg = CHG_CTRL_BATT_MISSING_DET_THERM_IO; mask = CHG_CTRL_BATT_MISSING_DET_MASK; rc = smb349_masked_write(chip, CHG_CTRL_REG, mask, reg); if (rc) { dev_err(chip->dev, "Couldn't set CHG_CTRL_REG rc=%d\n", rc); return rc; } /* setup defaults for PIN_CTRL_REG */ reg = CHG_PIN_CTRL_USBCS_REG_BIT | CHG_PIN_CTRL_CHG_EN_LOW_REG_BIT | CHG_PIN_CTRL_APSD_IRQ_BIT | CHG_PIN_CTRL_CHG_ERR_IRQ_BIT; mask = CHG_PIN_CTRL_CHG_EN_MASK | CHG_PIN_CTRL_USBCS_REG_MASK | CHG_PIN_CTRL_APSD_IRQ_MASK | CHG_PIN_CTRL_CHG_ERR_IRQ_MASK; rc = smb349_masked_write(chip, CHG_PIN_EN_CTRL_REG, mask, reg); if (rc) { dev_err(chip->dev, "Couldn't set CHG_PIN_EN_CTRL_REG rc=%d\n", rc); return rc; } /* setup USB 2.0/3.0 detection mechanism */ rc = smb349_masked_write(chip, CHG_OTH_CURRENT_CTRL_REG, CHG_OTH_CTRL_USB_2_3_PIN_REG_MASK, CHG_OTH_CTRL_USB_2_3_REG_CTRL_BIT); if (rc) { dev_err(chip->dev, "Couldn't set USB_2_3_REG_CTRL_BIT rc=%d\n", rc); return rc; } /* setup USB suspend and APSD */ reg = VARIOUS_FUNC_USB_SUSP_EN_REG_BIT; if (!chip->disable_apsd) reg |= VARIOUS_FUNC_APSD_EN_BIT; mask = VARIOUS_FUNC_USB_SUSP_MASK | VARIOUS_FUNC_APSD_MASK; rc = smb349_masked_write(chip, VARIOUS_FUNC_REG, mask, reg); if (rc) { dev_err(chip->dev, "Couldn't set VARIOUS_FUNC_REG rc=%d\n", rc); return rc; } /* Fault and Status IRQ configuration */ reg = FAULT_INT_HOT_COLD_HARD_BIT | FAULT_INT_HOT_COLD_SOFT_BIT | FAULT_INT_INPUT_UV_BIT | FAULT_INT_AICL_COMPLETE_BIT; rc = smb349_write_reg(chip, FAULT_INT_REG, reg); if (rc) { dev_err(chip->dev, "Couldn't set FAULT_INT_REG rc=%d\n", rc); return rc; } reg = STATUS_INT_CHG_TIMEOUT_BIT | STATUS_INT_OTG_DETECT_BIT | STATUS_INT_BATT_OV_BIT | STATUS_INT_TERM_TAPER_BIT | STATUS_INT_FAST_CHG_BIT | STATUS_INT_LOW_BATT_BIT | STATUS_INT_MISSING_BATT_BIT; rc = smb349_write_reg(chip, STATUS_INT_REG, reg); if (rc) { dev_err(chip->dev, "Couldn't set STATUS_INT_REG rc=%d\n", rc); return rc; } /* setup THERM Monitor */ rc = smb349_masked_write(chip, THERM_A_CTRL_REG, THERM_A_THERM_MONITOR_EN_MASK, THERM_A_THERM_MONITOR_EN_BIT); if (rc) { dev_err(chip->dev, "Couldn't set THERM_A_CTRL_REG rc=%d\n", rc); return rc; } /* set the fast charge current limit */ rc = smb349_fastchg_current_set(chip); if (rc) { dev_err(chip->dev, "Couldn't set fastchg current rc=%d\n", rc); return rc; } /* set the float voltage */ if (chip->vfloat_mv != -EINVAL) { rc = smb349_float_voltage_set(chip, chip->vfloat_mv); if (rc < 0) { dev_err(chip->dev, "Couldn't set float voltage rc = %d\n", rc); return rc; } } /* set iterm */ if (chip->iterm_ma != -EINVAL) { if (chip->iterm_disabled) { dev_err(chip->dev, "Error: Both iterm_disabled and iterm_ma set\n"); return -EINVAL; } else { if (chip->iterm_ma <= 100) reg = CHG_ITERM_100MA; else if (chip->iterm_ma <= 200) reg = CHG_ITERM_200MA; else if (chip->iterm_ma <= 300) reg = CHG_ITERM_300MA; else if (chip->iterm_ma <= 400) reg = CHG_ITERM_400MA; else if (chip->iterm_ma <= 500) reg = CHG_ITERM_500MA; else if (chip->iterm_ma <= 600) reg = CHG_ITERM_600MA; else reg = CHG_ITERM_700MA; rc = smb349_masked_write(chip, CHG_OTH_CURRENT_CTRL_REG, CHG_ITERM_MASK, reg); if (rc) { dev_err(chip->dev, "Couldn't set iterm rc = %d\n", rc); return rc; } rc = smb349_masked_write(chip, CHG_CTRL_REG, CHG_CTRL_CURR_TERM_END_MASK, 0); if (rc) { dev_err(chip->dev, "Couldn't enable iterm rc = %d\n", rc); return rc; } } } else if (chip->iterm_disabled) { rc = smb349_masked_write(chip, CHG_CTRL_REG, CHG_CTRL_CURR_TERM_END_MASK, CHG_CTRL_CURR_TERM_END_MASK); if (rc) { dev_err(chip->dev, "Couldn't set iterm rc = %d\n", rc); return rc; } } /* set recharge-threshold */ if (chip->recharge_mv != -EINVAL) { if (chip->recharge_disabled) { dev_err(chip->dev, "Error: Both recharge_disabled and recharge_mv set\n"); return -EINVAL; } else { reg = 0; if (chip->recharge_mv > 50) reg = CHG_CTRL_RECHG_100MV_BIT; rc = smb349_masked_write(chip, CHG_CTRL_REG, CHG_CTRL_RECHG_50_100_MASK | CHG_CTRL_AUTO_RECHARGE_MASK, reg); if (rc) { dev_err(chip->dev, "Couldn't set rechg-cfg rc = %d\n", rc); return rc; } } } else if (chip->recharge_disabled) { rc = smb349_masked_write(chip, CHG_CTRL_REG, CHG_CTRL_AUTO_RECHARGE_MASK, CHG_CTRL_AUTO_RECHARGE_MASK); if (rc) { dev_err(chip->dev, "Couldn't disable auto-rechg rc = %d\n", rc); return rc; } } /* enable/disable charging */ rc = smb349_masked_write(chip, CMD_A_REG, CMD_A_CHG_ENABLE_BIT, chip->charging_disabled ? 0 : CMD_A_CHG_ENABLE_BIT); if (rc) { dev_err(chip->dev, "Unable to %s charging. rc=%d\n", chip->charging_disabled ? "disable" : "enable", rc); } return rc; }
static int smb349_hw_init(struct smb349_dual_charger *chip) { int rc; u8 reg = 0; rc = smb349_enable_volatile_writes(chip); if (rc) { dev_err(chip->dev, "Couldn't configure volatile writes rc=%d\n", rc); return rc; } /* overwrite OTP defaults */ rc = smb349_masked_write(chip, CHG_CURRENT_CTRL_REG, 0xFF, 0x5F); if (rc) { dev_err(chip->dev, "Couldn't set current control rc=%d\n", rc); return rc; } rc = smb349_masked_write(chip, THERM_A_CTRL_REG, 0xFF, 0xCF); if (rc) { dev_err(chip->dev, "Couldn't set thermal control rc=%d\n", rc); return rc; } rc = smb349_masked_write(chip, OTG_TLIM_THERM_CTRL_REG, 0xFF, 0x5B); if (rc) { dev_err(chip->dev, "Couldn't set otg thermal limits rc=%d\n", rc); return rc; } rc = smb349_masked_write(chip, HARD_SOFT_TLIM_CTRL_REG, 0xFF, 0x23); if (rc) { dev_err(chip->dev, "Couldn't set thermal limits rc=%d\n", rc); return rc; } /* set the fast charge current limit */ rc = smb349_fastchg_current_set(chip); if (rc) { dev_err(chip->dev, "Couldn't set fastchg current rc=%d\n", rc); return rc; } /* set the float voltage */ if (chip->vfloat_mv != -EINVAL) { rc = smb349_float_voltage_set(chip, chip->vfloat_mv); if (rc < 0) { dev_err(chip->dev, "Couldn't set float voltage rc = %d\n", rc); return rc; } } /* set iterm */ if (chip->iterm_ma != -EINVAL) { if (chip->iterm_disabled) { dev_err(chip->dev, "Error: Both iterm_disabled and iterm_ma set\n"); return -EINVAL; } else { if (chip->iterm_ma <= 100) reg = CHG_ITERM_100MA; else if (chip->iterm_ma <= 200) reg = CHG_ITERM_200MA; else if (chip->iterm_ma <= 300) reg = CHG_ITERM_300MA; else if (chip->iterm_ma <= 400) reg = CHG_ITERM_400MA; else if (chip->iterm_ma <= 500) reg = CHG_ITERM_500MA; else if (chip->iterm_ma <= 600) reg = CHG_ITERM_600MA; else reg = CHG_ITERM_700MA; rc = smb349_masked_write(chip, CHG_OTH_CURRENT_CTRL_REG, CHG_ITERM_MASK, reg); if (rc) { dev_err(chip->dev, "Couldn't set iterm rc = %d\n", rc); return rc; } rc = smb349_masked_write(chip, CHG_CTRL_REG, CHG_CTRL_CURR_TERM_END_MASK, 0); if (rc) { dev_err(chip->dev, "Couldn't enable iterm rc = %d\n", rc); return rc; } } } else if (chip->iterm_disabled) { rc = smb349_masked_write(chip, CHG_CTRL_REG, CHG_CTRL_CURR_TERM_END_MASK, CHG_CTRL_CURR_TERM_END_MASK); if (rc) { dev_err(chip->dev, "Couldn't set iterm rc = %d\n", rc); return rc; } } /* set recharge-threshold */ if (chip->recharge_mv != -EINVAL) { if (chip->recharge_disabled) { dev_err(chip->dev, "Error: Both recharge_disabled and recharge_mv set\n"); return -EINVAL; } else { reg = 0; if (chip->recharge_mv > SMB_RECHARGE_THRESHOLD_MV) reg = CHG_CTRL_RECHG_100MV_BIT; rc = smb349_masked_write(chip, CHG_CTRL_REG, CHG_CTRL_RECHG_50_100_MASK | CHG_CTRL_AUTO_RECHARGE_MASK, reg); if (rc) { dev_err(chip->dev, "Couldn't set rechg-cfg rc = %d\n", rc); return rc; } } } else if (chip->recharge_disabled) { rc = smb349_masked_write(chip, CHG_CTRL_REG, CHG_CTRL_AUTO_RECHARGE_MASK, CHG_CTRL_AUTO_RECHARGE_MASK); if (rc) { dev_err(chip->dev, "Couldn't disable auto-rechg rc = %d\n", rc); return rc; } } /* enable/disable charging */ rc = smb349_masked_write(chip, CMD_A_REG, CMD_A_CHG_ENABLE_BIT, chip->charging_disabled ? 0 : CMD_A_CHG_ENABLE_BIT); if (rc) { dev_err(chip->dev, "Unable to %s charging. rc=%d\n", chip->charging_disabled ? "disable" : "enable", rc); } return rc; }