blob: 04cd6651374eaa4423912d0ddb906d105edff368 [file] [log] [blame]
Svyatoslav Ryhel2f98a672025-03-17 20:49:22 +02001// 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
75static 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
128static 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
147static 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
181static 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
194static 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
228static 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
256static 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
263U_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
270U_BOOT_DRIVER(cpcap_ldo) = {
271 .name = CPCAP_LDO_DRIVER,
272 .id = UCLASS_REGULATOR,
273 .ops = &cpcap_regulator_ops,
274 .probe = cpcap_regulator_probe,
275};