]>
Commit | Line | Data |
---|---|---|
b014e9fa MV |
1 | // SPDX-License-Identifier: GPL-2.0 |
2 | // Copyright (C) 2020 ROHM Semiconductors | |
3 | // ROHM BD9576MUF/BD9573MUF regulator driver | |
4 | ||
b014e9fa MV |
5 | #include <linux/err.h> |
6 | #include <linux/gpio/consumer.h> | |
7 | #include <linux/interrupt.h> | |
e7bf1fa5 | 8 | #include <linux/jiffies.h> |
b014e9fa MV |
9 | #include <linux/kernel.h> |
10 | #include <linux/mfd/rohm-bd957x.h> | |
11 | #include <linux/mfd/rohm-generic.h> | |
12 | #include <linux/module.h> | |
13 | #include <linux/of.h> | |
14 | #include <linux/platform_device.h> | |
15 | #include <linux/regulator/driver.h> | |
16 | #include <linux/regulator/machine.h> | |
17 | #include <linux/regulator/of_regulator.h> | |
18 | #include <linux/slab.h> | |
e7bf1fa5 MV |
19 | #include <linux/spinlock.h> |
20 | #include <linux/workqueue.h> | |
b014e9fa MV |
21 | |
22 | #define BD957X_VOUTS1_VOLT 3300000 | |
23 | #define BD957X_VOUTS4_BASE_VOLT 1030000 | |
24 | #define BD957X_VOUTS34_NUM_VOLT 32 | |
25 | ||
e7bf1fa5 MV |
26 | #define BD9576_THERM_IRQ_MASK_TW BIT(5) |
27 | #define BD9576_xVD_IRQ_MASK_VOUTL1 BIT(5) | |
28 | #define BD9576_UVD_IRQ_MASK_VOUTS1_OCW BIT(6) | |
29 | #define BD9576_xVD_IRQ_MASK_VOUT1TO4 0x0F | |
30 | ||
6041d5fe AL |
31 | static const unsigned int vout1_volt_table[] = { |
32 | 5000000, 4900000, 4800000, 4700000, 4600000, | |
33 | 4500000, 4500000, 4500000, 5000000, 5100000, | |
34 | 5200000, 5300000, 5400000, 5500000, 5500000, | |
35 | 5500000 | |
36 | }; | |
b014e9fa | 37 | |
6041d5fe AL |
38 | static const unsigned int vout2_volt_table[] = { |
39 | 1800000, 1780000, 1760000, 1740000, 1720000, | |
40 | 1700000, 1680000, 1660000, 1800000, 1820000, | |
41 | 1840000, 1860000, 1880000, 1900000, 1920000, | |
42 | 1940000 | |
43 | }; | |
b014e9fa | 44 | |
6041d5fe AL |
45 | static const unsigned int voutl1_volt_table[] = { |
46 | 2500000, 2540000, 2580000, 2620000, 2660000, | |
47 | 2700000, 2740000, 2780000, 2500000, 2460000, | |
48 | 2420000, 2380000, 2340000, 2300000, 2260000, | |
49 | 2220000 | |
50 | }; | |
b014e9fa | 51 | |
e7bf1fa5 MV |
52 | static const struct linear_range vout1_xvd_ranges[] = { |
53 | REGULATOR_LINEAR_RANGE(225000, 0x01, 0x2b, 0), | |
54 | REGULATOR_LINEAR_RANGE(225000, 0x2c, 0x54, 5000), | |
55 | REGULATOR_LINEAR_RANGE(425000, 0x55, 0x7f, 0), | |
56 | }; | |
57 | ||
58 | static const struct linear_range vout234_xvd_ranges[] = { | |
59 | REGULATOR_LINEAR_RANGE(17000, 0x01, 0x0f, 0), | |
60 | REGULATOR_LINEAR_RANGE(17000, 0x10, 0x6d, 1000), | |
61 | REGULATOR_LINEAR_RANGE(110000, 0x6e, 0x7f, 0), | |
62 | }; | |
63 | ||
64 | static const struct linear_range voutL1_xvd_ranges[] = { | |
65 | REGULATOR_LINEAR_RANGE(34000, 0x01, 0x0f, 0), | |
66 | REGULATOR_LINEAR_RANGE(34000, 0x10, 0x6d, 2000), | |
67 | REGULATOR_LINEAR_RANGE(220000, 0x6e, 0x7f, 0), | |
68 | }; | |
69 | ||
70 | static struct linear_range voutS1_ocw_ranges_internal[] = { | |
71 | REGULATOR_LINEAR_RANGE(200000, 0x01, 0x04, 0), | |
72 | REGULATOR_LINEAR_RANGE(250000, 0x05, 0x18, 50000), | |
73 | REGULATOR_LINEAR_RANGE(1200000, 0x19, 0x3f, 0), | |
74 | }; | |
75 | ||
76 | static struct linear_range voutS1_ocw_ranges[] = { | |
77 | REGULATOR_LINEAR_RANGE(50000, 0x01, 0x04, 0), | |
78 | REGULATOR_LINEAR_RANGE(60000, 0x05, 0x18, 10000), | |
79 | REGULATOR_LINEAR_RANGE(250000, 0x19, 0x3f, 0), | |
80 | }; | |
81 | ||
82 | static struct linear_range voutS1_ocp_ranges_internal[] = { | |
83 | REGULATOR_LINEAR_RANGE(300000, 0x01, 0x06, 0), | |
84 | REGULATOR_LINEAR_RANGE(350000, 0x7, 0x1b, 50000), | |
85 | REGULATOR_LINEAR_RANGE(1350000, 0x1c, 0x3f, 0), | |
86 | }; | |
87 | ||
88 | static struct linear_range voutS1_ocp_ranges[] = { | |
89 | REGULATOR_LINEAR_RANGE(70000, 0x01, 0x06, 0), | |
90 | REGULATOR_LINEAR_RANGE(80000, 0x7, 0x1b, 10000), | |
91 | REGULATOR_LINEAR_RANGE(280000, 0x1c, 0x3f, 0), | |
92 | }; | |
93 | ||
b014e9fa MV |
94 | struct bd957x_regulator_data { |
95 | struct regulator_desc desc; | |
96 | int base_voltage; | |
e7bf1fa5 MV |
97 | struct regulator_dev *rdev; |
98 | int ovd_notif; | |
99 | int uvd_notif; | |
100 | int temp_notif; | |
101 | int ovd_err; | |
102 | int uvd_err; | |
103 | int temp_err; | |
104 | const struct linear_range *xvd_ranges; | |
105 | int num_xvd_ranges; | |
106 | bool oc_supported; | |
107 | unsigned int ovd_reg; | |
108 | unsigned int uvd_reg; | |
109 | unsigned int xvd_mask; | |
110 | unsigned int ocp_reg; | |
111 | unsigned int ocp_mask; | |
112 | unsigned int ocw_reg; | |
113 | unsigned int ocw_mask; | |
114 | unsigned int ocw_rfet; | |
115 | }; | |
116 | ||
117 | #define BD9576_NUM_REGULATORS 6 | |
118 | #define BD9576_NUM_OVD_REGULATORS 5 | |
119 | ||
120 | struct bd957x_data { | |
121 | struct bd957x_regulator_data regulator_data[BD9576_NUM_REGULATORS]; | |
122 | struct regmap *regmap; | |
123 | struct delayed_work therm_irq_suppress; | |
124 | struct delayed_work ovd_irq_suppress; | |
125 | struct delayed_work uvd_irq_suppress; | |
126 | unsigned int therm_irq; | |
127 | unsigned int ovd_irq; | |
128 | unsigned int uvd_irq; | |
129 | spinlock_t err_lock; | |
130 | int regulator_global_err; | |
b014e9fa MV |
131 | }; |
132 | ||
133 | static int bd957x_vout34_list_voltage(struct regulator_dev *rdev, | |
134 | unsigned int selector) | |
135 | { | |
136 | const struct regulator_desc *desc = rdev->desc; | |
137 | int multiplier = selector & desc->vsel_mask & 0x7f; | |
138 | int tune; | |
139 | ||
140 | /* VOUT3 and 4 has 10mV step */ | |
141 | tune = multiplier * 10000; | |
142 | ||
143 | if (!(selector & 0x80)) | |
144 | return desc->fixed_uV - tune; | |
145 | ||
146 | return desc->fixed_uV + tune; | |
147 | } | |
148 | ||
149 | static int bd957x_list_voltage(struct regulator_dev *rdev, | |
150 | unsigned int selector) | |
151 | { | |
152 | const struct regulator_desc *desc = rdev->desc; | |
153 | int index = selector & desc->vsel_mask & 0x7f; | |
154 | ||
155 | if (!(selector & 0x80)) | |
156 | index += desc->n_voltages/2; | |
157 | ||
158 | if (index >= desc->n_voltages) | |
159 | return -EINVAL; | |
160 | ||
161 | return desc->volt_table[index]; | |
162 | } | |
163 | ||
e7bf1fa5 MV |
164 | static void bd9576_fill_ovd_flags(struct bd957x_regulator_data *data, |
165 | bool warn) | |
166 | { | |
167 | if (warn) { | |
168 | data->ovd_notif = REGULATOR_EVENT_OVER_VOLTAGE_WARN; | |
169 | data->ovd_err = REGULATOR_ERROR_OVER_VOLTAGE_WARN; | |
170 | } else { | |
171 | data->ovd_notif = REGULATOR_EVENT_REGULATION_OUT; | |
172 | data->ovd_err = REGULATOR_ERROR_REGULATION_OUT; | |
173 | } | |
174 | } | |
175 | ||
176 | static void bd9576_fill_ocp_flags(struct bd957x_regulator_data *data, | |
177 | bool warn) | |
178 | { | |
179 | if (warn) { | |
180 | data->uvd_notif = REGULATOR_EVENT_OVER_CURRENT_WARN; | |
181 | data->uvd_err = REGULATOR_ERROR_OVER_CURRENT_WARN; | |
182 | } else { | |
183 | data->uvd_notif = REGULATOR_EVENT_OVER_CURRENT; | |
184 | data->uvd_err = REGULATOR_ERROR_OVER_CURRENT; | |
185 | } | |
186 | } | |
187 | ||
188 | static void bd9576_fill_uvd_flags(struct bd957x_regulator_data *data, | |
189 | bool warn) | |
190 | { | |
191 | if (warn) { | |
192 | data->uvd_notif = REGULATOR_EVENT_UNDER_VOLTAGE_WARN; | |
193 | data->uvd_err = REGULATOR_ERROR_UNDER_VOLTAGE_WARN; | |
194 | } else { | |
195 | data->uvd_notif = REGULATOR_EVENT_UNDER_VOLTAGE; | |
196 | data->uvd_err = REGULATOR_ERROR_UNDER_VOLTAGE; | |
197 | } | |
198 | } | |
199 | ||
200 | static void bd9576_fill_temp_flags(struct bd957x_regulator_data *data, | |
201 | bool enable, bool warn) | |
202 | { | |
203 | if (!enable) { | |
204 | data->temp_notif = 0; | |
205 | data->temp_err = 0; | |
206 | } else if (warn) { | |
207 | data->temp_notif = REGULATOR_EVENT_OVER_TEMP_WARN; | |
208 | data->temp_err = REGULATOR_ERROR_OVER_TEMP_WARN; | |
209 | } else { | |
210 | data->temp_notif = REGULATOR_EVENT_OVER_TEMP; | |
211 | data->temp_err = REGULATOR_ERROR_OVER_TEMP; | |
212 | } | |
213 | } | |
214 | ||
215 | static int bd9576_set_limit(const struct linear_range *r, int num_ranges, | |
216 | struct regmap *regmap, int reg, int mask, int lim) | |
217 | { | |
218 | int ret; | |
219 | bool found; | |
220 | int sel = 0; | |
221 | ||
222 | if (lim) { | |
223 | ||
224 | ret = linear_range_get_selector_low_array(r, num_ranges, | |
225 | lim, &sel, &found); | |
226 | if (ret) | |
227 | return ret; | |
228 | ||
229 | if (!found) | |
230 | dev_warn(regmap_get_device(regmap), | |
231 | "limit %d out of range. Setting lower\n", | |
232 | lim); | |
233 | } | |
234 | ||
235 | return regmap_update_bits(regmap, reg, mask, sel); | |
236 | } | |
237 | ||
238 | static bool check_ocp_flag_mismatch(struct regulator_dev *rdev, int severity, | |
239 | struct bd957x_regulator_data *r) | |
240 | { | |
241 | if ((severity == REGULATOR_SEVERITY_ERR && | |
242 | r->uvd_notif != REGULATOR_EVENT_OVER_CURRENT) || | |
243 | (severity == REGULATOR_SEVERITY_WARN && | |
244 | r->uvd_notif != REGULATOR_EVENT_OVER_CURRENT_WARN)) { | |
245 | dev_warn(rdev_get_dev(rdev), | |
246 | "Can't support both OCP WARN and ERR\n"); | |
247 | /* Do not overwrite ERR config with WARN */ | |
248 | if (severity == REGULATOR_SEVERITY_WARN) | |
249 | return true; | |
250 | ||
251 | bd9576_fill_ocp_flags(r, 0); | |
252 | } | |
253 | ||
254 | return false; | |
255 | } | |
256 | ||
257 | static bool check_uvd_flag_mismatch(struct regulator_dev *rdev, int severity, | |
258 | struct bd957x_regulator_data *r) | |
259 | { | |
260 | if ((severity == REGULATOR_SEVERITY_ERR && | |
261 | r->uvd_notif != REGULATOR_EVENT_UNDER_VOLTAGE) || | |
262 | (severity == REGULATOR_SEVERITY_WARN && | |
263 | r->uvd_notif != REGULATOR_EVENT_UNDER_VOLTAGE_WARN)) { | |
264 | dev_warn(rdev_get_dev(rdev), | |
265 | "Can't support both UVD WARN and ERR\n"); | |
266 | if (severity == REGULATOR_SEVERITY_WARN) | |
267 | return true; | |
268 | ||
269 | bd9576_fill_uvd_flags(r, 0); | |
270 | } | |
271 | ||
272 | return false; | |
273 | } | |
274 | ||
275 | static bool check_ovd_flag_mismatch(struct regulator_dev *rdev, int severity, | |
276 | struct bd957x_regulator_data *r) | |
277 | { | |
278 | if ((severity == REGULATOR_SEVERITY_ERR && | |
279 | r->ovd_notif != REGULATOR_EVENT_REGULATION_OUT) || | |
280 | (severity == REGULATOR_SEVERITY_WARN && | |
281 | r->ovd_notif != REGULATOR_EVENT_OVER_VOLTAGE_WARN)) { | |
282 | dev_warn(rdev_get_dev(rdev), | |
283 | "Can't support both OVD WARN and ERR\n"); | |
284 | if (severity == REGULATOR_SEVERITY_WARN) | |
285 | return true; | |
286 | ||
287 | bd9576_fill_ovd_flags(r, 0); | |
288 | } | |
289 | ||
290 | return false; | |
291 | } | |
292 | ||
293 | static bool check_temp_flag_mismatch(struct regulator_dev *rdev, int severity, | |
294 | struct bd957x_regulator_data *r) | |
295 | { | |
296 | if ((severity == REGULATOR_SEVERITY_ERR && | |
297 | r->ovd_notif != REGULATOR_EVENT_OVER_TEMP) || | |
298 | (severity == REGULATOR_SEVERITY_WARN && | |
299 | r->ovd_notif != REGULATOR_EVENT_OVER_TEMP_WARN)) { | |
300 | dev_warn(rdev_get_dev(rdev), | |
301 | "Can't support both thermal WARN and ERR\n"); | |
302 | if (severity == REGULATOR_SEVERITY_WARN) | |
303 | return true; | |
304 | } | |
305 | ||
306 | return false; | |
307 | } | |
308 | ||
309 | static int bd9576_set_ocp(struct regulator_dev *rdev, int lim_uA, int severity, | |
310 | bool enable) | |
311 | { | |
312 | struct bd957x_data *d; | |
313 | struct bd957x_regulator_data *r; | |
314 | int reg, mask; | |
315 | int Vfet, rfet; | |
316 | const struct linear_range *range; | |
317 | int num_ranges; | |
318 | ||
319 | if ((lim_uA && !enable) || (!lim_uA && enable)) | |
320 | return -EINVAL; | |
321 | ||
322 | r = container_of(rdev->desc, struct bd957x_regulator_data, desc); | |
323 | if (!r->oc_supported) | |
324 | return -EINVAL; | |
325 | ||
326 | d = rdev_get_drvdata(rdev); | |
327 | ||
328 | if (severity == REGULATOR_SEVERITY_PROT) { | |
329 | reg = r->ocp_reg; | |
330 | mask = r->ocp_mask; | |
331 | if (r->ocw_rfet) { | |
332 | range = voutS1_ocp_ranges; | |
333 | num_ranges = ARRAY_SIZE(voutS1_ocp_ranges); | |
334 | rfet = r->ocw_rfet / 1000; | |
335 | } else { | |
336 | range = voutS1_ocp_ranges_internal; | |
337 | num_ranges = ARRAY_SIZE(voutS1_ocp_ranges_internal); | |
338 | /* Internal values are already micro-amperes */ | |
339 | rfet = 1000; | |
340 | } | |
341 | } else { | |
342 | reg = r->ocw_reg; | |
343 | mask = r->ocw_mask; | |
344 | ||
345 | if (r->ocw_rfet) { | |
346 | range = voutS1_ocw_ranges; | |
347 | num_ranges = ARRAY_SIZE(voutS1_ocw_ranges); | |
348 | rfet = r->ocw_rfet / 1000; | |
349 | } else { | |
350 | range = voutS1_ocw_ranges_internal; | |
351 | num_ranges = ARRAY_SIZE(voutS1_ocw_ranges_internal); | |
352 | /* Internal values are already micro-amperes */ | |
353 | rfet = 1000; | |
354 | } | |
355 | ||
356 | /* We abuse uvd fields for OCW on VoutS1 */ | |
357 | if (r->uvd_notif) { | |
358 | /* | |
359 | * If both warning and error are requested, prioritize | |
360 | * ERROR configuration | |
361 | */ | |
362 | if (check_ocp_flag_mismatch(rdev, severity, r)) | |
363 | return 0; | |
364 | } else { | |
365 | bool warn = severity == REGULATOR_SEVERITY_WARN; | |
366 | ||
367 | bd9576_fill_ocp_flags(r, warn); | |
368 | } | |
369 | } | |
370 | ||
371 | /* | |
372 | * limits are given in uA, rfet is mOhm | |
373 | * Divide lim_uA by 1000 to get Vfet in uV. | |
374 | * (We expect both Rfet and limit uA to be magnitude of hundreds of | |
375 | * milli Amperes & milli Ohms => we should still have decent accuracy) | |
376 | */ | |
377 | Vfet = lim_uA/1000 * rfet; | |
378 | ||
379 | return bd9576_set_limit(range, num_ranges, d->regmap, | |
380 | reg, mask, Vfet); | |
381 | } | |
382 | ||
383 | static int bd9576_set_uvp(struct regulator_dev *rdev, int lim_uV, int severity, | |
384 | bool enable) | |
385 | { | |
386 | struct bd957x_data *d; | |
387 | struct bd957x_regulator_data *r; | |
388 | int mask, reg; | |
389 | ||
390 | if (severity == REGULATOR_SEVERITY_PROT) { | |
391 | if (!enable || lim_uV) | |
392 | return -EINVAL; | |
393 | return 0; | |
394 | } | |
395 | ||
396 | /* | |
397 | * BD9576 has enable control as a special value in limit reg. Can't | |
398 | * set limit but keep feature disabled or enable W/O given limit. | |
399 | */ | |
400 | if ((lim_uV && !enable) || (!lim_uV && enable)) | |
401 | return -EINVAL; | |
402 | ||
403 | r = container_of(rdev->desc, struct bd957x_regulator_data, desc); | |
404 | d = rdev_get_drvdata(rdev); | |
405 | ||
406 | mask = r->xvd_mask; | |
407 | reg = r->uvd_reg; | |
408 | /* | |
409 | * Check that there is no mismatch for what the detection IRQs are to | |
410 | * be used. | |
411 | */ | |
412 | if (r->uvd_notif) { | |
413 | if (check_uvd_flag_mismatch(rdev, severity, r)) | |
414 | return 0; | |
415 | } else { | |
416 | bd9576_fill_uvd_flags(r, severity == REGULATOR_SEVERITY_WARN); | |
417 | } | |
418 | ||
419 | return bd9576_set_limit(r->xvd_ranges, r->num_xvd_ranges, d->regmap, | |
420 | reg, mask, lim_uV); | |
421 | } | |
422 | ||
423 | static int bd9576_set_ovp(struct regulator_dev *rdev, int lim_uV, int severity, | |
424 | bool enable) | |
425 | { | |
426 | struct bd957x_data *d; | |
427 | struct bd957x_regulator_data *r; | |
428 | int mask, reg; | |
429 | ||
430 | if (severity == REGULATOR_SEVERITY_PROT) { | |
431 | if (!enable || lim_uV) | |
432 | return -EINVAL; | |
433 | return 0; | |
434 | } | |
435 | ||
436 | /* | |
437 | * BD9576 has enable control as a special value in limit reg. Can't | |
438 | * set limit but keep feature disabled or enable W/O given limit. | |
439 | */ | |
440 | if ((lim_uV && !enable) || (!lim_uV && enable)) | |
441 | return -EINVAL; | |
442 | ||
443 | r = container_of(rdev->desc, struct bd957x_regulator_data, desc); | |
444 | d = rdev_get_drvdata(rdev); | |
445 | ||
446 | mask = r->xvd_mask; | |
447 | reg = r->ovd_reg; | |
448 | /* | |
449 | * Check that there is no mismatch for what the detection IRQs are to | |
450 | * be used. | |
451 | */ | |
452 | if (r->ovd_notif) { | |
453 | if (check_ovd_flag_mismatch(rdev, severity, r)) | |
454 | return 0; | |
455 | } else { | |
456 | bd9576_fill_ovd_flags(r, severity == REGULATOR_SEVERITY_WARN); | |
457 | } | |
458 | ||
459 | return bd9576_set_limit(r->xvd_ranges, r->num_xvd_ranges, d->regmap, | |
460 | reg, mask, lim_uV); | |
461 | } | |
462 | ||
463 | ||
464 | static int bd9576_set_tw(struct regulator_dev *rdev, int lim, int severity, | |
465 | bool enable) | |
466 | { | |
467 | struct bd957x_data *d; | |
468 | struct bd957x_regulator_data *r; | |
469 | int i; | |
470 | ||
471 | /* | |
472 | * BD9576MUF has fixed temperature limits | |
473 | * The detection can only be enabled/disabled | |
474 | */ | |
475 | if (lim) | |
476 | return -EINVAL; | |
477 | ||
478 | /* Protection can't be disabled */ | |
479 | if (severity == REGULATOR_SEVERITY_PROT) { | |
480 | if (!enable) | |
481 | return -EINVAL; | |
482 | else | |
483 | return 0; | |
484 | } | |
485 | ||
486 | r = container_of(rdev->desc, struct bd957x_regulator_data, desc); | |
487 | d = rdev_get_drvdata(rdev); | |
488 | ||
489 | /* | |
490 | * Check that there is no mismatch for what the detection IRQs are to | |
491 | * be used. | |
492 | */ | |
493 | if (r->temp_notif) | |
494 | if (check_temp_flag_mismatch(rdev, severity, r)) | |
495 | return 0; | |
496 | ||
497 | bd9576_fill_temp_flags(r, enable, severity == REGULATOR_SEVERITY_WARN); | |
498 | ||
499 | if (enable) | |
500 | return regmap_update_bits(d->regmap, BD957X_REG_INT_THERM_MASK, | |
501 | BD9576_THERM_IRQ_MASK_TW, 0); | |
502 | ||
503 | /* | |
504 | * If any of the regulators is interested in thermal warning we keep IRQ | |
505 | * enabled. | |
506 | */ | |
507 | for (i = 0; i < BD9576_NUM_REGULATORS; i++) | |
508 | if (d->regulator_data[i].temp_notif) | |
509 | return 0; | |
510 | ||
511 | return regmap_update_bits(d->regmap, BD957X_REG_INT_THERM_MASK, | |
512 | BD9576_THERM_IRQ_MASK_TW, | |
513 | BD9576_THERM_IRQ_MASK_TW); | |
514 | } | |
515 | ||
516 | static const struct regulator_ops bd9573_vout34_ops = { | |
b014e9fa MV |
517 | .is_enabled = regulator_is_enabled_regmap, |
518 | .list_voltage = bd957x_vout34_list_voltage, | |
519 | .get_voltage_sel = regulator_get_voltage_sel_regmap, | |
520 | }; | |
521 | ||
e7bf1fa5 MV |
522 | static const struct regulator_ops bd9576_vout34_ops = { |
523 | .is_enabled = regulator_is_enabled_regmap, | |
524 | .list_voltage = bd957x_vout34_list_voltage, | |
525 | .get_voltage_sel = regulator_get_voltage_sel_regmap, | |
526 | .set_over_voltage_protection = bd9576_set_ovp, | |
527 | .set_under_voltage_protection = bd9576_set_uvp, | |
528 | .set_thermal_protection = bd9576_set_tw, | |
529 | }; | |
530 | ||
531 | static const struct regulator_ops bd9573_vouts1_regulator_ops = { | |
532 | .is_enabled = regulator_is_enabled_regmap, | |
533 | }; | |
534 | ||
535 | static const struct regulator_ops bd9576_vouts1_regulator_ops = { | |
536 | .is_enabled = regulator_is_enabled_regmap, | |
537 | .set_over_current_protection = bd9576_set_ocp, | |
538 | }; | |
539 | ||
540 | static const struct regulator_ops bd9573_ops = { | |
b014e9fa | 541 | .is_enabled = regulator_is_enabled_regmap, |
e7bf1fa5 MV |
542 | .list_voltage = bd957x_list_voltage, |
543 | .get_voltage_sel = regulator_get_voltage_sel_regmap, | |
b014e9fa MV |
544 | }; |
545 | ||
e7bf1fa5 | 546 | static const struct regulator_ops bd9576_ops = { |
b014e9fa MV |
547 | .is_enabled = regulator_is_enabled_regmap, |
548 | .list_voltage = bd957x_list_voltage, | |
549 | .get_voltage_sel = regulator_get_voltage_sel_regmap, | |
e7bf1fa5 MV |
550 | .set_over_voltage_protection = bd9576_set_ovp, |
551 | .set_under_voltage_protection = bd9576_set_uvp, | |
552 | .set_thermal_protection = bd9576_set_tw, | |
553 | }; | |
554 | ||
555 | static const struct regulator_ops *bd9573_ops_arr[] = { | |
556 | [BD957X_VD50] = &bd9573_ops, | |
557 | [BD957X_VD18] = &bd9573_ops, | |
558 | [BD957X_VDDDR] = &bd9573_vout34_ops, | |
559 | [BD957X_VD10] = &bd9573_vout34_ops, | |
560 | [BD957X_VOUTL1] = &bd9573_ops, | |
561 | [BD957X_VOUTS1] = &bd9573_vouts1_regulator_ops, | |
b014e9fa MV |
562 | }; |
563 | ||
e7bf1fa5 MV |
564 | static const struct regulator_ops *bd9576_ops_arr[] = { |
565 | [BD957X_VD50] = &bd9576_ops, | |
566 | [BD957X_VD18] = &bd9576_ops, | |
567 | [BD957X_VDDDR] = &bd9576_vout34_ops, | |
568 | [BD957X_VD10] = &bd9576_vout34_ops, | |
569 | [BD957X_VOUTL1] = &bd9576_ops, | |
570 | [BD957X_VOUTS1] = &bd9576_vouts1_regulator_ops, | |
571 | }; | |
572 | ||
573 | static int vouts1_get_fet_res(struct device_node *np, | |
574 | const struct regulator_desc *desc, | |
575 | struct regulator_config *cfg) | |
576 | { | |
577 | struct bd957x_regulator_data *data; | |
578 | int ret; | |
579 | u32 uohms; | |
580 | ||
581 | data = container_of(desc, struct bd957x_regulator_data, desc); | |
582 | ||
583 | ret = of_property_read_u32(np, "rohm,ocw-fet-ron-micro-ohms", &uohms); | |
584 | if (ret) { | |
585 | if (ret != -EINVAL) | |
586 | return ret; | |
587 | ||
588 | return 0; | |
589 | } | |
590 | data->ocw_rfet = uohms; | |
591 | return 0; | |
592 | } | |
593 | ||
594 | static struct bd957x_data bd957x_regulators = { | |
595 | .regulator_data = { | |
596 | { | |
597 | .desc = { | |
598 | .name = "VD50", | |
599 | .of_match = of_match_ptr("regulator-vd50"), | |
600 | .regulators_node = of_match_ptr("regulators"), | |
601 | .id = BD957X_VD50, | |
602 | .type = REGULATOR_VOLTAGE, | |
603 | .volt_table = &vout1_volt_table[0], | |
604 | .n_voltages = ARRAY_SIZE(vout1_volt_table), | |
605 | .vsel_reg = BD957X_REG_VOUT1_TUNE, | |
606 | .vsel_mask = BD957X_MASK_VOUT1_TUNE, | |
607 | .enable_reg = BD957X_REG_POW_TRIGGER1, | |
608 | .enable_mask = BD957X_REGULATOR_EN_MASK, | |
609 | .enable_val = BD957X_REGULATOR_DIS_VAL, | |
610 | .enable_is_inverted = true, | |
611 | .owner = THIS_MODULE, | |
612 | }, | |
613 | .xvd_ranges = vout1_xvd_ranges, | |
614 | .num_xvd_ranges = ARRAY_SIZE(vout1_xvd_ranges), | |
615 | .ovd_reg = BD9576_REG_VOUT1_OVD, | |
616 | .uvd_reg = BD9576_REG_VOUT1_UVD, | |
617 | .xvd_mask = BD9576_MASK_XVD, | |
b014e9fa | 618 | }, |
e7bf1fa5 MV |
619 | { |
620 | .desc = { | |
621 | .name = "VD18", | |
622 | .of_match = of_match_ptr("regulator-vd18"), | |
623 | .regulators_node = of_match_ptr("regulators"), | |
624 | .id = BD957X_VD18, | |
625 | .type = REGULATOR_VOLTAGE, | |
626 | .volt_table = &vout2_volt_table[0], | |
627 | .n_voltages = ARRAY_SIZE(vout2_volt_table), | |
628 | .vsel_reg = BD957X_REG_VOUT2_TUNE, | |
629 | .vsel_mask = BD957X_MASK_VOUT2_TUNE, | |
630 | .enable_reg = BD957X_REG_POW_TRIGGER2, | |
631 | .enable_mask = BD957X_REGULATOR_EN_MASK, | |
632 | .enable_val = BD957X_REGULATOR_DIS_VAL, | |
633 | .enable_is_inverted = true, | |
634 | .owner = THIS_MODULE, | |
635 | }, | |
636 | .xvd_ranges = vout234_xvd_ranges, | |
637 | .num_xvd_ranges = ARRAY_SIZE(vout234_xvd_ranges), | |
638 | .ovd_reg = BD9576_REG_VOUT2_OVD, | |
639 | .uvd_reg = BD9576_REG_VOUT2_UVD, | |
640 | .xvd_mask = BD9576_MASK_XVD, | |
b014e9fa | 641 | }, |
e7bf1fa5 MV |
642 | { |
643 | .desc = { | |
644 | .name = "VDDDR", | |
645 | .of_match = of_match_ptr("regulator-vdddr"), | |
646 | .regulators_node = of_match_ptr("regulators"), | |
647 | .id = BD957X_VDDDR, | |
648 | .type = REGULATOR_VOLTAGE, | |
649 | .n_voltages = BD957X_VOUTS34_NUM_VOLT, | |
650 | .vsel_reg = BD957X_REG_VOUT3_TUNE, | |
651 | .vsel_mask = BD957X_MASK_VOUT3_TUNE, | |
652 | .enable_reg = BD957X_REG_POW_TRIGGER3, | |
653 | .enable_mask = BD957X_REGULATOR_EN_MASK, | |
654 | .enable_val = BD957X_REGULATOR_DIS_VAL, | |
655 | .enable_is_inverted = true, | |
656 | .owner = THIS_MODULE, | |
657 | }, | |
658 | .ovd_reg = BD9576_REG_VOUT3_OVD, | |
659 | .uvd_reg = BD9576_REG_VOUT3_UVD, | |
660 | .xvd_mask = BD9576_MASK_XVD, | |
661 | .xvd_ranges = vout234_xvd_ranges, | |
662 | .num_xvd_ranges = ARRAY_SIZE(vout234_xvd_ranges), | |
b014e9fa | 663 | }, |
e7bf1fa5 MV |
664 | { |
665 | .desc = { | |
666 | .name = "VD10", | |
667 | .of_match = of_match_ptr("regulator-vd10"), | |
668 | .regulators_node = of_match_ptr("regulators"), | |
669 | .id = BD957X_VD10, | |
670 | .type = REGULATOR_VOLTAGE, | |
671 | .fixed_uV = BD957X_VOUTS4_BASE_VOLT, | |
672 | .n_voltages = BD957X_VOUTS34_NUM_VOLT, | |
673 | .vsel_reg = BD957X_REG_VOUT4_TUNE, | |
674 | .vsel_mask = BD957X_MASK_VOUT4_TUNE, | |
675 | .enable_reg = BD957X_REG_POW_TRIGGER4, | |
676 | .enable_mask = BD957X_REGULATOR_EN_MASK, | |
677 | .enable_val = BD957X_REGULATOR_DIS_VAL, | |
678 | .enable_is_inverted = true, | |
679 | .owner = THIS_MODULE, | |
680 | }, | |
681 | .xvd_ranges = vout234_xvd_ranges, | |
682 | .num_xvd_ranges = ARRAY_SIZE(vout234_xvd_ranges), | |
683 | .ovd_reg = BD9576_REG_VOUT4_OVD, | |
684 | .uvd_reg = BD9576_REG_VOUT4_UVD, | |
685 | .xvd_mask = BD9576_MASK_XVD, | |
b014e9fa | 686 | }, |
e7bf1fa5 MV |
687 | { |
688 | .desc = { | |
689 | .name = "VOUTL1", | |
690 | .of_match = of_match_ptr("regulator-voutl1"), | |
691 | .regulators_node = of_match_ptr("regulators"), | |
692 | .id = BD957X_VOUTL1, | |
693 | .type = REGULATOR_VOLTAGE, | |
694 | .volt_table = &voutl1_volt_table[0], | |
695 | .n_voltages = ARRAY_SIZE(voutl1_volt_table), | |
696 | .vsel_reg = BD957X_REG_VOUTL1_TUNE, | |
697 | .vsel_mask = BD957X_MASK_VOUTL1_TUNE, | |
698 | .enable_reg = BD957X_REG_POW_TRIGGERL1, | |
699 | .enable_mask = BD957X_REGULATOR_EN_MASK, | |
700 | .enable_val = BD957X_REGULATOR_DIS_VAL, | |
701 | .enable_is_inverted = true, | |
702 | .owner = THIS_MODULE, | |
703 | }, | |
704 | .xvd_ranges = voutL1_xvd_ranges, | |
705 | .num_xvd_ranges = ARRAY_SIZE(voutL1_xvd_ranges), | |
706 | .ovd_reg = BD9576_REG_VOUTL1_OVD, | |
707 | .uvd_reg = BD9576_REG_VOUTL1_UVD, | |
708 | .xvd_mask = BD9576_MASK_XVD, | |
b014e9fa | 709 | }, |
e7bf1fa5 MV |
710 | { |
711 | .desc = { | |
712 | .name = "VOUTS1", | |
713 | .of_match = of_match_ptr("regulator-vouts1"), | |
714 | .regulators_node = of_match_ptr("regulators"), | |
715 | .id = BD957X_VOUTS1, | |
716 | .type = REGULATOR_VOLTAGE, | |
717 | .n_voltages = 1, | |
718 | .fixed_uV = BD957X_VOUTS1_VOLT, | |
719 | .enable_reg = BD957X_REG_POW_TRIGGERS1, | |
720 | .enable_mask = BD957X_REGULATOR_EN_MASK, | |
721 | .enable_val = BD957X_REGULATOR_DIS_VAL, | |
722 | .enable_is_inverted = true, | |
723 | .owner = THIS_MODULE, | |
724 | .of_parse_cb = vouts1_get_fet_res, | |
725 | }, | |
726 | .oc_supported = true, | |
727 | .ocw_reg = BD9576_REG_VOUT1S_OCW, | |
728 | .ocw_mask = BD9576_MASK_VOUT1S_OCW, | |
729 | .ocp_reg = BD9576_REG_VOUT1S_OCP, | |
730 | .ocp_mask = BD9576_MASK_VOUT1S_OCP, | |
b014e9fa MV |
731 | }, |
732 | }, | |
733 | }; | |
734 | ||
e7bf1fa5 MV |
735 | static int bd9576_renable(struct regulator_irq_data *rid, int reg, int mask) |
736 | { | |
737 | int val, ret; | |
738 | struct bd957x_data *d = (struct bd957x_data *)rid->data; | |
739 | ||
740 | ret = regmap_read(d->regmap, reg, &val); | |
741 | if (ret) | |
742 | return REGULATOR_FAILED_RETRY; | |
743 | ||
744 | if (rid->opaque && rid->opaque == (val & mask)) { | |
745 | /* | |
746 | * It seems we stil have same status. Ack and return | |
747 | * information that we are still out of limits and core | |
748 | * should not enable IRQ | |
749 | */ | |
750 | regmap_write(d->regmap, reg, mask & val); | |
751 | return REGULATOR_ERROR_ON; | |
752 | } | |
753 | rid->opaque = 0; | |
754 | /* | |
755 | * Status was changed. Either prolem was solved or we have new issues. | |
756 | * Let's re-enable IRQs and be prepared to report problems again | |
757 | */ | |
758 | return REGULATOR_ERROR_CLEARED; | |
759 | } | |
760 | ||
761 | static int bd9576_uvd_renable(struct regulator_irq_data *rid) | |
762 | { | |
763 | return bd9576_renable(rid, BD957X_REG_INT_UVD_STAT, UVD_IRQ_VALID_MASK); | |
764 | } | |
765 | ||
766 | static int bd9576_ovd_renable(struct regulator_irq_data *rid) | |
767 | { | |
768 | return bd9576_renable(rid, BD957X_REG_INT_OVD_STAT, OVD_IRQ_VALID_MASK); | |
769 | } | |
770 | ||
771 | static int bd9576_temp_renable(struct regulator_irq_data *rid) | |
772 | { | |
773 | return bd9576_renable(rid, BD957X_REG_INT_THERM_STAT, | |
774 | BD9576_THERM_IRQ_MASK_TW); | |
775 | } | |
776 | ||
777 | static int bd9576_uvd_handler(int irq, struct regulator_irq_data *rid, | |
778 | unsigned long *dev_mask) | |
779 | { | |
780 | int val, ret, i; | |
781 | struct bd957x_data *d = (struct bd957x_data *)rid->data; | |
782 | ||
783 | ret = regmap_read(d->regmap, BD957X_REG_INT_UVD_STAT, &val); | |
784 | if (ret) | |
785 | return REGULATOR_FAILED_RETRY; | |
786 | ||
787 | *dev_mask = 0; | |
788 | ||
789 | rid->opaque = val & UVD_IRQ_VALID_MASK; | |
790 | ||
791 | /* | |
792 | * Go through the set status bits and report either error or warning | |
793 | * to the notifier depending on what was flagged in DT | |
794 | */ | |
795 | *dev_mask = val & BD9576_xVD_IRQ_MASK_VOUT1TO4; | |
796 | /* There is 1 bit gap in register after Vout1 .. Vout4 statuses */ | |
797 | *dev_mask |= ((val & BD9576_xVD_IRQ_MASK_VOUTL1) >> 1); | |
798 | /* | |
799 | * We (ab)use the uvd for OCW notification. DT parsing should | |
800 | * have added correct OCW flag to uvd_notif and uvd_err for S1 | |
801 | */ | |
802 | *dev_mask |= ((val & BD9576_UVD_IRQ_MASK_VOUTS1_OCW) >> 1); | |
803 | ||
804 | for_each_set_bit(i, dev_mask, 6) { | |
805 | struct bd957x_regulator_data *rdata; | |
806 | struct regulator_err_state *stat; | |
807 | ||
808 | rdata = &d->regulator_data[i]; | |
809 | stat = &rid->states[i]; | |
810 | ||
811 | stat->notifs = rdata->uvd_notif; | |
812 | stat->errors = rdata->uvd_err; | |
813 | } | |
814 | ||
815 | ret = regmap_write(d->regmap, BD957X_REG_INT_UVD_STAT, | |
816 | UVD_IRQ_VALID_MASK & val); | |
817 | ||
818 | return 0; | |
819 | } | |
820 | ||
821 | static int bd9576_ovd_handler(int irq, struct regulator_irq_data *rid, | |
822 | unsigned long *dev_mask) | |
823 | { | |
824 | int val, ret, i; | |
825 | struct bd957x_data *d = (struct bd957x_data *)rid->data; | |
826 | ||
827 | ret = regmap_read(d->regmap, BD957X_REG_INT_OVD_STAT, &val); | |
828 | if (ret) | |
829 | return REGULATOR_FAILED_RETRY; | |
830 | ||
831 | rid->opaque = val & OVD_IRQ_VALID_MASK; | |
832 | *dev_mask = 0; | |
833 | ||
834 | if (!(val & OVD_IRQ_VALID_MASK)) | |
835 | return 0; | |
836 | ||
837 | *dev_mask = val & BD9576_xVD_IRQ_MASK_VOUT1TO4; | |
838 | /* There is 1 bit gap in register after Vout1 .. Vout4 statuses */ | |
839 | *dev_mask |= ((val & BD9576_xVD_IRQ_MASK_VOUTL1) >> 1); | |
840 | ||
841 | for_each_set_bit(i, dev_mask, 5) { | |
842 | struct bd957x_regulator_data *rdata; | |
843 | struct regulator_err_state *stat; | |
844 | ||
845 | rdata = &d->regulator_data[i]; | |
846 | stat = &rid->states[i]; | |
847 | ||
848 | stat->notifs = rdata->ovd_notif; | |
849 | stat->errors = rdata->ovd_err; | |
850 | } | |
851 | ||
852 | /* Clear the sub-IRQ status */ | |
853 | regmap_write(d->regmap, BD957X_REG_INT_OVD_STAT, | |
854 | OVD_IRQ_VALID_MASK & val); | |
855 | ||
856 | return 0; | |
857 | } | |
858 | ||
859 | #define BD9576_DEV_MASK_ALL_REGULATORS 0x3F | |
860 | ||
861 | static int bd9576_thermal_handler(int irq, struct regulator_irq_data *rid, | |
862 | unsigned long *dev_mask) | |
863 | { | |
864 | int val, ret, i; | |
865 | struct bd957x_data *d = (struct bd957x_data *)rid->data; | |
866 | ||
867 | ret = regmap_read(d->regmap, BD957X_REG_INT_THERM_STAT, &val); | |
868 | if (ret) | |
869 | return REGULATOR_FAILED_RETRY; | |
870 | ||
871 | if (!(val & BD9576_THERM_IRQ_MASK_TW)) { | |
872 | *dev_mask = 0; | |
873 | return 0; | |
874 | } | |
875 | ||
876 | *dev_mask = BD9576_DEV_MASK_ALL_REGULATORS; | |
877 | ||
878 | for (i = 0; i < BD9576_NUM_REGULATORS; i++) { | |
879 | struct bd957x_regulator_data *rdata; | |
880 | struct regulator_err_state *stat; | |
881 | ||
882 | rdata = &d->regulator_data[i]; | |
883 | stat = &rid->states[i]; | |
884 | ||
885 | stat->notifs = rdata->temp_notif; | |
886 | stat->errors = rdata->temp_err; | |
887 | } | |
888 | ||
889 | /* Clear the sub-IRQ status */ | |
890 | regmap_write(d->regmap, BD957X_REG_INT_THERM_STAT, | |
891 | BD9576_THERM_IRQ_MASK_TW); | |
892 | ||
893 | return 0; | |
894 | } | |
895 | ||
b014e9fa MV |
896 | static int bd957x_probe(struct platform_device *pdev) |
897 | { | |
e7bf1fa5 MV |
898 | int i; |
899 | unsigned int num_reg_data; | |
ddf275b2 | 900 | bool vout_mode, ddr_sel, may_have_irqs = false; |
b014e9fa | 901 | struct regmap *regmap; |
e7bf1fa5 | 902 | struct bd957x_data *ic_data; |
b014e9fa | 903 | struct regulator_config config = { 0 }; |
e7bf1fa5 MV |
904 | /* All regulators are related to UVD and thermal IRQs... */ |
905 | struct regulator_dev *rdevs[BD9576_NUM_REGULATORS]; | |
906 | /* ...But VoutS1 is not flagged by OVD IRQ */ | |
907 | struct regulator_dev *ovd_devs[BD9576_NUM_OVD_REGULATORS]; | |
908 | static const struct regulator_irq_desc bd9576_notif_uvd = { | |
909 | .name = "bd9576-uvd", | |
910 | .irq_off_ms = 1000, | |
911 | .map_event = bd9576_uvd_handler, | |
912 | .renable = bd9576_uvd_renable, | |
913 | .data = &bd957x_regulators, | |
914 | }; | |
915 | static const struct regulator_irq_desc bd9576_notif_ovd = { | |
916 | .name = "bd9576-ovd", | |
917 | .irq_off_ms = 1000, | |
918 | .map_event = bd9576_ovd_handler, | |
919 | .renable = bd9576_ovd_renable, | |
920 | .data = &bd957x_regulators, | |
921 | }; | |
922 | static const struct regulator_irq_desc bd9576_notif_temp = { | |
923 | .name = "bd9576-temp", | |
924 | .irq_off_ms = 1000, | |
925 | .map_event = bd9576_thermal_handler, | |
926 | .renable = bd9576_temp_renable, | |
927 | .data = &bd957x_regulators, | |
928 | }; | |
b014e9fa MV |
929 | enum rohm_chip_type chip = platform_get_device_id(pdev)->driver_data; |
930 | ||
e7bf1fa5 MV |
931 | num_reg_data = ARRAY_SIZE(bd957x_regulators.regulator_data); |
932 | ||
933 | ic_data = &bd957x_regulators; | |
934 | ||
b014e9fa MV |
935 | regmap = dev_get_regmap(pdev->dev.parent, NULL); |
936 | if (!regmap) { | |
937 | dev_err(&pdev->dev, "No regmap\n"); | |
938 | return -EINVAL; | |
939 | } | |
e7bf1fa5 MV |
940 | |
941 | ic_data->regmap = regmap; | |
b014e9fa MV |
942 | vout_mode = of_property_read_bool(pdev->dev.parent->of_node, |
943 | "rohm,vout1-en-low"); | |
944 | if (vout_mode) { | |
945 | struct gpio_desc *en; | |
946 | ||
947 | dev_dbg(&pdev->dev, "GPIO controlled mode\n"); | |
948 | ||
949 | /* VOUT1 enable state judged by VOUT1_EN pin */ | |
950 | /* See if we have GPIO defined */ | |
951 | en = devm_gpiod_get_from_of_node(&pdev->dev, | |
952 | pdev->dev.parent->of_node, | |
953 | "rohm,vout1-en-gpios", 0, | |
954 | GPIOD_OUT_LOW, "vout1-en"); | |
955 | if (!IS_ERR(en)) { | |
956 | /* VOUT1_OPS gpio ctrl */ | |
957 | /* | |
958 | * Regulator core prioritizes the ena_gpio over | |
959 | * enable/disable/is_enabled callbacks so no need to | |
960 | * clear them. We can still use same ops | |
961 | */ | |
962 | config.ena_gpiod = en; | |
963 | } else { | |
964 | /* | |
965 | * In theory it is possible someone wants to set | |
966 | * vout1-en LOW during OTP loading and set VOUT1 to be | |
967 | * controlled by GPIO - but control the GPIO from some | |
968 | * where else than this driver. For that to work we | |
969 | * should unset the is_enabled callback here. | |
970 | * | |
971 | * I believe such case where rohm,vout1-en-low is set | |
972 | * and vout1-en-gpios is not is likely to be a | |
973 | * misconfiguration. So let's just err out for now. | |
974 | */ | |
975 | dev_err(&pdev->dev, | |
976 | "Failed to get VOUT1 control GPIO\n"); | |
977 | return PTR_ERR(en); | |
978 | } | |
979 | } | |
980 | ||
981 | /* | |
982 | * If more than one PMIC needs to be controlled by same processor then | |
983 | * allocate the regulator data array here and use bd9576_regulators as | |
984 | * template. At the moment I see no such use-case so I spare some | |
985 | * bytes and use bd9576_regulators directly for non-constant configs | |
986 | * like DDR voltage selection. | |
987 | */ | |
e7bf1fa5 | 988 | platform_set_drvdata(pdev, ic_data); |
b014e9fa MV |
989 | ddr_sel = of_property_read_bool(pdev->dev.parent->of_node, |
990 | "rohm,ddr-sel-low"); | |
991 | if (ddr_sel) | |
e7bf1fa5 | 992 | ic_data->regulator_data[2].desc.fixed_uV = 1350000; |
b014e9fa | 993 | else |
e7bf1fa5 | 994 | ic_data->regulator_data[2].desc.fixed_uV = 1500000; |
b014e9fa MV |
995 | |
996 | switch (chip) { | |
997 | case ROHM_CHIP_TYPE_BD9576: | |
e7bf1fa5 | 998 | may_have_irqs = true; |
b014e9fa MV |
999 | dev_dbg(&pdev->dev, "Found BD9576MUF\n"); |
1000 | break; | |
1001 | case ROHM_CHIP_TYPE_BD9573: | |
184cdb8f | 1002 | dev_dbg(&pdev->dev, "Found BD9573MUF\n"); |
b014e9fa MV |
1003 | break; |
1004 | default: | |
1005 | dev_err(&pdev->dev, "Unsupported chip type\n"); | |
320fcd6b | 1006 | return -EINVAL; |
b014e9fa MV |
1007 | } |
1008 | ||
e7bf1fa5 MV |
1009 | for (i = 0; i < num_reg_data; i++) { |
1010 | struct regulator_desc *d; | |
1011 | ||
1012 | d = &ic_data->regulator_data[i].desc; | |
1013 | ||
1014 | ||
1015 | if (may_have_irqs) { | |
1016 | if (d->id >= ARRAY_SIZE(bd9576_ops_arr)) | |
1017 | return -EINVAL; | |
1018 | ||
1019 | d->ops = bd9576_ops_arr[d->id]; | |
1020 | } else { | |
1021 | if (d->id >= ARRAY_SIZE(bd9573_ops_arr)) | |
1022 | return -EINVAL; | |
1023 | ||
1024 | d->ops = bd9573_ops_arr[d->id]; | |
1025 | } | |
1026 | } | |
1027 | ||
b014e9fa MV |
1028 | config.dev = pdev->dev.parent; |
1029 | config.regmap = regmap; | |
e7bf1fa5 | 1030 | config.driver_data = ic_data; |
b014e9fa MV |
1031 | |
1032 | for (i = 0; i < num_reg_data; i++) { | |
1033 | ||
e7bf1fa5 MV |
1034 | struct bd957x_regulator_data *r = &ic_data->regulator_data[i]; |
1035 | const struct regulator_desc *desc = &r->desc; | |
b014e9fa | 1036 | |
e7bf1fa5 MV |
1037 | r->rdev = devm_regulator_register(&pdev->dev, desc, |
1038 | &config); | |
1039 | if (IS_ERR(r->rdev)) { | |
b014e9fa MV |
1040 | dev_err(&pdev->dev, |
1041 | "failed to register %s regulator\n", | |
1042 | desc->name); | |
e7bf1fa5 | 1043 | return PTR_ERR(r->rdev); |
b014e9fa MV |
1044 | } |
1045 | /* | |
1046 | * Clear the VOUT1 GPIO setting - rest of the regulators do not | |
1047 | * support GPIO control | |
1048 | */ | |
1049 | config.ena_gpiod = NULL; | |
e7bf1fa5 MV |
1050 | |
1051 | if (!may_have_irqs) | |
1052 | continue; | |
1053 | ||
1054 | rdevs[i] = r->rdev; | |
1055 | if (i < BD957X_VOUTS1) | |
1056 | ovd_devs[i] = r->rdev; | |
b014e9fa | 1057 | } |
e7bf1fa5 MV |
1058 | if (may_have_irqs) { |
1059 | void *ret; | |
1060 | /* | |
1061 | * We can add both the possible error and warning flags here | |
1062 | * because the core uses these only for status clearing and | |
1063 | * if we use warnings - errors are always clear and the other | |
1064 | * way around. We can also add CURRENT flag for all regulators | |
1065 | * because it is never set if it is not supported. Same applies | |
1066 | * to setting UVD for VoutS1 - it is not accidentally cleared | |
1067 | * as it is never set. | |
1068 | */ | |
1069 | int uvd_errs = REGULATOR_ERROR_UNDER_VOLTAGE | | |
1070 | REGULATOR_ERROR_UNDER_VOLTAGE_WARN | | |
1071 | REGULATOR_ERROR_OVER_CURRENT | | |
1072 | REGULATOR_ERROR_OVER_CURRENT_WARN; | |
1073 | int ovd_errs = REGULATOR_ERROR_OVER_VOLTAGE_WARN | | |
1074 | REGULATOR_ERROR_REGULATION_OUT; | |
1075 | int temp_errs = REGULATOR_ERROR_OVER_TEMP | | |
1076 | REGULATOR_ERROR_OVER_TEMP_WARN; | |
1077 | int irq; | |
1078 | ||
1079 | irq = platform_get_irq_byname(pdev, "bd9576-uvd"); | |
1080 | ||
1081 | /* Register notifiers - can fail if IRQ is not given */ | |
1082 | ret = devm_regulator_irq_helper(&pdev->dev, &bd9576_notif_uvd, | |
1083 | irq, 0, uvd_errs, NULL, | |
1084 | &rdevs[0], | |
1085 | BD9576_NUM_REGULATORS); | |
1086 | if (IS_ERR(ret)) { | |
1087 | if (PTR_ERR(ret) == -EPROBE_DEFER) | |
1088 | return -EPROBE_DEFER; | |
1089 | ||
1090 | dev_warn(&pdev->dev, "UVD disabled %pe\n", ret); | |
1091 | } | |
1092 | ||
1093 | irq = platform_get_irq_byname(pdev, "bd9576-ovd"); | |
1094 | ||
1095 | ret = devm_regulator_irq_helper(&pdev->dev, &bd9576_notif_ovd, | |
1096 | irq, 0, ovd_errs, NULL, | |
1097 | &ovd_devs[0], | |
1098 | BD9576_NUM_OVD_REGULATORS); | |
1099 | if (IS_ERR(ret)) { | |
1100 | if (PTR_ERR(ret) == -EPROBE_DEFER) | |
1101 | return -EPROBE_DEFER; | |
1102 | ||
1103 | dev_warn(&pdev->dev, "OVD disabled %pe\n", ret); | |
1104 | } | |
1105 | irq = platform_get_irq_byname(pdev, "bd9576-temp"); | |
1106 | ||
1107 | ret = devm_regulator_irq_helper(&pdev->dev, &bd9576_notif_temp, | |
1108 | irq, 0, temp_errs, NULL, | |
1109 | &rdevs[0], | |
1110 | BD9576_NUM_REGULATORS); | |
1111 | if (IS_ERR(ret)) { | |
1112 | if (PTR_ERR(ret) == -EPROBE_DEFER) | |
1113 | return -EPROBE_DEFER; | |
b014e9fa | 1114 | |
e7bf1fa5 MV |
1115 | dev_warn(&pdev->dev, "Thermal warning disabled %pe\n", |
1116 | ret); | |
1117 | } | |
1118 | } | |
320fcd6b | 1119 | return 0; |
b014e9fa MV |
1120 | } |
1121 | ||
1122 | static const struct platform_device_id bd957x_pmic_id[] = { | |
e71e7d3d MV |
1123 | { "bd9573-regulator", ROHM_CHIP_TYPE_BD9573 }, |
1124 | { "bd9576-regulator", ROHM_CHIP_TYPE_BD9576 }, | |
b014e9fa MV |
1125 | { }, |
1126 | }; | |
1127 | MODULE_DEVICE_TABLE(platform, bd957x_pmic_id); | |
1128 | ||
1129 | static struct platform_driver bd957x_regulator = { | |
1130 | .driver = { | |
1131 | .name = "bd957x-pmic", | |
1132 | }, | |
1133 | .probe = bd957x_probe, | |
1134 | .id_table = bd957x_pmic_id, | |
1135 | }; | |
1136 | ||
1137 | module_platform_driver(bd957x_regulator); | |
1138 | ||
1139 | MODULE_AUTHOR("Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>"); | |
1140 | MODULE_DESCRIPTION("ROHM BD9576/BD9573 voltage regulator driver"); | |
1141 | MODULE_LICENSE("GPL"); | |
1142 | MODULE_ALIAS("platform:bd957x-pmic"); |