tps65217-regulator.c 9.3 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
/*
 * tps65217-regulator.c
 *
 * Regulator driver for TPS65217 PMIC
 *
 * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.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 version 2.
 *
 * This program is distributed "as is" WITHOUT ANY WARRANTY of any
 * kind, whether express or implied; without even the implied warranty
 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 */

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/device.h>
#include <linux/init.h>
#include <linux/err.h>
#include <linux/platform_device.h>

#include <linux/regulator/driver.h>
#include <linux/regulator/machine.h>
#include <linux/mfd/tps65217.h>

29
#define TPS65217_REGULATOR(_name, _id, _ops, _n, _vr, _vm, _em, _t) \
30 31 32 33 34 35 36
	{						\
		.name		= _name,		\
		.id		= _id,			\
		.ops		= &_ops,		\
		.n_voltages	= _n,			\
		.type		= REGULATOR_VOLTAGE,	\
		.owner		= THIS_MODULE,		\
37 38 39 40
		.vsel_reg	= _vr,			\
		.vsel_mask	= _vm,			\
		.enable_reg	= TPS65217_REG_ENABLE,	\
		.enable_mask	= _em,			\
41
		.volt_table	= _t,			\
42 43
	}						\

44
#define TPS65217_INFO(_nm, _min, _max, _f1, _f2)	\
45 46 47 48 49 50 51 52
	{						\
		.name		= _nm,			\
		.min_uV		= _min,			\
		.max_uV		= _max,			\
		.vsel_to_uv	= _f1,			\
		.uv_to_vsel	= _f2,			\
	}

53
static const unsigned int LDO1_VSEL_table[] = {
54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80
	1000000, 1100000, 1200000, 1250000,
	1300000, 1350000, 1400000, 1500000,
	1600000, 1800000, 2500000, 2750000,
	2800000, 3000000, 3100000, 3300000,
};

static int tps65217_vsel_to_uv1(unsigned int vsel)
{
	int uV = 0;

	if (vsel > 63)
		return -EINVAL;

	if (vsel <= 24)
		uV = vsel * 25000 + 900000;
	else if (vsel <= 52)
		uV = (vsel - 24) * 50000 + 1500000;
	else if (vsel < 56)
		uV = (vsel - 52) * 100000 + 2900000;
	else
		uV = 3300000;

	return uV;
}

static int tps65217_uv_to_vsel1(int uV, unsigned int *vsel)
{
A
Alan Cox 已提交
81
	if (uV < 0 || uV > 3300000)
82 83 84
		return -EINVAL;

	if (uV <= 1500000)
85
		*vsel = DIV_ROUND_UP(uV - 900000, 25000);
86
	else if (uV <= 2900000)
87
		*vsel = 24 + DIV_ROUND_UP(uV - 1500000, 50000);
88
	else if (uV < 3300000)
89
		*vsel = 52 + DIV_ROUND_UP(uV - 2900000, 100000);
90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114
	else
		*vsel = 56;

	return 0;
}

static int tps65217_vsel_to_uv2(unsigned int vsel)
{
	int uV = 0;

	if (vsel > 31)
		return -EINVAL;

	if (vsel <= 8)
		uV = vsel * 50000 + 1500000;
	else if (vsel <= 13)
		uV = (vsel - 8) * 100000 + 1900000;
	else
		uV = (vsel - 13) * 50000 + 2400000;

	return uV;
}

static int tps65217_uv_to_vsel2(int uV, unsigned int *vsel)
{
A
Alan Cox 已提交
115
	if (uV < 0 || uV > 3300000)
116 117 118
		return -EINVAL;

	if (uV <= 1900000)
119
		*vsel = DIV_ROUND_UP(uV - 1500000, 50000);
120
	else if (uV <= 2400000)
121
		*vsel = 8 + DIV_ROUND_UP(uV - 1900000, 100000);
122
	else
123
		*vsel = 13 + DIV_ROUND_UP(uV - 2400000, 50000);
124 125 126 127 128 129

	return 0;
}

static struct tps_info tps65217_pmic_regs[] = {
	TPS65217_INFO("DCDC1", 900000, 1800000, tps65217_vsel_to_uv1,
130
			tps65217_uv_to_vsel1),
131
	TPS65217_INFO("DCDC2", 900000, 3300000, tps65217_vsel_to_uv1,
132
			tps65217_uv_to_vsel1),
133
	TPS65217_INFO("DCDC3", 900000, 1500000, tps65217_vsel_to_uv1,
134 135
			tps65217_uv_to_vsel1),
	TPS65217_INFO("LDO1", 1000000, 3300000, NULL, NULL),
136
	TPS65217_INFO("LDO2", 900000, 3300000, tps65217_vsel_to_uv1,
137
			tps65217_uv_to_vsel1),
138
	TPS65217_INFO("LDO3", 1800000, 3300000, tps65217_vsel_to_uv2,
139
			tps65217_uv_to_vsel2),
140
	TPS65217_INFO("LDO4", 1800000, 3300000, tps65217_vsel_to_uv2,
141
			tps65217_uv_to_vsel2),
142 143
};

144
static int tps65217_pmic_enable(struct regulator_dev *dev)
145 146
{
	struct tps65217 *tps = rdev_get_drvdata(dev);
147
	unsigned int rid = rdev_get_id(dev);
148

149
	if (rid < TPS65217_DCDC_1 || rid > TPS65217_LDO_4)
150 151 152 153
		return -EINVAL;

	/* Enable the regulator and password protection is level 1 */
	return tps65217_set_bits(tps, TPS65217_REG_ENABLE,
154 155
				 dev->desc->enable_mask, dev->desc->enable_mask,
				 TPS65217_PROTECT_L1);
156 157
}

158
static int tps65217_pmic_disable(struct regulator_dev *dev)
159 160
{
	struct tps65217 *tps = rdev_get_drvdata(dev);
161
	unsigned int rid = rdev_get_id(dev);
162

163
	if (rid < TPS65217_DCDC_1 || rid > TPS65217_LDO_4)
164 165 166 167
		return -EINVAL;

	/* Disable the regulator and password protection is level 1 */
	return tps65217_clear_bits(tps, TPS65217_REG_ENABLE,
168
				   dev->desc->enable_mask, TPS65217_PROTECT_L1);
169 170
}

171 172
static int tps65217_pmic_set_voltage_sel(struct regulator_dev *dev,
					 unsigned selector)
173
{
174
	int ret;
175
	struct tps65217 *tps = rdev_get_drvdata(dev);
176
	unsigned int rid = rdev_get_id(dev);
177

178
	/* Set the voltage based on vsel value and write protect level is 2 */
179
	ret = tps65217_set_bits(tps, dev->desc->vsel_reg, dev->desc->vsel_mask,
180
				selector, TPS65217_PROTECT_L2);
181

182 183 184 185 186 187 188 189
	/* Set GO bit for DCDCx to initiate voltage transistion */
	switch (rid) {
	case TPS65217_DCDC_1 ... TPS65217_DCDC_3:
		ret = tps65217_set_bits(tps, TPS65217_REG_DEFSLEW,
				       TPS65217_DEFSLEW_GO, TPS65217_DEFSLEW_GO,
				       TPS65217_PROTECT_L2);
		break;
	}
190

191
	return ret;
192 193
}

194 195
static int tps65217_pmic_map_voltage(struct regulator_dev *dev,
				     int min_uV, int max_uV)
196
{
197

198
	struct tps65217 *tps = rdev_get_drvdata(dev);
199 200
	unsigned int sel, rid = rdev_get_id(dev);
	int ret;
201

202
	/* LDO1 uses regulator_map_voltage_iterate() */
203
	if (rid == TPS65217_LDO_1)
204 205
		return -EINVAL;

206
	if (rid < TPS65217_DCDC_1 || rid > TPS65217_LDO_4)
207 208
		return -EINVAL;

209
	if (min_uV < tps->info[rid]->min_uV || min_uV > tps->info[rid]->max_uV)
210 211
		return -EINVAL;

212
	if (max_uV < tps->info[rid]->min_uV || max_uV > tps->info[rid]->max_uV)
213 214
		return -EINVAL;

215
	ret = tps->info[rid]->uv_to_vsel(min_uV, &sel);
216 217 218
	if (ret)
		return ret;

219
	return sel;
220 221
}

222
static int tps65217_pmic_list_voltage(struct regulator_dev *dev,
223 224 225
					unsigned selector)
{
	struct tps65217 *tps = rdev_get_drvdata(dev);
226
	unsigned int rid = rdev_get_id(dev);
227

228
	if (rid < TPS65217_DCDC_1 || rid > TPS65217_LDO_4)
229 230
		return -EINVAL;

231
	if (selector >= dev->desc->n_voltages)
232 233
		return -EINVAL;

234
	return tps->info[rid]->vsel_to_uv(selector);
235 236
}

237 238
/* Operations permitted on DCDCx, LDO2, LDO3 and LDO4 */
static struct regulator_ops tps65217_pmic_ops = {
239
	.is_enabled		= regulator_is_enabled_regmap,
240 241
	.enable			= tps65217_pmic_enable,
	.disable		= tps65217_pmic_disable,
242
	.get_voltage_sel	= regulator_get_voltage_sel_regmap,
243
	.set_voltage_sel	= tps65217_pmic_set_voltage_sel,
244
	.list_voltage		= tps65217_pmic_list_voltage,
245
	.map_voltage		= tps65217_pmic_map_voltage,
246 247 248 249
};

/* Operations permitted on LDO1 */
static struct regulator_ops tps65217_pmic_ldo1_ops = {
250
	.is_enabled		= regulator_is_enabled_regmap,
251 252
	.enable			= tps65217_pmic_enable,
	.disable		= tps65217_pmic_disable,
253
	.get_voltage_sel	= regulator_get_voltage_sel_regmap,
254
	.set_voltage_sel	= tps65217_pmic_set_voltage_sel,
255
	.list_voltage		= regulator_list_voltage_table,
256 257
};

258
static const struct regulator_desc regulators[] = {
259 260
	TPS65217_REGULATOR("DCDC1", TPS65217_DCDC_1, tps65217_pmic_ops, 64,
			   TPS65217_REG_DEFDCDC1, TPS65217_DEFDCDCX_DCDC_MASK,
261
			   TPS65217_ENABLE_DC1_EN, NULL),
262 263
	TPS65217_REGULATOR("DCDC2", TPS65217_DCDC_2, tps65217_pmic_ops, 64,
			   TPS65217_REG_DEFDCDC2, TPS65217_DEFDCDCX_DCDC_MASK,
264
			   TPS65217_ENABLE_DC2_EN, NULL),
265 266
	TPS65217_REGULATOR("DCDC3", TPS65217_DCDC_3, tps65217_pmic_ops, 64,
			   TPS65217_REG_DEFDCDC3, TPS65217_DEFDCDCX_DCDC_MASK,
267
			   TPS65217_ENABLE_DC3_EN, NULL),
268 269
	TPS65217_REGULATOR("LDO1", TPS65217_LDO_1, tps65217_pmic_ldo1_ops, 16,
			   TPS65217_REG_DEFLDO1, TPS65217_DEFLDO1_LDO1_MASK,
270
			   TPS65217_ENABLE_LDO1_EN, LDO1_VSEL_table),
271 272
	TPS65217_REGULATOR("LDO2", TPS65217_LDO_2, tps65217_pmic_ops, 64,
			   TPS65217_REG_DEFLDO2, TPS65217_DEFLDO2_LDO2_MASK,
273
			   TPS65217_ENABLE_LDO2_EN, NULL),
274 275
	TPS65217_REGULATOR("LDO3", TPS65217_LDO_3, tps65217_pmic_ops, 32,
			   TPS65217_REG_DEFLS1, TPS65217_DEFLDO3_LDO3_MASK,
276 277
			   TPS65217_ENABLE_LS1_EN | TPS65217_DEFLDO3_LDO3_EN,
			   NULL),
278 279
	TPS65217_REGULATOR("LDO4", TPS65217_LDO_4, tps65217_pmic_ops, 32,
			   TPS65217_REG_DEFLS2, TPS65217_DEFLDO4_LDO4_MASK,
280 281
			   TPS65217_ENABLE_LS2_EN | TPS65217_DEFLDO4_LDO4_EN,
			   NULL),
282 283 284 285 286 287 288
};

static int __devinit tps65217_regulator_probe(struct platform_device *pdev)
{
	struct regulator_dev *rdev;
	struct tps65217 *tps;
	struct tps_info *info = &tps65217_pmic_regs[pdev->id];
289
	struct regulator_config config = { };
290 291 292 293 294

	/* Already set by core driver */
	tps = dev_to_tps65217(pdev->dev.parent);
	tps->info[pdev->id] = info;

295 296 297 298 299
	config.dev = &pdev->dev;
	config.init_data = pdev->dev.platform_data;
	config.driver_data = tps;

	rdev = regulator_register(&regulators[pdev->id], &config);
300 301 302 303 304 305 306 307 308 309 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 336 337 338 339 340 341
	if (IS_ERR(rdev))
		return PTR_ERR(rdev);

	platform_set_drvdata(pdev, rdev);

	return 0;
}

static int __devexit tps65217_regulator_remove(struct platform_device *pdev)
{
	struct regulator_dev *rdev = platform_get_drvdata(pdev);

	platform_set_drvdata(pdev, NULL);
	regulator_unregister(rdev);

	return 0;
}

static struct platform_driver tps65217_regulator_driver = {
	.driver = {
		.name = "tps65217-pmic",
	},
	.probe = tps65217_regulator_probe,
	.remove = __devexit_p(tps65217_regulator_remove),
};

static int __init tps65217_regulator_init(void)
{
	return platform_driver_register(&tps65217_regulator_driver);
}
subsys_initcall(tps65217_regulator_init);

static void __exit tps65217_regulator_exit(void)
{
	platform_driver_unregister(&tps65217_regulator_driver);
}
module_exit(tps65217_regulator_exit);

MODULE_AUTHOR("AnilKumar Ch <anilkumar@ti.com>");
MODULE_DESCRIPTION("TPS65217 voltage regulator driver");
MODULE_ALIAS("platform:tps65217-pmic");
MODULE_LICENSE("GPL v2");