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, ®, 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, ®, 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; }