xref: /linux/drivers/regulator/tps65132-regulator.c (revision 77c129bfefc85bae4dbaa655a5d9b75c9c665da9)
1*77c129bfSVenkat Reddy Talla /*
2*77c129bfSVenkat Reddy Talla  * TI TPS65132 Regulator driver
3*77c129bfSVenkat Reddy Talla  *
4*77c129bfSVenkat Reddy Talla  * Copyright (C) 2017 NVIDIA CORPORATION. All rights reserved.
5*77c129bfSVenkat Reddy Talla  *
6*77c129bfSVenkat Reddy Talla  * Author: Venkat Reddy Talla <vreddytalla@nvidia.com>
7*77c129bfSVenkat Reddy Talla  *		Laxman Dewangan <ldewangan@nvidia.com>
8*77c129bfSVenkat Reddy Talla  *
9*77c129bfSVenkat Reddy Talla  * This program is free software; you can redistribute it and/or
10*77c129bfSVenkat Reddy Talla  * modify it under the terms of the GNU General Public License as
11*77c129bfSVenkat Reddy Talla  * published by the Free Software Foundation; either version 2 of the
12*77c129bfSVenkat Reddy Talla  * License, or (at your option) any later version.
13*77c129bfSVenkat Reddy Talla  *
14*77c129bfSVenkat Reddy Talla  * This program is distributed "as is" WITHOUT ANY WARRANTY of any kind,
15*77c129bfSVenkat Reddy Talla  * whether express or implied; without even the implied warranty of
16*77c129bfSVenkat Reddy Talla  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17*77c129bfSVenkat Reddy Talla  * General Public License for more details.
18*77c129bfSVenkat Reddy Talla  */
19*77c129bfSVenkat Reddy Talla 
20*77c129bfSVenkat Reddy Talla #include <linux/delay.h>
21*77c129bfSVenkat Reddy Talla #include <linux/err.h>
22*77c129bfSVenkat Reddy Talla #include <linux/gpio/consumer.h>
23*77c129bfSVenkat Reddy Talla #include <linux/i2c.h>
24*77c129bfSVenkat Reddy Talla #include <linux/module.h>
25*77c129bfSVenkat Reddy Talla #include <linux/regmap.h>
26*77c129bfSVenkat Reddy Talla #include <linux/regulator/driver.h>
27*77c129bfSVenkat Reddy Talla #include <linux/regulator/machine.h>
28*77c129bfSVenkat Reddy Talla 
29*77c129bfSVenkat Reddy Talla #define TPS65132_REG_VPOS		0x00
30*77c129bfSVenkat Reddy Talla #define TPS65132_REG_VNEG		0x01
31*77c129bfSVenkat Reddy Talla #define TPS65132_REG_APPS_DISP_DISN	0x03
32*77c129bfSVenkat Reddy Talla #define TPS65132_REG_CONTROL		0x0FF
33*77c129bfSVenkat Reddy Talla 
34*77c129bfSVenkat Reddy Talla #define TPS65132_VOUT_MASK		0x1F
35*77c129bfSVenkat Reddy Talla #define TPS65132_VOUT_N_VOLTAGE		0x15
36*77c129bfSVenkat Reddy Talla #define TPS65132_VOUT_VMIN		4000000
37*77c129bfSVenkat Reddy Talla #define TPS65132_VOUT_VMAX		6000000
38*77c129bfSVenkat Reddy Talla #define TPS65132_VOUT_STEP		100000
39*77c129bfSVenkat Reddy Talla 
40*77c129bfSVenkat Reddy Talla #define TPS65132_REG_APPS_DIS_VPOS		BIT(0)
41*77c129bfSVenkat Reddy Talla #define TPS65132_REG_APPS_DIS_VNEG		BIT(1)
42*77c129bfSVenkat Reddy Talla 
43*77c129bfSVenkat Reddy Talla #define TPS65132_REGULATOR_ID_VPOS	0
44*77c129bfSVenkat Reddy Talla #define TPS65132_REGULATOR_ID_VNEG	1
45*77c129bfSVenkat Reddy Talla #define TPS65132_MAX_REGULATORS		2
46*77c129bfSVenkat Reddy Talla 
47*77c129bfSVenkat Reddy Talla #define TPS65132_ACT_DIS_TIME_SLACK		1000
48*77c129bfSVenkat Reddy Talla 
49*77c129bfSVenkat Reddy Talla struct tps65132_reg_pdata {
50*77c129bfSVenkat Reddy Talla 	struct gpio_desc *en_gpiod;
51*77c129bfSVenkat Reddy Talla 	struct gpio_desc *act_dis_gpiod;
52*77c129bfSVenkat Reddy Talla 	unsigned int act_dis_time_us;
53*77c129bfSVenkat Reddy Talla 	int ena_gpio_state;
54*77c129bfSVenkat Reddy Talla };
55*77c129bfSVenkat Reddy Talla 
56*77c129bfSVenkat Reddy Talla struct tps65132_regulator {
57*77c129bfSVenkat Reddy Talla 	struct device *dev;
58*77c129bfSVenkat Reddy Talla 	struct regmap *rmap;
59*77c129bfSVenkat Reddy Talla 	struct regulator_desc *rdesc[TPS65132_MAX_REGULATORS];
60*77c129bfSVenkat Reddy Talla 	struct tps65132_reg_pdata reg_pdata[TPS65132_MAX_REGULATORS];
61*77c129bfSVenkat Reddy Talla 	struct regulator_dev *rdev[TPS65132_MAX_REGULATORS];
62*77c129bfSVenkat Reddy Talla };
63*77c129bfSVenkat Reddy Talla 
64*77c129bfSVenkat Reddy Talla static int tps65132_regulator_enable(struct regulator_dev *rdev)
65*77c129bfSVenkat Reddy Talla {
66*77c129bfSVenkat Reddy Talla 	struct tps65132_regulator *tps = rdev_get_drvdata(rdev);
67*77c129bfSVenkat Reddy Talla 	int id = rdev_get_id(rdev);
68*77c129bfSVenkat Reddy Talla 	struct tps65132_reg_pdata *rpdata = &tps->reg_pdata[id];
69*77c129bfSVenkat Reddy Talla 	int ret;
70*77c129bfSVenkat Reddy Talla 
71*77c129bfSVenkat Reddy Talla 	if (!IS_ERR(rpdata->en_gpiod)) {
72*77c129bfSVenkat Reddy Talla 		gpiod_set_value_cansleep(rpdata->en_gpiod, 1);
73*77c129bfSVenkat Reddy Talla 		rpdata->ena_gpio_state = 1;
74*77c129bfSVenkat Reddy Talla 	}
75*77c129bfSVenkat Reddy Talla 
76*77c129bfSVenkat Reddy Talla 	/* Hardware automatically enable discharge bit in enable */
77*77c129bfSVenkat Reddy Talla 	if (rdev->constraints->active_discharge ==
78*77c129bfSVenkat Reddy Talla 			REGULATOR_ACTIVE_DISCHARGE_DISABLE) {
79*77c129bfSVenkat Reddy Talla 		ret = regulator_set_active_discharge_regmap(rdev, false);
80*77c129bfSVenkat Reddy Talla 		if (ret < 0) {
81*77c129bfSVenkat Reddy Talla 			dev_err(tps->dev, "Failed to disable active discharge: %d\n",
82*77c129bfSVenkat Reddy Talla 				ret);
83*77c129bfSVenkat Reddy Talla 			return ret;
84*77c129bfSVenkat Reddy Talla 		}
85*77c129bfSVenkat Reddy Talla 	}
86*77c129bfSVenkat Reddy Talla 
87*77c129bfSVenkat Reddy Talla 	return 0;
88*77c129bfSVenkat Reddy Talla }
89*77c129bfSVenkat Reddy Talla 
90*77c129bfSVenkat Reddy Talla static int tps65132_regulator_disable(struct regulator_dev *rdev)
91*77c129bfSVenkat Reddy Talla {
92*77c129bfSVenkat Reddy Talla 	struct tps65132_regulator *tps = rdev_get_drvdata(rdev);
93*77c129bfSVenkat Reddy Talla 	int id = rdev_get_id(rdev);
94*77c129bfSVenkat Reddy Talla 	struct tps65132_reg_pdata *rpdata = &tps->reg_pdata[id];
95*77c129bfSVenkat Reddy Talla 
96*77c129bfSVenkat Reddy Talla 	if (!IS_ERR(rpdata->en_gpiod)) {
97*77c129bfSVenkat Reddy Talla 		gpiod_set_value_cansleep(rpdata->en_gpiod, 0);
98*77c129bfSVenkat Reddy Talla 		rpdata->ena_gpio_state = 0;
99*77c129bfSVenkat Reddy Talla 	}
100*77c129bfSVenkat Reddy Talla 
101*77c129bfSVenkat Reddy Talla 	if (!IS_ERR(rpdata->act_dis_gpiod)) {
102*77c129bfSVenkat Reddy Talla 		gpiod_set_value_cansleep(rpdata->act_dis_gpiod, 1);
103*77c129bfSVenkat Reddy Talla 		usleep_range(rpdata->act_dis_time_us, rpdata->act_dis_time_us +
104*77c129bfSVenkat Reddy Talla 			     TPS65132_ACT_DIS_TIME_SLACK);
105*77c129bfSVenkat Reddy Talla 		gpiod_set_value_cansleep(rpdata->act_dis_gpiod, 0);
106*77c129bfSVenkat Reddy Talla 	}
107*77c129bfSVenkat Reddy Talla 
108*77c129bfSVenkat Reddy Talla 	return 0;
109*77c129bfSVenkat Reddy Talla }
110*77c129bfSVenkat Reddy Talla 
111*77c129bfSVenkat Reddy Talla static int tps65132_regulator_is_enabled(struct regulator_dev *rdev)
112*77c129bfSVenkat Reddy Talla {
113*77c129bfSVenkat Reddy Talla 	struct tps65132_regulator *tps = rdev_get_drvdata(rdev);
114*77c129bfSVenkat Reddy Talla 	int id = rdev_get_id(rdev);
115*77c129bfSVenkat Reddy Talla 	struct tps65132_reg_pdata *rpdata = &tps->reg_pdata[id];
116*77c129bfSVenkat Reddy Talla 
117*77c129bfSVenkat Reddy Talla 	if (!IS_ERR(rpdata->en_gpiod))
118*77c129bfSVenkat Reddy Talla 		return rpdata->ena_gpio_state;
119*77c129bfSVenkat Reddy Talla 
120*77c129bfSVenkat Reddy Talla 	return 1;
121*77c129bfSVenkat Reddy Talla }
122*77c129bfSVenkat Reddy Talla 
123*77c129bfSVenkat Reddy Talla static struct regulator_ops tps65132_regulator_ops = {
124*77c129bfSVenkat Reddy Talla 	.enable = tps65132_regulator_enable,
125*77c129bfSVenkat Reddy Talla 	.disable = tps65132_regulator_disable,
126*77c129bfSVenkat Reddy Talla 	.is_enabled = tps65132_regulator_is_enabled,
127*77c129bfSVenkat Reddy Talla 	.list_voltage = regulator_list_voltage_linear,
128*77c129bfSVenkat Reddy Talla 	.map_voltage = regulator_map_voltage_linear,
129*77c129bfSVenkat Reddy Talla 	.get_voltage_sel = regulator_get_voltage_sel_regmap,
130*77c129bfSVenkat Reddy Talla 	.set_voltage_sel = regulator_set_voltage_sel_regmap,
131*77c129bfSVenkat Reddy Talla 	.set_active_discharge = regulator_set_active_discharge_regmap,
132*77c129bfSVenkat Reddy Talla };
133*77c129bfSVenkat Reddy Talla 
134*77c129bfSVenkat Reddy Talla static int tps65132_of_parse_cb(struct device_node *np,
135*77c129bfSVenkat Reddy Talla 				const struct regulator_desc *desc,
136*77c129bfSVenkat Reddy Talla 				struct regulator_config *config)
137*77c129bfSVenkat Reddy Talla {
138*77c129bfSVenkat Reddy Talla 	struct tps65132_regulator *tps = config->driver_data;
139*77c129bfSVenkat Reddy Talla 	struct tps65132_reg_pdata *rpdata = &tps->reg_pdata[desc->id];
140*77c129bfSVenkat Reddy Talla 	int ret;
141*77c129bfSVenkat Reddy Talla 
142*77c129bfSVenkat Reddy Talla 	rpdata->en_gpiod = devm_fwnode_get_index_gpiod_from_child(tps->dev,
143*77c129bfSVenkat Reddy Talla 					"enable", 0, &np->fwnode, 0, "enable");
144*77c129bfSVenkat Reddy Talla 	if (IS_ERR(rpdata->en_gpiod)) {
145*77c129bfSVenkat Reddy Talla 		ret = PTR_ERR(rpdata->en_gpiod);
146*77c129bfSVenkat Reddy Talla 
147*77c129bfSVenkat Reddy Talla 		/* Ignore the error other than probe defer */
148*77c129bfSVenkat Reddy Talla 		if (ret == -EPROBE_DEFER)
149*77c129bfSVenkat Reddy Talla 			return ret;
150*77c129bfSVenkat Reddy Talla 		return 0;
151*77c129bfSVenkat Reddy Talla 	}
152*77c129bfSVenkat Reddy Talla 
153*77c129bfSVenkat Reddy Talla 	rpdata->act_dis_gpiod = devm_fwnode_get_index_gpiod_from_child(
154*77c129bfSVenkat Reddy Talla 					tps->dev, "active-discharge", 0,
155*77c129bfSVenkat Reddy Talla 					&np->fwnode, 0, "active-discharge");
156*77c129bfSVenkat Reddy Talla 	if (IS_ERR(rpdata->act_dis_gpiod)) {
157*77c129bfSVenkat Reddy Talla 		ret = PTR_ERR(rpdata->act_dis_gpiod);
158*77c129bfSVenkat Reddy Talla 
159*77c129bfSVenkat Reddy Talla 		/* Ignore the error other than probe defer */
160*77c129bfSVenkat Reddy Talla 		if (ret == -EPROBE_DEFER)
161*77c129bfSVenkat Reddy Talla 			return ret;
162*77c129bfSVenkat Reddy Talla 
163*77c129bfSVenkat Reddy Talla 		return 0;
164*77c129bfSVenkat Reddy Talla 	}
165*77c129bfSVenkat Reddy Talla 
166*77c129bfSVenkat Reddy Talla 	ret = of_property_read_u32(np, "ti,active-discharge-time-us",
167*77c129bfSVenkat Reddy Talla 				   &rpdata->act_dis_time_us);
168*77c129bfSVenkat Reddy Talla 	if (ret < 0) {
169*77c129bfSVenkat Reddy Talla 		dev_err(tps->dev, "Failed to read active discharge time:%d\n",
170*77c129bfSVenkat Reddy Talla 			ret);
171*77c129bfSVenkat Reddy Talla 		return ret;
172*77c129bfSVenkat Reddy Talla 	}
173*77c129bfSVenkat Reddy Talla 
174*77c129bfSVenkat Reddy Talla 	return 0;
175*77c129bfSVenkat Reddy Talla }
176*77c129bfSVenkat Reddy Talla 
177*77c129bfSVenkat Reddy Talla #define TPS65132_REGULATOR_DESC(_id, _name)		\
178*77c129bfSVenkat Reddy Talla 	[TPS65132_REGULATOR_ID_##_id] = {		\
179*77c129bfSVenkat Reddy Talla 		.name = "tps65132-"#_name,		\
180*77c129bfSVenkat Reddy Talla 		.supply_name = "vin",			\
181*77c129bfSVenkat Reddy Talla 		.id = TPS65132_REGULATOR_ID_##_id,	\
182*77c129bfSVenkat Reddy Talla 		.of_match = of_match_ptr(#_name),	\
183*77c129bfSVenkat Reddy Talla 		.of_parse_cb	= tps65132_of_parse_cb,	\
184*77c129bfSVenkat Reddy Talla 		.ops = &tps65132_regulator_ops,		\
185*77c129bfSVenkat Reddy Talla 		.n_voltages = TPS65132_VOUT_N_VOLTAGE,	\
186*77c129bfSVenkat Reddy Talla 		.min_uV = TPS65132_VOUT_VMIN,		\
187*77c129bfSVenkat Reddy Talla 		.uV_step = TPS65132_VOUT_STEP,		\
188*77c129bfSVenkat Reddy Talla 		.enable_time = 500,			\
189*77c129bfSVenkat Reddy Talla 		.vsel_mask = TPS65132_VOUT_MASK,	\
190*77c129bfSVenkat Reddy Talla 		.vsel_reg = TPS65132_REG_##_id,		\
191*77c129bfSVenkat Reddy Talla 		.active_discharge_off = 0,			\
192*77c129bfSVenkat Reddy Talla 		.active_discharge_on = TPS65132_REG_APPS_DIS_##_id, \
193*77c129bfSVenkat Reddy Talla 		.active_discharge_mask = TPS65132_REG_APPS_DIS_##_id, \
194*77c129bfSVenkat Reddy Talla 		.active_discharge_reg = TPS65132_REG_APPS_DISP_DISN, \
195*77c129bfSVenkat Reddy Talla 		.type = REGULATOR_VOLTAGE,		\
196*77c129bfSVenkat Reddy Talla 		.owner = THIS_MODULE,			\
197*77c129bfSVenkat Reddy Talla 	}
198*77c129bfSVenkat Reddy Talla 
199*77c129bfSVenkat Reddy Talla static struct regulator_desc tps_regs_desc[TPS65132_MAX_REGULATORS] = {
200*77c129bfSVenkat Reddy Talla 	TPS65132_REGULATOR_DESC(VPOS, outp),
201*77c129bfSVenkat Reddy Talla 	TPS65132_REGULATOR_DESC(VNEG, outn),
202*77c129bfSVenkat Reddy Talla };
203*77c129bfSVenkat Reddy Talla 
204*77c129bfSVenkat Reddy Talla static const struct regmap_range tps65132_no_reg_ranges[] = {
205*77c129bfSVenkat Reddy Talla 	regmap_reg_range(TPS65132_REG_APPS_DISP_DISN + 1,
206*77c129bfSVenkat Reddy Talla 			 TPS65132_REG_CONTROL - 1),
207*77c129bfSVenkat Reddy Talla };
208*77c129bfSVenkat Reddy Talla 
209*77c129bfSVenkat Reddy Talla static const struct regmap_access_table tps65132_no_reg_table = {
210*77c129bfSVenkat Reddy Talla 	.no_ranges = tps65132_no_reg_ranges,
211*77c129bfSVenkat Reddy Talla 	.n_no_ranges = ARRAY_SIZE(tps65132_no_reg_ranges),
212*77c129bfSVenkat Reddy Talla };
213*77c129bfSVenkat Reddy Talla 
214*77c129bfSVenkat Reddy Talla static const struct regmap_config tps65132_regmap_config = {
215*77c129bfSVenkat Reddy Talla 	.reg_bits	= 8,
216*77c129bfSVenkat Reddy Talla 	.val_bits	= 8,
217*77c129bfSVenkat Reddy Talla 	.max_register	= TPS65132_REG_CONTROL + 1,
218*77c129bfSVenkat Reddy Talla 	.cache_type	= REGCACHE_NONE,
219*77c129bfSVenkat Reddy Talla 	.rd_table	= &tps65132_no_reg_table,
220*77c129bfSVenkat Reddy Talla 	.wr_table	= &tps65132_no_reg_table,
221*77c129bfSVenkat Reddy Talla };
222*77c129bfSVenkat Reddy Talla 
223*77c129bfSVenkat Reddy Talla static int tps65132_probe(struct i2c_client *client,
224*77c129bfSVenkat Reddy Talla 			  const struct i2c_device_id *client_id)
225*77c129bfSVenkat Reddy Talla {
226*77c129bfSVenkat Reddy Talla 	struct device *dev = &client->dev;
227*77c129bfSVenkat Reddy Talla 	struct tps65132_regulator *tps;
228*77c129bfSVenkat Reddy Talla 	struct regulator_config config = { };
229*77c129bfSVenkat Reddy Talla 	int id;
230*77c129bfSVenkat Reddy Talla 	int ret;
231*77c129bfSVenkat Reddy Talla 
232*77c129bfSVenkat Reddy Talla 	tps = devm_kzalloc(dev, sizeof(*tps), GFP_KERNEL);
233*77c129bfSVenkat Reddy Talla 	if (!tps)
234*77c129bfSVenkat Reddy Talla 		return -ENOMEM;
235*77c129bfSVenkat Reddy Talla 
236*77c129bfSVenkat Reddy Talla 	tps->rmap = devm_regmap_init_i2c(client, &tps65132_regmap_config);
237*77c129bfSVenkat Reddy Talla 	if (IS_ERR(tps->rmap)) {
238*77c129bfSVenkat Reddy Talla 		ret = PTR_ERR(tps->rmap);
239*77c129bfSVenkat Reddy Talla 		dev_err(dev, "regmap init failed: %d\n", ret);
240*77c129bfSVenkat Reddy Talla 		return ret;
241*77c129bfSVenkat Reddy Talla 	}
242*77c129bfSVenkat Reddy Talla 
243*77c129bfSVenkat Reddy Talla 	i2c_set_clientdata(client, tps);
244*77c129bfSVenkat Reddy Talla 	tps->dev = dev;
245*77c129bfSVenkat Reddy Talla 
246*77c129bfSVenkat Reddy Talla 	for (id = 0; id < TPS65132_MAX_REGULATORS; ++id) {
247*77c129bfSVenkat Reddy Talla 		tps->rdesc[id] = &tps_regs_desc[id];
248*77c129bfSVenkat Reddy Talla 
249*77c129bfSVenkat Reddy Talla 		config.regmap = tps->rmap;
250*77c129bfSVenkat Reddy Talla 		config.dev = dev;
251*77c129bfSVenkat Reddy Talla 		config.driver_data = tps;
252*77c129bfSVenkat Reddy Talla 
253*77c129bfSVenkat Reddy Talla 		tps->rdev[id] = devm_regulator_register(dev,
254*77c129bfSVenkat Reddy Talla 					tps->rdesc[id], &config);
255*77c129bfSVenkat Reddy Talla 		if (IS_ERR(tps->rdev[id])) {
256*77c129bfSVenkat Reddy Talla 			ret = PTR_ERR(tps->rdev[id]);
257*77c129bfSVenkat Reddy Talla 			dev_err(dev, "regulator %s register failed: %d\n",
258*77c129bfSVenkat Reddy Talla 				tps->rdesc[id]->name, ret);
259*77c129bfSVenkat Reddy Talla 			return ret;
260*77c129bfSVenkat Reddy Talla 		}
261*77c129bfSVenkat Reddy Talla 	}
262*77c129bfSVenkat Reddy Talla 	return 0;
263*77c129bfSVenkat Reddy Talla }
264*77c129bfSVenkat Reddy Talla 
265*77c129bfSVenkat Reddy Talla static const struct i2c_device_id tps65132_id[] = {
266*77c129bfSVenkat Reddy Talla 	{.name = "tps65132",},
267*77c129bfSVenkat Reddy Talla 	{},
268*77c129bfSVenkat Reddy Talla };
269*77c129bfSVenkat Reddy Talla MODULE_DEVICE_TABLE(i2c, tps65132_id);
270*77c129bfSVenkat Reddy Talla 
271*77c129bfSVenkat Reddy Talla static struct i2c_driver tps65132_i2c_driver = {
272*77c129bfSVenkat Reddy Talla 	.driver = {
273*77c129bfSVenkat Reddy Talla 		.name = "tps65132",
274*77c129bfSVenkat Reddy Talla 		.owner = THIS_MODULE,
275*77c129bfSVenkat Reddy Talla 	},
276*77c129bfSVenkat Reddy Talla 	.probe = tps65132_probe,
277*77c129bfSVenkat Reddy Talla 	.id_table = tps65132_id,
278*77c129bfSVenkat Reddy Talla };
279*77c129bfSVenkat Reddy Talla 
280*77c129bfSVenkat Reddy Talla module_i2c_driver(tps65132_i2c_driver);
281*77c129bfSVenkat Reddy Talla 
282*77c129bfSVenkat Reddy Talla MODULE_DESCRIPTION("tps65132 regulator driver");
283*77c129bfSVenkat Reddy Talla MODULE_AUTHOR("Venkat Reddy Talla <vreddytalla@nvidia.com>");
284*77c129bfSVenkat Reddy Talla MODULE_AUTHOR("Laxman Dewangan <ldewangan@nvidia.com>");
285*77c129bfSVenkat Reddy Talla MODULE_LICENSE("GPL v2");
286