tps65217-regulator.c 9.4 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)	\
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 42
	}						\

43
#define TPS65217_INFO(_nm, _min, _max, _f1, _f2, _t, _n)\
44 45 46 47 48 49 50 51 52 53 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 81 82 83 84 85
	{						\
		.name		= _nm,			\
		.min_uV		= _min,			\
		.max_uV		= _max,			\
		.vsel_to_uv	= _f1,			\
		.uv_to_vsel	= _f2,			\
		.table		= _t,			\
		.table_len	= _n,			\
	}

static const int LDO1_VSEL_table[] = {
	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)
{
	if ((uV < 0) && (uV > 3300000))
		return -EINVAL;

	if (uV <= 1500000)
86
		*vsel = DIV_ROUND_UP(uV - 900000, 25000);
87
	else if (uV <= 2900000)
88
		*vsel = 24 + DIV_ROUND_UP(uV - 1500000, 50000);
89
	else if (uV < 3300000)
90
		*vsel = 52 + DIV_ROUND_UP(uV - 2900000, 100000);
91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119
	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)
{
	if ((uV < 0) && (uV > 3300000))
		return -EINVAL;

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

	return 0;
}

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

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

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

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

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

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

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

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

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

184 185 186 187 188 189 190 191
	/* 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;
	}
192

193
	return ret;
194 195
}

196 197
static int tps65217_pmic_map_voltage(struct regulator_dev *dev,
				     int min_uV, int max_uV)
198
{
199

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

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

208
	if (rid < TPS65217_DCDC_1 || rid > TPS65217_LDO_4)
209 210
		return -EINVAL;

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

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

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

221
	return sel;
222 223
}

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

230
	if (rid < TPS65217_DCDC_1 || rid > TPS65217_LDO_4)
231 232
		return -EINVAL;

233
	if (selector >= tps->info[rid]->table_len)
234 235
		return -EINVAL;

236 237
	if (tps->info[rid]->table)
		return tps->info[rid]->table[selector];
238

239
	return tps->info[rid]->vsel_to_uv(selector);
240 241
}

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

/* Operations permitted on LDO1 */
static struct regulator_ops tps65217_pmic_ldo1_ops = {
255
	.is_enabled		= regulator_is_enabled_regmap,
256 257
	.enable			= tps65217_pmic_enable,
	.disable		= tps65217_pmic_disable,
258
	.get_voltage_sel	= regulator_get_voltage_sel_regmap,
259
	.set_voltage_sel	= tps65217_pmic_set_voltage_sel,
260
	.list_voltage		= tps65217_pmic_list_voltage,
261 262
};

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

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];
292
	struct regulator_config config = { };
293 294 295 296 297

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

298 299 300 301 302
	config.dev = &pdev->dev;
	config.init_data = pdev->dev.platform_data;
	config.driver_data = tps;

	rdev = regulator_register(&regulators[pdev->id], &config);
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 342 343 344
	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");