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