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