summaryrefslogtreecommitdiff
path: root/drivers/regulator/anatop-regulator.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/regulator/anatop-regulator.c')
-rw-r--r--drivers/regulator/anatop-regulator.c103
1 files changed, 88 insertions, 15 deletions
diff --git a/drivers/regulator/anatop-regulator.c b/drivers/regulator/anatop-regulator.c
index c5e272ea4372..21f72f1c1100 100644
--- a/drivers/regulator/anatop-regulator.c
+++ b/drivers/regulator/anatop-regulator.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2011 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright (C) 2011-2015 Freescale Semiconductor, Inc. All Rights Reserved.
*/
/*
@@ -38,6 +38,8 @@
#define LDO_POWER_GATE 0x00
#define LDO_FET_FULL_ON 0x1f
+#define LDO_MIN_DROPOUT_UV 125000
+
struct anatop_regulator {
const char *name;
u32 control_reg;
@@ -54,8 +56,12 @@ struct anatop_regulator {
struct regulator_init_data *initdata;
bool bypass;
int sel;
+ u32 enable_bit;
};
+static struct anatop_regulator *vddpu;
+static struct anatop_regulator *vddsoc;
+
static int anatop_regmap_set_voltage_time_sel(struct regulator_dev *reg,
unsigned int old_sel,
unsigned int new_sel)
@@ -82,21 +88,32 @@ static int anatop_regmap_set_voltage_time_sel(struct regulator_dev *reg,
return ret;
}
-static int anatop_regmap_enable(struct regulator_dev *reg)
+static int anatop_core_regmap_enable(struct regulator_dev *reg)
{
struct anatop_regulator *anatop_reg = rdev_get_drvdata(reg);
int sel;
+ /*
+ * The vddpu has to stay at the same voltage level as vddsoc
+ * whenever it's about to be enabled.
+ */
+ if (anatop_reg == vddpu && vddsoc) {
+ anatop_reg->sel = vddsoc->sel;
+ anatop_reg->bypass = vddsoc->bypass;
+ if (anatop_reg->bypass)
+ anatop_reg->rdesc.min_dropout_uV = 0;
+ }
+
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)
+static int anatop_core_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)
+static int anatop_core_regmap_is_enabled(struct regulator_dev *reg)
{
return regulator_get_voltage_sel_regmap(reg) != LDO_POWER_GATE;
}
@@ -107,7 +124,7 @@ static int anatop_regmap_core_set_voltage_sel(struct regulator_dev *reg,
struct anatop_regulator *anatop_reg = rdev_get_drvdata(reg);
int ret;
- if (anatop_reg->bypass || !anatop_regmap_is_enabled(reg)) {
+ if (anatop_reg->bypass || !anatop_core_regmap_is_enabled(reg)) {
anatop_reg->sel = selector;
return 0;
}
@@ -122,7 +139,7 @@ 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))
+ if (anatop_reg->bypass || !anatop_core_regmap_is_enabled(reg))
return anatop_reg->sel;
return regulator_get_voltage_sel_regmap(reg);
@@ -153,11 +170,52 @@ static int anatop_regmap_set_bypass(struct regulator_dev *reg, bool enable)
sel = enable ? LDO_FET_FULL_ON : anatop_reg->sel;
anatop_reg->bypass = enable;
+ if (anatop_reg->bypass)
+ anatop_reg->rdesc.min_dropout_uV = 0;
+ else
+ anatop_reg->rdesc.min_dropout_uV = LDO_MIN_DROPOUT_UV;
return regulator_set_voltage_sel_regmap(reg, sel);
}
+static int anatop_regmap_enable(struct regulator_dev *reg)
+{
+ u32 val;
+ struct anatop_regulator *anatop_reg = rdev_get_drvdata(reg);
+
+ regmap_read(anatop_reg->anatop, anatop_reg->control_reg, &val);
+ val |= (1 << anatop_reg->enable_bit);
+ regmap_write(anatop_reg->anatop, anatop_reg->control_reg, val);
+
+ return 0;
+}
+
+static int anatop_regmap_disable(struct regulator_dev *reg)
+{
+ u32 val;
+ struct anatop_regulator *anatop_reg = rdev_get_drvdata(reg);
+
+ regmap_read(anatop_reg->anatop, anatop_reg->control_reg, &val);
+ val &= ~(1 << anatop_reg->enable_bit);
+ regmap_write(anatop_reg->anatop, anatop_reg->control_reg, val);
+
+ return 0;
+}
+
+static int anatop_regmap_is_enabled(struct regulator_dev *reg)
+{
+ u32 val;
+ struct anatop_regulator *anatop_reg = rdev_get_drvdata(reg);
+
+ regmap_read(anatop_reg->anatop, anatop_reg->control_reg, &val);
+
+ return !!(val & (1 << anatop_reg->enable_bit));
+}
+
static struct regulator_ops anatop_rops = {
+ .enable = anatop_regmap_enable,
+ .disable = anatop_regmap_disable,
+ .is_enabled = anatop_regmap_is_enabled,
.set_voltage_sel = regulator_set_voltage_sel_regmap,
.get_voltage_sel = regulator_get_voltage_sel_regmap,
.list_voltage = regulator_list_voltage_linear,
@@ -165,9 +223,9 @@ static struct regulator_ops anatop_rops = {
};
static struct regulator_ops anatop_core_rops = {
- .enable = anatop_regmap_enable,
- .disable = anatop_regmap_disable,
- .is_enabled = anatop_regmap_is_enabled,
+ .enable = anatop_core_regmap_enable,
+ .disable = anatop_core_regmap_disable,
+ .is_enabled = anatop_core_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_core_get_voltage_sel,
@@ -194,6 +252,12 @@ static int anatop_regulator_probe(struct platform_device *pdev)
if (!sreg)
return -ENOMEM;
sreg->name = of_get_property(np, "regulator-name", NULL);
+
+ if (!sreg->name) {
+ dev_err(dev, "no regulator-name set\n");
+ return -EINVAL;
+ }
+
rdesc = &sreg->rdesc;
rdesc->name = sreg->name;
rdesc->type = REGULATOR_VOLTAGE;
@@ -203,6 +267,11 @@ static int anatop_regulator_probe(struct platform_device *pdev)
initdata->supply_regulator = "vin";
sreg->initdata = initdata;
+ if (strcmp(sreg->name, "vddpu") == 0)
+ vddpu = sreg;
+ else if (strcmp(sreg->name, "vddsoc") == 0)
+ vddsoc = sreg;
+
anatop_np = of_get_parent(np);
if (!anatop_np)
return -ENODEV;
@@ -256,6 +325,9 @@ static int anatop_regulator_probe(struct platform_device *pdev)
of_property_read_u32(np, "anatop-delay-bit-shift",
&sreg->delay_bit_shift);
+ /* Only 3p0, 2p5, and 1p1 has enable bit */
+ of_property_read_u32(np, "anatop-enable-bit", &sreg->enable_bit);
+
rdesc->n_voltages = (sreg->max_voltage - sreg->min_voltage) / 25000 + 1
+ sreg->min_bit_val;
rdesc->min_uV = sreg->min_voltage;
@@ -264,7 +336,7 @@ static int anatop_regulator_probe(struct platform_device *pdev)
rdesc->vsel_reg = sreg->control_reg;
rdesc->vsel_mask = ((1 << sreg->vol_bit_width) - 1) <<
sreg->vol_bit_shift;
- rdesc->min_dropout_uV = 125000;
+ rdesc->min_dropout_uV = LDO_MIN_DROPOUT_UV;
config.dev = &pdev->dev;
config.init_data = initdata;
@@ -286,6 +358,7 @@ static int anatop_regulator_probe(struct platform_device *pdev)
if (sreg->sel == LDO_FET_FULL_ON) {
sreg->sel = 0;
sreg->bypass = true;
+ rdesc->min_dropout_uV = 0;
}
/*
@@ -297,8 +370,7 @@ static int anatop_regulator_probe(struct platform_device *pdev)
sreg->sel = 22;
/* set the default voltage of the pcie phy to be 1.100v */
- if (!sreg->sel && rdesc->name &&
- !strcmp(rdesc->name, "vddpcie"))
+ if (!sreg->sel && !strcmp(sreg->name, "vddpcie-phy"))
sreg->sel = 0x10;
if (!sreg->bypass && !sreg->sel) {
@@ -312,9 +384,10 @@ static int anatop_regulator_probe(struct platform_device *pdev)
/* register regulator */
rdev = devm_regulator_register(dev, rdesc, &config);
if (IS_ERR(rdev)) {
- dev_err(dev, "failed to register %s\n",
- rdesc->name);
- return PTR_ERR(rdev);
+ ret = PTR_ERR(rdev);
+ if (ret != -EPROBE_DEFER)
+ dev_err(dev, "failed to register %s\n", rdesc->name);
+ return ret;
}
platform_set_drvdata(pdev, rdev);