1 | // SPDX-License-Identifier: GPL-2.0+ |
2 | // |
3 | // Regulator driver for ATC260x PMICs |
4 | // |
5 | // Copyright (C) 2019 Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org> |
6 | // Copyright (C) 2020 Cristian Ciocaltea <cristian.ciocaltea@gmail.com> |
7 | |
8 | #include <linux/mfd/atc260x/core.h> |
9 | #include <linux/module.h> |
10 | #include <linux/of.h> |
11 | #include <linux/platform_device.h> |
12 | #include <linux/regmap.h> |
13 | #include <linux/regulator/driver.h> |
14 | |
15 | struct atc260x_regulator_data { |
16 | int voltage_time_dcdc; |
17 | int voltage_time_ldo; |
18 | }; |
19 | |
20 | static const struct linear_range atc2603c_dcdc_voltage_ranges[] = { |
21 | REGULATOR_LINEAR_RANGE(1300000, 0, 13, 50000), |
22 | REGULATOR_LINEAR_RANGE(1950000, 14, 15, 100000), |
23 | }; |
24 | |
25 | static const struct linear_range atc2609a_dcdc_voltage_ranges[] = { |
26 | REGULATOR_LINEAR_RANGE(600000, 0, 127, 6250), |
27 | REGULATOR_LINEAR_RANGE(1400000, 128, 232, 25000), |
28 | }; |
29 | |
30 | static const struct linear_range atc2609a_ldo_voltage_ranges0[] = { |
31 | REGULATOR_LINEAR_RANGE(700000, 0, 15, 100000), |
32 | REGULATOR_LINEAR_RANGE(2100000, 0, 12, 100000), |
33 | }; |
34 | |
35 | static const struct linear_range atc2609a_ldo_voltage_ranges1[] = { |
36 | REGULATOR_LINEAR_RANGE(850000, 0, 15, 100000), |
37 | REGULATOR_LINEAR_RANGE(2100000, 0, 11, 100000), |
38 | }; |
39 | |
40 | static const unsigned int atc260x_ldo_voltage_range_sel[] = { |
41 | 0x0, 0x1, |
42 | }; |
43 | |
44 | static int atc260x_dcdc_set_voltage_time_sel(struct regulator_dev *rdev, |
45 | unsigned int old_selector, |
46 | unsigned int new_selector) |
47 | { |
48 | struct atc260x_regulator_data *data = rdev_get_drvdata(rdev); |
49 | |
50 | if (new_selector > old_selector) |
51 | return data->voltage_time_dcdc; |
52 | |
53 | return 0; |
54 | } |
55 | |
56 | static int atc260x_ldo_set_voltage_time_sel(struct regulator_dev *rdev, |
57 | unsigned int old_selector, |
58 | unsigned int new_selector) |
59 | { |
60 | struct atc260x_regulator_data *data = rdev_get_drvdata(rdev); |
61 | |
62 | if (new_selector > old_selector) |
63 | return data->voltage_time_ldo; |
64 | |
65 | return 0; |
66 | } |
67 | |
68 | static const struct regulator_ops atc260x_dcdc_ops = { |
69 | .enable = regulator_enable_regmap, |
70 | .disable = regulator_disable_regmap, |
71 | .is_enabled = regulator_is_enabled_regmap, |
72 | .list_voltage = regulator_list_voltage_linear, |
73 | .set_voltage_sel = regulator_set_voltage_sel_regmap, |
74 | .get_voltage_sel = regulator_get_voltage_sel_regmap, |
75 | .set_voltage_time_sel = atc260x_dcdc_set_voltage_time_sel, |
76 | }; |
77 | |
78 | static const struct regulator_ops atc260x_ldo_ops = { |
79 | .enable = regulator_enable_regmap, |
80 | .disable = regulator_disable_regmap, |
81 | .is_enabled = regulator_is_enabled_regmap, |
82 | .list_voltage = regulator_list_voltage_linear, |
83 | .set_voltage_sel = regulator_set_voltage_sel_regmap, |
84 | .get_voltage_sel = regulator_get_voltage_sel_regmap, |
85 | .set_voltage_time_sel = atc260x_ldo_set_voltage_time_sel, |
86 | }; |
87 | |
88 | static const struct regulator_ops atc260x_ldo_bypass_ops = { |
89 | .enable = regulator_enable_regmap, |
90 | .disable = regulator_disable_regmap, |
91 | .is_enabled = regulator_is_enabled_regmap, |
92 | .list_voltage = regulator_list_voltage_linear, |
93 | .set_voltage_sel = regulator_set_voltage_sel_regmap, |
94 | .get_voltage_sel = regulator_get_voltage_sel_regmap, |
95 | .set_voltage_time_sel = atc260x_ldo_set_voltage_time_sel, |
96 | .set_bypass = regulator_set_bypass_regmap, |
97 | .get_bypass = regulator_get_bypass_regmap, |
98 | }; |
99 | |
100 | static const struct regulator_ops atc260x_ldo_bypass_discharge_ops = { |
101 | .enable = regulator_enable_regmap, |
102 | .disable = regulator_disable_regmap, |
103 | .is_enabled = regulator_is_enabled_regmap, |
104 | .list_voltage = regulator_list_voltage_linear, |
105 | .set_voltage_sel = regulator_set_voltage_sel_regmap, |
106 | .get_voltage_sel = regulator_get_voltage_sel_regmap, |
107 | .set_voltage_time_sel = atc260x_ldo_set_voltage_time_sel, |
108 | .set_bypass = regulator_set_bypass_regmap, |
109 | .get_bypass = regulator_get_bypass_regmap, |
110 | .set_active_discharge = regulator_set_active_discharge_regmap, |
111 | }; |
112 | |
113 | static const struct regulator_ops atc260x_dcdc_range_ops = { |
114 | .enable = regulator_enable_regmap, |
115 | .disable = regulator_disable_regmap, |
116 | .is_enabled = regulator_is_enabled_regmap, |
117 | .list_voltage = regulator_list_voltage_linear_range, |
118 | .set_voltage_sel = regulator_set_voltage_sel_regmap, |
119 | .get_voltage_sel = regulator_get_voltage_sel_regmap, |
120 | .set_voltage_time_sel = atc260x_dcdc_set_voltage_time_sel, |
121 | }; |
122 | |
123 | static const struct regulator_ops atc260x_ldo_range_pick_ops = { |
124 | .enable = regulator_enable_regmap, |
125 | .disable = regulator_disable_regmap, |
126 | .is_enabled = regulator_is_enabled_regmap, |
127 | .list_voltage = regulator_list_voltage_pickable_linear_range, |
128 | .set_voltage_sel = regulator_set_voltage_sel_pickable_regmap, |
129 | .get_voltage_sel = regulator_get_voltage_sel_pickable_regmap, |
130 | .set_voltage_time_sel = atc260x_ldo_set_voltage_time_sel, |
131 | }; |
132 | |
133 | static const struct regulator_ops atc260x_dcdc_fixed_ops = { |
134 | .list_voltage = regulator_list_voltage_linear, |
135 | .set_voltage_sel = regulator_set_voltage_sel_regmap, |
136 | .get_voltage_sel = regulator_get_voltage_sel_regmap, |
137 | .set_voltage_time_sel = atc260x_dcdc_set_voltage_time_sel, |
138 | }; |
139 | |
140 | static const struct regulator_ops atc260x_ldo_fixed_ops = { |
141 | .list_voltage = regulator_list_voltage_linear, |
142 | .set_voltage_sel = regulator_set_voltage_sel_regmap, |
143 | .get_voltage_sel = regulator_get_voltage_sel_regmap, |
144 | .set_voltage_time_sel = atc260x_ldo_set_voltage_time_sel, |
145 | }; |
146 | |
147 | static const struct regulator_ops atc260x_no_ops = { |
148 | }; |
149 | |
150 | /* |
151 | * Note LDO8 is not documented in datasheet (v2.4), but supported |
152 | * in the vendor's driver implementation (xapp-le-kernel). |
153 | */ |
154 | enum atc2603c_reg_ids { |
155 | ATC2603C_ID_DCDC1, |
156 | ATC2603C_ID_DCDC2, |
157 | ATC2603C_ID_DCDC3, |
158 | ATC2603C_ID_LDO1, |
159 | ATC2603C_ID_LDO2, |
160 | ATC2603C_ID_LDO3, |
161 | ATC2603C_ID_LDO5, |
162 | ATC2603C_ID_LDO6, |
163 | ATC2603C_ID_LDO7, |
164 | ATC2603C_ID_LDO8, |
165 | ATC2603C_ID_LDO11, |
166 | ATC2603C_ID_LDO12, |
167 | ATC2603C_ID_SWITCHLDO1, |
168 | ATC2603C_ID_MAX, |
169 | }; |
170 | |
171 | #define atc2603c_reg_desc_dcdc(num, min, step, n_volt, vsel_h, vsel_l) { \ |
172 | .name = "DCDC"#num, \ |
173 | .supply_name = "dcdc"#num, \ |
174 | .of_match = of_match_ptr("dcdc"#num), \ |
175 | .regulators_node = of_match_ptr("regulators"), \ |
176 | .id = ATC2603C_ID_DCDC##num, \ |
177 | .ops = &atc260x_dcdc_ops, \ |
178 | .type = REGULATOR_VOLTAGE, \ |
179 | .min_uV = min, \ |
180 | .uV_step = step, \ |
181 | .n_voltages = n_volt, \ |
182 | .vsel_reg = ATC2603C_PMU_DC##num##_CTL0, \ |
183 | .vsel_mask = GENMASK(vsel_h, vsel_l), \ |
184 | .enable_reg = ATC2603C_PMU_DC##num##_CTL0, \ |
185 | .enable_mask = BIT(15), \ |
186 | .enable_time = 800, \ |
187 | .owner = THIS_MODULE, \ |
188 | } |
189 | |
190 | #define atc2603c_reg_desc_dcdc_range(num, vsel_h, vsel_l) { \ |
191 | .name = "DCDC"#num, \ |
192 | .supply_name = "dcdc"#num, \ |
193 | .of_match = of_match_ptr("dcdc"#num), \ |
194 | .regulators_node = of_match_ptr("regulators"), \ |
195 | .id = ATC2603C_ID_DCDC##num, \ |
196 | .ops = &atc260x_dcdc_range_ops, \ |
197 | .type = REGULATOR_VOLTAGE, \ |
198 | .n_voltages = 16, \ |
199 | .linear_ranges = atc2603c_dcdc_voltage_ranges, \ |
200 | .n_linear_ranges = ARRAY_SIZE(atc2603c_dcdc_voltage_ranges), \ |
201 | .vsel_reg = ATC2603C_PMU_DC##num##_CTL0, \ |
202 | .vsel_mask = GENMASK(vsel_h, vsel_l), \ |
203 | .enable_reg = ATC2603C_PMU_DC##num##_CTL0, \ |
204 | .enable_mask = BIT(15), \ |
205 | .enable_time = 800, \ |
206 | .owner = THIS_MODULE, \ |
207 | } |
208 | |
209 | #define atc2603c_reg_desc_dcdc_fixed(num, min, step, n_volt, vsel_h, vsel_l) { \ |
210 | .name = "DCDC"#num, \ |
211 | .supply_name = "dcdc"#num, \ |
212 | .of_match = of_match_ptr("dcdc"#num), \ |
213 | .regulators_node = of_match_ptr("regulators"), \ |
214 | .id = ATC2603C_ID_DCDC##num, \ |
215 | .ops = &atc260x_dcdc_fixed_ops, \ |
216 | .type = REGULATOR_VOLTAGE, \ |
217 | .min_uV = min, \ |
218 | .uV_step = step, \ |
219 | .n_voltages = n_volt, \ |
220 | .vsel_reg = ATC2603C_PMU_DC##num##_CTL0, \ |
221 | .vsel_mask = GENMASK(vsel_h, vsel_l), \ |
222 | .enable_time = 800, \ |
223 | .owner = THIS_MODULE, \ |
224 | } |
225 | |
226 | #define atc2603c_reg_desc_ldo(num, min, step, n_volt, vsel_h, vsel_l) { \ |
227 | .name = "LDO"#num, \ |
228 | .supply_name = "ldo"#num, \ |
229 | .of_match = of_match_ptr("ldo"#num), \ |
230 | .regulators_node = of_match_ptr("regulators"), \ |
231 | .id = ATC2603C_ID_LDO##num, \ |
232 | .ops = &atc260x_ldo_ops, \ |
233 | .type = REGULATOR_VOLTAGE, \ |
234 | .min_uV = min, \ |
235 | .uV_step = step, \ |
236 | .n_voltages = n_volt, \ |
237 | .vsel_reg = ATC2603C_PMU_LDO##num##_CTL, \ |
238 | .vsel_mask = GENMASK(vsel_h, vsel_l), \ |
239 | .enable_reg = ATC2603C_PMU_LDO##num##_CTL, \ |
240 | .enable_mask = BIT(0), \ |
241 | .enable_time = 2000, \ |
242 | .owner = THIS_MODULE, \ |
243 | } |
244 | |
245 | #define atc2603c_reg_desc_ldo_fixed(num, min, step, n_volt, vsel_h, vsel_l) { \ |
246 | .name = "LDO"#num, \ |
247 | .supply_name = "ldo"#num, \ |
248 | .of_match = of_match_ptr("ldo"#num), \ |
249 | .regulators_node = of_match_ptr("regulators"), \ |
250 | .id = ATC2603C_ID_LDO##num, \ |
251 | .ops = &atc260x_ldo_fixed_ops, \ |
252 | .type = REGULATOR_VOLTAGE, \ |
253 | .min_uV = min, \ |
254 | .uV_step = step, \ |
255 | .n_voltages = n_volt, \ |
256 | .vsel_reg = ATC2603C_PMU_LDO##num##_CTL, \ |
257 | .vsel_mask = GENMASK(vsel_h, vsel_l), \ |
258 | .enable_time = 2000, \ |
259 | .owner = THIS_MODULE, \ |
260 | } |
261 | |
262 | #define atc2603c_reg_desc_ldo_noops(num, vfixed) { \ |
263 | .name = "LDO"#num, \ |
264 | .supply_name = "ldo"#num, \ |
265 | .of_match = of_match_ptr("ldo"#num), \ |
266 | .regulators_node = of_match_ptr("regulators"), \ |
267 | .id = ATC2603C_ID_LDO##num, \ |
268 | .ops = &atc260x_no_ops, \ |
269 | .type = REGULATOR_VOLTAGE, \ |
270 | .fixed_uV = vfixed, \ |
271 | .n_voltages = 1, \ |
272 | .owner = THIS_MODULE, \ |
273 | } |
274 | |
275 | #define atc2603c_reg_desc_ldo_switch(num, min, step, n_volt, vsel_h, vsel_l) { \ |
276 | .name = "SWITCHLDO"#num, \ |
277 | .supply_name = "switchldo"#num, \ |
278 | .of_match = of_match_ptr("switchldo"#num), \ |
279 | .regulators_node = of_match_ptr("regulators"), \ |
280 | .id = ATC2603C_ID_SWITCHLDO##num, \ |
281 | .ops = &atc260x_ldo_bypass_discharge_ops, \ |
282 | .type = REGULATOR_VOLTAGE, \ |
283 | .min_uV = min, \ |
284 | .uV_step = step, \ |
285 | .n_voltages = n_volt, \ |
286 | .vsel_reg = ATC2603C_PMU_SWITCH_CTL, \ |
287 | .vsel_mask = GENMASK(vsel_h, vsel_l), \ |
288 | .enable_reg = ATC2603C_PMU_SWITCH_CTL, \ |
289 | .enable_mask = BIT(15), \ |
290 | .enable_is_inverted = true, \ |
291 | .enable_time = 2000, \ |
292 | .bypass_reg = ATC2603C_PMU_SWITCH_CTL, \ |
293 | .bypass_mask = BIT(5), \ |
294 | .active_discharge_reg = ATC2603C_PMU_SWITCH_CTL, \ |
295 | .active_discharge_mask = BIT(1), \ |
296 | .active_discharge_on = BIT(1), \ |
297 | .owner = THIS_MODULE, \ |
298 | } |
299 | |
300 | static const struct regulator_desc atc2603c_reg[] = { |
301 | atc2603c_reg_desc_dcdc_fixed(1, 700000, 25000, 29, 11, 7), |
302 | atc2603c_reg_desc_dcdc_range(2, 12, 8), |
303 | atc2603c_reg_desc_dcdc_fixed(3, 2600000, 100000, 8, 11, 9), |
304 | atc2603c_reg_desc_ldo_fixed(1, 2600000, 100000, 8, 15, 13), |
305 | atc2603c_reg_desc_ldo_fixed(2, 2600000, 100000, 8, 15, 13), |
306 | atc2603c_reg_desc_ldo_fixed(3, 1500000, 100000, 6, 15, 13), |
307 | atc2603c_reg_desc_ldo(5, 2600000, 100000, 8, 15, 13), |
308 | atc2603c_reg_desc_ldo_fixed(6, 700000, 25000, 29, 15, 11), |
309 | atc2603c_reg_desc_ldo(7, 1500000, 100000, 6, 15, 13), |
310 | atc2603c_reg_desc_ldo(8, 2300000, 100000, 11, 15, 12), |
311 | atc2603c_reg_desc_ldo_fixed(11, 2600000, 100000, 8, 15, 13), |
312 | atc2603c_reg_desc_ldo_noops(12, 1800000), |
313 | atc2603c_reg_desc_ldo_switch(1, 3000000, 100000, 4, 4, 3), |
314 | }; |
315 | |
316 | static const struct regulator_desc atc2603c_reg_dcdc2_ver_b = |
317 | atc2603c_reg_desc_dcdc(2, 1000000, 50000, 18, 12, 8); |
318 | |
319 | enum atc2609a_reg_ids { |
320 | ATC2609A_ID_DCDC0, |
321 | ATC2609A_ID_DCDC1, |
322 | ATC2609A_ID_DCDC2, |
323 | ATC2609A_ID_DCDC3, |
324 | ATC2609A_ID_DCDC4, |
325 | ATC2609A_ID_LDO0, |
326 | ATC2609A_ID_LDO1, |
327 | ATC2609A_ID_LDO2, |
328 | ATC2609A_ID_LDO3, |
329 | ATC2609A_ID_LDO4, |
330 | ATC2609A_ID_LDO5, |
331 | ATC2609A_ID_LDO6, |
332 | ATC2609A_ID_LDO7, |
333 | ATC2609A_ID_LDO8, |
334 | ATC2609A_ID_LDO9, |
335 | ATC2609A_ID_MAX, |
336 | }; |
337 | |
338 | #define atc2609a_reg_desc_dcdc(num, en_bit) { \ |
339 | .name = "DCDC"#num, \ |
340 | .supply_name = "dcdc"#num, \ |
341 | .of_match = of_match_ptr("dcdc"#num), \ |
342 | .regulators_node = of_match_ptr("regulators"), \ |
343 | .id = ATC2609A_ID_DCDC##num, \ |
344 | .ops = &atc260x_dcdc_ops, \ |
345 | .type = REGULATOR_VOLTAGE, \ |
346 | .min_uV = 600000, \ |
347 | .uV_step = 6250, \ |
348 | .n_voltages = 256, \ |
349 | .vsel_reg = ATC2609A_PMU_DC##num##_CTL0, \ |
350 | .vsel_mask = GENMASK(15, 8), \ |
351 | .enable_reg = ATC2609A_PMU_DC_OSC, \ |
352 | .enable_mask = BIT(en_bit), \ |
353 | .enable_time = 800, \ |
354 | .owner = THIS_MODULE, \ |
355 | } |
356 | |
357 | #define atc2609a_reg_desc_dcdc_range(num, en_bit) { \ |
358 | .name = "DCDC"#num, \ |
359 | .supply_name = "dcdc"#num, \ |
360 | .of_match = of_match_ptr("dcdc"#num), \ |
361 | .regulators_node = of_match_ptr("regulators"), \ |
362 | .id = ATC2609A_ID_DCDC##num, \ |
363 | .ops = &atc260x_dcdc_range_ops, \ |
364 | .type = REGULATOR_VOLTAGE, \ |
365 | .n_voltages = 233, \ |
366 | .linear_ranges = atc2609a_dcdc_voltage_ranges, \ |
367 | .n_linear_ranges = ARRAY_SIZE(atc2609a_dcdc_voltage_ranges), \ |
368 | .vsel_reg = ATC2609A_PMU_DC##num##_CTL0, \ |
369 | .vsel_mask = GENMASK(15, 8), \ |
370 | .enable_reg = ATC2609A_PMU_DC_OSC, \ |
371 | .enable_mask = BIT(en_bit), \ |
372 | .enable_time = 800, \ |
373 | .owner = THIS_MODULE, \ |
374 | } |
375 | |
376 | #define atc2609a_reg_desc_ldo(num) { \ |
377 | .name = "LDO"#num, \ |
378 | .supply_name = "ldo"#num, \ |
379 | .of_match = of_match_ptr("ldo"#num), \ |
380 | .regulators_node = of_match_ptr("regulators"), \ |
381 | .id = ATC2609A_ID_LDO##num, \ |
382 | .ops = &atc260x_ldo_ops, \ |
383 | .type = REGULATOR_VOLTAGE, \ |
384 | .min_uV = 700000, \ |
385 | .uV_step = 100000, \ |
386 | .n_voltages = 16, \ |
387 | .vsel_reg = ATC2609A_PMU_LDO##num##_CTL0, \ |
388 | .vsel_mask = GENMASK(4, 1), \ |
389 | .enable_reg = ATC2609A_PMU_LDO##num##_CTL0, \ |
390 | .enable_mask = BIT(0), \ |
391 | .enable_time = 2000, \ |
392 | .owner = THIS_MODULE, \ |
393 | } |
394 | |
395 | #define atc2609a_reg_desc_ldo_bypass(num) { \ |
396 | .name = "LDO"#num, \ |
397 | .supply_name = "ldo"#num, \ |
398 | .of_match = of_match_ptr("ldo"#num), \ |
399 | .regulators_node = of_match_ptr("regulators"), \ |
400 | .id = ATC2609A_ID_LDO##num, \ |
401 | .ops = &atc260x_ldo_bypass_ops, \ |
402 | .type = REGULATOR_VOLTAGE, \ |
403 | .min_uV = 2300000, \ |
404 | .uV_step = 100000, \ |
405 | .n_voltages = 12, \ |
406 | .vsel_reg = ATC2609A_PMU_LDO##num##_CTL0, \ |
407 | .vsel_mask = GENMASK(5, 2), \ |
408 | .enable_reg = ATC2609A_PMU_LDO##num##_CTL0, \ |
409 | .enable_mask = BIT(0), \ |
410 | .enable_time = 2000, \ |
411 | .bypass_reg = ATC2609A_PMU_LDO##num##_CTL0, \ |
412 | .bypass_mask = BIT(1), \ |
413 | .owner = THIS_MODULE, \ |
414 | } |
415 | |
416 | #define atc2609a_reg_desc_ldo_range_pick(num, n_range, n_volt) { \ |
417 | .name = "LDO"#num, \ |
418 | .supply_name = "ldo"#num, \ |
419 | .of_match = of_match_ptr("ldo"#num), \ |
420 | .regulators_node = of_match_ptr("regulators"), \ |
421 | .id = ATC2609A_ID_LDO##num, \ |
422 | .ops = &atc260x_ldo_range_pick_ops, \ |
423 | .type = REGULATOR_VOLTAGE, \ |
424 | .linear_ranges = atc2609a_ldo_voltage_ranges##n_range, \ |
425 | .n_linear_ranges = ARRAY_SIZE(atc2609a_ldo_voltage_ranges##n_range), \ |
426 | .n_voltages = n_volt, \ |
427 | .vsel_reg = ATC2609A_PMU_LDO##num##_CTL0, \ |
428 | .vsel_mask = GENMASK(4, 1), \ |
429 | .vsel_range_reg = ATC2609A_PMU_LDO##num##_CTL0, \ |
430 | .vsel_range_mask = BIT(5), \ |
431 | .linear_range_selectors_bitfield = atc260x_ldo_voltage_range_sel, \ |
432 | .enable_reg = ATC2609A_PMU_LDO##num##_CTL0, \ |
433 | .enable_mask = BIT(0), \ |
434 | .enable_time = 2000, \ |
435 | .owner = THIS_MODULE, \ |
436 | } |
437 | |
438 | #define atc2609a_reg_desc_ldo_fixed(num) { \ |
439 | .name = "LDO"#num, \ |
440 | .supply_name = "ldo"#num, \ |
441 | .of_match = of_match_ptr("ldo"#num), \ |
442 | .regulators_node = of_match_ptr("regulators"), \ |
443 | .id = ATC2609A_ID_LDO##num, \ |
444 | .ops = &atc260x_ldo_fixed_ops, \ |
445 | .type = REGULATOR_VOLTAGE, \ |
446 | .min_uV = 2600000, \ |
447 | .uV_step = 100000, \ |
448 | .n_voltages = 8, \ |
449 | .vsel_reg = ATC2609A_PMU_LDO##num##_CTL, \ |
450 | .vsel_mask = GENMASK(15, 13), \ |
451 | .enable_time = 2000, \ |
452 | .owner = THIS_MODULE, \ |
453 | } |
454 | |
455 | static const struct regulator_desc atc2609a_reg[] = { |
456 | atc2609a_reg_desc_dcdc(0, 4), |
457 | atc2609a_reg_desc_dcdc(1, 5), |
458 | atc2609a_reg_desc_dcdc(2, 6), |
459 | atc2609a_reg_desc_dcdc_range(3, 7), |
460 | atc2609a_reg_desc_dcdc(4, 8), |
461 | atc2609a_reg_desc_ldo_bypass(0), |
462 | atc2609a_reg_desc_ldo_bypass(1), |
463 | atc2609a_reg_desc_ldo_bypass(2), |
464 | atc2609a_reg_desc_ldo_range_pick(3, 0, 29), |
465 | atc2609a_reg_desc_ldo_range_pick(4, 0, 29), |
466 | atc2609a_reg_desc_ldo(5), |
467 | atc2609a_reg_desc_ldo_range_pick(6, 1, 28), |
468 | atc2609a_reg_desc_ldo_range_pick(7, 0, 29), |
469 | atc2609a_reg_desc_ldo_range_pick(8, 0, 29), |
470 | atc2609a_reg_desc_ldo_fixed(9), |
471 | }; |
472 | |
473 | static int atc260x_regulator_probe(struct platform_device *pdev) |
474 | { |
475 | struct atc260x *atc260x = dev_get_drvdata(dev: pdev->dev.parent); |
476 | struct device *dev = atc260x->dev; |
477 | struct atc260x_regulator_data *atc260x_data; |
478 | struct regulator_config config = {}; |
479 | struct regulator_dev *atc260x_rdev; |
480 | const struct regulator_desc *regulators; |
481 | bool atc2603c_ver_b = false; |
482 | int i, nregulators; |
483 | |
484 | atc260x_data = devm_kzalloc(dev: &pdev->dev, size: sizeof(*atc260x_data), GFP_KERNEL); |
485 | if (!atc260x_data) |
486 | return -ENOMEM; |
487 | |
488 | atc260x_data->voltage_time_dcdc = 350; |
489 | atc260x_data->voltage_time_ldo = 800; |
490 | |
491 | switch (atc260x->ic_type) { |
492 | case ATC2603C: |
493 | regulators = atc2603c_reg; |
494 | nregulators = ATC2603C_ID_MAX; |
495 | atc2603c_ver_b = atc260x->ic_ver == ATC260X_B; |
496 | break; |
497 | case ATC2609A: |
498 | atc260x_data->voltage_time_dcdc = 250; |
499 | regulators = atc2609a_reg; |
500 | nregulators = ATC2609A_ID_MAX; |
501 | break; |
502 | default: |
503 | dev_err(dev, "unsupported ATC260X ID %d\n" , atc260x->ic_type); |
504 | return -EINVAL; |
505 | } |
506 | |
507 | config.dev = dev; |
508 | config.regmap = atc260x->regmap; |
509 | config.driver_data = atc260x_data; |
510 | |
511 | /* Instantiate the regulators */ |
512 | for (i = 0; i < nregulators; i++) { |
513 | if (atc2603c_ver_b && regulators[i].id == ATC2603C_ID_DCDC2) |
514 | atc260x_rdev = devm_regulator_register(dev: &pdev->dev, |
515 | regulator_desc: &atc2603c_reg_dcdc2_ver_b, |
516 | config: &config); |
517 | else |
518 | atc260x_rdev = devm_regulator_register(dev: &pdev->dev, |
519 | regulator_desc: ®ulators[i], |
520 | config: &config); |
521 | if (IS_ERR(ptr: atc260x_rdev)) { |
522 | dev_err(dev, "failed to register regulator: %d\n" , i); |
523 | return PTR_ERR(ptr: atc260x_rdev); |
524 | } |
525 | } |
526 | |
527 | return 0; |
528 | } |
529 | |
530 | static struct platform_driver atc260x_regulator_driver = { |
531 | .probe = atc260x_regulator_probe, |
532 | .driver = { |
533 | .name = "atc260x-regulator" , |
534 | .probe_type = PROBE_PREFER_ASYNCHRONOUS, |
535 | }, |
536 | }; |
537 | |
538 | module_platform_driver(atc260x_regulator_driver); |
539 | |
540 | MODULE_DESCRIPTION("Regulator driver for ATC260x PMICs" ); |
541 | MODULE_AUTHOR("Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>" ); |
542 | MODULE_AUTHOR("Cristian Ciocaltea <cristian.ciocaltea@gmail.com>" ); |
543 | MODULE_LICENSE("GPL" ); |
544 | |