static int pm8058_init_regulator(struct pm8058_chip *chip,
		struct pm8058_vreg *vreg)
{
	int rc = 0, i;
	u8 bank;

	/* save the current control register state */
	rc = pm8058_read(chip, vreg->ctrl_addr, &vreg->ctrl_reg, 1);
	if (rc)
		return rc;

	/* save the current test/test2 register state */
	if (vreg->type == REGULATOR_TYPE_LDO) {
		for (i = 0; i < LDO_TEST_BANKS; i++) {
			bank = REGULATOR_BANK_SEL(i);
			rc = pm8058_write(chip, vreg->test_addr,
					&bank, 1);
			if (rc)
				goto bail;

			rc = pm8058_read(chip, vreg->test_addr,
					&vreg->test_reg[i], 1);
			if (rc)
				goto bail;
		}
	} else if (vreg->type == REGULATOR_TYPE_SMPS) {
		for (i = 0; i < SMPS_TEST_BANKS; i++) {
			bank = REGULATOR_BANK_SEL(i);
			rc = pm8058_write(chip, vreg->test2_addr,
					&bank, 1);
			if (rc)
				goto bail;

			rc = pm8058_read(chip, vreg->test2_addr,
					&vreg->test2_reg[i], 1);
			if (rc)
				goto bail;
		}

		rc = pm8058_read(chip, vreg->clk_ctrl_addr,
				&vreg->clk_ctrl_reg, 1);
		if (rc)
			goto bail;
	}

bail:
	if (rc)
		pr_err("%s: pm8058_read/write failed\n", __func__);

	return rc;
}
static int pm8058_nldo_set_voltage(struct pm8058_chip *chip,
		struct pm8058_vreg *vreg, int uV)
{
	int rc;
	u8 mask, val = 0;

	if (uV > NLDO_UV_MAX) {
		uV -= NLDO_FINE_STEP_UV;
		val = LDO_TEST_FINE_STEP_MASK;
	}

	/* update reference voltage and fine step selection if necessary */
	if ((vreg->test_reg[2] & LDO_TEST_FINE_STEP_MASK) != val) {
		val |= REGULATOR_BANK_SEL(2) | REGULATOR_BANK_WRITE;
		mask = LDO_TEST_FINE_STEP_MASK | val;

		rc = pm8058_vreg_write(chip, vreg->test_addr, val,
				mask, &vreg->test_reg[2]);
		if (rc) {
			pr_err("%s: pm8058_write failed\n", __func__);
			return rc;
		}
	}

	/* voltage programming */
	val = (uV - NLDO_UV_MIN) / NLDO_UV_STEP;
	rc = pm8058_vreg_write(chip, vreg->ctrl_addr, val,
			LDO_CTRL_VPROG_MASK, &vreg->ctrl_reg);
	if (rc)
		pr_err("%s: pm8058_write failed\n", __func__);

	return rc;
}
static int pm8901_init_regulator(struct pm8901_chip *chip,
		struct pm8901_vreg *vreg)
{
	int rc, i;
	u8 bank;

	if (vreg->type == REGULATOR_TYPE_LDO) {
		for (i = 0; i < LDO_TEST_BANKS; i++) {
			bank = REGULATOR_BANK_SEL(i);
			rc = pm8901_write(chip, vreg->test_addr,
					&bank, 1);
			if (rc)
				goto bail;

			rc = pm8901_read(chip, vreg->test_addr,
					&vreg->test_reg[i], 1);
			if (rc)
				goto bail;
		}
	}

	rc = pm8901_read(chip, vreg->ctrl_addr, &vreg->ctrl_reg, 1);
	if (rc)
		goto bail;

	rc = pm8901_read(chip, vreg->pmr_addr, &vreg->pmr_reg, 1);

bail:
	if (rc)
		pr_err("%s: pm8901_read failed\n", __func__);

	return rc;
}
static int pm8058_ldo_set_mode(struct regulator_dev *dev, unsigned int mode)
{
	struct pm8058_vreg *vreg = rdev_get_drvdata(dev);
	struct pm8058_chip *chip = dev_get_drvdata(dev->dev.parent);
	int rc = 0;
	u8 ctrl, test, mask, val;

	if (mode == REGULATOR_MODE_NORMAL) {
		/* disable low power mode */
		test = LDO_TEST_LPM_SEL_TCXO;
		ctrl = LDO_CTRL_PM_NORMAL;
	} else if (mode == REGULATOR_MODE_IDLE) {
		/* enable low power mode but follow tcxo */
		test = LDO_TEST_LPM_SEL_TCXO;
		ctrl = LDO_CTRL_PM_LOW;
	} else if (mode == REGULATOR_MODE_STANDBY) {
		/* force low power mode */
		test = LDO_TEST_LPM_SEL_CTRL;
		ctrl = LDO_CTRL_PM_LOW;
	} else {
		return -EINVAL;
	}

	if ((vreg->test_reg[0] & LDO_TEST_LPM_MASK) != test) {
		val = REGULATOR_EN_MASK | REGULATOR_BANK_SEL(0) | test;
		mask = REGULATOR_EN_MASK | REGULATOR_BANK_SEL(0) |
			LDO_TEST_LPM_MASK;
		rc = pm8058_vreg_write(chip, vreg->test_addr,
				val, mask, &vreg->test_reg[0]);
		if (rc) {
			pr_err("%s: pm8058_vreg_write failed\n", __func__);
			return rc;
		}
	}

	if ((vreg->ctrl_reg & LDO_CTRL_PM_MASK) != ctrl) {
		val = ctrl;
		mask = LDO_CTRL_PM_MASK;
		rc = pm8058_vreg_write(chip, vreg->ctrl_addr,
				val, mask, &vreg->ctrl_reg);
		if (rc)
			pr_err("%s: pm8058_vreg_write failed\n", __func__);
	}

	return rc;
}
static int pm8058_smps_set_voltage(struct regulator_dev *dev,
		int min_uV, int max_uV)
{
	struct pm8058_vreg *vreg = rdev_get_drvdata(dev);
	struct pm8058_chip *chip = dev_get_drvdata(dev->dev.parent);
	int rc;
	u8 val, mask, vlow;

	if (min_uV >= SMPS_MODE3_UV_MIN && min_uV <= SMPS_MODE3_UV_MAX) {
		vlow = SMPS_VLOW_SEL_MASK;
		val = ((min_uV  - SMPS_MODE3_UV_MIN) / SMPS_MODE3_STEP) |
			SMPS_VREF_SEL_MASK;
	} else if (min_uV >= SMPS_MODE2_UV_MIN && min_uV <= SMPS_MODE2_UV_MAX) {
		vlow = 0;
		val = ((min_uV - SMPS_MODE2_UV_MIN) / SMPS_MODE2_STEP) |
			SMPS_VREF_SEL_MASK;
	} else if (min_uV >= SMPS_MODE1_UV_MIN && min_uV <= SMPS_MODE1_UV_MAX) {
		vlow = 0;
		val = (min_uV - SMPS_MODE1_UV_MIN) / SMPS_MODE1_STEP;
	} else {
		return -EINVAL;
	}

	/* set vlow bit for ultra low voltage mode */
	if ((vreg->test2_reg[1] & SMPS_VLOW_SEL_MASK) != vlow) {
		vlow |= REGULATOR_BANK_WRITE | REGULATOR_BANK_SEL(1);
		mask = vlow | SMPS_VLOW_SEL_MASK;
		rc = pm8058_vreg_write(chip, vreg->test2_addr,
				vlow, mask, &vreg->test2_reg[1]);
	}

	/* voltage setting */
	mask = SMPS_VREF_SEL_MASK | SMPS_VPROG_MASK;
	rc = pm8058_vreg_write(chip, vreg->ctrl_addr, val, mask,
			&vreg->ctrl_reg);
	if (rc)
		pr_err("%s: pm8058_vreg_write failed\n", __func__);

	return rc;
}
/*
 * Set an SMPS regulator to be disabled in its CTRL register, but enabled
 * in the master enable register.  Also set it's pull down enable bit.
 * Take care to make sure that the output voltage doesn't change if switching
 * from advanced mode to legacy mode.
 */
static int disable_smps_locally_set_pull_down(u16 ctrl_addr, u16 test2_addr,
		u16 master_enable_addr, u8 master_enable_bit)
{
	int rc = 0;
	u8 vref_sel, vlow_sel, band, vprog, bank, reg;

	if (pmic_chip == NULL)
		return -ENODEV;

	bank = REGULATOR_BANK_SEL(7);
	rc = ssbi_write(pmic_chip->dev, test2_addr, &bank, 1);
	if (rc) {
		pr_err("%s: FAIL ssbi_write(0x%03X): rc=%d\n", __func__,
			test2_addr, rc);
		goto done;
	}

	rc = ssbi_read(pmic_chip->dev, test2_addr, &reg, 1);
	if (rc) {
		pr_err("%s: FAIL pm8058_read(0x%03X): rc=%d\n",
		       __func__, test2_addr, rc);
		goto done;
	}

	/* Check if in advanced mode. */
	if ((reg & SMPS_ADVANCED_MODE_MASK) == SMPS_ADVANCED_MODE) {
		/* Determine current output voltage. */
		rc = ssbi_read(pmic_chip->dev, ctrl_addr, &reg, 1);
		if (rc) {
			pr_err("%s: FAIL pm8058_read(0x%03X): rc=%d\n",
			       __func__, ctrl_addr, rc);
			goto done;
		}

		band = (reg & SMPS_ADVANCED_BAND_MASK)
			>> SMPS_ADVANCED_BAND_SHIFT;
		switch (band) {
		case 3:
			vref_sel = 0;
			vlow_sel = 0;
			break;
		case 2:
			vref_sel = SMPS_LEGACY_VREF_SEL;
			vlow_sel = 0;
			break;
		case 1:
			vref_sel = SMPS_LEGACY_VREF_SEL;
			vlow_sel = SMPS_LEGACY_VLOW_SEL;
			break;
		default:
			pr_err("%s: regulator already disabled\n", __func__);
			return -EPERM;
		}
		vprog = (reg & SMPS_ADVANCED_VPROG_MASK);
		/* Round up if fine step is in use. */
		vprog = (vprog + 1) >> 1;
		if (vprog > SMPS_LEGACY_VPROG_MASK)
			vprog = SMPS_LEGACY_VPROG_MASK;

		/* Set VLOW_SEL bit. */
		bank = REGULATOR_BANK_SEL(1);
		rc = ssbi_write(pmic_chip->dev, test2_addr, &bank, 1);
		if (rc) {
			pr_err("%s: FAIL ssbi_write(0x%03X): rc=%d\n",
			       __func__, test2_addr, rc);
			goto done;
		}
		rc = pm8058_masked_write(test2_addr,
			REGULATOR_BANK_WRITE | REGULATOR_BANK_SEL(1)
				| vlow_sel,
			REGULATOR_BANK_WRITE | REGULATOR_BANK_MASK
				| SMPS_LEGACY_VLOW_SEL);
		if (rc)
			goto done;

		/* Switch to legacy mode */
		bank = REGULATOR_BANK_SEL(7);
		rc = ssbi_write(pmic_chip->dev, test2_addr, &bank, 1);
		if (rc) {
			pr_err("%s: FAIL ssbi_write(0x%03X): rc=%d\n", __func__,
				test2_addr, rc);
			goto done;
		}
		rc = pm8058_masked_write(test2_addr,
				REGULATOR_BANK_WRITE | REGULATOR_BANK_SEL(7)
					| SMPS_LEGACY_MODE,
				REGULATOR_BANK_WRITE | REGULATOR_BANK_MASK
					| SMPS_ADVANCED_MODE_MASK);
		if (rc)
			goto done;

		/* Enable locally, enable pull down, keep voltage the same. */
		rc = pm8058_masked_write(ctrl_addr,
			REGULATOR_ENABLE | REGULATOR_PULL_DOWN_EN
				| vref_sel | vprog,
			REGULATOR_ENABLE_MASK | REGULATOR_PULL_DOWN_MASK
			       | SMPS_LEGACY_VREF_SEL | SMPS_LEGACY_VPROG_MASK);
		if (rc)
			goto done;
	}
static int pm8058_pldo_set_voltage(struct pm8058_chip *chip,
		struct pm8058_vreg *vreg, int uV)
{
	int min, max, step, fine_step, rc;
	u8 range_extn, vref, mask, val = 0;

	if (uV >= PLDO_LOW_UV_MIN &&
			uV <= PLDO_LOW_UV_MAX + PLDO_LOW_UV_STEP) {
		min = PLDO_LOW_UV_MIN;
		max = PLDO_LOW_UV_MAX;
		step = PLDO_LOW_UV_STEP;
		fine_step = PLDO_LOW_FINE_STEP_UV;
		range_extn = 0;
		vref = LDO_TEST_VREF_MASK;
	} else if (uV >= PLDO_NORM_UV_MIN &&
			uV <= PLDO_NORM_UV_MAX + PLDO_NORM_UV_STEP) {
		min = PLDO_NORM_UV_MIN;
		max = PLDO_NORM_UV_MAX;
		step = PLDO_NORM_UV_STEP;
		fine_step = PLDO_NORM_FINE_STEP_UV;
		range_extn = 0;
		vref = 0;
	} else {
		min = PLDO_HIGH_UV_MIN;
		max = PLDO_HIGH_UV_MAX;
		step = PLDO_HIGH_UV_STEP;
		fine_step = PLDO_HIGH_FINE_STEP_UV;
		range_extn = LDO_TEST_RANGE_EXTN_MASK;
		vref = 0;
	}

	if (uV > max) {
		uV -= fine_step;
		val = LDO_TEST_FINE_STEP_MASK;
	}

	/* update reference voltage and fine step selection if necessary */
	if ((vreg->test_reg[2] & LDO_TEST_FINE_STEP_MASK) != val ||
			(vreg->test_reg[2] & LDO_TEST_VREF_MASK) != vref) {
		val |= REGULATOR_BANK_SEL(2) | REGULATOR_BANK_WRITE |
			LDO_TEST_VREF_UPDATE_MASK | vref;
		mask = LDO_TEST_VREF_MASK | LDO_TEST_FINE_STEP_MASK | val;

		rc = pm8058_vreg_write(chip, vreg->test_addr, val,
				mask, &vreg->test_reg[2]);
		if (rc) {
			pr_err("%s: pm8058_write failed\n", __func__);
			return rc;
		}
	}

	/* update range extension if necessary */
	if ((vreg->test_reg[4] & LDO_TEST_RANGE_EXTN_MASK) != range_extn) {
		val = REGULATOR_BANK_SEL(4) | REGULATOR_BANK_WRITE |
			range_extn;
		mask = LDO_TEST_RANGE_EXTN_MASK | val;

		rc = pm8058_vreg_write(chip, vreg->test_addr, val,
				mask, &vreg->test_reg[4]);
		if (rc) {
			pr_err("%s: pm8058_write failed\n", __func__);
			return rc;
		}
	}

	/* voltage programming */
	val = (uV - min) / step;
	rc = pm8058_vreg_write(chip, vreg->ctrl_addr, val,
			LDO_CTRL_VPROG_MASK, &vreg->ctrl_reg);
	if (rc)
		pr_err("%s: pm8058_write failed\n", __func__);

	return rc;
}