|
@@ -34,6 +34,9 @@
|
|
|
#define LDO_RAMP_UP_UNIT_IN_CYCLES 64 /* 64 cycles per step */
|
|
|
#define LDO_RAMP_UP_FREQ_IN_MHZ 24 /* cycle based on 24M OSC */
|
|
|
|
|
|
+#define LDO_POWER_GATE 0x00
|
|
|
+#define LDO_FET_FULL_ON 0x1f
|
|
|
+
|
|
|
struct anatop_regulator {
|
|
|
const char *name;
|
|
|
u32 control_reg;
|
|
@@ -48,19 +51,10 @@ struct anatop_regulator {
|
|
|
int max_voltage;
|
|
|
struct regulator_desc rdesc;
|
|
|
struct regulator_init_data *initdata;
|
|
|
+ bool bypass;
|
|
|
+ int sel;
|
|
|
};
|
|
|
|
|
|
-static int anatop_regmap_set_voltage_sel(struct regulator_dev *reg,
|
|
|
- unsigned selector)
|
|
|
-{
|
|
|
- struct anatop_regulator *anatop_reg = rdev_get_drvdata(reg);
|
|
|
-
|
|
|
- if (!anatop_reg->control_reg)
|
|
|
- return -ENOTSUPP;
|
|
|
-
|
|
|
- return regulator_set_voltage_sel_regmap(reg, selector);
|
|
|
-}
|
|
|
-
|
|
|
static int anatop_regmap_set_voltage_time_sel(struct regulator_dev *reg,
|
|
|
unsigned int old_sel,
|
|
|
unsigned int new_sel)
|
|
@@ -87,22 +81,99 @@ static int anatop_regmap_set_voltage_time_sel(struct regulator_dev *reg,
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
-static int anatop_regmap_get_voltage_sel(struct regulator_dev *reg)
|
|
|
+static int anatop_regmap_enable(struct regulator_dev *reg)
|
|
|
{
|
|
|
struct anatop_regulator *anatop_reg = rdev_get_drvdata(reg);
|
|
|
+ int sel;
|
|
|
|
|
|
- if (!anatop_reg->control_reg)
|
|
|
- return -ENOTSUPP;
|
|
|
+ sel = anatop_reg->bypass ? LDO_FET_FULL_ON : anatop_reg->sel;
|
|
|
+ return regulator_set_voltage_sel_regmap(reg, sel);
|
|
|
+}
|
|
|
+
|
|
|
+static int anatop_regmap_disable(struct regulator_dev *reg)
|
|
|
+{
|
|
|
+ return regulator_set_voltage_sel_regmap(reg, LDO_POWER_GATE);
|
|
|
+}
|
|
|
+
|
|
|
+static int anatop_regmap_is_enabled(struct regulator_dev *reg)
|
|
|
+{
|
|
|
+ return regulator_get_voltage_sel_regmap(reg) != LDO_POWER_GATE;
|
|
|
+}
|
|
|
+
|
|
|
+static int anatop_regmap_core_set_voltage_sel(struct regulator_dev *reg,
|
|
|
+ unsigned selector)
|
|
|
+{
|
|
|
+ struct anatop_regulator *anatop_reg = rdev_get_drvdata(reg);
|
|
|
+ int ret;
|
|
|
+
|
|
|
+ if (anatop_reg->bypass || !anatop_regmap_is_enabled(reg)) {
|
|
|
+ anatop_reg->sel = selector;
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ ret = regulator_set_voltage_sel_regmap(reg, selector);
|
|
|
+ if (!ret)
|
|
|
+ anatop_reg->sel = selector;
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|
|
|
+static int anatop_regmap_core_get_voltage_sel(struct regulator_dev *reg)
|
|
|
+{
|
|
|
+ struct anatop_regulator *anatop_reg = rdev_get_drvdata(reg);
|
|
|
+
|
|
|
+ if (anatop_reg->bypass || !anatop_regmap_is_enabled(reg))
|
|
|
+ return anatop_reg->sel;
|
|
|
|
|
|
return regulator_get_voltage_sel_regmap(reg);
|
|
|
}
|
|
|
|
|
|
+static int anatop_regmap_get_bypass(struct regulator_dev *reg, bool *enable)
|
|
|
+{
|
|
|
+ struct anatop_regulator *anatop_reg = rdev_get_drvdata(reg);
|
|
|
+ int sel;
|
|
|
+
|
|
|
+ sel = regulator_get_voltage_sel_regmap(reg);
|
|
|
+ if (sel == LDO_FET_FULL_ON)
|
|
|
+ WARN_ON(!anatop_reg->bypass);
|
|
|
+ else if (sel != LDO_POWER_GATE)
|
|
|
+ WARN_ON(anatop_reg->bypass);
|
|
|
+
|
|
|
+ *enable = anatop_reg->bypass;
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static int anatop_regmap_set_bypass(struct regulator_dev *reg, bool enable)
|
|
|
+{
|
|
|
+ struct anatop_regulator *anatop_reg = rdev_get_drvdata(reg);
|
|
|
+ int sel;
|
|
|
+
|
|
|
+ if (enable == anatop_reg->bypass)
|
|
|
+ return 0;
|
|
|
+
|
|
|
+ sel = enable ? LDO_FET_FULL_ON : anatop_reg->sel;
|
|
|
+ anatop_reg->bypass = enable;
|
|
|
+
|
|
|
+ return regulator_set_voltage_sel_regmap(reg, sel);
|
|
|
+}
|
|
|
+
|
|
|
static struct regulator_ops anatop_rops = {
|
|
|
- .set_voltage_sel = anatop_regmap_set_voltage_sel,
|
|
|
+ .set_voltage_sel = regulator_set_voltage_sel_regmap,
|
|
|
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
|
|
|
+ .list_voltage = regulator_list_voltage_linear,
|
|
|
+ .map_voltage = regulator_map_voltage_linear,
|
|
|
+};
|
|
|
+
|
|
|
+static struct regulator_ops anatop_core_rops = {
|
|
|
+ .enable = anatop_regmap_enable,
|
|
|
+ .disable = anatop_regmap_disable,
|
|
|
+ .is_enabled = anatop_regmap_is_enabled,
|
|
|
+ .set_voltage_sel = anatop_regmap_core_set_voltage_sel,
|
|
|
.set_voltage_time_sel = anatop_regmap_set_voltage_time_sel,
|
|
|
- .get_voltage_sel = anatop_regmap_get_voltage_sel,
|
|
|
+ .get_voltage_sel = anatop_regmap_core_get_voltage_sel,
|
|
|
.list_voltage = regulator_list_voltage_linear,
|
|
|
.map_voltage = regulator_map_voltage_linear,
|
|
|
+ .get_bypass = anatop_regmap_get_bypass,
|
|
|
+ .set_bypass = anatop_regmap_set_bypass,
|
|
|
};
|
|
|
|
|
|
static int anatop_regulator_probe(struct platform_device *pdev)
|
|
@@ -116,6 +187,7 @@ static int anatop_regulator_probe(struct platform_device *pdev)
|
|
|
struct regulator_init_data *initdata;
|
|
|
struct regulator_config config = { };
|
|
|
int ret = 0;
|
|
|
+ u32 val;
|
|
|
|
|
|
initdata = of_get_regulator_init_data(dev, np);
|
|
|
sreg = devm_kzalloc(dev, sizeof(*sreg), GFP_KERNEL);
|
|
@@ -125,7 +197,6 @@ static int anatop_regulator_probe(struct platform_device *pdev)
|
|
|
sreg->name = of_get_property(np, "regulator-name", NULL);
|
|
|
rdesc = &sreg->rdesc;
|
|
|
rdesc->name = sreg->name;
|
|
|
- rdesc->ops = &anatop_rops;
|
|
|
rdesc->type = REGULATOR_VOLTAGE;
|
|
|
rdesc->owner = THIS_MODULE;
|
|
|
|
|
@@ -197,6 +268,25 @@ static int anatop_regulator_probe(struct platform_device *pdev)
|
|
|
config.of_node = pdev->dev.of_node;
|
|
|
config.regmap = sreg->anatop;
|
|
|
|
|
|
+ /* Only core regulators have the ramp up delay configuration. */
|
|
|
+ if (sreg->control_reg && sreg->delay_bit_width) {
|
|
|
+ rdesc->ops = &anatop_core_rops;
|
|
|
+
|
|
|
+ ret = regmap_read(config.regmap, rdesc->vsel_reg, &val);
|
|
|
+ if (ret) {
|
|
|
+ dev_err(dev, "failed to read initial state\n");
|
|
|
+ return ret;
|
|
|
+ }
|
|
|
+
|
|
|
+ sreg->sel = (val & rdesc->vsel_mask) >> sreg->vol_bit_shift;
|
|
|
+ if (sreg->sel == LDO_FET_FULL_ON) {
|
|
|
+ sreg->sel = 0;
|
|
|
+ sreg->bypass = true;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ rdesc->ops = &anatop_rops;
|
|
|
+ }
|
|
|
+
|
|
|
/* register regulator */
|
|
|
rdev = devm_regulator_register(dev, rdesc, &config);
|
|
|
if (IS_ERR(rdev)) {
|