wm8994-regulator.c 7.7 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
/*
 * wm8994-regulator.c  --  Regulator driver for the WM8994
 *
 * Copyright 2009 Wolfson Microelectronics PLC.
 *
 * Author: Mark Brown <broonie@opensource.wolfsonmicro.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.
 */

#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/bitops.h>
#include <linux/err.h>
#include <linux/platform_device.h>
#include <linux/regulator/driver.h>
#include <linux/gpio.h>
22
#include <linux/slab.h>
23 24 25 26 27 28 29

#include <linux/mfd/wm8994/core.h>
#include <linux/mfd/wm8994/registers.h>
#include <linux/mfd/wm8994/pdata.h>

struct wm8994_ldo {
	int enable;
30
	bool is_enabled;
31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
	struct regulator_dev *regulator;
	struct wm8994 *wm8994;
};

#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;

46
	gpio_set_value_cansleep(ldo->enable, 1);
47
	ldo->is_enabled = true;
48 49 50 51 52 53 54 55 56 57 58 59

	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;

60
	gpio_set_value_cansleep(ldo->enable, 0);
61
	ldo->is_enabled = false;
62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88

	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;
}

89
static int wm8994_ldo1_get_voltage_sel(struct regulator_dev *rdev)
90 91 92 93 94 95 96 97
{
	struct wm8994_ldo *ldo = rdev_get_drvdata(rdev);
	int val;

	val = wm8994_reg_read(ldo->wm8994, WM8994_LDO_1);
	if (val < 0)
		return val;

98
	return (val & WM8994_LDO1_VSEL_MASK) >> WM8994_LDO1_VSEL_SHIFT;
99 100 101
}

static int wm8994_ldo1_set_voltage(struct regulator_dev *rdev,
102
				   int min_uV, int max_uV, unsigned *s)
103 104 105 106 107 108 109 110 111
{
	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;

112
	*s = selector;
113 114 115 116 117 118 119 120 121 122 123 124 125
	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,
126
	.get_voltage_sel = wm8994_ldo1_get_voltage_sel,
127 128 129 130 131 132
	.set_voltage = wm8994_ldo1_set_voltage,
};

static int wm8994_ldo2_list_voltage(struct regulator_dev *rdev,
				    unsigned int selector)
{
M
Mark Brown 已提交
133 134
	struct wm8994_ldo *ldo = rdev_get_drvdata(rdev);

135 136 137
	if (selector > WM8994_LDO2_MAX_SELECTOR)
		return -EINVAL;

M
Mark Brown 已提交
138 139 140 141 142
	switch (ldo->wm8994->type) {
	case WM8994:
		return (selector * 100000) + 900000;
	case WM8958:
		return (selector * 100000) + 1000000;
M
Mark Brown 已提交
143 144 145 146 147 148 149 150
	case WM1811:
		switch (selector) {
		case 0:
			return -EINVAL;
		default:
			return (selector * 100000) + 950000;
		}
		break;
M
Mark Brown 已提交
151 152 153
	default:
		return -EINVAL;
	}
154 155
}

156
static int wm8994_ldo2_get_voltage_sel(struct regulator_dev *rdev)
157 158 159 160 161 162 163 164
{
	struct wm8994_ldo *ldo = rdev_get_drvdata(rdev);
	int val;

	val = wm8994_reg_read(ldo->wm8994, WM8994_LDO_2);
	if (val < 0)
		return val;

165
	return (val & WM8994_LDO2_VSEL_MASK) >> WM8994_LDO2_VSEL_SHIFT;
166 167 168
}

static int wm8994_ldo2_set_voltage(struct regulator_dev *rdev,
169
				   int min_uV, int max_uV, unsigned *s)
170 171 172 173
{
	struct wm8994_ldo *ldo = rdev_get_drvdata(rdev);
	int selector, v;

M
Mark Brown 已提交
174 175 176 177 178 179 180
	switch (ldo->wm8994->type) {
	case WM8994:
		selector = (min_uV - 900000) / 100000;
		break;
	case WM8958:
		selector = (min_uV - 1000000) / 100000;
		break;
M
Mark Brown 已提交
181 182 183 184 185
	case WM1811:
		selector = (min_uV - 950000) / 100000;
		if (selector == 0)
			selector = 1;
		break;
M
Mark Brown 已提交
186 187 188 189
	default:
		return -EINVAL;
	}

190 191 192 193
	v = wm8994_ldo2_list_voltage(rdev, selector);
	if (v < 0 || v > max_uV)
		return -EINVAL;

194
	*s = selector;
195 196 197 198 199 200 201 202 203 204 205 206 207
	selector <<= WM8994_LDO2_VSEL_SHIFT;

	return wm8994_set_bits(ldo->wm8994, WM8994_LDO_2,
			       WM8994_LDO2_VSEL_MASK, selector);
}

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,
208
	.get_voltage_sel = wm8994_ldo2_get_voltage_sel,
209 210 211
	.set_voltage = wm8994_ldo2_set_voltage,
};

212
static const struct regulator_desc wm8994_ldo_desc[] = {
213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243
	{
		.name = "LDO1",
		.id = 1,
		.type = REGULATOR_VOLTAGE,
		.n_voltages = WM8994_LDO1_MAX_SELECTOR + 1,
		.ops = &wm8994_ldo1_ops,
		.owner = THIS_MODULE,
	},
	{
		.name = "LDO2",
		.id = 2,
		.type = REGULATOR_VOLTAGE,
		.n_voltages = WM8994_LDO2_MAX_SELECTOR + 1,
		.ops = &wm8994_ldo2_ops,
		.owner = THIS_MODULE,
	},
};

static __devinit 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;
	int id = pdev->id % ARRAY_SIZE(pdata->ldo);
	struct wm8994_ldo *ldo;
	int ret;

	dev_dbg(&pdev->dev, "Probing LDO%d\n", id + 1);

	if (!pdata)
		return -ENODEV;

244
	ldo = devm_kzalloc(&pdev->dev, sizeof(struct wm8994_ldo), GFP_KERNEL);
245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267
	if (ldo == NULL) {
		dev_err(&pdev->dev, "Unable to allocate private data\n");
		return -ENOMEM;
	}

	ldo->wm8994 = wm8994;

	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;
		}
268 269
	} else
		ldo->is_enabled = true;
270 271

	ldo->regulator = regulator_register(&wm8994_ldo_desc[id], &pdev->dev,
272
					     pdata->ldo[id].init_data, ldo, NULL);
273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294
	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;
	}

	platform_set_drvdata(pdev, ldo);

	return 0;

err_gpio:
	if (gpio_is_valid(ldo->enable))
		gpio_free(ldo->enable);
err:
	return ret;
}

static __devexit int wm8994_ldo_remove(struct platform_device *pdev)
{
	struct wm8994_ldo *ldo = platform_get_drvdata(pdev);

295 296
	platform_set_drvdata(pdev, NULL);

297 298 299 300 301 302 303 304 305 306 307 308
	regulator_unregister(ldo->regulator);
	if (gpio_is_valid(ldo->enable))
		gpio_free(ldo->enable);

	return 0;
}

static struct platform_driver wm8994_ldo_driver = {
	.probe = wm8994_ldo_probe,
	.remove = __devexit_p(wm8994_ldo_remove),
	.driver		= {
		.name	= "wm8994-ldo",
309
		.owner	= THIS_MODULE,
310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335
	},
};

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 information */
MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
MODULE_DESCRIPTION("WM8994 LDO driver");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:wm8994-ldo");