Patchwork [2/3] regulator: palmas: support for external regulator through control outputs

login
register
mail settings
Submitter Laxman Dewangan
Date April 17, 2013, 9:43 a.m.
Message ID <1366191793-13934-2-git-send-email-ldewangan@nvidia.com>
Download mbox | patch
Permalink /patch/237185/
State Not Applicable, archived
Headers show

Comments

Laxman Dewangan - April 17, 2013, 9:43 a.m.
Palmas device have control outputs like REGEN1, REGEN2, REGEN3,
SYSEN1 and SYSEN2. These control outputs can be used for controlling
external voltage switches to enabled/disable voltage outputs.

Add support of these control outputs through regulator framework.

Signed-off-by: Laxman Dewangan <ldewangan@nvidia.com>
---
 drivers/regulator/palmas-regulator.c |   95 +++++++++++++++++++++++++++++----
 include/linux/mfd/palmas.h           |    6 ++
 2 files changed, 89 insertions(+), 12 deletions(-)
Graeme Gregory - April 17, 2013, 1:51 p.m.
This looks good to me with one proviso!

SYSEN1/2 are not necessarily for regulators as given by the name, they
are more for use indicating to other chips that power is now
available/stable.

But it will not break things to have them exposed in regulator API so I
shall leave this to Mark.

Graeme

On 17/04/13 10:43, Laxman Dewangan wrote:
> Palmas device have control outputs like REGEN1, REGEN2, REGEN3,
> SYSEN1 and SYSEN2. These control outputs can be used for controlling
> external voltage switches to enabled/disable voltage outputs.
>
> Add support of these control outputs through regulator framework.
>
> Signed-off-by: Laxman Dewangan <ldewangan@nvidia.com>
> ---
>  drivers/regulator/palmas-regulator.c |   95 +++++++++++++++++++++++++++++----
>  include/linux/mfd/palmas.h           |    6 ++
>  2 files changed, 89 insertions(+), 12 deletions(-)
>
> diff --git a/drivers/regulator/palmas-regulator.c b/drivers/regulator/palmas-regulator.c
> index 7c7992b..28080a7 100644
> --- a/drivers/regulator/palmas-regulator.c
> +++ b/drivers/regulator/palmas-regulator.c
> @@ -166,6 +166,26 @@ static const struct regs_info palmas_regs_info[] = {
>  		.vsel_addr	= PALMAS_LDOUSB_VOLTAGE,
>  		.ctrl_addr	= PALMAS_LDOUSB_CTRL,
>  	},
> +	{
> +		.name		= "REGEN1",
> +		.ctrl_addr	= PALMAS_REGEN1_CTRL,
> +	},
> +	{
> +		.name		= "REGEN2",
> +		.ctrl_addr	= PALMAS_REGEN2_CTRL,
> +	},
> +	{
> +		.name		= "REGEN3",
> +		.ctrl_addr	= PALMAS_REGEN3_CTRL,
> +	},
> +	{
> +		.name		= "SYSEN1",
> +		.ctrl_addr	= PALMAS_SYSEN1_CTRL,
> +	},
> +	{
> +		.name		= "SYSEN2",
> +		.ctrl_addr	= PALMAS_SYSEN2_CTRL,
> +	},
>  };
>  
>  #define SMPS_CTRL_MODE_OFF		0x00
> @@ -423,6 +443,12 @@ static struct regulator_ops palmas_ops_ldo = {
>  	.map_voltage		= regulator_map_voltage_linear,
>  };
>  
> +static struct regulator_ops palmas_ops_extreg = {
> +	.is_enabled		= regulator_is_enabled_regmap,
> +	.enable			= regulator_enable_regmap,
> +	.disable		= regulator_disable_regmap,
> +};
> +
>  /*
>   * setup the hardware based sleep configuration of the SMPS/LDO regulators
>   * from the platform data. This is different to the software based control
> @@ -524,6 +550,28 @@ static int palmas_ldo_init(struct palmas *palmas, int id,
>  	return 0;
>  }
>  
> +static int palmas_extreg_init(struct palmas *palmas, int id,
> +		struct palmas_reg_init *reg_init)
> +{
> +	unsigned int addr;
> +	int ret;
> +	unsigned int val = 0;
> +
> +	addr = palmas_regs_info[id].ctrl_addr;
> +
> +	if (reg_init->mode_sleep)
> +		val = PALMAS_REGEN1_CTRL_MODE_SLEEP;
> +
> +	ret = palmas_update_bits(palmas, PALMAS_RESOURCE_BASE,
> +			addr, PALMAS_REGEN1_CTRL_MODE_SLEEP, val);
> +	if (ret < 0) {
> +		dev_err(palmas->dev, "Resource reg 0x%02x update failed %d\n",
> +			addr, ret);
> +		return ret;
> +	}
> +	return 0;
> +}
> +
>  static struct of_regulator_match palmas_matches[] = {
>  	{ .name = "smps12", },
>  	{ .name = "smps123", },
> @@ -546,6 +594,11 @@ static struct of_regulator_match palmas_matches[] = {
>  	{ .name = "ldo9", },
>  	{ .name = "ldoln", },
>  	{ .name = "ldousb", },
> +	{ .name = "regen1", },
> +	{ .name = "regen2", },
> +	{ .name = "regen3", },
> +	{ .name = "sysen1", },
> +	{ .name = "sysen2", },
>  };
>  
>  static void palmas_dt_to_pdata(struct device *dev,
> @@ -764,21 +817,34 @@ static int palmas_regulators_probe(struct platform_device *pdev)
>  		/* Register the regulators */
>  		pmic->desc[id].name = palmas_regs_info[id].name;
>  		pmic->desc[id].id = id;
> -		pmic->desc[id].n_voltages = PALMAS_LDO_NUM_VOLTAGES;
> -
> -		pmic->desc[id].ops = &palmas_ops_ldo;
> -
>  		pmic->desc[id].type = REGULATOR_VOLTAGE;
>  		pmic->desc[id].owner = THIS_MODULE;
> -		pmic->desc[id].min_uV = 900000;
> -		pmic->desc[id].uV_step = 50000;
> -		pmic->desc[id].linear_min_sel = 1;
> -		pmic->desc[id].vsel_reg = PALMAS_BASE_TO_REG(PALMAS_LDO_BASE,
> +
> +		if (id < PALMAS_REG_REGEN1) {
> +			pmic->desc[id].n_voltages = PALMAS_LDO_NUM_VOLTAGES;
> +			pmic->desc[id].ops = &palmas_ops_ldo;
> +			pmic->desc[id].min_uV = 900000;
> +			pmic->desc[id].uV_step = 50000;
> +			pmic->desc[id].linear_min_sel = 1;
> +			pmic->desc[id].vsel_reg =
> +					PALMAS_BASE_TO_REG(PALMAS_LDO_BASE,
>  						palmas_regs_info[id].vsel_addr);
> -		pmic->desc[id].vsel_mask = PALMAS_LDO1_VOLTAGE_VSEL_MASK;
> -		pmic->desc[id].enable_reg = PALMAS_BASE_TO_REG(PALMAS_LDO_BASE,
> +			pmic->desc[id].vsel_mask =
> +					PALMAS_LDO1_VOLTAGE_VSEL_MASK;
> +			pmic->desc[id].enable_reg =
> +					PALMAS_BASE_TO_REG(PALMAS_LDO_BASE,
> +						palmas_regs_info[id].ctrl_addr);
> +			pmic->desc[id].enable_mask =
> +					PALMAS_LDO1_CTRL_MODE_ACTIVE;
> +		} else {
> +			pmic->desc[id].n_voltages = 1;
> +			pmic->desc[id].ops = &palmas_ops_extreg;
> +			pmic->desc[id].enable_reg =
> +					PALMAS_BASE_TO_REG(PALMAS_RESOURCE_BASE,
>  						palmas_regs_info[id].ctrl_addr);
> -		pmic->desc[id].enable_mask = PALMAS_LDO1_CTRL_MODE_ACTIVE;
> +			pmic->desc[id].enable_mask =
> +					PALMAS_REGEN1_CTRL_MODE_ACTIVE;
> +		}
>  
>  		if (pdata)
>  			config.init_data = pdata->reg_data[id];
> @@ -804,7 +870,12 @@ static int palmas_regulators_probe(struct platform_device *pdev)
>  		if (pdata) {
>  			reg_init = pdata->reg_init[id];
>  			if (reg_init) {
> -				ret = palmas_ldo_init(palmas, id, reg_init);
> +				if (id < PALMAS_REG_REGEN1)
> +					ret = palmas_ldo_init(palmas,
> +							id, reg_init);
> +				else
> +					ret = palmas_extreg_init(palmas,
> +							id, reg_init);
>  				if (ret) {
>  					regulator_unregister(pmic->rdev[id]);
>  					goto err_unregister_regulator;
> diff --git a/include/linux/mfd/palmas.h b/include/linux/mfd/palmas.h
> index 4a066d0..fb04d07 100644
> --- a/include/linux/mfd/palmas.h
> +++ b/include/linux/mfd/palmas.h
> @@ -164,6 +164,12 @@ enum palmas_regulators {
>  	PALMAS_REG_LDO9,
>  	PALMAS_REG_LDOLN,
>  	PALMAS_REG_LDOUSB,
> +	/* External regulators */
> +	PALMAS_REG_REGEN1,
> +	PALMAS_REG_REGEN2,
> +	PALMAS_REG_REGEN3,
> +	PALMAS_REG_SYSEN1,
> +	PALMAS_REG_SYSEN2,
>  	/* Total number of regulators */
>  	PALMAS_NUM_REGS,
>  };

--
To unsubscribe from this list: send the line "unsubscribe linux-tegra" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Mark Brown - April 17, 2013, 2:06 p.m.
On Wed, Apr 17, 2013 at 02:51:34PM +0100, Graeme Gregory wrote:
> This looks good to me with one proviso!

> SYSEN1/2 are not necessarily for regulators as given by the name, they
> are more for use indicating to other chips that power is now
> available/stable.

> But it will not break things to have them exposed in regulator API so I
> shall leave this to Mark.

It's probably reasonable given that things like this normally end up
being part of the power sequencing or used for external regulators.
Applied, thanks.

Patch

diff --git a/drivers/regulator/palmas-regulator.c b/drivers/regulator/palmas-regulator.c
index 7c7992b..28080a7 100644
--- a/drivers/regulator/palmas-regulator.c
+++ b/drivers/regulator/palmas-regulator.c
@@ -166,6 +166,26 @@  static const struct regs_info palmas_regs_info[] = {
 		.vsel_addr	= PALMAS_LDOUSB_VOLTAGE,
 		.ctrl_addr	= PALMAS_LDOUSB_CTRL,
 	},
+	{
+		.name		= "REGEN1",
+		.ctrl_addr	= PALMAS_REGEN1_CTRL,
+	},
+	{
+		.name		= "REGEN2",
+		.ctrl_addr	= PALMAS_REGEN2_CTRL,
+	},
+	{
+		.name		= "REGEN3",
+		.ctrl_addr	= PALMAS_REGEN3_CTRL,
+	},
+	{
+		.name		= "SYSEN1",
+		.ctrl_addr	= PALMAS_SYSEN1_CTRL,
+	},
+	{
+		.name		= "SYSEN2",
+		.ctrl_addr	= PALMAS_SYSEN2_CTRL,
+	},
 };
 
 #define SMPS_CTRL_MODE_OFF		0x00
@@ -423,6 +443,12 @@  static struct regulator_ops palmas_ops_ldo = {
 	.map_voltage		= regulator_map_voltage_linear,
 };
 
+static struct regulator_ops palmas_ops_extreg = {
+	.is_enabled		= regulator_is_enabled_regmap,
+	.enable			= regulator_enable_regmap,
+	.disable		= regulator_disable_regmap,
+};
+
 /*
  * setup the hardware based sleep configuration of the SMPS/LDO regulators
  * from the platform data. This is different to the software based control
@@ -524,6 +550,28 @@  static int palmas_ldo_init(struct palmas *palmas, int id,
 	return 0;
 }
 
+static int palmas_extreg_init(struct palmas *palmas, int id,
+		struct palmas_reg_init *reg_init)
+{
+	unsigned int addr;
+	int ret;
+	unsigned int val = 0;
+
+	addr = palmas_regs_info[id].ctrl_addr;
+
+	if (reg_init->mode_sleep)
+		val = PALMAS_REGEN1_CTRL_MODE_SLEEP;
+
+	ret = palmas_update_bits(palmas, PALMAS_RESOURCE_BASE,
+			addr, PALMAS_REGEN1_CTRL_MODE_SLEEP, val);
+	if (ret < 0) {
+		dev_err(palmas->dev, "Resource reg 0x%02x update failed %d\n",
+			addr, ret);
+		return ret;
+	}
+	return 0;
+}
+
 static struct of_regulator_match palmas_matches[] = {
 	{ .name = "smps12", },
 	{ .name = "smps123", },
@@ -546,6 +594,11 @@  static struct of_regulator_match palmas_matches[] = {
 	{ .name = "ldo9", },
 	{ .name = "ldoln", },
 	{ .name = "ldousb", },
+	{ .name = "regen1", },
+	{ .name = "regen2", },
+	{ .name = "regen3", },
+	{ .name = "sysen1", },
+	{ .name = "sysen2", },
 };
 
 static void palmas_dt_to_pdata(struct device *dev,
@@ -764,21 +817,34 @@  static int palmas_regulators_probe(struct platform_device *pdev)
 		/* Register the regulators */
 		pmic->desc[id].name = palmas_regs_info[id].name;
 		pmic->desc[id].id = id;
-		pmic->desc[id].n_voltages = PALMAS_LDO_NUM_VOLTAGES;
-
-		pmic->desc[id].ops = &palmas_ops_ldo;
-
 		pmic->desc[id].type = REGULATOR_VOLTAGE;
 		pmic->desc[id].owner = THIS_MODULE;
-		pmic->desc[id].min_uV = 900000;
-		pmic->desc[id].uV_step = 50000;
-		pmic->desc[id].linear_min_sel = 1;
-		pmic->desc[id].vsel_reg = PALMAS_BASE_TO_REG(PALMAS_LDO_BASE,
+
+		if (id < PALMAS_REG_REGEN1) {
+			pmic->desc[id].n_voltages = PALMAS_LDO_NUM_VOLTAGES;
+			pmic->desc[id].ops = &palmas_ops_ldo;
+			pmic->desc[id].min_uV = 900000;
+			pmic->desc[id].uV_step = 50000;
+			pmic->desc[id].linear_min_sel = 1;
+			pmic->desc[id].vsel_reg =
+					PALMAS_BASE_TO_REG(PALMAS_LDO_BASE,
 						palmas_regs_info[id].vsel_addr);
-		pmic->desc[id].vsel_mask = PALMAS_LDO1_VOLTAGE_VSEL_MASK;
-		pmic->desc[id].enable_reg = PALMAS_BASE_TO_REG(PALMAS_LDO_BASE,
+			pmic->desc[id].vsel_mask =
+					PALMAS_LDO1_VOLTAGE_VSEL_MASK;
+			pmic->desc[id].enable_reg =
+					PALMAS_BASE_TO_REG(PALMAS_LDO_BASE,
+						palmas_regs_info[id].ctrl_addr);
+			pmic->desc[id].enable_mask =
+					PALMAS_LDO1_CTRL_MODE_ACTIVE;
+		} else {
+			pmic->desc[id].n_voltages = 1;
+			pmic->desc[id].ops = &palmas_ops_extreg;
+			pmic->desc[id].enable_reg =
+					PALMAS_BASE_TO_REG(PALMAS_RESOURCE_BASE,
 						palmas_regs_info[id].ctrl_addr);
-		pmic->desc[id].enable_mask = PALMAS_LDO1_CTRL_MODE_ACTIVE;
+			pmic->desc[id].enable_mask =
+					PALMAS_REGEN1_CTRL_MODE_ACTIVE;
+		}
 
 		if (pdata)
 			config.init_data = pdata->reg_data[id];
@@ -804,7 +870,12 @@  static int palmas_regulators_probe(struct platform_device *pdev)
 		if (pdata) {
 			reg_init = pdata->reg_init[id];
 			if (reg_init) {
-				ret = palmas_ldo_init(palmas, id, reg_init);
+				if (id < PALMAS_REG_REGEN1)
+					ret = palmas_ldo_init(palmas,
+							id, reg_init);
+				else
+					ret = palmas_extreg_init(palmas,
+							id, reg_init);
 				if (ret) {
 					regulator_unregister(pmic->rdev[id]);
 					goto err_unregister_regulator;
diff --git a/include/linux/mfd/palmas.h b/include/linux/mfd/palmas.h
index 4a066d0..fb04d07 100644
--- a/include/linux/mfd/palmas.h
+++ b/include/linux/mfd/palmas.h
@@ -164,6 +164,12 @@  enum palmas_regulators {
 	PALMAS_REG_LDO9,
 	PALMAS_REG_LDOLN,
 	PALMAS_REG_LDOUSB,
+	/* External regulators */
+	PALMAS_REG_REGEN1,
+	PALMAS_REG_REGEN2,
+	PALMAS_REG_REGEN3,
+	PALMAS_REG_SYSEN1,
+	PALMAS_REG_SYSEN2,
 	/* Total number of regulators */
 	PALMAS_NUM_REGS,
 };