struct tps65910_reg { struct regulator_desc *desc; struct tps65910 *mfd; struct regulator_dev **rdev; struct tps_info **info; int num_regulators; int mode; int (*get_ctrl_reg)(int); unsignedint *ext_sleep_control; unsignedint board_ext_control[TPS65910_NUM_REGS];
};
staticint tps65910_get_ctrl_register(int id)
{ switch (id) { case TPS65910_REG_VRTC: return TPS65910_VRTC; case TPS65910_REG_VIO: return TPS65910_VIO; case TPS65910_REG_VDD1: return TPS65910_VDD1; case TPS65910_REG_VDD2: return TPS65910_VDD2; case TPS65910_REG_VDD3: return TPS65910_VDD3; case TPS65910_REG_VDIG1: return TPS65910_VDIG1; case TPS65910_REG_VDIG2: return TPS65910_VDIG2; case TPS65910_REG_VPLL: return TPS65910_VPLL; case TPS65910_REG_VDAC: return TPS65910_VDAC; case TPS65910_REG_VAUX1: return TPS65910_VAUX1; case TPS65910_REG_VAUX2: return TPS65910_VAUX2; case TPS65910_REG_VAUX33: return TPS65910_VAUX33; case TPS65910_REG_VMMC: return TPS65910_VMMC; case TPS65910_REG_VBB: return TPS65910_BBCH; default: return -EINVAL;
}
}
staticint tps65911_get_ctrl_register(int id)
{ switch (id) { case TPS65910_REG_VRTC: return TPS65910_VRTC; case TPS65910_REG_VIO: return TPS65910_VIO; case TPS65910_REG_VDD1: return TPS65910_VDD1; case TPS65910_REG_VDD2: return TPS65910_VDD2; case TPS65911_REG_VDDCTRL: return TPS65911_VDDCTRL; case TPS65911_REG_LDO1: return TPS65911_LDO1; case TPS65911_REG_LDO2: return TPS65911_LDO2; case TPS65911_REG_LDO3: return TPS65911_LDO3; case TPS65911_REG_LDO4: return TPS65911_LDO4; case TPS65911_REG_LDO5: return TPS65911_LDO5; case TPS65911_REG_LDO6: return TPS65911_LDO6; case TPS65911_REG_LDO7: return TPS65911_LDO7; case TPS65911_REG_LDO8: return TPS65911_LDO8; default: return -EINVAL;
}
}
reg = pmic->get_ctrl_reg(id); if (reg < 0) return reg;
ret = regmap_read(regmap, reg, &value); if (ret < 0) return ret;
switch (id) { case TPS65910_REG_VIO: case TPS65910_REG_VDIG1: case TPS65910_REG_VDIG2: case TPS65910_REG_VPLL: case TPS65910_REG_VDAC: case TPS65910_REG_VAUX1: case TPS65910_REG_VAUX2: case TPS65910_REG_VAUX33: case TPS65910_REG_VMMC:
value &= LDO_SEL_MASK;
value >>= LDO_SEL_SHIFT; break; case TPS65910_REG_VBB:
value &= BBCH_BBSEL_MASK;
value >>= BBCH_BBSEL_SHIFT; break; default: return -EINVAL;
}
ret = regmap_read(regmap, reg, &value); if (ret < 0) return ret;
switch (id) { case TPS65911_REG_LDO1: case TPS65911_REG_LDO2: case TPS65911_REG_LDO4:
value &= LDO1_SEL_MASK;
value >>= LDO_SEL_SHIFT; break; case TPS65911_REG_LDO3: case TPS65911_REG_LDO5: case TPS65911_REG_LDO6: case TPS65911_REG_LDO7: case TPS65911_REG_LDO8:
value &= LDO3_SEL_MASK;
value >>= LDO_SEL_SHIFT; break; case TPS65910_REG_VIO:
value &= LDO_SEL_MASK;
value >>= LDO_SEL_SHIFT; break; default: return -EINVAL;
}
return value;
}
staticint tps65910_set_voltage_dcdc_sel(struct regulator_dev *dev, unsigned selector)
{ struct regmap *regmap = rdev_get_regmap(dev); int id = rdev_get_id(dev), vsel; int dcdc_mult = 0;
reg = pmic->get_ctrl_reg(id); if (reg < 0) return reg;
switch (id) { case TPS65910_REG_VIO: case TPS65910_REG_VDIG1: case TPS65910_REG_VDIG2: case TPS65910_REG_VPLL: case TPS65910_REG_VDAC: case TPS65910_REG_VAUX1: case TPS65910_REG_VAUX2: case TPS65910_REG_VAUX33: case TPS65910_REG_VMMC: return regmap_update_bits(regmap, reg, LDO_SEL_MASK,
selector << LDO_SEL_SHIFT); case TPS65910_REG_VBB: return regmap_update_bits(regmap, reg, BBCH_BBSEL_MASK,
selector << BBCH_BBSEL_SHIFT);
}
reg = pmic->get_ctrl_reg(id); if (reg < 0) return reg;
switch (id) { case TPS65911_REG_LDO1: case TPS65911_REG_LDO2: case TPS65911_REG_LDO4: return regmap_update_bits(regmap, reg, LDO1_SEL_MASK,
selector << LDO_SEL_SHIFT); case TPS65911_REG_LDO3: case TPS65911_REG_LDO5: case TPS65911_REG_LDO6: case TPS65911_REG_LDO7: case TPS65911_REG_LDO8: return regmap_update_bits(regmap, reg, LDO3_SEL_MASK,
selector << LDO_SEL_SHIFT); case TPS65910_REG_VIO: return regmap_update_bits(regmap, reg, LDO_SEL_MASK,
selector << LDO_SEL_SHIFT); case TPS65910_REG_VBB: return regmap_update_bits(regmap, reg, BBCH_BBSEL_MASK,
selector << BBCH_BBSEL_SHIFT);
}
return -EINVAL;
}
staticint tps65910_list_voltage_dcdc(struct regulator_dev *dev, unsigned selector)
{ int volt, mult = 1, id = rdev_get_id(dev);
switch (id) { case TPS65910_REG_VDD1: case TPS65910_REG_VDD2:
mult = (selector / VDD1_2_NUM_VOLT_FINE) + 1;
volt = VDD1_2_MIN_VOLT +
(selector % VDD1_2_NUM_VOLT_FINE) * VDD1_2_OFFSET; break; case TPS65911_REG_VDDCTRL:
volt = VDDCTRL_MIN_VOLT + (selector * VDDCTRL_OFFSET); break; default:
BUG(); return -EINVAL;
}
return volt * 100 * mult;
}
staticint tps65911_list_voltage(struct regulator_dev *dev, unsigned selector)
{ struct tps65910_reg *pmic = rdev_get_drvdata(dev); int step_mv = 0, id = rdev_get_id(dev);
switch (id) { case TPS65911_REG_LDO1: case TPS65911_REG_LDO2: case TPS65911_REG_LDO4: /* The first 5 values of the selector correspond to 1V */ if (selector < 5)
selector = 0; else
selector -= 4;
step_mv = 50; break; case TPS65911_REG_LDO3: case TPS65911_REG_LDO5: case TPS65911_REG_LDO6: case TPS65911_REG_LDO7: case TPS65911_REG_LDO8: /* The first 3 values of the selector correspond to 1V */ if (selector < 3)
selector = 0; else
selector -= 2;
/* * Regulator can not be control from multiple external input EN1, EN2 * and EN3 together.
*/ if (ext_sleep_config & EXT_SLEEP_CONTROL) { int en_count;
en_count = ((ext_sleep_config &
TPS65910_SLEEP_CONTROL_EXT_INPUT_EN1) != 0);
en_count += ((ext_sleep_config &
TPS65910_SLEEP_CONTROL_EXT_INPUT_EN2) != 0);
en_count += ((ext_sleep_config &
TPS65910_SLEEP_CONTROL_EXT_INPUT_EN3) != 0);
en_count += ((ext_sleep_config &
TPS65911_SLEEP_CONTROL_EXT_INPUT_SLEEP) != 0); if (en_count > 1) {
dev_err(mfd->dev, "External sleep control flag is not proper\n"); return -EINVAL;
}
}
pmic->board_ext_control[id] = ext_sleep_config;
/* External EN1 control */ if (ext_sleep_config & TPS65910_SLEEP_CONTROL_EXT_INPUT_EN1)
ret = regmap_set_bits(mfd->regmap,
TPS65910_EN1_LDO_ASS + regoffs, bit_pos); else
ret = regmap_clear_bits(mfd->regmap,
TPS65910_EN1_LDO_ASS + regoffs, bit_pos); if (ret < 0) {
dev_err(mfd->dev, "Error in configuring external control EN1\n"); return ret;
}
/* External EN2 control */ if (ext_sleep_config & TPS65910_SLEEP_CONTROL_EXT_INPUT_EN2)
ret = regmap_set_bits(mfd->regmap,
TPS65910_EN2_LDO_ASS + regoffs, bit_pos); else
ret = regmap_clear_bits(mfd->regmap,
TPS65910_EN2_LDO_ASS + regoffs, bit_pos); if (ret < 0) {
dev_err(mfd->dev, "Error in configuring external control EN2\n"); return ret;
}
/* External EN3 control for TPS65910 LDO only */ if ((tps65910_chip_id(mfd) == TPS65910) &&
(id >= TPS65910_REG_VDIG1)) { if (ext_sleep_config & TPS65910_SLEEP_CONTROL_EXT_INPUT_EN3)
ret = regmap_set_bits(mfd->regmap,
TPS65910_EN3_LDO_ASS + regoffs, bit_pos); else
ret = regmap_clear_bits(mfd->regmap,
TPS65910_EN3_LDO_ASS + regoffs, bit_pos); if (ret < 0) {
dev_err(mfd->dev, "Error in configuring external control EN3\n"); return ret;
}
}
/* Return if no external control is selected */ if (!(ext_sleep_config & EXT_SLEEP_CONTROL)) { /* Clear all sleep controls */
ret = regmap_clear_bits(mfd->regmap,
TPS65910_SLEEP_KEEP_LDO_ON + regoffs, bit_pos); if (!ret)
ret = regmap_clear_bits(mfd->regmap,
TPS65910_SLEEP_SET_LDO_OFF + regoffs, bit_pos); if (ret < 0)
dev_err(mfd->dev, "Error in configuring SLEEP register\n"); return ret;
}
/* * For regulator that has separate operational and sleep register make * sure that operational is used and clear sleep register to turn * regulator off when external control is inactive
*/ if ((id == TPS65910_REG_VDD1) ||
(id == TPS65910_REG_VDD2) ||
((id == TPS65911_REG_VDDCTRL) &&
(tps65910_chip_id(mfd) == TPS65911))) { int op_reg_add = pmic->get_ctrl_reg(id) + 1; int sr_reg_add = pmic->get_ctrl_reg(id) + 2; int opvsel, srvsel;
ret = regmap_read(mfd->regmap, op_reg_add, &opvsel); if (ret < 0) return ret;
ret = regmap_read(mfd->regmap, sr_reg_add, &srvsel); if (ret < 0) return ret;
ret = regmap_write(mfd->regmap, op_reg_add, reg_val); if (ret < 0) {
dev_err(mfd->dev, "Error in configuring op register\n"); return ret;
}
}
ret = regmap_write(mfd->regmap, sr_reg_add, 0); if (ret < 0) {
dev_err(mfd->dev, "Error in setting sr register\n"); return ret;
}
}
ret = regmap_clear_bits(mfd->regmap,
TPS65910_SLEEP_KEEP_LDO_ON + regoffs, bit_pos); if (!ret) { if (ext_sleep_config & TPS65911_SLEEP_CONTROL_EXT_INPUT_SLEEP)
ret = regmap_set_bits(mfd->regmap,
TPS65910_SLEEP_SET_LDO_OFF + regoffs, bit_pos); else
ret = regmap_clear_bits(mfd->regmap,
TPS65910_SLEEP_SET_LDO_OFF + regoffs, bit_pos);
} if (ret < 0)
dev_err(mfd->dev, "Error in configuring SLEEP register\n");
ret = of_property_read_u32(matches[idx].of_node, "ti,regulator-ext-sleep-control", &prop); if (!ret)
pmic_plat_data->regulator_ext_sleep_control[idx] = prop;
/* Give control of all register to control port */
err = regmap_set_bits(pmic->mfd->regmap, TPS65910_DEVCTRL,
DEVCTRL_SR_CTL_I2C_SEL_MASK); if (err < 0) return err;
switch (tps65910_chip_id(tps65910)) { case TPS65910:
BUILD_BUG_ON(TPS65910_NUM_REGS < ARRAY_SIZE(tps65910_regs));
pmic->get_ctrl_reg = &tps65910_get_ctrl_register;
pmic->num_regulators = ARRAY_SIZE(tps65910_regs);
pmic->ext_sleep_control = tps65910_ext_sleep_control;
info = tps65910_regs; /* Work around silicon erratum SWCZ010: output programmed * voltage level can go higher than expected or crash * Workaround: use no synchronization of DCDC clocks
*/
regmap_clear_bits(pmic->mfd->regmap, TPS65910_DCDCCTRL,
DCDCCTRL_DCDCCKSYNC_MASK); break; case TPS65911:
BUILD_BUG_ON(TPS65910_NUM_REGS < ARRAY_SIZE(tps65911_regs));
pmic->get_ctrl_reg = &tps65911_get_ctrl_register;
pmic->num_regulators = ARRAY_SIZE(tps65911_regs);
pmic->ext_sleep_control = tps65911_ext_sleep_control;
info = tps65911_regs; break; default:
dev_err(&pdev->dev, "Invalid tps chip version\n"); return -ENODEV;
}
err = tps65910_set_ext_sleep_config(pmic, i,
pmic_plat_data->regulator_ext_sleep_control[i]); /* * Failing on regulator for configuring externally control * is not a serious issue, just throw warning.
*/ if (err < 0)
dev_warn(tps65910->dev, "Failed to initialise ext control config\n");
/* * Before bootloader jumps to kernel, it makes sure that required * external control signals are in desired state so that given rails * can be configure accordingly. * If rails are configured to be controlled from external control * then before shutting down/rebooting the system, the external * control configuration need to be remove from the rails so that * its output will be available as per register programming even * if external controls are removed. This is require when the POR * value of the control signals are not in active state and before * bootloader initializes it, the system requires the rail output * to be active for booting.
*/ for (i = 0; i < pmic->num_regulators; i++) { int err; if (!pmic->rdev[i]) continue;
err = tps65910_set_ext_sleep_config(pmic, i, 0); if (err < 0)
dev_err(&pdev->dev, "Error in clearing external control\n");
}
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.