1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  *  Copyright(C) 2025 Svyatoslav Ryhel <clamor95@gmail.com>
4  */
5 
6 #include <dm.h>
7 #include <power/pmic.h>
8 #include <power/regulator.h>
9 #include <power/cpcap.h>
10 #include <linux/delay.h>
11 #include <linux/err.h>
12 
13 /* CPCAP_REG_ASSIGN2 bits - Resource Assignment 2 */
14 #define CPCAP_BIT_VSDIO_SEL		BIT(15)
15 #define CPCAP_BIT_VDIG_SEL		BIT(14)
16 #define CPCAP_BIT_VCAM_SEL		BIT(13)
17 #define CPCAP_BIT_SW6_SEL		BIT(12)
18 #define CPCAP_BIT_SW5_SEL		BIT(11)
19 #define CPCAP_BIT_SW4_SEL		BIT(10)
20 #define CPCAP_BIT_SW3_SEL		BIT(9)
21 #define CPCAP_BIT_SW2_SEL		BIT(8)
22 #define CPCAP_BIT_SW1_SEL		BIT(7)
23 
24 /* CPCAP_REG_ASSIGN3 bits - Resource Assignment 3 */
25 #define CPCAP_BIT_VUSBINT2_SEL		BIT(15)
26 #define CPCAP_BIT_VUSBINT1_SEL		BIT(14)
27 #define CPCAP_BIT_VVIB_SEL		BIT(13)
28 #define CPCAP_BIT_VWLAN1_SEL		BIT(12)
29 #define CPCAP_BIT_VRF1_SEL		BIT(11)
30 #define CPCAP_BIT_VHVIO_SEL		BIT(10)
31 #define CPCAP_BIT_VDAC_SEL		BIT(9)
32 #define CPCAP_BIT_VUSB_SEL		BIT(8)
33 #define CPCAP_BIT_VSIM_SEL		BIT(7)
34 #define CPCAP_BIT_VRFREF_SEL		BIT(6)
35 #define CPCAP_BIT_VPLL_SEL		BIT(5)
36 #define CPCAP_BIT_VFUSE_SEL		BIT(4)
37 #define CPCAP_BIT_VCSI_SEL		BIT(3)
38 #define CPCAP_BIT_SPARE_14_2		BIT(2)
39 #define CPCAP_BIT_VWLAN2_SEL		BIT(1)
40 #define CPCAP_BIT_VRF2_SEL		BIT(0)
41 #define CPCAP_BIT_NONE			0
42 
43 /* CPCAP_REG_ASSIGN4 bits - Resource Assignment 4 */
44 #define CPCAP_BIT_VAUDIO_SEL		BIT(0)
45 
46 /*
47  * Off mode configuration bit. Used currently only by SW5 on omap4. There's
48  * the following comment in Motorola Linux kernel tree for it:
49  *
50  * When set in the regulator mode, the regulator assignment will be changed
51  * to secondary when the regulator is disabled. The mode will be set back to
52  * primary when the regulator is turned on.
53  */
54 #define CPCAP_REG_OFF_MODE_SEC		BIT(15)
55 
56 #define CPCAP_REG(_reg, _assignment_reg, _assignment_mask, _mode_mask,		\
57 		  _volt_mask, _volt_shft, _mode_val, _off_mode_val, _val_tbl,	\
58 		  _mode_cntr, _volt_trans_time, _turn_on_time, _bit_offset) {	\
59 	.reg = CPCAP_REG_##_reg,						\
60 	.assignment_reg = CPCAP_REG_##_assignment_reg,				\
61 	.assignment_mask = CPCAP_BIT_##_assignment_mask,			\
62 	.mode_mask = _mode_mask,						\
63 	.volt_mask = _volt_mask,						\
64 	.volt_shft = _volt_shft,						\
65 	.mode_val = _mode_val,							\
66 	.off_mode_val = _off_mode_val,						\
67 	.val_tbl_sz = ARRAY_SIZE(_val_tbl),					\
68 	.val_tbl = _val_tbl,							\
69 	.mode_cntr = _mode_cntr,						\
70 	.volt_trans_time = _volt_trans_time,					\
71 	.turn_on_time = _turn_on_time,						\
72 	.bit_offset_from_cpcap_lowest_voltage = _bit_offset,			\
73 }
74 
75 static const struct cpcap_regulator_data tegra20_regulators[CPCAP_REGULATORS_COUNT] = {
76 	/* BUCK */
77 	[CPCAP_SW1]      = CPCAP_REG(S1C1, ASSIGN2, SW1_SEL, 0x6f00, 0x007f,
78 				     0, 0x6800, 0, sw1_val_tbl, 0, 0, 1500, 0x0c),
79 	[CPCAP_SW2]      = CPCAP_REG(S2C1, ASSIGN2, SW2_SEL, 0x6f00, 0x007f,
80 				     0, 0x4804, 0, sw2_sw4_val_tbl, 0, 0, 1500, 0x18),
81 	[CPCAP_SW3]      = CPCAP_REG(S3C, ASSIGN2, SW3_SEL, 0x0578, 0x0003,
82 				     0, 0x043c, 0, sw3_val_tbl, 0, 0, 0, 0),
83 	[CPCAP_SW4]      = CPCAP_REG(S4C1, ASSIGN2, SW4_SEL, 0x6f00, 0x007f,
84 				     0, 0x4909, 0, sw2_sw4_val_tbl, 0, 0, 1500, 0x18),
85 	[CPCAP_SW5]      = CPCAP_REG(S5C, ASSIGN2, SW5_SEL, 0x0028, 0x0000,
86 				     0, 0x0020, 0, sw5_val_tbl, 0, 0, 1500, 0),
87 	[CPCAP_SW6]      = CPCAP_REG(S6C, ASSIGN2, SW6_SEL, 0x0000, 0x0000,
88 				     0, 0, 0, unknown_val_tbl, 0, 0, 0, 0),
89 	/* LDO */
90 	[CPCAP_VCAM]     = CPCAP_REG(VCAMC, ASSIGN2, VCAM_SEL, 0x0087, 0x0030,
91 				     4, 0x7, 0, vcam_val_tbl, 0, 420, 1000, 0),
92 	[CPCAP_VCSI]     = CPCAP_REG(VCSIC, ASSIGN3, VCSI_SEL, 0x0047, 0x0010,
93 				     4, 0x7, 0, vcsi_val_tbl, 0, 350, 1000, 0),
94 	[CPCAP_VDAC]     = CPCAP_REG(VDACC, ASSIGN3, VDAC_SEL, 0x0087, 0x0030,
95 				     4, 0x0, 0, vdac_val_tbl, 0, 420, 1000, 0),
96 	[CPCAP_VDIG]     = CPCAP_REG(VDIGC, ASSIGN2, VDIG_SEL, 0x0087, 0x0030,
97 				     4, 0x0, 0, vdig_val_tbl, 0, 420, 1000, 0),
98 	[CPCAP_VFUSE]    = CPCAP_REG(VFUSEC, ASSIGN3, VFUSE_SEL, 0x00a0, 0x000f,
99 				     0, 0x0, 0, vfuse_val_tbl, 0, 420, 1000, 0),
100 	[CPCAP_VHVIO]    = CPCAP_REG(VHVIOC, ASSIGN3, VHVIO_SEL, 0x0017, 0x0000,
101 				     0, 0x2, 0, vhvio_val_tbl, 0, 0, 1000, 0),
102 	[CPCAP_VSDIO]    = CPCAP_REG(VSDIOC, ASSIGN2, VSDIO_SEL, 0x0087, 0x0038,
103 				     3, 0x2, 0, vsdio_val_tbl, 0, 420, 1000, 0),
104 	[CPCAP_VPLL]     = CPCAP_REG(VPLLC, ASSIGN3, VPLL_SEL, 0x0047, 0x0018,
105 				     3, 0x1, 0, vpll_val_tbl, 0, 420, 100, 0),
106 	[CPCAP_VRF1]     = CPCAP_REG(VRF1C, ASSIGN3, VRF1_SEL, 0x00ac, 0x0002,
107 				     1, 0x0, 0, vrf1_val_tbl, 0, 10, 1000, 0),
108 	[CPCAP_VRF2]     = CPCAP_REG(VRF2C, ASSIGN3, VRF2_SEL, 0x0023, 0x0008,
109 				     3, 0x0, 0, vrf2_val_tbl, 0, 10, 1000, 0),
110 	[CPCAP_VRFREF]   = CPCAP_REG(VRFREFC, ASSIGN3, VRFREF_SEL, 0x0023, 0x0008,
111 				     3, 0x0, 0, vrfref_val_tbl, 0, 420, 100, 0),
112 	[CPCAP_VWLAN1]   = CPCAP_REG(VWLAN1C, ASSIGN3, VWLAN1_SEL, 0x0047, 0x0010,
113 				     4, 0x0, 0, vwlan1_val_tbl, 0, 420, 1000, 0),
114 	[CPCAP_VWLAN2]   = CPCAP_REG(VWLAN2C, ASSIGN3, VWLAN2_SEL, 0x020c, 0x00c0,
115 				     6, 0xd, 0, vwlan2_val_tbl, 0, 420, 1000, 0),
116 	[CPCAP_VSIM]     = CPCAP_REG(VSIMC, ASSIGN3, NONE, 0x0023, 0x0008,
117 				     3, 0x0, 0, vsim_val_tbl, 0, 420, 1000, 0),
118 	[CPCAP_VSIMCARD] = CPCAP_REG(VSIMC, ASSIGN3, NONE, 0x1e80, 0x0008,
119 				     3, 0x1E00, 0, vsimcard_val_tbl, 0, 420, 1000, 0),
120 	[CPCAP_VVIB]     = CPCAP_REG(VVIBC, ASSIGN3, VVIB_SEL, 0x0001, 0x000c,
121 				     2, 0x1, 0, vvib_val_tbl, 0, 500, 500, 0),
122 	[CPCAP_VUSB]     = CPCAP_REG(VUSBC, ASSIGN3, VUSB_SEL, 0x011c, 0x0040,
123 				     6, 0xc, 0, vusb_val_tbl, 0, 0, 1000, 0),
124 	[CPCAP_VAUDIO]   = CPCAP_REG(VAUDIOC, ASSIGN4, VAUDIO_SEL, 0x0016, 0x0001,
125 				     0, 0x5, 0, vaudio_val_tbl, 0, 0, 1000, 0),
126 };
127 
cpcap_regulator_get_value(struct udevice * dev)128 static int cpcap_regulator_get_value(struct udevice *dev)
129 {
130 	const struct cpcap_regulator_data *regulator =
131 					&tegra20_regulators[dev->driver_data];
132 	int value, volt_shift = regulator->volt_shft;
133 
134 	value = pmic_reg_read(dev->parent, regulator->reg);
135 	if (value < 0)
136 		return value;
137 
138 	if (!(value & regulator->mode_mask))
139 		return 0;
140 
141 	value &= regulator->volt_mask;
142 	value -= regulator->bit_offset_from_cpcap_lowest_voltage;
143 
144 	return regulator->val_tbl[value >> volt_shift];
145 }
146 
cpcap_regulator_set_value(struct udevice * dev,int uV)147 static int cpcap_regulator_set_value(struct udevice *dev, int uV)
148 {
149 	const struct cpcap_regulator_data *regulator =
150 					&tegra20_regulators[dev->driver_data];
151 	int value, ret, volt_shift = regulator->volt_shft;
152 
153 	if (dev->driver_data == CPCAP_VRF1) {
154 		if (uV > 2500000)
155 			value = 0;
156 		else
157 			value = regulator->volt_mask;
158 	} else {
159 		for (value = 0; value < regulator->val_tbl_sz; value++)
160 			if (regulator->val_tbl[value] >= uV)
161 				break;
162 
163 		if (value >= regulator->val_tbl_sz)
164 			value = regulator->val_tbl_sz;
165 
166 		value <<= volt_shift;
167 		value += regulator->bit_offset_from_cpcap_lowest_voltage;
168 	}
169 
170 	ret = pmic_clrsetbits(dev->parent, regulator->reg, regulator->volt_mask,
171 			      value);
172 	if (ret)
173 		return ret;
174 
175 	if (regulator->volt_trans_time)
176 		udelay(regulator->volt_trans_time);
177 
178 	return 0;
179 }
180 
cpcap_regulator_get_enable(struct udevice * dev)181 static int cpcap_regulator_get_enable(struct udevice *dev)
182 {
183 	const struct cpcap_regulator_data *regulator =
184 					&tegra20_regulators[dev->driver_data];
185 	int value;
186 
187 	value = pmic_reg_read(dev->parent, regulator->reg);
188 	if (value < 0)
189 		return value;
190 
191 	return (value & regulator->mode_mask) ? 1 : 0;
192 }
193 
cpcap_regulator_set_enable(struct udevice * dev,bool enable)194 static int cpcap_regulator_set_enable(struct udevice *dev, bool enable)
195 {
196 	const struct cpcap_regulator_data *regulator =
197 					&tegra20_regulators[dev->driver_data];
198 	int ret;
199 
200 	if (enable) {
201 		ret = pmic_clrsetbits(dev->parent, regulator->reg, regulator->mode_mask,
202 				      regulator->mode_val);
203 		if (ret)
204 			return ret;
205 	}
206 
207 	if (regulator->mode_val & CPCAP_REG_OFF_MODE_SEC) {
208 		ret = pmic_clrsetbits(dev->parent, regulator->assignment_reg,
209 				      regulator->assignment_mask,
210 				      enable ? 0 : regulator->assignment_mask);
211 		if (ret)
212 			return ret;
213 	}
214 
215 	if (!enable) {
216 		ret = pmic_clrsetbits(dev->parent, regulator->reg, regulator->mode_mask,
217 				      regulator->off_mode_val);
218 		if (ret)
219 			return ret;
220 	}
221 
222 	if (regulator->turn_on_time)
223 		udelay(regulator->turn_on_time);
224 
225 	return 0;
226 }
227 
cpcap_regulator_probe(struct udevice * dev)228 static int cpcap_regulator_probe(struct udevice *dev)
229 {
230 	struct dm_regulator_uclass_plat *uc_pdata = dev_get_uclass_plat(dev);
231 	int id;
232 
233 	for (id = 0; id < CPCAP_REGULATORS_COUNT; id++)
234 		if (cpcap_regulator_to_name[id])
235 			if (!strcmp(dev->name, cpcap_regulator_to_name[id]))
236 				break;
237 
238 	switch (id) {
239 	case CPCAP_SW1 ... CPCAP_SW6:
240 		uc_pdata->type = REGULATOR_TYPE_BUCK;
241 		break;
242 
243 	case CPCAP_VCAM ... CPCAP_VAUDIO:
244 		uc_pdata->type = REGULATOR_TYPE_LDO;
245 		break;
246 
247 	default:
248 		log_err("CPCAP: Invalid regulator ID\n");
249 		return -ENODEV;
250 	}
251 
252 	dev->driver_data = id;
253 	return 0;
254 }
255 
256 static const struct dm_regulator_ops cpcap_regulator_ops = {
257 	.get_value  = cpcap_regulator_get_value,
258 	.set_value  = cpcap_regulator_set_value,
259 	.get_enable = cpcap_regulator_get_enable,
260 	.set_enable = cpcap_regulator_set_enable,
261 };
262 
263 U_BOOT_DRIVER(cpcap_sw) = {
264 	.name = CPCAP_SW_DRIVER,
265 	.id = UCLASS_REGULATOR,
266 	.ops = &cpcap_regulator_ops,
267 	.probe = cpcap_regulator_probe,
268 };
269 
270 U_BOOT_DRIVER(cpcap_ldo) = {
271 	.name = CPCAP_LDO_DRIVER,
272 	.id = UCLASS_REGULATOR,
273 	.ops = &cpcap_regulator_ops,
274 	.probe = cpcap_regulator_probe,
275 };
276