act8865-regulator.c 10.7 KB
Newer Older
1
/*
2 3 4
 * act8865-regulator.c - Voltage regulation for active-semi ACT88xx PMUs
 *
 * http://www.active-semi.com/products/power-management-units/act88xx/
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
 *
 * Copyright (C) 2013 Atmel Corporation
 *
 * 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.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 */

#include <linux/module.h>
#include <linux/init.h>
#include <linux/i2c.h>
#include <linux/err.h>
#include <linux/platform_device.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/act8865.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/regulator/of_regulator.h>
#include <linux/regmap.h>

31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64
/*
 * ACT8846 Global Register Map.
 */
#define	ACT8846_SYS0		0x00
#define	ACT8846_SYS1		0x01
#define	ACT8846_REG1_VSET	0x10
#define	ACT8846_REG1_CTRL	0x12
#define	ACT8846_REG2_VSET0	0x20
#define	ACT8846_REG2_VSET1	0x21
#define	ACT8846_REG2_CTRL	0x22
#define	ACT8846_REG3_VSET0	0x30
#define	ACT8846_REG3_VSET1	0x31
#define	ACT8846_REG3_CTRL	0x32
#define	ACT8846_REG4_VSET0	0x40
#define	ACT8846_REG4_VSET1	0x41
#define	ACT8846_REG4_CTRL	0x42
#define	ACT8846_REG5_VSET	0x50
#define	ACT8846_REG5_CTRL	0x51
#define	ACT8846_REG6_VSET	0x58
#define	ACT8846_REG6_CTRL	0x59
#define	ACT8846_REG7_VSET	0x60
#define	ACT8846_REG7_CTRL	0x61
#define	ACT8846_REG8_VSET	0x68
#define	ACT8846_REG8_CTRL	0x69
#define	ACT8846_REG9_VSET	0x70
#define	ACT8846_REG9_CTRL	0x71
#define	ACT8846_REG10_VSET	0x80
#define	ACT8846_REG10_CTRL	0x81
#define	ACT8846_REG11_VSET	0x90
#define	ACT8846_REG11_CTRL	0x91
#define	ACT8846_REG12_VSET	0xa0
#define	ACT8846_REG12_CTRL	0xa1
#define	ACT8846_REG13_CTRL	0xb1

65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107
/*
 * ACT8865 Global Register Map.
 */
#define	ACT8865_SYS_MODE	0x00
#define	ACT8865_SYS_CTRL	0x01
#define	ACT8865_DCDC1_VSET1	0x20
#define	ACT8865_DCDC1_VSET2	0x21
#define	ACT8865_DCDC1_CTRL	0x22
#define	ACT8865_DCDC2_VSET1	0x30
#define	ACT8865_DCDC2_VSET2	0x31
#define	ACT8865_DCDC2_CTRL	0x32
#define	ACT8865_DCDC3_VSET1	0x40
#define	ACT8865_DCDC3_VSET2	0x41
#define	ACT8865_DCDC3_CTRL	0x42
#define	ACT8865_LDO1_VSET	0x50
#define	ACT8865_LDO1_CTRL	0x51
#define	ACT8865_LDO2_VSET	0x54
#define	ACT8865_LDO2_CTRL	0x55
#define	ACT8865_LDO3_VSET	0x60
#define	ACT8865_LDO3_CTRL	0x61
#define	ACT8865_LDO4_VSET	0x64
#define	ACT8865_LDO4_CTRL	0x65

/*
 * Field Definitions.
 */
#define	ACT8865_ENA		0x80	/* ON - [7] */
#define	ACT8865_VSEL_MASK	0x3F	/* VSET - [5:0] */

/*
 * ACT8865 voltage number
 */
#define	ACT8865_VOLTAGE_NUM	64

struct act8865 {
	struct regmap *regmap;
};

static const struct regmap_config act8865_regmap_config = {
	.reg_bits = 8,
	.val_bits = 8,
};

108
static const struct regulator_linear_range act8865_voltage_ranges[] = {
109 110 111 112 113 114 115 116 117 118 119 120 121 122 123
	REGULATOR_LINEAR_RANGE(600000, 0, 23, 25000),
	REGULATOR_LINEAR_RANGE(1200000, 24, 47, 50000),
	REGULATOR_LINEAR_RANGE(2400000, 48, 63, 100000),
};

static struct regulator_ops act8865_ops = {
	.list_voltage		= regulator_list_voltage_linear_range,
	.map_voltage		= regulator_map_voltage_linear_range,
	.get_voltage_sel	= regulator_get_voltage_sel_regmap,
	.set_voltage_sel	= regulator_set_voltage_sel_regmap,
	.enable			= regulator_enable_regmap,
	.disable		= regulator_disable_regmap,
	.is_enabled		= regulator_is_enabled_regmap,
};

124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139
#define ACT88xx_REG(_name, _family, _id, _vsel_reg)			\
	[_family##_ID_##_id] = {					\
		.name			= _name,			\
		.id			= _family##_ID_##_id,		\
		.type			= REGULATOR_VOLTAGE,		\
		.ops			= &act8865_ops,			\
		.n_voltages		= ACT8865_VOLTAGE_NUM,		\
		.linear_ranges		= act8865_voltage_ranges,	\
		.n_linear_ranges	= ARRAY_SIZE(act8865_voltage_ranges), \
		.vsel_reg		= _family##_##_id##_##_vsel_reg, \
		.vsel_mask		= ACT8865_VSEL_MASK,		\
		.enable_reg		= _family##_##_id##_CTRL,	\
		.enable_mask		= ACT8865_ENA,			\
		.owner			= THIS_MODULE,			\
	}

140 141 142 143 144 145 146 147 148 149 150 151 152 153 154
static const struct regulator_desc act8846_regulators[] = {
	ACT88xx_REG("REG1", ACT8846, REG1, VSET),
	ACT88xx_REG("REG2", ACT8846, REG2, VSET0),
	ACT88xx_REG("REG3", ACT8846, REG3, VSET0),
	ACT88xx_REG("REG4", ACT8846, REG4, VSET0),
	ACT88xx_REG("REG5", ACT8846, REG5, VSET),
	ACT88xx_REG("REG6", ACT8846, REG6, VSET),
	ACT88xx_REG("REG7", ACT8846, REG7, VSET),
	ACT88xx_REG("REG8", ACT8846, REG8, VSET),
	ACT88xx_REG("REG9", ACT8846, REG9, VSET),
	ACT88xx_REG("REG10", ACT8846, REG10, VSET),
	ACT88xx_REG("REG11", ACT8846, REG11, VSET),
	ACT88xx_REG("REG12", ACT8846, REG12, VSET),
};

155 156 157 158 159 160 161 162
static const struct regulator_desc act8865_regulators[] = {
	ACT88xx_REG("DCDC_REG1", ACT8865, DCDC1, VSET1),
	ACT88xx_REG("DCDC_REG2", ACT8865, DCDC2, VSET1),
	ACT88xx_REG("DCDC_REG3", ACT8865, DCDC3, VSET1),
	ACT88xx_REG("LDO_REG1", ACT8865, LDO1, VSET),
	ACT88xx_REG("LDO_REG2", ACT8865, LDO2, VSET),
	ACT88xx_REG("LDO_REG3", ACT8865, LDO3, VSET),
	ACT88xx_REG("LDO_REG4", ACT8865, LDO4, VSET),
163 164 165 166
};

#ifdef CONFIG_OF
static const struct of_device_id act8865_dt_ids[] = {
167
	{ .compatible = "active-semi,act8846", .data = (void *)ACT8846 },
168
	{ .compatible = "active-semi,act8865", .data = (void *)ACT8865 },
169 170 171 172
	{ }
};
MODULE_DEVICE_TABLE(of, act8865_dt_ids);

173 174 175 176 177 178 179 180 181 182 183 184 185 186 187
static struct of_regulator_match act8846_matches[] = {
	[ACT8846_ID_REG1]	= { .name = "REG1" },
	[ACT8846_ID_REG2]	= { .name = "REG2" },
	[ACT8846_ID_REG3]	= { .name = "REG3" },
	[ACT8846_ID_REG4]	= { .name = "REG4" },
	[ACT8846_ID_REG5]	= { .name = "REG5" },
	[ACT8846_ID_REG6]	= { .name = "REG6" },
	[ACT8846_ID_REG7]	= { .name = "REG7" },
	[ACT8846_ID_REG8]	= { .name = "REG8" },
	[ACT8846_ID_REG9]	= { .name = "REG9" },
	[ACT8846_ID_REG10]	= { .name = "REG10" },
	[ACT8846_ID_REG11]	= { .name = "REG11" },
	[ACT8846_ID_REG12]	= { .name = "REG12" },
};

188 189 190 191 192 193 194 195 196 197 198 199
static struct of_regulator_match act8865_matches[] = {
	[ACT8865_ID_DCDC1]	= { .name = "DCDC_REG1"},
	[ACT8865_ID_DCDC2]	= { .name = "DCDC_REG2"},
	[ACT8865_ID_DCDC3]	= { .name = "DCDC_REG3"},
	[ACT8865_ID_LDO1]	= { .name = "LDO_REG1"},
	[ACT8865_ID_LDO2]	= { .name = "LDO_REG2"},
	[ACT8865_ID_LDO3]	= { .name = "LDO_REG3"},
	[ACT8865_ID_LDO4]	= { .name = "LDO_REG4"},
};

static int act8865_pdata_from_dt(struct device *dev,
				 struct device_node **of_node,
200
				 struct act8865_platform_data *pdata,
201
				 unsigned long type)
202
{
203
	int matched, i, num_matches;
204 205
	struct device_node *np;
	struct act8865_regulator_data *regulator;
206
	struct of_regulator_match *matches;
207

208
	np = of_get_child_by_name(dev->of_node, "regulators");
209 210 211 212 213
	if (!np) {
		dev_err(dev, "missing 'regulators' subnode in DT\n");
		return -EINVAL;
	}

214 215 216 217 218 219 220 221 222 223 224 225 226 227
	switch (type) {
	case ACT8846:
		matches = act8846_matches;
		num_matches = ARRAY_SIZE(act8846_matches);
		break;
	case ACT8865:
		matches = act8865_matches;
		num_matches = ARRAY_SIZE(act8865_matches);
		break;
	default:
		dev_err(dev, "invalid device id %lu\n", type);
		return -EINVAL;
	}

228
	matched = of_regulator_match(dev, np, matches, num_matches);
229
	of_node_put(np);
230 231 232 233
	if (matched <= 0)
		return matched;

	pdata->regulators = devm_kzalloc(dev,
234 235
					 sizeof(struct act8865_regulator_data) *
					 num_matches, GFP_KERNEL);
236
	if (!pdata->regulators)
237 238
		return -ENOMEM;

239
	pdata->num_regulators = num_matches;
240 241
	regulator = pdata->regulators;

242
	for (i = 0; i < num_matches; i++) {
243
		regulator->id = i;
244 245 246
		regulator->name = matches[i].name;
		regulator->platform_data = matches[i].init_data;
		of_node[i] = matches[i].of_node;
247 248 249 250 251 252 253 254
		regulator++;
	}

	return 0;
}
#else
static inline int act8865_pdata_from_dt(struct device *dev,
					struct device_node **of_node,
255 256
					struct act8865_platform_data *pdata,
					unsigned long type)
257 258 259 260 261
{
	return 0;
}
#endif

262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277
static struct regulator_init_data
*act8865_get_init_data(int id, struct act8865_platform_data *pdata)
{
	int i;

	if (!pdata)
		return NULL;

	for (i = 0; i < pdata->num_regulators; i++) {
		if (pdata->regulators[i].id == id)
			return pdata->regulators[i].platform_data;
	}

	return NULL;
}

278
static int act8865_pmic_probe(struct i2c_client *client,
279
			      const struct i2c_device_id *i2c_id)
280
{
281 282
	static const struct regulator_desc *regulators;
	struct act8865_platform_data pdata_of, *pdata;
283
	struct device *dev = &client->dev;
284 285
	struct device_node **of_node;
	int i, ret, num_regulators;
286
	struct act8865 *act8865;
287 288 289
	unsigned long type;

	pdata = dev_get_platdata(dev);
290 291 292 293 294 295 296 297

	if (dev->of_node && !pdata) {
		const struct of_device_id *id;

		id = of_match_device(of_match_ptr(act8865_dt_ids), dev);
		if (!id)
			return -ENODEV;

298 299 300 301 302 303
		type = (unsigned long) id->data;
	} else {
		type = i2c_id->driver_data;
	}

	switch (type) {
304 305 306 307
	case ACT8846:
		regulators = act8846_regulators;
		num_regulators = ARRAY_SIZE(act8846_regulators);
		break;
308 309 310 311 312 313 314 315 316 317 318 319 320 321 322
	case ACT8865:
		regulators = act8865_regulators;
		num_regulators = ARRAY_SIZE(act8865_regulators);
		break;
	default:
		dev_err(dev, "invalid device id %lu\n", type);
		return -EINVAL;
	}

	of_node = devm_kzalloc(dev, sizeof(struct device_node *) *
			       num_regulators, GFP_KERNEL);
	if (!of_node)
		return -ENOMEM;

	if (dev->of_node && !pdata) {
323
		ret = act8865_pdata_from_dt(dev, of_node, &pdata_of, type);
324 325 326 327 328 329
		if (ret < 0)
			return ret;

		pdata = &pdata_of;
	}

330 331 332
	if (pdata->num_regulators > num_regulators) {
		dev_err(dev, "too many regulators: %d\n",
			pdata->num_regulators);
333 334 335
		return -EINVAL;
	}

336
	act8865 = devm_kzalloc(dev, sizeof(struct act8865), GFP_KERNEL);
337 338 339 340 341
	if (!act8865)
		return -ENOMEM;

	act8865->regmap = devm_regmap_init_i2c(client, &act8865_regmap_config);
	if (IS_ERR(act8865->regmap)) {
342
		ret = PTR_ERR(act8865->regmap);
343
		dev_err(&client->dev, "Failed to allocate register map: %d\n",
344 345
			ret);
		return ret;
346 347 348
	}

	/* Finally register devices */
349 350 351 352
	for (i = 0; i < num_regulators; i++) {
		const struct regulator_desc *desc = &regulators[i];
		struct regulator_config config = { };
		struct regulator_dev *rdev;
353 354

		config.dev = dev;
355
		config.init_data = act8865_get_init_data(desc->id, pdata);
356 357 358 359
		config.of_node = of_node[i];
		config.driver_data = act8865;
		config.regmap = act8865->regmap;

360
		rdev = devm_regulator_register(&client->dev, desc, &config);
361
		if (IS_ERR(rdev)) {
362
			dev_err(dev, "failed to register %s\n", desc->name);
363
			return PTR_ERR(rdev);
364 365 366 367
		}
	}

	i2c_set_clientdata(client, act8865);
368
	devm_kfree(dev, of_node);
369 370 371 372 373

	return 0;
}

static const struct i2c_device_id act8865_ids[] = {
374
	{ .name = "act8846", .driver_data = ACT8846 },
375
	{ .name = "act8865", .driver_data = ACT8865 },
376 377 378 379 380 381 382 383 384 385 386 387 388 389 390
	{ },
};
MODULE_DEVICE_TABLE(i2c, act8865_ids);

static struct i2c_driver act8865_pmic_driver = {
	.driver	= {
		.name	= "act8865",
		.owner	= THIS_MODULE,
	},
	.probe		= act8865_pmic_probe,
	.id_table	= act8865_ids,
};

module_i2c_driver(act8865_pmic_driver);

391
MODULE_DESCRIPTION("active-semi act88xx voltage regulator driver");
392 393
MODULE_AUTHOR("Wenyou Yang <wenyou.yang@atmel.com>");
MODULE_LICENSE("GPL v2");