1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * NXP PCA9450 regulator driver
4  * Copyright (C) 2022 Marek Vasut <marex@denx.de>
5  *
6  * Largely based on:
7  * ROHM BD71837 regulator driver
8  */
9 
10 #include <common.h>
11 #include <dm.h>
12 #include <log.h>
13 #include <linux/bitops.h>
14 #include <power/pca9450.h>
15 #include <power/pmic.h>
16 #include <power/regulator.h>
17 
18 #define HW_STATE_CONTROL 0
19 #define DEBUG
20 
21 /**
22  * struct pca9450_vrange - describe linear range of voltages
23  *
24  * @min_volt:	smallest voltage in range
25  * @step:	how much voltage changes at each selector step
26  * @min_sel:	smallest selector in the range
27  * @max_sel:	maximum selector in the range
28  */
29 struct pca9450_vrange {
30 	unsigned int	min_volt;
31 	unsigned int	step;
32 	u8		min_sel;
33 	u8		max_sel;
34 };
35 
36 /**
37  * struct pca9450_plat - describe regulator control registers
38  *
39  * @name:	name of the regulator. Used for matching the dt-entry
40  * @enable_reg:	register address used to enable/disable regulator
41  * @enablemask:	register mask used to enable/disable regulator
42  * @volt_reg:	register address used to configure regulator voltage
43  * @volt_mask:	register mask used to configure regulator voltage
44  * @ranges:	pointer to ranges of regulator voltages and matching register
45  *		values
46  * @numranges:	number of voltage ranges pointed by ranges
47  */
48 struct pca9450_plat {
49 	const char		*name;
50 	u8			enable_reg;
51 	u8			enablemask;
52 	u8			volt_reg;
53 	u8			volt_mask;
54 	struct pca9450_vrange	*ranges;
55 	unsigned int		numranges;
56 };
57 
58 #define PCA_RANGE(_min, _vstep, _sel_low, _sel_hi) \
59 { \
60 	.min_volt = (_min), .step = (_vstep), \
61 	.min_sel = (_sel_low), .max_sel = (_sel_hi), \
62 }
63 
64 #define PCA_DATA(_name, enreg, enmask, vreg, vmask, _range) \
65 { \
66 	.name = (_name), .enable_reg = (enreg), .enablemask = (enmask), \
67 	.volt_reg = (vreg), .volt_mask = (vmask), .ranges = (_range), \
68 	.numranges = ARRAY_SIZE(_range) \
69 }
70 
71 static struct pca9450_vrange pca9450_buck123_vranges[] = {
72 	PCA_RANGE(600000, 12500, 0, 0x7f),
73 };
74 
75 static struct pca9450_vrange pca9450_buck456_vranges[] = {
76 	PCA_RANGE(600000, 25000, 0, 0x70),
77 	PCA_RANGE(3400000, 0, 0x71, 0x7f),
78 };
79 
80 static struct pca9450_vrange pca9450_ldo1_vranges[] = {
81 	PCA_RANGE(1600000, 100000, 0x0, 0x3),
82 	PCA_RANGE(3000000, 100000, 0x4, 0x7),
83 };
84 
85 static struct pca9450_vrange pca9450_ldo2_vranges[] = {
86 	PCA_RANGE(800000, 50000, 0x0, 0x7),
87 };
88 
89 static struct pca9450_vrange pca9450_ldo34_vranges[] = {
90 	PCA_RANGE(800000, 100000, 0x0, 0x19),
91 	PCA_RANGE(3300000, 0, 0x1a, 0x1f),
92 };
93 
94 static struct pca9450_vrange pca9450_ldo5_vranges[] = {
95 	PCA_RANGE(1800000, 100000, 0x0, 0xf),
96 };
97 
98 /*
99  * We use enable mask 'HW_STATE_CONTROL' to indicate that this regulator
100  * must not be enabled or disabled by SW. The typical use-case for PCA9450
101  * is powering NXP i.MX8. In this use-case we (for now) only allow control
102  * for BUCK4, BUCK5, BUCK6 which are not boot critical.
103  */
104 static struct pca9450_plat pca9450_reg_data[] = {
105 	/* Bucks 1-3 which support dynamic voltage scaling */
106 	PCA_DATA("BUCK1", PCA9450_BUCK1CTRL, HW_STATE_CONTROL,
107 		 PCA9450_BUCK1OUT_DVS0, PCA9450_DVS_BUCK_RUN_MASK,
108 		 pca9450_buck123_vranges),
109 	PCA_DATA("BUCK2", PCA9450_BUCK2CTRL, HW_STATE_CONTROL,
110 		 PCA9450_BUCK2OUT_DVS0, PCA9450_DVS_BUCK_RUN_MASK,
111 		 pca9450_buck123_vranges),
112 	PCA_DATA("BUCK3", PCA9450_BUCK3CTRL, HW_STATE_CONTROL,
113 		 PCA9450_BUCK3OUT_DVS0, PCA9450_DVS_BUCK_RUN_MASK,
114 		 pca9450_buck123_vranges),
115 	/* Bucks 4-6 which do not support dynamic voltage scaling */
116 	PCA_DATA("BUCK4", PCA9450_BUCK4CTRL, HW_STATE_CONTROL,
117 		 PCA9450_BUCK4OUT, PCA9450_DVS_BUCK_RUN_MASK,
118 		 pca9450_buck456_vranges),
119 	PCA_DATA("BUCK5", PCA9450_BUCK5CTRL, HW_STATE_CONTROL,
120 		 PCA9450_BUCK5OUT, PCA9450_DVS_BUCK_RUN_MASK,
121 		 pca9450_buck456_vranges),
122 	PCA_DATA("BUCK6", PCA9450_BUCK6CTRL, HW_STATE_CONTROL,
123 		 PCA9450_BUCK6OUT, PCA9450_DVS_BUCK_RUN_MASK,
124 		 pca9450_buck456_vranges),
125 	/* LDOs */
126 	PCA_DATA("LDO1", PCA9450_LDO1CTRL, HW_STATE_CONTROL,
127 		 PCA9450_LDO1CTRL, PCA9450_LDO12_MASK,
128 		 pca9450_ldo1_vranges),
129 	PCA_DATA("LDO2", PCA9450_LDO2CTRL, HW_STATE_CONTROL,
130 		 PCA9450_LDO2CTRL, PCA9450_LDO12_MASK,
131 		 pca9450_ldo2_vranges),
132 	PCA_DATA("LDO3", PCA9450_LDO3CTRL, HW_STATE_CONTROL,
133 		 PCA9450_LDO3CTRL, PCA9450_LDO34_MASK,
134 		 pca9450_ldo34_vranges),
135 	PCA_DATA("LDO4", PCA9450_LDO4CTRL, HW_STATE_CONTROL,
136 		 PCA9450_LDO4CTRL, PCA9450_LDO34_MASK,
137 		 pca9450_ldo34_vranges),
138 	PCA_DATA("LDO5", PCA9450_LDO5CTRL_H, HW_STATE_CONTROL,
139 		 PCA9450_LDO5CTRL_H, PCA9450_LDO5_MASK,
140 		 pca9450_ldo5_vranges),
141 };
142 
vrange_find_value(struct pca9450_vrange * r,unsigned int sel,unsigned int * val)143 static int vrange_find_value(struct pca9450_vrange *r, unsigned int sel,
144 			     unsigned int *val)
145 {
146 	if (!val || sel < r->min_sel || sel > r->max_sel)
147 		return -EINVAL;
148 
149 	*val = r->min_volt + r->step * (sel - r->min_sel);
150 	return 0;
151 }
152 
vrange_find_selector(struct pca9450_vrange * r,int val,unsigned int * sel)153 static int vrange_find_selector(struct pca9450_vrange *r, int val,
154 				unsigned int *sel)
155 {
156 	int ret = -EINVAL;
157 	int num_vals = r->max_sel - r->min_sel + 1;
158 
159 	if (val >= r->min_volt &&
160 	    val <= r->min_volt + r->step * (num_vals - 1)) {
161 		if (r->step) {
162 			*sel = r->min_sel + ((val - r->min_volt) / r->step);
163 			ret = 0;
164 		} else {
165 			*sel = r->min_sel;
166 			ret = 0;
167 		}
168 	}
169 	return ret;
170 }
171 
pca9450_get_enable(struct udevice * dev)172 static int pca9450_get_enable(struct udevice *dev)
173 {
174 	struct pca9450_plat *plat = dev_get_plat(dev);
175 	int val;
176 
177 	/*
178 	 * boot critical regulators on pca9450 must not be controlled by sw
179 	 * due to the 'feature' which leaves power rails down if pca9450 is
180 	 * reseted to snvs state. hence we can't get the state here.
181 	 *
182 	 * if we are alive it means we probably are on run state and
183 	 * if the regulator can't be controlled we can assume it is
184 	 * enabled.
185 	 */
186 	if (plat->enablemask == HW_STATE_CONTROL)
187 		return 1;
188 
189 	val = pmic_reg_read(dev->parent, plat->enable_reg);
190 	if (val < 0)
191 		return val;
192 
193 	return (val & plat->enablemask);
194 }
195 
pca9450_set_enable(struct udevice * dev,bool enable)196 static int pca9450_set_enable(struct udevice *dev, bool enable)
197 {
198 	int val = 0;
199 	struct pca9450_plat *plat = dev_get_plat(dev);
200 
201 	/*
202 	 * boot critical regulators on pca9450 must not be controlled by sw
203 	 * due to the 'feature' which leaves power rails down if pca9450 is
204 	 * reseted to snvs state. Hence we can't set the state here.
205 	 */
206 	if (plat->enablemask == HW_STATE_CONTROL)
207 		return enable ? 0 : -EINVAL;
208 
209 	if (enable)
210 		val = plat->enablemask;
211 
212 	return pmic_clrsetbits(dev->parent, plat->enable_reg, plat->enablemask,
213 			       val);
214 }
215 
pca9450_get_value(struct udevice * dev)216 static int pca9450_get_value(struct udevice *dev)
217 {
218 	struct pca9450_plat *plat = dev_get_plat(dev);
219 	unsigned int reg, tmp;
220 	int i, ret;
221 
222 	ret = pmic_reg_read(dev->parent, plat->volt_reg);
223 	if (ret < 0)
224 		return ret;
225 
226 	reg = ret;
227 	reg &= plat->volt_mask;
228 
229 	for (i = 0; i < plat->numranges; i++) {
230 		struct pca9450_vrange *r = &plat->ranges[i];
231 
232 		if (!vrange_find_value(r, reg, &tmp))
233 			return tmp;
234 	}
235 
236 	pr_err("Unknown voltage value read from pmic\n");
237 
238 	return -EINVAL;
239 }
240 
pca9450_set_value(struct udevice * dev,int uvolt)241 static int pca9450_set_value(struct udevice *dev, int uvolt)
242 {
243 	struct pca9450_plat *plat = dev_get_plat(dev);
244 	unsigned int sel;
245 	int i, found = 0;
246 
247 	for (i = 0; i < plat->numranges; i++) {
248 		struct pca9450_vrange *r = &plat->ranges[i];
249 
250 		found = !vrange_find_selector(r, uvolt, &sel);
251 		if (found) {
252 			unsigned int tmp;
253 
254 			/*
255 			 * We require exactly the requested value to be
256 			 * supported - this can be changed later if needed
257 			 */
258 			found = !vrange_find_value(r, sel, &tmp);
259 			if (found && tmp == uvolt)
260 				break;
261 			found = 0;
262 		}
263 	}
264 
265 	if (!found)
266 		return -EINVAL;
267 
268 	return pmic_clrsetbits(dev->parent, plat->volt_reg,
269 			       plat->volt_mask, sel);
270 }
271 
pca9450_regulator_probe(struct udevice * dev)272 static int pca9450_regulator_probe(struct udevice *dev)
273 {
274 	struct pca9450_plat *plat = dev_get_plat(dev);
275 	int i, type;
276 
277 	type = dev_get_driver_data(dev_get_parent(dev));
278 
279 	if (type != NXP_CHIP_TYPE_PCA9450A && type != NXP_CHIP_TYPE_PCA9450BC &&
280 	    type != NXP_CHIP_TYPE_PCA9451A) {
281 		debug("Unknown PMIC type\n");
282 		return -EINVAL;
283 	}
284 
285 	for (i = 0; i < ARRAY_SIZE(pca9450_reg_data); i++) {
286 		if (strcmp(dev->name, pca9450_reg_data[i].name))
287 			continue;
288 
289 		/* PCA9450B/PCA9450C uses BUCK1 and BUCK3 in dual-phase */
290 		if (type == NXP_CHIP_TYPE_PCA9450BC &&
291 		    !strcmp(pca9450_reg_data[i].name, "BUCK3")) {
292 			continue;
293 		}
294 
295 		/* PCA9451A uses BUCK3 in dual-phase and don't have LDO2 and LDO3 */
296 		if (type == NXP_CHIP_TYPE_PCA9451A &&
297 		    (!strcmp(pca9450_reg_data[i].name, "BUCK3") ||
298 		    !strcmp(pca9450_reg_data[i].name, "LDO2") ||
299 		    !strcmp(pca9450_reg_data[i].name, "LDO3"))) {
300 			continue;
301 		}
302 
303 		*plat = pca9450_reg_data[i];
304 
305 		return 0;
306 	}
307 
308 	pr_err("Unknown regulator '%s'\n", dev->name);
309 
310 	return -ENOENT;
311 }
312 
313 static const struct dm_regulator_ops pca9450_regulator_ops = {
314 	.get_value	= pca9450_get_value,
315 	.set_value	= pca9450_set_value,
316 	.get_enable	= pca9450_get_enable,
317 	.set_enable	= pca9450_set_enable,
318 };
319 
320 U_BOOT_DRIVER(pca9450_regulator) = {
321 	.name		= PCA9450_REGULATOR_DRIVER,
322 	.id		= UCLASS_REGULATOR,
323 	.ops		= &pca9450_regulator_ops,
324 	.probe		= pca9450_regulator_probe,
325 	.plat_auto	= sizeof(struct pca9450_plat),
326 };
327