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> | |
045a44d4 RH |
10 | #include <linux/of.h> |
11 | #include <linux/platform_device.h> | |
3b15ccac CC |
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), | |
1963fa67 | 32 | REGULATOR_LINEAR_RANGE(2100000, 0, 12, 100000), |
3b15ccac CC |
33 | }; |
34 | ||
35 | static const struct linear_range atc2609a_ldo_voltage_ranges1[] = { | |
36 | REGULATOR_LINEAR_RANGE(850000, 0, 15, 100000), | |
1963fa67 | 37 | REGULATOR_LINEAR_RANGE(2100000, 0, 11, 100000), |
3b15ccac CC |
38 | }; |
39 | ||
40 | static const unsigned int atc260x_ldo_voltage_range_sel[] = { | |
269cb04b | 41 | 0x0, 0x1, |
3b15ccac CC |
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), \ | |
2316f0fc | 296 | .active_discharge_on = BIT(1), \ |
3b15ccac CC |
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 | ||
1963fa67 | 416 | #define atc2609a_reg_desc_ldo_range_pick(num, n_range, n_volt) { \ |
3b15ccac CC |
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), \ | |
1963fa67 | 426 | .n_voltages = n_volt, \ |
3b15ccac CC |
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), \ | |
269cb04b | 431 | .linear_range_selectors_bitfield = atc260x_ldo_voltage_range_sel, \ |
3b15ccac CC |
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), | |
1963fa67 AL |
464 | atc2609a_reg_desc_ldo_range_pick(3, 0, 29), |
465 | atc2609a_reg_desc_ldo_range_pick(4, 0, 29), | |
3b15ccac | 466 | atc2609a_reg_desc_ldo(5), |
1963fa67 AL |
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), | |
3b15ccac CC |
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(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(&pdev->dev, 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(&pdev->dev, | |
515 | &atc2603c_reg_dcdc2_ver_b, | |
516 | &config); | |
517 | else | |
518 | atc260x_rdev = devm_regulator_register(&pdev->dev, | |
519 | ®ulators[i], | |
520 | &config); | |
521 | if (IS_ERR(atc260x_rdev)) { | |
522 | dev_err(dev, "failed to register regulator: %d\n", i); | |
523 | return PTR_ERR(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", | |
46600ab1 | 534 | .probe_type = PROBE_PREFER_ASYNCHRONOUS, |
3b15ccac CC |
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"); |