max8649.c 9.0 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
/*
 * Regulators driver for Maxim max8649
 *
 * Copyright (C) 2009-2010 Marvell International Ltd.
 *      Haojian Zhuang <haojian.zhuang@marvell.com>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 */
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/err.h>
#include <linux/i2c.h>
#include <linux/platform_device.h>
#include <linux/regulator/driver.h>
17
#include <linux/slab.h>
18
#include <linux/regulator/max8649.h>
19
#include <linux/regmap.h>
20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53

#define MAX8649_DCDC_VMIN	750000		/* uV */
#define MAX8649_DCDC_VMAX	1380000		/* uV */
#define MAX8649_DCDC_STEP	10000		/* uV */
#define MAX8649_VOL_MASK	0x3f

/* Registers */
#define MAX8649_MODE0		0x00
#define MAX8649_MODE1		0x01
#define MAX8649_MODE2		0x02
#define MAX8649_MODE3		0x03
#define MAX8649_CONTROL		0x04
#define MAX8649_SYNC		0x05
#define MAX8649_RAMP		0x06
#define MAX8649_CHIP_ID1	0x08
#define MAX8649_CHIP_ID2	0x09

/* Bits */
#define MAX8649_EN_PD		(1 << 7)
#define MAX8649_VID0_PD		(1 << 6)
#define MAX8649_VID1_PD		(1 << 5)
#define MAX8649_VID_MASK	(3 << 5)

#define MAX8649_FORCE_PWM	(1 << 7)
#define MAX8649_SYNC_EXTCLK	(1 << 6)

#define MAX8649_EXT_MASK	(3 << 6)

#define MAX8649_RAMP_MASK	(7 << 5)
#define MAX8649_RAMP_DOWN	(1 << 1)

struct max8649_regulator_info {
	struct regulator_dev	*regulator;
	struct device		*dev;
54
	struct regmap		*regmap;
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

	int		vol_reg;
	unsigned	mode:2;	/* bit[1:0] = VID1, VID0 */
	unsigned	extclk_freq:2;
	unsigned	extclk:1;
	unsigned	ramp_timing:3;
	unsigned	ramp_down:1;
};

/* I2C operations */

static inline int check_range(int min_uV, int max_uV)
{
	if ((min_uV < MAX8649_DCDC_VMIN) || (max_uV > MAX8649_DCDC_VMAX)
		|| (min_uV > max_uV))
		return -EINVAL;
	return 0;
}

static int max8649_list_voltage(struct regulator_dev *rdev, unsigned index)
{
	return (MAX8649_DCDC_VMIN + index * MAX8649_DCDC_STEP);
}

static int max8649_get_voltage(struct regulator_dev *rdev)
{
	struct max8649_regulator_info *info = rdev_get_drvdata(rdev);
82
	unsigned int val;
83 84 85
	unsigned char data;
	int ret;

86 87
	ret = regmap_read(info->regmap, info->vol_reg, &val);
	if (ret != 0)
88
		return ret;
89
	data = (unsigned char)val & MAX8649_VOL_MASK;
90 91 92 93
	return max8649_list_voltage(rdev, data);
}

static int max8649_set_voltage(struct regulator_dev *rdev,
94
			       int min_uV, int max_uV, unsigned *selector)
95 96 97 98 99 100 101 102 103
{
	struct max8649_regulator_info *info = rdev_get_drvdata(rdev);
	unsigned char data, mask;

	if (check_range(min_uV, max_uV)) {
		dev_err(info->dev, "invalid voltage range (%d, %d) uV\n",
			min_uV, max_uV);
		return -EINVAL;
	}
104
	data = DIV_ROUND_UP(min_uV - MAX8649_DCDC_VMIN, MAX8649_DCDC_STEP);
105
	mask = MAX8649_VOL_MASK;
106
	*selector = data & mask;
107

108
	return regmap_update_bits(info->regmap, info->vol_reg, mask, data);
109 110 111 112 113 114
}

/* EN_PD means pulldown on EN input */
static int max8649_enable(struct regulator_dev *rdev)
{
	struct max8649_regulator_info *info = rdev_get_drvdata(rdev);
115
	return regmap_update_bits(info->regmap, MAX8649_CONTROL, MAX8649_EN_PD, 0);
116 117 118 119 120 121 122 123 124
}

/*
 * Applied internal pulldown resistor on EN input pin.
 * If pulldown EN pin outside, it would be better.
 */
static int max8649_disable(struct regulator_dev *rdev)
{
	struct max8649_regulator_info *info = rdev_get_drvdata(rdev);
125
	return regmap_update_bits(info->regmap, MAX8649_CONTROL, MAX8649_EN_PD,
126 127 128 129 130 131
				MAX8649_EN_PD);
}

static int max8649_is_enabled(struct regulator_dev *rdev)
{
	struct max8649_regulator_info *info = rdev_get_drvdata(rdev);
132
	unsigned int val;
133 134
	int ret;

135 136
	ret = regmap_read(info->regmap, MAX8649_CONTROL, &val);
	if (ret != 0)
137
		return ret;
138
	return !((unsigned char)val & MAX8649_EN_PD);
139 140 141 142 143 144
}

static int max8649_enable_time(struct regulator_dev *rdev)
{
	struct max8649_regulator_info *info = rdev_get_drvdata(rdev);
	int voltage, rate, ret;
145
	unsigned int val;
146 147

	/* get voltage */
148 149
	ret = regmap_read(info->regmap, info->vol_reg, &val);
	if (ret != 0)
150
		return ret;
151
	val &= MAX8649_VOL_MASK;
152
	voltage = max8649_list_voltage(rdev, (unsigned char)val); /* uV */
153 154

	/* get rate */
155 156
	ret = regmap_read(info->regmap, MAX8649_RAMP, &val);
	if (ret != 0)
157
		return ret;
158
	ret = (val & MAX8649_RAMP_MASK) >> 5;
159 160
	rate = (32 * 1000) >> ret;	/* uV/uS */

161
	return DIV_ROUND_UP(voltage, rate);
162 163 164 165 166 167 168 169
}

static int max8649_set_mode(struct regulator_dev *rdev, unsigned int mode)
{
	struct max8649_regulator_info *info = rdev_get_drvdata(rdev);

	switch (mode) {
	case REGULATOR_MODE_FAST:
170 171
		regmap_update_bits(info->regmap, info->vol_reg, MAX8649_FORCE_PWM,
				   MAX8649_FORCE_PWM);
172 173
		break;
	case REGULATOR_MODE_NORMAL:
174 175
		regmap_update_bits(info->regmap, info->vol_reg,
				   MAX8649_FORCE_PWM, 0);
176 177 178 179 180 181 182 183 184 185
		break;
	default:
		return -EINVAL;
	}
	return 0;
}

static unsigned int max8649_get_mode(struct regulator_dev *rdev)
{
	struct max8649_regulator_info *info = rdev_get_drvdata(rdev);
186
	unsigned int val;
187 188
	int ret;

189 190 191 192
	ret = regmap_read(info->regmap, info->vol_reg, &val);
	if (ret != 0)
		return ret;
	if (val & MAX8649_FORCE_PWM)
193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209
		return REGULATOR_MODE_FAST;
	return REGULATOR_MODE_NORMAL;
}

static struct regulator_ops max8649_dcdc_ops = {
	.set_voltage	= max8649_set_voltage,
	.get_voltage	= max8649_get_voltage,
	.list_voltage	= max8649_list_voltage,
	.enable		= max8649_enable,
	.disable	= max8649_disable,
	.is_enabled	= max8649_is_enabled,
	.enable_time	= max8649_enable_time,
	.set_mode	= max8649_set_mode,
	.get_mode	= max8649_get_mode,

};

210
static const struct regulator_desc dcdc_desc = {
211 212 213 214 215 216 217
	.name		= "max8649",
	.ops		= &max8649_dcdc_ops,
	.type		= REGULATOR_VOLTAGE,
	.n_voltages	= 1 << 6,
	.owner		= THIS_MODULE,
};

218 219 220 221 222
static struct regmap_config max8649_regmap_config = {
	.reg_bits = 8,
	.val_bits = 8,
};

223 224 225 226 227
static int __devinit max8649_regulator_probe(struct i2c_client *client,
					     const struct i2c_device_id *id)
{
	struct max8649_platform_data *pdata = client->dev.platform_data;
	struct max8649_regulator_info *info = NULL;
228
	struct regulator_config config = { };
229
	unsigned int val;
230 231 232 233 234 235 236 237 238
	unsigned char data;
	int ret;

	info = kzalloc(sizeof(struct max8649_regulator_info), GFP_KERNEL);
	if (!info) {
		dev_err(&client->dev, "No enough memory\n");
		return -ENOMEM;
	}

239 240 241 242 243 244 245
	info->regmap = regmap_init_i2c(client, &max8649_regmap_config);
	if (IS_ERR(info->regmap)) {
		ret = PTR_ERR(info->regmap);
		dev_err(&client->dev, "Failed to allocate register map: %d\n", ret);
		goto fail;
	}

246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266
	info->dev = &client->dev;
	i2c_set_clientdata(client, info);

	info->mode = pdata->mode;
	switch (info->mode) {
	case 0:
		info->vol_reg = MAX8649_MODE0;
		break;
	case 1:
		info->vol_reg = MAX8649_MODE1;
		break;
	case 2:
		info->vol_reg = MAX8649_MODE2;
		break;
	case 3:
		info->vol_reg = MAX8649_MODE3;
		break;
	default:
		break;
	}

267 268
	ret = regmap_read(info->regmap, MAX8649_CHIP_ID1, &val);
	if (ret != 0) {
269 270 271 272
		dev_err(info->dev, "Failed to detect ID of MAX8649:%d\n",
			ret);
		goto out;
	}
273
	dev_info(info->dev, "Detected MAX8649 (ID:%x)\n", val);
274 275

	/* enable VID0 & VID1 */
276
	regmap_update_bits(info->regmap, MAX8649_CONTROL, MAX8649_VID_MASK, 0);
277 278 279 280

	/* enable/disable external clock synchronization */
	info->extclk = pdata->extclk;
	data = (info->extclk) ? MAX8649_SYNC_EXTCLK : 0;
281
	regmap_update_bits(info->regmap, info->vol_reg, MAX8649_SYNC_EXTCLK, data);
282 283 284
	if (info->extclk) {
		/* set external clock frequency */
		info->extclk_freq = pdata->extclk_freq;
285 286
		regmap_update_bits(info->regmap, MAX8649_SYNC, MAX8649_EXT_MASK,
				   info->extclk_freq << 6);
287 288 289 290
	}

	if (pdata->ramp_timing) {
		info->ramp_timing = pdata->ramp_timing;
291 292
		regmap_update_bits(info->regmap, MAX8649_RAMP, MAX8649_RAMP_MASK,
				   info->ramp_timing << 5);
293 294 295 296
	}

	info->ramp_down = pdata->ramp_down;
	if (info->ramp_down) {
297 298
		regmap_update_bits(info->regmap, MAX8649_RAMP, MAX8649_RAMP_DOWN,
				   MAX8649_RAMP_DOWN);
299 300
	}

301 302 303 304 305
	config.dev = &client->dev;
	config.init_data = pdata->regulator;
	config.driver_data = info;

	info->regulator = regulator_register(&dcdc_desc, &config);
306 307 308 309 310 311 312 313 314
	if (IS_ERR(info->regulator)) {
		dev_err(info->dev, "failed to register regulator %s\n",
			dcdc_desc.name);
		ret = PTR_ERR(info->regulator);
		goto out;
	}

	return 0;
out:
315 316
	regmap_exit(info->regmap);
fail:
317 318 319 320 321 322 323 324 325 326 327
	kfree(info);
	return ret;
}

static int __devexit max8649_regulator_remove(struct i2c_client *client)
{
	struct max8649_regulator_info *info = i2c_get_clientdata(client);

	if (info) {
		if (info->regulator)
			regulator_unregister(info->regulator);
328
		regmap_exit(info->regmap);
329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366
		kfree(info);
	}

	return 0;
}

static const struct i2c_device_id max8649_id[] = {
	{ "max8649", 0 },
	{ }
};
MODULE_DEVICE_TABLE(i2c, max8649_id);

static struct i2c_driver max8649_driver = {
	.probe		= max8649_regulator_probe,
	.remove		= __devexit_p(max8649_regulator_remove),
	.driver		= {
		.name	= "max8649",
	},
	.id_table	= max8649_id,
};

static int __init max8649_init(void)
{
	return i2c_add_driver(&max8649_driver);
}
subsys_initcall(max8649_init);

static void __exit max8649_exit(void)
{
	i2c_del_driver(&max8649_driver);
}
module_exit(max8649_exit);

/* Module information */
MODULE_DESCRIPTION("MAXIM 8649 voltage regulator driver");
MODULE_AUTHOR("Haojian Zhuang <haojian.zhuang@marvell.com>");
MODULE_LICENSE("GPL");