diff options
Diffstat (limited to 'drivers/regulator/wm8994-regulator.c')
| -rw-r--r-- | drivers/regulator/wm8994-regulator.c | 287 | 
1 files changed, 89 insertions, 198 deletions
diff --git a/drivers/regulator/wm8994-regulator.c b/drivers/regulator/wm8994-regulator.c index 03713bc66e4..c24346db8a7 100644 --- a/drivers/regulator/wm8994-regulator.c +++ b/drivers/regulator/wm8994-regulator.c @@ -18,6 +18,7 @@  #include <linux/err.h>  #include <linux/platform_device.h>  #include <linux/regulator/driver.h> +#include <linux/regulator/machine.h>  #include <linux/gpio.h>  #include <linux/slab.h> @@ -26,166 +27,66 @@  #include <linux/mfd/wm8994/pdata.h>  struct wm8994_ldo { -	int enable; -	bool is_enabled;  	struct regulator_dev *regulator;  	struct wm8994 *wm8994; +	struct regulator_consumer_supply supply; +	struct regulator_init_data init_data;  };  #define WM8994_LDO1_MAX_SELECTOR 0x7  #define WM8994_LDO2_MAX_SELECTOR 0x3 -static int wm8994_ldo_enable(struct regulator_dev *rdev) -{ -	struct wm8994_ldo *ldo = rdev_get_drvdata(rdev); - -	/* If we have no soft control assume that the LDO is always enabled. */ -	if (!ldo->enable) -		return 0; - -	gpio_set_value(ldo->enable, 1); -	ldo->is_enabled = true; - -	return 0; -} - -static int wm8994_ldo_disable(struct regulator_dev *rdev) -{ -	struct wm8994_ldo *ldo = rdev_get_drvdata(rdev); - -	/* If we have no soft control assume that the LDO is always enabled. */ -	if (!ldo->enable) -		return -EINVAL; - -	gpio_set_value(ldo->enable, 0); -	ldo->is_enabled = false; - -	return 0; -} - -static int wm8994_ldo_is_enabled(struct regulator_dev *rdev) -{ -	struct wm8994_ldo *ldo = rdev_get_drvdata(rdev); - -	return ldo->is_enabled; -} - -static int wm8994_ldo_enable_time(struct regulator_dev *rdev) -{ -	/* 3ms is fairly conservative but this shouldn't be too performance -	 * critical; can be tweaked per-system if required. */ -	return 3000; -} - -static int wm8994_ldo1_list_voltage(struct regulator_dev *rdev, -				    unsigned int selector) -{ -	if (selector > WM8994_LDO1_MAX_SELECTOR) -		return -EINVAL; - -	return (selector * 100000) + 2400000; -} - -static int wm8994_ldo1_get_voltage(struct regulator_dev *rdev) -{ -	struct wm8994_ldo *ldo = rdev_get_drvdata(rdev); -	int val; - -	val = wm8994_reg_read(ldo->wm8994, WM8994_LDO_1); -	if (val < 0) -		return val; - -	val = (val & WM8994_LDO1_VSEL_MASK) >> WM8994_LDO1_VSEL_SHIFT; - -	return wm8994_ldo1_list_voltage(rdev, val); -} - -static int wm8994_ldo1_set_voltage(struct regulator_dev *rdev, -				   int min_uV, int max_uV) -{ -	struct wm8994_ldo *ldo = rdev_get_drvdata(rdev); -	int selector, v; - -	selector = (min_uV - 2400000) / 100000; -	v = wm8994_ldo1_list_voltage(rdev, selector); -	if (v < 0 || v > max_uV) -		return -EINVAL; - -	selector <<= WM8994_LDO1_VSEL_SHIFT; - -	return wm8994_set_bits(ldo->wm8994, WM8994_LDO_1, -			       WM8994_LDO1_VSEL_MASK, selector); -} -  static struct regulator_ops wm8994_ldo1_ops = { -	.enable = wm8994_ldo_enable, -	.disable = wm8994_ldo_disable, -	.is_enabled = wm8994_ldo_is_enabled, -	.enable_time = wm8994_ldo_enable_time, - -	.list_voltage = wm8994_ldo1_list_voltage, -	.get_voltage = wm8994_ldo1_get_voltage, -	.set_voltage = wm8994_ldo1_set_voltage, +	.list_voltage = regulator_list_voltage_linear, +	.map_voltage = regulator_map_voltage_linear, +	.get_voltage_sel = regulator_get_voltage_sel_regmap, +	.set_voltage_sel = regulator_set_voltage_sel_regmap,  };  static int wm8994_ldo2_list_voltage(struct regulator_dev *rdev,  				    unsigned int selector)  { -	if (selector > WM8994_LDO2_MAX_SELECTOR) -		return -EINVAL; - -	return (selector * 100000) + 900000; -} - -static int wm8994_ldo2_get_voltage(struct regulator_dev *rdev) -{  	struct wm8994_ldo *ldo = rdev_get_drvdata(rdev); -	int val; -	val = wm8994_reg_read(ldo->wm8994, WM8994_LDO_2); -	if (val < 0) -		return val; - -	val = (val & WM8994_LDO2_VSEL_MASK) >> WM8994_LDO2_VSEL_SHIFT; - -	return wm8994_ldo2_list_voltage(rdev, val); -} - -static int wm8994_ldo2_set_voltage(struct regulator_dev *rdev, -				   int min_uV, int max_uV) -{ -	struct wm8994_ldo *ldo = rdev_get_drvdata(rdev); -	int selector, v; - -	selector = (min_uV - 900000) / 100000; -	v = wm8994_ldo2_list_voltage(rdev, selector); -	if (v < 0 || v > max_uV) +	if (selector > WM8994_LDO2_MAX_SELECTOR)  		return -EINVAL; -	selector <<= WM8994_LDO2_VSEL_SHIFT; - -	return wm8994_set_bits(ldo->wm8994, WM8994_LDO_2, -			       WM8994_LDO2_VSEL_MASK, selector); +	switch (ldo->wm8994->type) { +	case WM8994: +		return (selector * 100000) + 900000; +	case WM8958: +		return (selector * 100000) + 1000000; +	case WM1811: +		switch (selector) { +		case 0: +			return -EINVAL; +		default: +			return (selector * 100000) + 950000; +		} +		break; +	default: +		return -EINVAL; +	}  }  static struct regulator_ops wm8994_ldo2_ops = { -	.enable = wm8994_ldo_enable, -	.disable = wm8994_ldo_disable, -	.is_enabled = wm8994_ldo_is_enabled, -	.enable_time = wm8994_ldo_enable_time, -  	.list_voltage = wm8994_ldo2_list_voltage, -	.get_voltage = wm8994_ldo2_get_voltage, -	.set_voltage = wm8994_ldo2_set_voltage, +	.get_voltage_sel = regulator_get_voltage_sel_regmap, +	.set_voltage_sel = regulator_set_voltage_sel_regmap,  }; -static struct regulator_desc wm8994_ldo_desc[] = { +static const struct regulator_desc wm8994_ldo_desc[] = {  	{  		.name = "LDO1",  		.id = 1,  		.type = REGULATOR_VOLTAGE,  		.n_voltages = WM8994_LDO1_MAX_SELECTOR + 1, +		.vsel_reg = WM8994_LDO_1, +		.vsel_mask = WM8994_LDO1_VSEL_MASK,  		.ops = &wm8994_ldo1_ops, +		.min_uV = 2400000, +		.uV_step = 100000, +		.enable_time = 3000,  		.owner = THIS_MODULE,  	},  	{ @@ -193,112 +94,102 @@ static struct regulator_desc wm8994_ldo_desc[] = {  		.id = 2,  		.type = REGULATOR_VOLTAGE,  		.n_voltages = WM8994_LDO2_MAX_SELECTOR + 1, +		.vsel_reg = WM8994_LDO_2, +		.vsel_mask = WM8994_LDO2_VSEL_MASK,  		.ops = &wm8994_ldo2_ops, +		.enable_time = 3000,  		.owner = THIS_MODULE,  	},  }; -static __devinit int wm8994_ldo_probe(struct platform_device *pdev) +static const struct regulator_consumer_supply wm8994_ldo_consumer[] = { +	{ .supply = "AVDD1" }, +	{ .supply = "DCVDD" }, +}; + +static const struct regulator_init_data wm8994_ldo_default[] = { +	{ +		.constraints = { +			.valid_ops_mask = REGULATOR_CHANGE_STATUS, +		}, +		.num_consumer_supplies = 1, +	}, +	{ +		.constraints = { +			.valid_ops_mask = REGULATOR_CHANGE_STATUS, +		}, +		.num_consumer_supplies = 1, +	}, +}; + +static int wm8994_ldo_probe(struct platform_device *pdev)  {  	struct wm8994 *wm8994 = dev_get_drvdata(pdev->dev.parent); -	struct wm8994_pdata *pdata = wm8994->dev->platform_data; +	struct wm8994_pdata *pdata = dev_get_platdata(wm8994->dev);  	int id = pdev->id % ARRAY_SIZE(pdata->ldo); +	struct regulator_config config = { };  	struct wm8994_ldo *ldo;  	int ret;  	dev_dbg(&pdev->dev, "Probing LDO%d\n", id + 1); -	if (!pdata) -		return -ENODEV; - -	ldo = kzalloc(sizeof(struct wm8994_ldo), GFP_KERNEL); -	if (ldo == NULL) { -		dev_err(&pdev->dev, "Unable to allocate private data\n"); +	ldo = devm_kzalloc(&pdev->dev, sizeof(struct wm8994_ldo), GFP_KERNEL); +	if (!ldo)  		return -ENOMEM; -	}  	ldo->wm8994 = wm8994; +	ldo->supply = wm8994_ldo_consumer[id]; +	ldo->supply.dev_name = dev_name(wm8994->dev); + +	config.dev = wm8994->dev; +	config.driver_data = ldo; +	config.regmap = wm8994->regmap; +	config.init_data = &ldo->init_data; +	if (pdata) +		config.ena_gpio = pdata->ldo[id].enable; +	else if (wm8994->dev->of_node) +		config.ena_gpio = wm8994->pdata.ldo[id].enable; + +	/* Use default constraints if none set up */ +	if (!pdata || !pdata->ldo[id].init_data || wm8994->dev->of_node) { +		dev_dbg(wm8994->dev, "Using default init data, supply %s %s\n", +			ldo->supply.dev_name, ldo->supply.supply); + +		ldo->init_data = wm8994_ldo_default[id]; +		ldo->init_data.consumer_supplies = &ldo->supply; +		if (!config.ena_gpio) +			ldo->init_data.constraints.valid_ops_mask = 0; +	} else { +		ldo->init_data = *pdata->ldo[id].init_data; +	} -	if (pdata->ldo[id].enable && gpio_is_valid(pdata->ldo[id].enable)) { -		ldo->enable = pdata->ldo[id].enable; - -		ret = gpio_request(ldo->enable, "WM8994 LDO enable"); -		if (ret < 0) { -			dev_err(&pdev->dev, "Failed to get enable GPIO: %d\n", -				ret); -			goto err; -		} - -		ret = gpio_direction_output(ldo->enable, ldo->is_enabled); -		if (ret < 0) { -			dev_err(&pdev->dev, "Failed to set GPIO up: %d\n", -				ret); -			goto err_gpio; -		} -	} else -		ldo->is_enabled = true; - -	ldo->regulator = regulator_register(&wm8994_ldo_desc[id], &pdev->dev, -					     pdata->ldo[id].init_data, ldo); +	ldo->regulator = devm_regulator_register(&pdev->dev, +						 &wm8994_ldo_desc[id], +						 &config);  	if (IS_ERR(ldo->regulator)) {  		ret = PTR_ERR(ldo->regulator);  		dev_err(wm8994->dev, "Failed to register LDO%d: %d\n",  			id + 1, ret); -		goto err_gpio; +		goto err;  	}  	platform_set_drvdata(pdev, ldo);  	return 0; -err_gpio: -	if (gpio_is_valid(ldo->enable)) -		gpio_free(ldo->enable);  err: -	kfree(ldo);  	return ret;  } -static __devexit int wm8994_ldo_remove(struct platform_device *pdev) -{ -	struct wm8994_ldo *ldo = platform_get_drvdata(pdev); - -	platform_set_drvdata(pdev, NULL); - -	regulator_unregister(ldo->regulator); -	if (gpio_is_valid(ldo->enable)) -		gpio_free(ldo->enable); -	kfree(ldo); - -	return 0; -} -  static struct platform_driver wm8994_ldo_driver = {  	.probe = wm8994_ldo_probe, -	.remove = __devexit_p(wm8994_ldo_remove),  	.driver		= {  		.name	= "wm8994-ldo",  		.owner	= THIS_MODULE,  	},  }; -static int __init wm8994_ldo_init(void) -{ -	int ret; - -	ret = platform_driver_register(&wm8994_ldo_driver); -	if (ret != 0) -		pr_err("Failed to register Wm8994 GP LDO driver: %d\n", ret); - -	return ret; -} -subsys_initcall(wm8994_ldo_init); - -static void __exit wm8994_ldo_exit(void) -{ -	platform_driver_unregister(&wm8994_ldo_driver); -} -module_exit(wm8994_ldo_exit); +module_platform_driver(wm8994_ldo_driver);  /* Module information */  MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");  | 
