diff options
Diffstat (limited to 'drivers/regulator/anatop-regulator.c')
| -rw-r--r-- | drivers/regulator/anatop-regulator.c | 169 | 
1 files changed, 120 insertions, 49 deletions
diff --git a/drivers/regulator/anatop-regulator.c b/drivers/regulator/anatop-regulator.c index 0d4a8ccbb53..4f730af70e7 100644 --- a/drivers/regulator/anatop-regulator.c +++ b/drivers/regulator/anatop-regulator.c @@ -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,18 +187,16 @@ 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);  	if (!sreg)  		return -ENOMEM;  	sreg->initdata = initdata; -	sreg->name = kstrdup(of_get_property(np, "regulator-name", NULL), -			     GFP_KERNEL); +	sreg->name = of_get_property(np, "regulator-name", NULL);  	rdesc = &sreg->rdesc; -	memset(rdesc, 0, sizeof(*rdesc));  	rdesc->name = sreg->name; -	rdesc->ops = &anatop_rops;  	rdesc->type = REGULATOR_VOLTAGE;  	rdesc->owner = THIS_MODULE; @@ -143,37 +212,37 @@ static int anatop_regulator_probe(struct platform_device *pdev)  				   &sreg->control_reg);  	if (ret) {  		dev_err(dev, "no anatop-reg-offset property set\n"); -		goto anatop_probe_end; +		return ret;  	}  	ret = of_property_read_u32(np, "anatop-vol-bit-width",  				   &sreg->vol_bit_width);  	if (ret) {  		dev_err(dev, "no anatop-vol-bit-width property set\n"); -		goto anatop_probe_end; +		return ret;  	}  	ret = of_property_read_u32(np, "anatop-vol-bit-shift",  				   &sreg->vol_bit_shift);  	if (ret) {  		dev_err(dev, "no anatop-vol-bit-shift property set\n"); -		goto anatop_probe_end; +		return ret;  	}  	ret = of_property_read_u32(np, "anatop-min-bit-val",  				   &sreg->min_bit_val);  	if (ret) {  		dev_err(dev, "no anatop-min-bit-val property set\n"); -		goto anatop_probe_end; +		return ret;  	}  	ret = of_property_read_u32(np, "anatop-min-voltage",  				   &sreg->min_voltage);  	if (ret) {  		dev_err(dev, "no anatop-min-voltage property set\n"); -		goto anatop_probe_end; +		return ret;  	}  	ret = of_property_read_u32(np, "anatop-max-voltage",  				   &sreg->max_voltage);  	if (ret) {  		dev_err(dev, "no anatop-max-voltage property set\n"); -		goto anatop_probe_end; +		return ret;  	}  	/* read LDO ramp up setting, only for core reg */ @@ -199,37 +268,39 @@ 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 = regulator_register(rdesc, &config); +	rdev = devm_regulator_register(dev, rdesc, &config);  	if (IS_ERR(rdev)) {  		dev_err(dev, "failed to register %s\n",  			rdesc->name); -		ret = PTR_ERR(rdev); -		goto anatop_probe_end; +		return PTR_ERR(rdev);  	}  	platform_set_drvdata(pdev, rdev); -anatop_probe_end: -	if (ret) -		kfree(sreg->name); - -	return ret; -} - -static int anatop_regulator_remove(struct platform_device *pdev) -{ -	struct regulator_dev *rdev = platform_get_drvdata(pdev); -	struct anatop_regulator *sreg = rdev_get_drvdata(rdev); -	const char *name = sreg->name; - -	regulator_unregister(rdev); -	kfree(name); -  	return 0;  } -static struct of_device_id of_anatop_regulator_match_tbl[] = { +static const struct of_device_id of_anatop_regulator_match_tbl[] = {  	{ .compatible = "fsl,anatop-regulator", },  	{ /* end */ }  }; @@ -241,7 +312,6 @@ static struct platform_driver anatop_regulator_driver = {  		.of_match_table = of_anatop_regulator_match_tbl,  	},  	.probe	= anatop_regulator_probe, -	.remove	= anatop_regulator_remove,  };  static int __init anatop_regulator_init(void) @@ -256,7 +326,8 @@ static void __exit anatop_regulator_exit(void)  }  module_exit(anatop_regulator_exit); -MODULE_AUTHOR("Nancy Chen <Nancy.Chen@freescale.com>, " -	      "Ying-Chun Liu (PaulLiu) <paul.liu@linaro.org>"); +MODULE_AUTHOR("Nancy Chen <Nancy.Chen@freescale.com>"); +MODULE_AUTHOR("Ying-Chun Liu (PaulLiu) <paul.liu@linaro.org>");  MODULE_DESCRIPTION("ANATOP Regulator driver");  MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:anatop_regulator");  | 
