tps65090-regulator.c 6.2 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 29
/*
 * Regulator driver for tps65090 power management chip.
 *
 * Copyright (c) 2012, NVIDIA CORPORATION.  All rights reserved.

 * This program is free software; you can redistribute it and/or modify it
 * under the terms and conditions of the GNU General Public License,
 * version 2, as published by the Free Software Foundation.

 * This program is distributed in the hope 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.

 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>
 */

#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/err.h>
#include <linux/platform_device.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/machine.h>
#include <linux/mfd/tps65090.h>

struct tps65090_regulator {
	struct device		*dev;
30 31
	struct regulator_desc	*desc;
	struct regulator_dev	*rdev;
32 33 34
};

static struct regulator_ops tps65090_ops = {
35 36 37
	.enable = regulator_enable_regmap,
	.disable = regulator_disable_regmap,
	.is_enabled = regulator_is_enabled_regmap,
38 39
};

40
#define tps65090_REG_DESC(_id, _sname, _en_reg, _ops)	\
41
{							\
42 43
	.name = "TPS65090_RAILS"#_id,			\
	.supply_name = _sname,				\
44
	.id = TPS65090_REGULATOR_##_id,			\
45 46 47 48 49
	.ops = &_ops,					\
	.enable_reg = _en_reg,				\
	.enable_mask = BIT(0),				\
	.type = REGULATOR_VOLTAGE,			\
	.owner = THIS_MODULE,				\
50 51
}

52 53 54 55 56 57 58 59 60 61 62
static struct regulator_desc tps65090_regulator_desc[] = {
	tps65090_REG_DESC(DCDC1, "vsys1",   0x0C, tps65090_ops),
	tps65090_REG_DESC(DCDC2, "vsys2",   0x0D, tps65090_ops),
	tps65090_REG_DESC(DCDC3, "vsys3",   0x0E, tps65090_ops),
	tps65090_REG_DESC(FET1,  "infet1",  0x0F, tps65090_ops),
	tps65090_REG_DESC(FET2,  "infet2",  0x10, tps65090_ops),
	tps65090_REG_DESC(FET3,  "infet3",  0x11, tps65090_ops),
	tps65090_REG_DESC(FET4,  "infet4",  0x12, tps65090_ops),
	tps65090_REG_DESC(FET5,  "infet5",  0x13, tps65090_ops),
	tps65090_REG_DESC(FET6,  "infet6",  0x14, tps65090_ops),
	tps65090_REG_DESC(FET7,  "infet7",  0x15, tps65090_ops),
63 64
};

65
static inline bool is_dcdc(int id)
66
{
67
	switch (id) {
68 69 70
	case TPS65090_REGULATOR_DCDC1:
	case TPS65090_REGULATOR_DCDC2:
	case TPS65090_REGULATOR_DCDC3:
71 72 73 74 75
		return true;
	default:
		return false;
	}
}
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 108 109 110 111
static int __devinit tps65090_config_ext_control(
	struct tps65090_regulator *ri, bool enable)
{
	int ret;
	struct device *parent = ri->dev->parent;
	unsigned int reg_en_reg = ri->desc->enable_reg;

	if (enable)
		ret = tps65090_set_bits(parent, reg_en_reg, 1);
	else
		ret =  tps65090_clr_bits(parent, reg_en_reg, 1);
	if (ret < 0)
		dev_err(ri->dev, "Error in updating reg 0x%x\n", reg_en_reg);
	return ret;
}

static int __devinit tps65090_regulator_disable_ext_control(
		struct tps65090_regulator *ri,
		struct tps65090_regulator_plat_data *tps_pdata)
{
	int ret = 0;
	struct device *parent = ri->dev->parent;
	unsigned int reg_en_reg = ri->desc->enable_reg;

	/*
	 * First enable output for internal control if require.
	 * And then disable external control.
	 */
	if (tps_pdata->reg_init_data->constraints.always_on ||
			tps_pdata->reg_init_data->constraints.boot_on) {
		ret =  tps65090_set_bits(parent, reg_en_reg, 0);
		if (ret < 0) {
			dev_err(ri->dev, "Error in set reg 0x%x\n", reg_en_reg);
			return ret;
		}
112
	}
113
	return tps65090_config_ext_control(ri, false);
114 115 116 117
}

static int __devinit tps65090_regulator_probe(struct platform_device *pdev)
{
118
	struct tps65090 *tps65090_mfd = dev_get_drvdata(pdev->dev.parent);
119
	struct tps65090_regulator *ri = NULL;
120
	struct regulator_config config = { };
121
	struct regulator_dev *rdev;
122 123 124 125 126
	struct tps65090_regulator_plat_data *tps_pdata;
	struct tps65090_regulator *pmic;
	struct tps65090_platform_data *tps65090_pdata;
	int num;
	int ret;
127

128
	dev_dbg(&pdev->dev, "Probing regulator\n");
129

130 131 132
	tps65090_pdata = dev_get_platdata(pdev->dev.parent);
	if (!tps65090_pdata) {
		dev_err(&pdev->dev, "Platform data missing\n");
133 134
		return -EINVAL;
	}
135

136
	pmic = devm_kzalloc(&pdev->dev, TPS65090_REGULATOR_MAX * sizeof(*pmic),
137 138 139 140 141 142
			GFP_KERNEL);
	if (!pmic) {
		dev_err(&pdev->dev, "mem alloc for pmic failed\n");
		return -ENOMEM;
	}

143
	for (num = 0; num < TPS65090_REGULATOR_MAX; num++) {
144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179
		tps_pdata = tps65090_pdata->reg_pdata[num];

		ri = &pmic[num];
		ri->dev = &pdev->dev;
		ri->desc = &tps65090_regulator_desc[num];

		/*
		 * TPS5090 DCDC support the control from external digital input.
		 * It may be possible that during boot, the external control is
		 * enabled. Disabling external control for DCDC.
		 */
		if (tps_pdata && is_dcdc(num) && tps_pdata->reg_init_data) {
			ret = tps65090_regulator_disable_ext_control(
						ri, tps_pdata);
			if (ret < 0) {
				dev_err(&pdev->dev,
						"failed disable ext control\n");
				goto scrub;
			}
		}
		config.dev = &pdev->dev;
		config.driver_data = ri;
		config.regmap = tps65090_mfd->rmap;
		if (tps_pdata)
			config.init_data = tps_pdata->reg_init_data;
		else
			config.init_data = NULL;

		rdev = regulator_register(ri->desc, &config);
		if (IS_ERR(rdev)) {
			dev_err(&pdev->dev, "failed to register regulator %s\n",
				ri->desc->name);
			ret = PTR_ERR(rdev);
			goto scrub;
		}
		ri->rdev = rdev;
180 181
	}

182
	platform_set_drvdata(pdev, pmic);
183
	return 0;
184 185 186 187 188 189 190

scrub:
	while (--num >= 0) {
		ri = &pmic[num];
		regulator_unregister(ri->rdev);
	}
	return ret;
191 192 193 194
}

static int __devexit tps65090_regulator_remove(struct platform_device *pdev)
{
195 196 197
	struct tps65090_regulator *pmic = platform_get_drvdata(pdev);
	struct tps65090_regulator *ri;
	int num;
198

199
	for (num = 0; num < TPS65090_REGULATOR_MAX; ++num) {
200 201 202
		ri = &pmic[num];
		regulator_unregister(ri->rdev);
	}
203 204 205 206 207
	return 0;
}

static struct platform_driver tps65090_regulator_driver = {
	.driver	= {
208
		.name	= "tps65090-pmic",
209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229
		.owner	= THIS_MODULE,
	},
	.probe		= tps65090_regulator_probe,
	.remove		= __devexit_p(tps65090_regulator_remove),
};

static int __init tps65090_regulator_init(void)
{
	return platform_driver_register(&tps65090_regulator_driver);
}
subsys_initcall(tps65090_regulator_init);

static void __exit tps65090_regulator_exit(void)
{
	platform_driver_unregister(&tps65090_regulator_driver);
}
module_exit(tps65090_regulator_exit);

MODULE_DESCRIPTION("tps65090 regulator driver");
MODULE_AUTHOR("Venu Byravarasu <vbyravarasu@nvidia.com>");
MODULE_LICENSE("GPL v2");