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;
}
Example #2
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;
}
Example #3
0
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;
}
Example #4
0
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;
}
Example #7
0
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;
}
Example #8
0
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);
}
Example #9
0
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;
}
Example #10
0
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, &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;
}