diff options
Diffstat (limited to 'drivers/regulator/s2mps11.c')
| -rw-r--r-- | drivers/regulator/s2mps11.c | 479 | 
1 files changed, 369 insertions, 110 deletions
diff --git a/drivers/regulator/s2mps11.c b/drivers/regulator/s2mps11.c index 5eba2ff8c0e..02e2fb2fca6 100644 --- a/drivers/regulator/s2mps11.c +++ b/drivers/regulator/s2mps11.c @@ -1,13 +1,18 @@  /*   * s2mps11.c   * - * Copyright (c) 2012 Samsung Electronics Co., Ltd + * Copyright (c) 2012-2014 Samsung Electronics Co., Ltd   *              http://www.samsung.com   * - *  This program is free software; you can redistribute  it and/or modify it - *  under  the terms of  the GNU General  Public License as published by the - *  Free Software Foundation;  either version 2 of the  License, or (at your - *  option) any later version. + * This program is free software; you can redistribute  it and/or modify it + * under  the terms of  the GNU General  Public License as published by the + * Free Software Foundation;  either version 2 of the  License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details.   *   */ @@ -22,20 +27,26 @@  #include <linux/regulator/driver.h>  #include <linux/regulator/machine.h>  #include <linux/regulator/of_regulator.h> +#include <linux/of_gpio.h>  #include <linux/mfd/samsung/core.h>  #include <linux/mfd/samsung/s2mps11.h> - -#define S2MPS11_REGULATOR_CNT ARRAY_SIZE(regulators) +#include <linux/mfd/samsung/s2mps14.h>  struct s2mps11_info { -	struct regulator_dev *rdev[S2MPS11_REGULATOR_MAX]; - +	unsigned int rdev_num;  	int ramp_delay2;  	int ramp_delay34;  	int ramp_delay5;  	int ramp_delay16;  	int ramp_delay7810;  	int ramp_delay9; +	/* +	 * One bit for each S2MPS14 regulator whether the suspend mode +	 * was enabled. +	 */ +	unsigned int s2mps14_suspend_state:30; +	/* Array of size rdev_num with GPIO-s for external sleep control */ +	int *ext_control_gpio;  };  static int get_ramp_delay(int ramp_delay) @@ -65,13 +76,11 @@ static int s2mps11_regulator_set_voltage_time_sel(struct regulator_dev *rdev,  	unsigned int ramp_delay = 0;  	int old_volt, new_volt; -	switch (rdev->desc->id) { +	switch (rdev_get_id(rdev)) {  	case S2MPS11_BUCK2:  		ramp_delay = s2mps11->ramp_delay2;  		break;  	case S2MPS11_BUCK3: -		ramp_delay = s2mps11->ramp_delay34; -		break;  	case S2MPS11_BUCK4:  		ramp_delay = s2mps11->ramp_delay34;  		break; @@ -107,7 +116,7 @@ static int s2mps11_set_ramp_delay(struct regulator_dev *rdev, int ramp_delay)  	unsigned int ramp_enable = 1, enable_shift = 0;  	int ret; -	switch (rdev->desc->id) { +	switch (rdev_get_id(rdev)) {  	case S2MPS11_BUCK1:  		if (ramp_delay > s2mps11->ramp_delay16)  			s2mps11->ramp_delay16 = ramp_delay; @@ -196,9 +205,12 @@ static int s2mps11_set_ramp_delay(struct regulator_dev *rdev, int ramp_delay)  	if (!ramp_enable)  		goto ramp_disable; -	if (enable_shift) { +	/* Ramp delay can be enabled/disabled only for buck[2346] */ +	if ((rdev_get_id(rdev) >= S2MPS11_BUCK2 && +			rdev_get_id(rdev) <= S2MPS11_BUCK4) || +			rdev_get_id(rdev) == S2MPS11_BUCK6)  {  		ret = regmap_update_bits(rdev->regmap, S2MPS11_REG_RAMP, -					1 << enable_shift, 1 << enable_shift); +					 1 << enable_shift, 1 << enable_shift);  		if (ret) {  			dev_err(&rdev->dev, "failed to enable ramp rate\n");  			return ret; @@ -238,7 +250,7 @@ static struct regulator_ops s2mps11_buck_ops = {  	.set_ramp_delay		= s2mps11_set_ramp_delay,  }; -#define regulator_desc_ldo1(num)	{		\ +#define regulator_desc_s2mps11_ldo1(num)	{		\  	.name		= "LDO"#num,			\  	.id		= S2MPS11_LDO##num,		\  	.ops		= &s2mps11_ldo_ops,		\ @@ -252,7 +264,7 @@ static struct regulator_ops s2mps11_buck_ops = {  	.enable_reg	= S2MPS11_REG_L1CTRL + num - 1,	\  	.enable_mask	= S2MPS11_ENABLE_MASK		\  } -#define regulator_desc_ldo2(num)	{		\ +#define regulator_desc_s2mps11_ldo2(num) {		\  	.name		= "LDO"#num,			\  	.id		= S2MPS11_LDO##num,		\  	.ops		= &s2mps11_ldo_ops,		\ @@ -267,7 +279,7 @@ static struct regulator_ops s2mps11_buck_ops = {  	.enable_mask	= S2MPS11_ENABLE_MASK		\  } -#define regulator_desc_buck1_4(num)	{			\ +#define regulator_desc_s2mps11_buck1_4(num) {			\  	.name		= "BUCK"#num,				\  	.id		= S2MPS11_BUCK##num,			\  	.ops		= &s2mps11_buck_ops,			\ @@ -283,7 +295,7 @@ static struct regulator_ops s2mps11_buck_ops = {  	.enable_mask	= S2MPS11_ENABLE_MASK			\  } -#define regulator_desc_buck5	{				\ +#define regulator_desc_s2mps11_buck5 {				\  	.name		= "BUCK5",				\  	.id		= S2MPS11_BUCK5,			\  	.ops		= &s2mps11_buck_ops,			\ @@ -299,7 +311,7 @@ static struct regulator_ops s2mps11_buck_ops = {  	.enable_mask	= S2MPS11_ENABLE_MASK			\  } -#define regulator_desc_buck6_8(num)	{			\ +#define regulator_desc_s2mps11_buck6_8(num) {			\  	.name		= "BUCK"#num,				\  	.id		= S2MPS11_BUCK##num,			\  	.ops		= &s2mps11_buck_ops,			\ @@ -315,7 +327,7 @@ static struct regulator_ops s2mps11_buck_ops = {  	.enable_mask	= S2MPS11_ENABLE_MASK			\  } -#define regulator_desc_buck9	{				\ +#define regulator_desc_s2mps11_buck9 {				\  	.name		= "BUCK9",				\  	.id		= S2MPS11_BUCK9,			\  	.ops		= &s2mps11_buck_ops,			\ @@ -331,7 +343,7 @@ static struct regulator_ops s2mps11_buck_ops = {  	.enable_mask	= S2MPS11_ENABLE_MASK			\  } -#define regulator_desc_buck10	{				\ +#define regulator_desc_s2mps11_buck10 {				\  	.name		= "BUCK10",				\  	.id		= S2MPS11_BUCK10,			\  	.ops		= &s2mps11_buck_ops,			\ @@ -347,74 +359,318 @@ static struct regulator_ops s2mps11_buck_ops = {  	.enable_mask	= S2MPS11_ENABLE_MASK			\  } -static struct regulator_desc regulators[] = { -	regulator_desc_ldo2(1), -	regulator_desc_ldo1(2), -	regulator_desc_ldo1(3), -	regulator_desc_ldo1(4), -	regulator_desc_ldo1(5), -	regulator_desc_ldo2(6), -	regulator_desc_ldo1(7), -	regulator_desc_ldo1(8), -	regulator_desc_ldo1(9), -	regulator_desc_ldo1(10), -	regulator_desc_ldo2(11), -	regulator_desc_ldo1(12), -	regulator_desc_ldo1(13), -	regulator_desc_ldo1(14), -	regulator_desc_ldo1(15), -	regulator_desc_ldo1(16), -	regulator_desc_ldo1(17), -	regulator_desc_ldo1(18), -	regulator_desc_ldo1(19), -	regulator_desc_ldo1(20), -	regulator_desc_ldo1(21), -	regulator_desc_ldo2(22), -	regulator_desc_ldo2(23), -	regulator_desc_ldo1(24), -	regulator_desc_ldo1(25), -	regulator_desc_ldo1(26), -	regulator_desc_ldo2(27), -	regulator_desc_ldo1(28), -	regulator_desc_ldo1(29), -	regulator_desc_ldo1(30), -	regulator_desc_ldo1(31), -	regulator_desc_ldo1(32), -	regulator_desc_ldo1(33), -	regulator_desc_ldo1(34), -	regulator_desc_ldo1(35), -	regulator_desc_ldo1(36), -	regulator_desc_ldo1(37), -	regulator_desc_ldo1(38), -	regulator_desc_buck1_4(1), -	regulator_desc_buck1_4(2), -	regulator_desc_buck1_4(3), -	regulator_desc_buck1_4(4), -	regulator_desc_buck5, -	regulator_desc_buck6_8(6), -	regulator_desc_buck6_8(7), -	regulator_desc_buck6_8(8), -	regulator_desc_buck9, -	regulator_desc_buck10, +static const struct regulator_desc s2mps11_regulators[] = { +	regulator_desc_s2mps11_ldo2(1), +	regulator_desc_s2mps11_ldo1(2), +	regulator_desc_s2mps11_ldo1(3), +	regulator_desc_s2mps11_ldo1(4), +	regulator_desc_s2mps11_ldo1(5), +	regulator_desc_s2mps11_ldo2(6), +	regulator_desc_s2mps11_ldo1(7), +	regulator_desc_s2mps11_ldo1(8), +	regulator_desc_s2mps11_ldo1(9), +	regulator_desc_s2mps11_ldo1(10), +	regulator_desc_s2mps11_ldo2(11), +	regulator_desc_s2mps11_ldo1(12), +	regulator_desc_s2mps11_ldo1(13), +	regulator_desc_s2mps11_ldo1(14), +	regulator_desc_s2mps11_ldo1(15), +	regulator_desc_s2mps11_ldo1(16), +	regulator_desc_s2mps11_ldo1(17), +	regulator_desc_s2mps11_ldo1(18), +	regulator_desc_s2mps11_ldo1(19), +	regulator_desc_s2mps11_ldo1(20), +	regulator_desc_s2mps11_ldo1(21), +	regulator_desc_s2mps11_ldo2(22), +	regulator_desc_s2mps11_ldo2(23), +	regulator_desc_s2mps11_ldo1(24), +	regulator_desc_s2mps11_ldo1(25), +	regulator_desc_s2mps11_ldo1(26), +	regulator_desc_s2mps11_ldo2(27), +	regulator_desc_s2mps11_ldo1(28), +	regulator_desc_s2mps11_ldo1(29), +	regulator_desc_s2mps11_ldo1(30), +	regulator_desc_s2mps11_ldo1(31), +	regulator_desc_s2mps11_ldo1(32), +	regulator_desc_s2mps11_ldo1(33), +	regulator_desc_s2mps11_ldo1(34), +	regulator_desc_s2mps11_ldo1(35), +	regulator_desc_s2mps11_ldo1(36), +	regulator_desc_s2mps11_ldo1(37), +	regulator_desc_s2mps11_ldo1(38), +	regulator_desc_s2mps11_buck1_4(1), +	regulator_desc_s2mps11_buck1_4(2), +	regulator_desc_s2mps11_buck1_4(3), +	regulator_desc_s2mps11_buck1_4(4), +	regulator_desc_s2mps11_buck5, +	regulator_desc_s2mps11_buck6_8(6), +	regulator_desc_s2mps11_buck6_8(7), +	regulator_desc_s2mps11_buck6_8(8), +	regulator_desc_s2mps11_buck9, +	regulator_desc_s2mps11_buck10, +}; + +static int s2mps14_regulator_enable(struct regulator_dev *rdev) +{ +	struct s2mps11_info *s2mps11 = rdev_get_drvdata(rdev); +	unsigned int val; + +	if (s2mps11->s2mps14_suspend_state & (1 << rdev_get_id(rdev))) +		val = S2MPS14_ENABLE_SUSPEND; +	else if (gpio_is_valid(s2mps11->ext_control_gpio[rdev_get_id(rdev)])) +		val = S2MPS14_ENABLE_EXT_CONTROL; +	else +		val = rdev->desc->enable_mask; + +	return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg, +			rdev->desc->enable_mask, val); +} + +static int s2mps14_regulator_set_suspend_disable(struct regulator_dev *rdev) +{ +	int ret; +	unsigned int val; +	struct s2mps11_info *s2mps11 = rdev_get_drvdata(rdev); + +	/* LDO3 should be always on and does not support suspend mode */ +	if (rdev_get_id(rdev) == S2MPS14_LDO3) +		return 0; + +	ret = regmap_read(rdev->regmap, rdev->desc->enable_reg, &val); +	if (ret < 0) +		return ret; + +	s2mps11->s2mps14_suspend_state |= (1 << rdev_get_id(rdev)); +	/* +	 * Don't enable suspend mode if regulator is already disabled because +	 * this would effectively for a short time turn on the regulator after +	 * resuming. +	 * However we still want to toggle the suspend_state bit for regulator +	 * in case if it got enabled before suspending the system. +	 */ +	if (!(val & rdev->desc->enable_mask)) +		return 0; + +	return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg, +			rdev->desc->enable_mask, S2MPS14_ENABLE_SUSPEND); +} + +static struct regulator_ops s2mps14_reg_ops = { +	.list_voltage		= regulator_list_voltage_linear, +	.map_voltage		= regulator_map_voltage_linear, +	.is_enabled		= regulator_is_enabled_regmap, +	.enable			= s2mps14_regulator_enable, +	.disable		= regulator_disable_regmap, +	.get_voltage_sel	= regulator_get_voltage_sel_regmap, +	.set_voltage_sel	= regulator_set_voltage_sel_regmap, +	.set_voltage_time_sel	= regulator_set_voltage_time_sel, +	.set_suspend_disable	= s2mps14_regulator_set_suspend_disable, +}; + +#define regulator_desc_s2mps14_ldo1(num) {		\ +	.name		= "LDO"#num,			\ +	.id		= S2MPS14_LDO##num,		\ +	.ops		= &s2mps14_reg_ops,		\ +	.type		= REGULATOR_VOLTAGE,		\ +	.owner		= THIS_MODULE,			\ +	.min_uV		= S2MPS14_LDO_MIN_800MV,	\ +	.uV_step	= S2MPS14_LDO_STEP_25MV,	\ +	.n_voltages	= S2MPS14_LDO_N_VOLTAGES,	\ +	.vsel_reg	= S2MPS14_REG_L1CTRL + num - 1,	\ +	.vsel_mask	= S2MPS14_LDO_VSEL_MASK,	\ +	.enable_reg	= S2MPS14_REG_L1CTRL + num - 1,	\ +	.enable_mask	= S2MPS14_ENABLE_MASK		\ +} +#define regulator_desc_s2mps14_ldo2(num) {		\ +	.name		= "LDO"#num,			\ +	.id		= S2MPS14_LDO##num,		\ +	.ops		= &s2mps14_reg_ops,		\ +	.type		= REGULATOR_VOLTAGE,		\ +	.owner		= THIS_MODULE,			\ +	.min_uV		= S2MPS14_LDO_MIN_1800MV,	\ +	.uV_step	= S2MPS14_LDO_STEP_25MV,	\ +	.n_voltages	= S2MPS14_LDO_N_VOLTAGES,	\ +	.vsel_reg	= S2MPS14_REG_L1CTRL + num - 1,	\ +	.vsel_mask	= S2MPS14_LDO_VSEL_MASK,	\ +	.enable_reg	= S2MPS14_REG_L1CTRL + num - 1,	\ +	.enable_mask	= S2MPS14_ENABLE_MASK		\ +} +#define regulator_desc_s2mps14_ldo3(num) {		\ +	.name		= "LDO"#num,			\ +	.id		= S2MPS14_LDO##num,		\ +	.ops		= &s2mps14_reg_ops,		\ +	.type		= REGULATOR_VOLTAGE,		\ +	.owner		= THIS_MODULE,			\ +	.min_uV		= S2MPS14_LDO_MIN_800MV,	\ +	.uV_step	= S2MPS14_LDO_STEP_12_5MV,	\ +	.n_voltages	= S2MPS14_LDO_N_VOLTAGES,	\ +	.vsel_reg	= S2MPS14_REG_L1CTRL + num - 1,	\ +	.vsel_mask	= S2MPS14_LDO_VSEL_MASK,	\ +	.enable_reg	= S2MPS14_REG_L1CTRL + num - 1,	\ +	.enable_mask	= S2MPS14_ENABLE_MASK		\ +} +#define regulator_desc_s2mps14_buck1235(num) {			\ +	.name		= "BUCK"#num,				\ +	.id		= S2MPS14_BUCK##num,			\ +	.ops		= &s2mps14_reg_ops,			\ +	.type		= REGULATOR_VOLTAGE,			\ +	.owner		= THIS_MODULE,				\ +	.min_uV		= S2MPS14_BUCK1235_MIN_600MV,		\ +	.uV_step	= S2MPS14_BUCK1235_STEP_6_25MV,		\ +	.n_voltages	= S2MPS14_BUCK_N_VOLTAGES,		\ +	.linear_min_sel = S2MPS14_BUCK1235_START_SEL,		\ +	.ramp_delay	= S2MPS14_BUCK_RAMP_DELAY,		\ +	.vsel_reg	= S2MPS14_REG_B1CTRL2 + (num - 1) * 2,	\ +	.vsel_mask	= S2MPS14_BUCK_VSEL_MASK,		\ +	.enable_reg	= S2MPS14_REG_B1CTRL1 + (num - 1) * 2,	\ +	.enable_mask	= S2MPS14_ENABLE_MASK			\ +} +#define regulator_desc_s2mps14_buck4(num) {			\ +	.name		= "BUCK"#num,				\ +	.id		= S2MPS14_BUCK##num,			\ +	.ops		= &s2mps14_reg_ops,			\ +	.type		= REGULATOR_VOLTAGE,			\ +	.owner		= THIS_MODULE,				\ +	.min_uV		= S2MPS14_BUCK4_MIN_1400MV,		\ +	.uV_step	= S2MPS14_BUCK4_STEP_12_5MV,		\ +	.n_voltages	= S2MPS14_BUCK_N_VOLTAGES,		\ +	.linear_min_sel = S2MPS14_BUCK4_START_SEL,		\ +	.ramp_delay	= S2MPS14_BUCK_RAMP_DELAY,		\ +	.vsel_reg	= S2MPS14_REG_B1CTRL2 + (num - 1) * 2,	\ +	.vsel_mask	= S2MPS14_BUCK_VSEL_MASK,		\ +	.enable_reg	= S2MPS14_REG_B1CTRL1 + (num - 1) * 2,	\ +	.enable_mask	= S2MPS14_ENABLE_MASK			\ +} + +static const struct regulator_desc s2mps14_regulators[] = { +	regulator_desc_s2mps14_ldo3(1), +	regulator_desc_s2mps14_ldo3(2), +	regulator_desc_s2mps14_ldo1(3), +	regulator_desc_s2mps14_ldo1(4), +	regulator_desc_s2mps14_ldo3(5), +	regulator_desc_s2mps14_ldo3(6), +	regulator_desc_s2mps14_ldo1(7), +	regulator_desc_s2mps14_ldo2(8), +	regulator_desc_s2mps14_ldo3(9), +	regulator_desc_s2mps14_ldo3(10), +	regulator_desc_s2mps14_ldo1(11), +	regulator_desc_s2mps14_ldo2(12), +	regulator_desc_s2mps14_ldo2(13), +	regulator_desc_s2mps14_ldo2(14), +	regulator_desc_s2mps14_ldo2(15), +	regulator_desc_s2mps14_ldo2(16), +	regulator_desc_s2mps14_ldo2(17), +	regulator_desc_s2mps14_ldo2(18), +	regulator_desc_s2mps14_ldo1(19), +	regulator_desc_s2mps14_ldo1(20), +	regulator_desc_s2mps14_ldo1(21), +	regulator_desc_s2mps14_ldo3(22), +	regulator_desc_s2mps14_ldo1(23), +	regulator_desc_s2mps14_ldo2(24), +	regulator_desc_s2mps14_ldo2(25), +	regulator_desc_s2mps14_buck1235(1), +	regulator_desc_s2mps14_buck1235(2), +	regulator_desc_s2mps14_buck1235(3), +	regulator_desc_s2mps14_buck4(4), +	regulator_desc_s2mps14_buck1235(5),  }; +static int s2mps14_pmic_enable_ext_control(struct s2mps11_info *s2mps11, +		struct regulator_dev *rdev) +{ +	return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg, +			rdev->desc->enable_mask, S2MPS14_ENABLE_EXT_CONTROL); +} + +static void s2mps14_pmic_dt_parse_ext_control_gpio(struct platform_device *pdev, +		struct of_regulator_match *rdata, struct s2mps11_info *s2mps11) +{ +	int *gpio = s2mps11->ext_control_gpio; +	unsigned int i; +	unsigned int valid_regulators[3] = { S2MPS14_LDO10, S2MPS14_LDO11, +		S2MPS14_LDO12 }; + +	for (i = 0; i < ARRAY_SIZE(valid_regulators); i++) { +		unsigned int reg = valid_regulators[i]; + +		if (!rdata[reg].init_data || !rdata[reg].of_node) +			continue; + +		gpio[reg] = of_get_named_gpio(rdata[reg].of_node, +				"samsung,ext-control-gpios", 0); +		if (gpio_is_valid(gpio[reg])) +			dev_dbg(&pdev->dev, "Using GPIO %d for ext-control over %d/%s\n", +					gpio[reg], reg, rdata[reg].name); +	} +} + +static int s2mps11_pmic_dt_parse(struct platform_device *pdev, +		struct of_regulator_match *rdata, struct s2mps11_info *s2mps11, +		enum sec_device_type dev_type) +{ +	struct device_node *reg_np; + +	reg_np = of_get_child_by_name(pdev->dev.parent->of_node, "regulators"); +	if (!reg_np) { +		dev_err(&pdev->dev, "could not find regulators sub-node\n"); +		return -EINVAL; +	} + +	of_regulator_match(&pdev->dev, reg_np, rdata, s2mps11->rdev_num); +	if (dev_type == S2MPS14X) +		s2mps14_pmic_dt_parse_ext_control_gpio(pdev, rdata, s2mps11); + +	of_node_put(reg_np); + +	return 0; +} +  static int s2mps11_pmic_probe(struct platform_device *pdev)  {  	struct sec_pmic_dev *iodev = dev_get_drvdata(pdev->dev.parent); -	struct sec_platform_data *pdata = dev_get_platdata(iodev->dev); -	struct of_regulator_match rdata[S2MPS11_REGULATOR_MAX]; -	struct device_node *reg_np = NULL; +	struct sec_platform_data *pdata = NULL; +	struct of_regulator_match *rdata = NULL;  	struct regulator_config config = { };  	struct s2mps11_info *s2mps11; -	int i, ret; +	int i, ret = 0; +	const struct regulator_desc *regulators; +	enum sec_device_type dev_type;  	s2mps11 = devm_kzalloc(&pdev->dev, sizeof(struct s2mps11_info),  				GFP_KERNEL);  	if (!s2mps11)  		return -ENOMEM; +	dev_type = platform_get_device_id(pdev)->driver_data; +	switch (dev_type) { +	case S2MPS11X: +		s2mps11->rdev_num = ARRAY_SIZE(s2mps11_regulators); +		regulators = s2mps11_regulators; +		break; +	case S2MPS14X: +		s2mps11->rdev_num = ARRAY_SIZE(s2mps14_regulators); +		regulators = s2mps14_regulators; +		break; +	default: +		dev_err(&pdev->dev, "Invalid device type: %u\n", dev_type); +		return -EINVAL; +	}; + +	s2mps11->ext_control_gpio = devm_kzalloc(&pdev->dev, +			sizeof(*s2mps11->ext_control_gpio) * s2mps11->rdev_num, +			GFP_KERNEL); +	if (!s2mps11->ext_control_gpio) +		return -ENOMEM; +	/* +	 * 0 is a valid GPIO so initialize all GPIO-s to negative value +	 * to indicate that external control won't be used for this regulator. +	 */ +	for (i = 0; i < s2mps11->rdev_num; i++) +		s2mps11->ext_control_gpio[i] = -EINVAL; +  	if (!iodev->dev->of_node) { -		if (pdata) { +		if (iodev->pdata) { +			pdata = iodev->pdata;  			goto common_reg;  		} else {  			dev_err(pdev->dev.parent, @@ -423,62 +679,66 @@ static int s2mps11_pmic_probe(struct platform_device *pdev)  		}  	} -	for (i = 0; i < S2MPS11_REGULATOR_CNT; i++) -		rdata[i].name = regulators[i].name; +	rdata = kzalloc(sizeof(*rdata) * s2mps11->rdev_num, GFP_KERNEL); +	if (!rdata) +		return -ENOMEM; -	reg_np = of_find_node_by_name(iodev->dev->of_node, "regulators"); -	if (!reg_np) { -		dev_err(&pdev->dev, "could not find regulators sub-node\n"); -		return -EINVAL; -	} +	for (i = 0; i < s2mps11->rdev_num; i++) +		rdata[i].name = regulators[i].name; -	of_regulator_match(&pdev->dev, reg_np, rdata, S2MPS11_REGULATOR_MAX); +	ret = s2mps11_pmic_dt_parse(pdev, rdata, s2mps11, dev_type); +	if (ret) +		goto out;  common_reg:  	platform_set_drvdata(pdev, s2mps11);  	config.dev = &pdev->dev; -	config.regmap = iodev->regmap; +	config.regmap = iodev->regmap_pmic;  	config.driver_data = s2mps11; -	for (i = 0; i < S2MPS11_REGULATOR_MAX; i++) { -		if (!reg_np) { +	config.ena_gpio_flags = GPIOF_OUT_INIT_HIGH; +	for (i = 0; i < s2mps11->rdev_num; i++) { +		struct regulator_dev *regulator; + +		if (pdata) {  			config.init_data = pdata->regulators[i].initdata; +			config.of_node = pdata->regulators[i].reg_node;  		} else {  			config.init_data = rdata[i].init_data;  			config.of_node = rdata[i].of_node;  		} +		config.ena_gpio = s2mps11->ext_control_gpio[i]; -		s2mps11->rdev[i] = regulator_register(®ulators[i], &config); -		if (IS_ERR(s2mps11->rdev[i])) { -			ret = PTR_ERR(s2mps11->rdev[i]); +		regulator = devm_regulator_register(&pdev->dev, +						®ulators[i], &config); +		if (IS_ERR(regulator)) { +			ret = PTR_ERR(regulator);  			dev_err(&pdev->dev, "regulator init failed for %d\n",  				i); -			s2mps11->rdev[i] = NULL; -			goto err; +			goto out; +		} + +		if (gpio_is_valid(s2mps11->ext_control_gpio[i])) { +			ret = s2mps14_pmic_enable_ext_control(s2mps11, +					regulator); +			if (ret < 0) { +				dev_err(&pdev->dev, +						"failed to enable GPIO control over %s: %d\n", +						regulator->desc->name, ret); +				goto out; +			}  		}  	} -	return 0; -err: -	for (i = 0; i < S2MPS11_REGULATOR_MAX; i++) -		regulator_unregister(s2mps11->rdev[i]); +out: +	kfree(rdata);  	return ret;  } -static int s2mps11_pmic_remove(struct platform_device *pdev) -{ -	struct s2mps11_info *s2mps11 = platform_get_drvdata(pdev); -	int i; - -	for (i = 0; i < S2MPS11_REGULATOR_MAX; i++) -		regulator_unregister(s2mps11->rdev[i]); - -	return 0; -} -  static const struct platform_device_id s2mps11_pmic_id[] = { -	{ "s2mps11-pmic", 0}, +	{ "s2mps11-pmic", S2MPS11X}, +	{ "s2mps14-pmic", S2MPS14X},  	{ },  };  MODULE_DEVICE_TABLE(platform, s2mps11_pmic_id); @@ -489,7 +749,6 @@ static struct platform_driver s2mps11_pmic_driver = {  		.owner = THIS_MODULE,  	},  	.probe = s2mps11_pmic_probe, -	.remove = s2mps11_pmic_remove,  	.id_table = s2mps11_pmic_id,  }; @@ -507,5 +766,5 @@ module_exit(s2mps11_pmic_exit);  /* Module information */  MODULE_AUTHOR("Sangbeom Kim <sbkim73@samsung.com>"); -MODULE_DESCRIPTION("SAMSUNG S2MPS11 Regulator Driver"); +MODULE_DESCRIPTION("SAMSUNG S2MPS11/S2MPS14 Regulator Driver");  MODULE_LICENSE("GPL");  | 
