116f10918SSteve Twiss /*
216f10918SSteve Twiss  * da9210-regulator.c - Regulator device driver for DA9210
316f10918SSteve Twiss  * Copyright (C) 2013  Dialog Semiconductor Ltd.
416f10918SSteve Twiss  *
516f10918SSteve Twiss  * This library is free software; you can redistribute it and/or
616f10918SSteve Twiss  * modify it under the terms of the GNU Library General Public
716f10918SSteve Twiss  * License as published by the Free Software Foundation; either
816f10918SSteve Twiss  * version 2 of the License, or (at your option) any later version.
916f10918SSteve Twiss  *
1016f10918SSteve Twiss  * This library is distributed in the hope that it will be useful,
1116f10918SSteve Twiss  * but WITHOUT ANY WARRANTY; without even the implied warranty of
1216f10918SSteve Twiss  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
1316f10918SSteve Twiss  * Library General Public License for more details.
1416f10918SSteve Twiss  *
1516f10918SSteve Twiss  * You should have received a copy of the GNU Library General Public
1616f10918SSteve Twiss  * License along with this library; if not, write to the
1716f10918SSteve Twiss  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
1816f10918SSteve Twiss  * Boston, MA  02110-1301, USA.
1916f10918SSteve Twiss  */
2016f10918SSteve Twiss 
2116f10918SSteve Twiss #include <linux/err.h>
2216f10918SSteve Twiss #include <linux/i2c.h>
2316f10918SSteve Twiss #include <linux/module.h>
2416f10918SSteve Twiss #include <linux/init.h>
2516f10918SSteve Twiss #include <linux/slab.h>
2616f10918SSteve Twiss #include <linux/regulator/driver.h>
2716f10918SSteve Twiss #include <linux/regulator/machine.h>
28937433c2SGuennadi Liakhovetski #include <linux/regulator/of_regulator.h>
2916f10918SSteve Twiss #include <linux/regmap.h>
3016f10918SSteve Twiss 
3116f10918SSteve Twiss #include "da9210-regulator.h"
3216f10918SSteve Twiss 
3316f10918SSteve Twiss struct da9210 {
3416f10918SSteve Twiss 	struct regulator_dev *rdev;
3516f10918SSteve Twiss 	struct regmap *regmap;
3616f10918SSteve Twiss };
3716f10918SSteve Twiss 
3816f10918SSteve Twiss static const struct regmap_config da9210_regmap_config = {
3916f10918SSteve Twiss 	.reg_bits = 8,
4016f10918SSteve Twiss 	.val_bits = 8,
4116f10918SSteve Twiss };
4216f10918SSteve Twiss 
4316f10918SSteve Twiss static int da9210_set_current_limit(struct regulator_dev *rdev, int min_uA,
4416f10918SSteve Twiss 				    int max_uA);
4516f10918SSteve Twiss static int da9210_get_current_limit(struct regulator_dev *rdev);
4616f10918SSteve Twiss 
4716f10918SSteve Twiss static struct regulator_ops da9210_buck_ops = {
4816f10918SSteve Twiss 	.enable = regulator_enable_regmap,
4916f10918SSteve Twiss 	.disable = regulator_disable_regmap,
5016f10918SSteve Twiss 	.is_enabled = regulator_is_enabled_regmap,
5116f10918SSteve Twiss 	.set_voltage_sel = regulator_set_voltage_sel_regmap,
5216f10918SSteve Twiss 	.get_voltage_sel = regulator_get_voltage_sel_regmap,
5316f10918SSteve Twiss 	.list_voltage = regulator_list_voltage_linear,
5416f10918SSteve Twiss 	.set_current_limit = da9210_set_current_limit,
5516f10918SSteve Twiss 	.get_current_limit = da9210_get_current_limit,
5616f10918SSteve Twiss };
5716f10918SSteve Twiss 
5816f10918SSteve Twiss /* Default limits measured in millivolts and milliamps */
5916f10918SSteve Twiss #define DA9210_MIN_MV		300
6016f10918SSteve Twiss #define DA9210_MAX_MV		1570
6116f10918SSteve Twiss #define DA9210_STEP_MV		10
6216f10918SSteve Twiss 
6316f10918SSteve Twiss /* Current limits for buck (uA) indices corresponds with register values */
6416f10918SSteve Twiss static const int da9210_buck_limits[] = {
6516f10918SSteve Twiss 	1600000, 1800000, 2000000, 2200000, 2400000, 2600000, 2800000, 3000000,
6616f10918SSteve Twiss 	3200000, 3400000, 3600000, 3800000, 4000000, 4200000, 4400000, 4600000
6716f10918SSteve Twiss };
6816f10918SSteve Twiss 
6916f10918SSteve Twiss static const struct regulator_desc da9210_reg = {
7016f10918SSteve Twiss 	.name = "DA9210",
7116f10918SSteve Twiss 	.id = 0,
7216f10918SSteve Twiss 	.ops = &da9210_buck_ops,
7316f10918SSteve Twiss 	.type = REGULATOR_VOLTAGE,
7416f10918SSteve Twiss 	.n_voltages = ((DA9210_MAX_MV - DA9210_MIN_MV) / DA9210_STEP_MV) + 1,
7516f10918SSteve Twiss 	.min_uV = (DA9210_MIN_MV * 1000),
7616f10918SSteve Twiss 	.uV_step = (DA9210_STEP_MV * 1000),
7716f10918SSteve Twiss 	.vsel_reg = DA9210_REG_VBUCK_A,
7816f10918SSteve Twiss 	.vsel_mask = DA9210_VBUCK_MASK,
7916f10918SSteve Twiss 	.enable_reg = DA9210_REG_BUCK_CONT,
8016f10918SSteve Twiss 	.enable_mask = DA9210_BUCK_EN,
8116f10918SSteve Twiss 	.owner = THIS_MODULE,
8216f10918SSteve Twiss };
8316f10918SSteve Twiss 
8416f10918SSteve Twiss static int da9210_set_current_limit(struct regulator_dev *rdev, int min_uA,
8516f10918SSteve Twiss 				    int max_uA)
8616f10918SSteve Twiss {
8716f10918SSteve Twiss 	struct da9210 *chip = rdev_get_drvdata(rdev);
8816f10918SSteve Twiss 	unsigned int sel;
8916f10918SSteve Twiss 	int i;
9016f10918SSteve Twiss 
9116f10918SSteve Twiss 	/* search for closest to maximum */
9216f10918SSteve Twiss 	for (i = ARRAY_SIZE(da9210_buck_limits)-1; i >= 0; i--) {
9316f10918SSteve Twiss 		if (min_uA <= da9210_buck_limits[i] &&
9416f10918SSteve Twiss 		    max_uA >= da9210_buck_limits[i]) {
9516f10918SSteve Twiss 			sel = i;
9616f10918SSteve Twiss 			sel = sel << DA9210_BUCK_ILIM_SHIFT;
9716f10918SSteve Twiss 			return regmap_update_bits(chip->regmap,
9816f10918SSteve Twiss 						  DA9210_REG_BUCK_ILIM,
9916f10918SSteve Twiss 						  DA9210_BUCK_ILIM_MASK, sel);
10016f10918SSteve Twiss 		}
10116f10918SSteve Twiss 	}
10216f10918SSteve Twiss 
10316f10918SSteve Twiss 	return -EINVAL;
10416f10918SSteve Twiss }
10516f10918SSteve Twiss 
10616f10918SSteve Twiss static int da9210_get_current_limit(struct regulator_dev *rdev)
10716f10918SSteve Twiss {
10816f10918SSteve Twiss 	struct da9210 *chip = rdev_get_drvdata(rdev);
10916f10918SSteve Twiss 	unsigned int data;
11016f10918SSteve Twiss 	unsigned int sel;
11116f10918SSteve Twiss 	int ret;
11216f10918SSteve Twiss 
11316f10918SSteve Twiss 	ret = regmap_read(chip->regmap, DA9210_REG_BUCK_ILIM, &data);
11416f10918SSteve Twiss 	if (ret < 0)
11516f10918SSteve Twiss 		return ret;
11616f10918SSteve Twiss 
11716f10918SSteve Twiss 	/* select one of 16 values: 0000 (1600mA) to 1111 (4600mA) */
11816f10918SSteve Twiss 	sel = (data & DA9210_BUCK_ILIM_MASK) >> DA9210_BUCK_ILIM_SHIFT;
11916f10918SSteve Twiss 
12016f10918SSteve Twiss 	return da9210_buck_limits[sel];
12116f10918SSteve Twiss }
12216f10918SSteve Twiss 
12316f10918SSteve Twiss /*
12416f10918SSteve Twiss  * I2C driver interface functions
12516f10918SSteve Twiss  */
12616f10918SSteve Twiss static int da9210_i2c_probe(struct i2c_client *i2c,
12716f10918SSteve Twiss 			    const struct i2c_device_id *id)
12816f10918SSteve Twiss {
12916f10918SSteve Twiss 	struct da9210 *chip;
130937433c2SGuennadi Liakhovetski 	struct device *dev = &i2c->dev;
131937433c2SGuennadi Liakhovetski 	struct da9210_pdata *pdata = dev_get_platdata(dev);
13216f10918SSteve Twiss 	struct regulator_dev *rdev = NULL;
13316f10918SSteve Twiss 	struct regulator_config config = { };
13416f10918SSteve Twiss 	int error;
13516f10918SSteve Twiss 
13616f10918SSteve Twiss 	chip = devm_kzalloc(&i2c->dev, sizeof(struct da9210), GFP_KERNEL);
13716f10918SSteve Twiss 	if (NULL == chip) {
13816f10918SSteve Twiss 		dev_err(&i2c->dev,
13916f10918SSteve Twiss 			"Cannot kzalloc memory for regulator structure\n");
14016f10918SSteve Twiss 		return -ENOMEM;
14116f10918SSteve Twiss 	}
14216f10918SSteve Twiss 
14316f10918SSteve Twiss 	chip->regmap = devm_regmap_init_i2c(i2c, &da9210_regmap_config);
14416f10918SSteve Twiss 	if (IS_ERR(chip->regmap)) {
14516f10918SSteve Twiss 		error = PTR_ERR(chip->regmap);
14616f10918SSteve Twiss 		dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
14716f10918SSteve Twiss 			error);
14816f10918SSteve Twiss 		return error;
14916f10918SSteve Twiss 	}
15016f10918SSteve Twiss 
15116f10918SSteve Twiss 	config.dev = &i2c->dev;
152937433c2SGuennadi Liakhovetski 	config.init_data = pdata ? &pdata->da9210_constraints :
153937433c2SGuennadi Liakhovetski 		of_get_regulator_init_data(dev, dev->of_node);
15416f10918SSteve Twiss 	config.driver_data = chip;
15516f10918SSteve Twiss 	config.regmap = chip->regmap;
156937433c2SGuennadi Liakhovetski 	config.of_node = dev->of_node;
15716f10918SSteve Twiss 
15811c0da7bSJingoo Han 	rdev = devm_regulator_register(&i2c->dev, &da9210_reg, &config);
15916f10918SSteve Twiss 	if (IS_ERR(rdev)) {
16016f10918SSteve Twiss 		dev_err(&i2c->dev, "Failed to register DA9210 regulator\n");
16116f10918SSteve Twiss 		return PTR_ERR(rdev);
16216f10918SSteve Twiss 	}
16316f10918SSteve Twiss 
16416f10918SSteve Twiss 	chip->rdev = rdev;
16516f10918SSteve Twiss 
16616f10918SSteve Twiss 	i2c_set_clientdata(i2c, chip);
16716f10918SSteve Twiss 
16816f10918SSteve Twiss 	return 0;
16916f10918SSteve Twiss }
17016f10918SSteve Twiss 
17116f10918SSteve Twiss static const struct i2c_device_id da9210_i2c_id[] = {
17216f10918SSteve Twiss 	{"da9210", 0},
17316f10918SSteve Twiss 	{},
17416f10918SSteve Twiss };
17516f10918SSteve Twiss 
17616f10918SSteve Twiss MODULE_DEVICE_TABLE(i2c, da9210_i2c_id);
17716f10918SSteve Twiss 
17816f10918SSteve Twiss static struct i2c_driver da9210_regulator_driver = {
17916f10918SSteve Twiss 	.driver = {
18016f10918SSteve Twiss 		.name = "da9210",
18116f10918SSteve Twiss 		.owner = THIS_MODULE,
18216f10918SSteve Twiss 	},
18316f10918SSteve Twiss 	.probe = da9210_i2c_probe,
18416f10918SSteve Twiss 	.id_table = da9210_i2c_id,
18516f10918SSteve Twiss };
18616f10918SSteve Twiss 
18716f10918SSteve Twiss module_i2c_driver(da9210_regulator_driver);
18816f10918SSteve Twiss 
18916f10918SSteve Twiss MODULE_AUTHOR("S Twiss <stwiss.opensource@diasemi.com>");
19016f10918SSteve Twiss MODULE_DESCRIPTION("Regulator device driver for Dialog DA9210");
19116f10918SSteve Twiss MODULE_LICENSE("GPL v2");
192