1 | // SPDX-License-Identifier: GPL-2.0+ |
2 | |
3 | #include <dt-bindings/regulator/richtek,rt5190a-regulator.h> |
4 | #include <linux/bits.h> |
5 | #include <linux/i2c.h> |
6 | #include <linux/interrupt.h> |
7 | #include <linux/kernel.h> |
8 | #include <linux/module.h> |
9 | #include <linux/of.h> |
10 | #include <linux/property.h> |
11 | #include <linux/regmap.h> |
12 | #include <linux/regulator/driver.h> |
13 | #include <linux/regulator/machine.h> |
14 | #include <linux/regulator/of_regulator.h> |
15 | |
16 | #define RT5190A_REG_MANUFACTURE 0x00 |
17 | #define RT5190A_REG_BUCK2VSEL 0x04 |
18 | #define RT5190A_REG_BUCK3VSEL 0x05 |
19 | #define RT5190A_REG_DCDCCNTL 0x06 |
20 | #define RT5190A_REG_ENABLE 0x07 |
21 | #define RT5190A_REG_DISCHARGE 0x09 |
22 | #define RT5190A_REG_PROTMODE 0x0A |
23 | #define RT5190A_REG_MUTECNTL 0x0B |
24 | #define RT5190A_REG_PGSTAT 0x0F |
25 | #define RT5190A_REG_OVINT 0x10 |
26 | #define RT5190A_REG_HOTDIEMASK 0x17 |
27 | |
28 | #define RT5190A_VSEL_MASK GENMASK(6, 0) |
29 | #define RT5190A_RID_BITMASK(rid) BIT(rid + 1) |
30 | #define RT5190A_BUCK1_DISCHG_MASK GENMASK(1, 0) |
31 | #define RT5190A_BUCK1_DISCHG_ONVAL 0x01 |
32 | #define RT5190A_OVERVOLT_MASK GENMASK(7, 0) |
33 | #define RT5190A_UNDERVOLT_MASK GENMASK(15, 8) |
34 | #define RT5190A_CH234OT_MASK BIT(29) |
35 | #define RT5190A_CHIPOT_MASK BIT(28) |
36 | |
37 | #define RT5190A_BUCK23_MINUV 600000 |
38 | #define RT5190A_BUCK23_MAXUV 1400000 |
39 | #define RT5190A_BUCK23_STEPUV 10000 |
40 | #define RT5190A_BUCK23_STEPNUM ((1400000 - 600000) / 10000 + 1) |
41 | |
42 | enum { |
43 | RT5190A_IDX_BUCK1 = 0, |
44 | RT5190A_IDX_BUCK2, |
45 | RT5190A_IDX_BUCK3, |
46 | RT5190A_IDX_BUCK4, |
47 | RT5190A_IDX_LDO, |
48 | RT5190A_MAX_IDX |
49 | }; |
50 | |
51 | struct rt5190a_priv { |
52 | struct device *dev; |
53 | struct regmap *regmap; |
54 | struct regulator_desc rdesc[RT5190A_MAX_IDX]; |
55 | struct regulator_dev *rdev[RT5190A_MAX_IDX]; |
56 | }; |
57 | |
58 | static int rt5190a_get_error_flags(struct regulator_dev *rdev, |
59 | unsigned int *flags) |
60 | { |
61 | struct regmap *regmap = rdev_get_regmap(rdev); |
62 | int rid = rdev_get_id(rdev); |
63 | unsigned int pgood_stat; |
64 | int ret; |
65 | |
66 | ret = regmap_read(map: regmap, RT5190A_REG_PGSTAT, val: &pgood_stat); |
67 | if (ret) |
68 | return ret; |
69 | |
70 | if (!(pgood_stat & RT5190A_RID_BITMASK(rid))) |
71 | *flags = REGULATOR_ERROR_FAIL; |
72 | else |
73 | *flags = 0; |
74 | |
75 | return 0; |
76 | } |
77 | |
78 | static int rt5190a_fixed_buck_set_mode(struct regulator_dev *rdev, |
79 | unsigned int mode) |
80 | { |
81 | struct regmap *regmap = rdev_get_regmap(rdev); |
82 | int rid = rdev_get_id(rdev); |
83 | unsigned int mask = RT5190A_RID_BITMASK(rid), val; |
84 | |
85 | switch (mode) { |
86 | case REGULATOR_MODE_FAST: |
87 | val = mask; |
88 | break; |
89 | case REGULATOR_MODE_NORMAL: |
90 | val = 0; |
91 | break; |
92 | default: |
93 | return -EINVAL; |
94 | } |
95 | |
96 | return regmap_update_bits(map: regmap, RT5190A_REG_DCDCCNTL, mask, val); |
97 | } |
98 | |
99 | static unsigned int rt5190a_fixed_buck_get_mode(struct regulator_dev *rdev) |
100 | { |
101 | struct regmap *regmap = rdev_get_regmap(rdev); |
102 | int rid = rdev_get_id(rdev); |
103 | unsigned int val; |
104 | int ret; |
105 | |
106 | ret = regmap_read(map: regmap, RT5190A_REG_DCDCCNTL, val: &val); |
107 | if (ret) { |
108 | dev_err(&rdev->dev, "Failed to get mode [%d]\n" , ret); |
109 | return ret; |
110 | } |
111 | |
112 | if (val & RT5190A_RID_BITMASK(rid)) |
113 | return REGULATOR_MODE_FAST; |
114 | |
115 | return REGULATOR_MODE_NORMAL; |
116 | } |
117 | |
118 | static const struct regulator_ops rt5190a_ranged_buck_ops = { |
119 | .enable = regulator_enable_regmap, |
120 | .disable = regulator_disable_regmap, |
121 | .is_enabled = regulator_is_enabled_regmap, |
122 | .set_voltage_sel = regulator_set_voltage_sel_regmap, |
123 | .get_voltage_sel = regulator_get_voltage_sel_regmap, |
124 | .list_voltage = regulator_list_voltage_linear, |
125 | .set_active_discharge = regulator_set_active_discharge_regmap, |
126 | .get_error_flags = rt5190a_get_error_flags, |
127 | }; |
128 | |
129 | static const struct regulator_ops rt5190a_fixed_buck_ops = { |
130 | .enable = regulator_enable_regmap, |
131 | .disable = regulator_disable_regmap, |
132 | .is_enabled = regulator_is_enabled_regmap, |
133 | .set_active_discharge = regulator_set_active_discharge_regmap, |
134 | .set_mode = rt5190a_fixed_buck_set_mode, |
135 | .get_mode = rt5190a_fixed_buck_get_mode, |
136 | .get_error_flags = rt5190a_get_error_flags, |
137 | }; |
138 | |
139 | static const struct regulator_ops rt5190a_fixed_ldo_ops = { |
140 | .enable = regulator_enable_regmap, |
141 | .disable = regulator_disable_regmap, |
142 | .is_enabled = regulator_is_enabled_regmap, |
143 | .set_active_discharge = regulator_set_active_discharge_regmap, |
144 | .get_error_flags = rt5190a_get_error_flags, |
145 | }; |
146 | |
147 | static irqreturn_t rt5190a_irq_handler(int irq, void *data) |
148 | { |
149 | struct rt5190a_priv *priv = data; |
150 | __le32 raws; |
151 | unsigned int events, fields; |
152 | static const struct { |
153 | unsigned int bitmask; |
154 | unsigned int report; |
155 | } event_tbl[] = { |
156 | { RT5190A_OVERVOLT_MASK, REGULATOR_ERROR_REGULATION_OUT }, |
157 | { RT5190A_UNDERVOLT_MASK, REGULATOR_ERROR_UNDER_VOLTAGE } |
158 | }; |
159 | int i, j, ret; |
160 | |
161 | ret = regmap_raw_read(map: priv->regmap, RT5190A_REG_OVINT, val: &raws, |
162 | val_len: sizeof(raws)); |
163 | if (ret) { |
164 | dev_err(priv->dev, "Failed to read events\n" ); |
165 | return IRQ_NONE; |
166 | } |
167 | |
168 | events = le32_to_cpu(raws); |
169 | |
170 | ret = regmap_raw_write(map: priv->regmap, RT5190A_REG_OVINT, val: &raws, |
171 | val_len: sizeof(raws)); |
172 | if (ret) |
173 | dev_err(priv->dev, "Failed to write-clear events\n" ); |
174 | |
175 | /* Handle OV,UV events */ |
176 | for (i = 0; i < ARRAY_SIZE(event_tbl); i++) { |
177 | fields = events & event_tbl[i].bitmask; |
178 | fields >>= ffs(event_tbl[i].bitmask) - 1; |
179 | |
180 | for (j = 0; j < RT5190A_MAX_IDX; j++) { |
181 | if (!(fields & RT5190A_RID_BITMASK(j))) |
182 | continue; |
183 | |
184 | regulator_notifier_call_chain(rdev: priv->rdev[j], |
185 | event: event_tbl[i].report, |
186 | NULL); |
187 | } |
188 | } |
189 | |
190 | /* Handle CH234 OT event */ |
191 | if (events & RT5190A_CH234OT_MASK) { |
192 | for (j = RT5190A_IDX_BUCK2; j < RT5190A_IDX_LDO; j++) { |
193 | regulator_notifier_call_chain(rdev: priv->rdev[j], |
194 | REGULATOR_ERROR_OVER_TEMP, |
195 | NULL); |
196 | } |
197 | } |
198 | |
199 | /* Warning if CHIP OT occur */ |
200 | if (events & RT5190A_CHIPOT_MASK) |
201 | dev_warn(priv->dev, "CHIP overheat\n" ); |
202 | |
203 | return IRQ_HANDLED; |
204 | } |
205 | |
206 | static unsigned int rt5190a_of_map_mode(unsigned int mode) |
207 | { |
208 | switch (mode) { |
209 | case RT5190A_OPMODE_AUTO: |
210 | return REGULATOR_MODE_NORMAL; |
211 | case RT5190A_OPMODE_FPWM: |
212 | return REGULATOR_MODE_FAST; |
213 | default: |
214 | return REGULATOR_MODE_INVALID; |
215 | } |
216 | } |
217 | |
218 | static int rt5190a_of_parse_cb(struct rt5190a_priv *priv, int rid, |
219 | struct of_regulator_match *match) |
220 | { |
221 | struct regulator_desc *desc = priv->rdesc + rid; |
222 | struct regulator_init_data *init_data = match->init_data; |
223 | struct device_node *np = match->of_node; |
224 | bool latchup_enable; |
225 | unsigned int mask = RT5190A_RID_BITMASK(rid), val; |
226 | |
227 | if (!init_data) |
228 | return 0; |
229 | |
230 | switch (rid) { |
231 | case RT5190A_IDX_BUCK1: |
232 | case RT5190A_IDX_BUCK4: |
233 | case RT5190A_IDX_LDO: |
234 | init_data->constraints.apply_uV = 0; |
235 | |
236 | if (init_data->constraints.min_uV == |
237 | init_data->constraints.max_uV) |
238 | desc->fixed_uV = init_data->constraints.min_uV; |
239 | else { |
240 | dev_err(priv->dev, |
241 | "Variable voltage for fixed regulator\n" ); |
242 | return -EINVAL; |
243 | } |
244 | break; |
245 | default: |
246 | break; |
247 | } |
248 | |
249 | latchup_enable = of_property_read_bool(np, propname: "richtek,latchup-enable" ); |
250 | |
251 | /* latchup: 0, default hiccup: 1 */ |
252 | val = !latchup_enable ? mask : 0; |
253 | |
254 | return regmap_update_bits(map: priv->regmap, RT5190A_REG_PROTMODE, mask, val); |
255 | } |
256 | |
257 | static void rt5190a_fillin_regulator_desc(struct regulator_desc *desc, int rid) |
258 | { |
259 | static const char * const regu_name[] = { "buck1" , "buck2" , |
260 | "buck3" , "buck4" , |
261 | "ldo" }; |
262 | static const char * const supply[] = { NULL, "vin2" , "vin3" , "vin4" , |
263 | "vinldo" }; |
264 | |
265 | desc->name = regu_name[rid]; |
266 | desc->supply_name = supply[rid]; |
267 | desc->owner = THIS_MODULE; |
268 | desc->type = REGULATOR_VOLTAGE; |
269 | desc->id = rid; |
270 | desc->enable_reg = RT5190A_REG_ENABLE; |
271 | desc->enable_mask = RT5190A_RID_BITMASK(rid); |
272 | desc->active_discharge_reg = RT5190A_REG_DISCHARGE; |
273 | desc->active_discharge_mask = RT5190A_RID_BITMASK(rid); |
274 | desc->active_discharge_on = RT5190A_RID_BITMASK(rid); |
275 | |
276 | switch (rid) { |
277 | case RT5190A_IDX_BUCK1: |
278 | desc->active_discharge_mask = RT5190A_BUCK1_DISCHG_MASK; |
279 | desc->active_discharge_on = RT5190A_BUCK1_DISCHG_ONVAL; |
280 | desc->n_voltages = 1; |
281 | desc->ops = &rt5190a_fixed_buck_ops; |
282 | desc->of_map_mode = rt5190a_of_map_mode; |
283 | break; |
284 | case RT5190A_IDX_BUCK2: |
285 | desc->vsel_reg = RT5190A_REG_BUCK2VSEL; |
286 | desc->vsel_mask = RT5190A_VSEL_MASK; |
287 | desc->min_uV = RT5190A_BUCK23_MINUV; |
288 | desc->uV_step = RT5190A_BUCK23_STEPUV; |
289 | desc->n_voltages = RT5190A_BUCK23_STEPNUM; |
290 | desc->ops = &rt5190a_ranged_buck_ops; |
291 | break; |
292 | case RT5190A_IDX_BUCK3: |
293 | desc->vsel_reg = RT5190A_REG_BUCK3VSEL; |
294 | desc->vsel_mask = RT5190A_VSEL_MASK; |
295 | desc->min_uV = RT5190A_BUCK23_MINUV; |
296 | desc->uV_step = RT5190A_BUCK23_STEPUV; |
297 | desc->n_voltages = RT5190A_BUCK23_STEPNUM; |
298 | desc->ops = &rt5190a_ranged_buck_ops; |
299 | break; |
300 | case RT5190A_IDX_BUCK4: |
301 | desc->n_voltages = 1; |
302 | desc->ops = &rt5190a_fixed_buck_ops; |
303 | desc->of_map_mode = rt5190a_of_map_mode; |
304 | break; |
305 | case RT5190A_IDX_LDO: |
306 | desc->n_voltages = 1; |
307 | desc->ops = &rt5190a_fixed_ldo_ops; |
308 | break; |
309 | } |
310 | } |
311 | |
312 | static struct of_regulator_match rt5190a_regulator_match[] = { |
313 | { .name = "buck1" , }, |
314 | { .name = "buck2" , }, |
315 | { .name = "buck3" , }, |
316 | { .name = "buck4" , }, |
317 | { .name = "ldo" , } |
318 | }; |
319 | |
320 | static int rt5190a_parse_regulator_dt_data(struct rt5190a_priv *priv) |
321 | { |
322 | struct device_node *regulator_np; |
323 | struct regulator_desc *reg_desc; |
324 | struct of_regulator_match *match; |
325 | int i, ret; |
326 | |
327 | for (i = 0; i < RT5190A_MAX_IDX; i++) { |
328 | reg_desc = priv->rdesc + i; |
329 | match = rt5190a_regulator_match + i; |
330 | |
331 | rt5190a_fillin_regulator_desc(desc: reg_desc, rid: i); |
332 | |
333 | match->desc = reg_desc; |
334 | } |
335 | |
336 | regulator_np = of_get_child_by_name(node: priv->dev->of_node, name: "regulators" ); |
337 | if (!regulator_np) { |
338 | dev_err(priv->dev, "Could not find 'regulators' node\n" ); |
339 | return -ENODEV; |
340 | } |
341 | |
342 | ret = of_regulator_match(dev: priv->dev, node: regulator_np, |
343 | matches: rt5190a_regulator_match, |
344 | ARRAY_SIZE(rt5190a_regulator_match)); |
345 | |
346 | of_node_put(node: regulator_np); |
347 | |
348 | if (ret < 0) { |
349 | dev_err(priv->dev, |
350 | "Error parsing regulator init data: %d\n" , ret); |
351 | return ret; |
352 | } |
353 | |
354 | for (i = 0; i < RT5190A_MAX_IDX; i++) { |
355 | match = rt5190a_regulator_match + i; |
356 | |
357 | ret = rt5190a_of_parse_cb(priv, rid: i, match); |
358 | if (ret) { |
359 | dev_err(priv->dev, "Failed in [%d] of_parse_cb\n" , i); |
360 | return ret; |
361 | } |
362 | } |
363 | |
364 | return 0; |
365 | } |
366 | |
367 | static const struct reg_sequence rt5190a_init_patch[] = { |
368 | { 0x09, 0x3d, }, |
369 | { 0x0a, 0x3e, }, |
370 | { 0x0b, 0x01, }, |
371 | { 0x10, 0xff, }, |
372 | { 0x11, 0xff, }, |
373 | { 0x12, 0xff, }, |
374 | { 0x13, 0xff, }, |
375 | { 0x14, 0, }, |
376 | { 0x15, 0, }, |
377 | { 0x16, 0x3e, }, |
378 | { 0x17, 0, } |
379 | }; |
380 | |
381 | static int rt5190a_device_initialize(struct rt5190a_priv *priv) |
382 | { |
383 | bool mute_enable; |
384 | int ret; |
385 | |
386 | ret = regmap_register_patch(map: priv->regmap, regs: rt5190a_init_patch, |
387 | ARRAY_SIZE(rt5190a_init_patch)); |
388 | if (ret) { |
389 | dev_err(priv->dev, "Failed to do register patch\n" ); |
390 | return ret; |
391 | } |
392 | |
393 | mute_enable = device_property_read_bool(dev: priv->dev, |
394 | propname: "richtek,mute-enable" ); |
395 | |
396 | if (mute_enable) { |
397 | ret = regmap_write(map: priv->regmap, RT5190A_REG_MUTECNTL, val: 0x00); |
398 | if (ret) { |
399 | dev_err(priv->dev, "Failed to enable mute function\n" ); |
400 | return ret; |
401 | } |
402 | } |
403 | |
404 | return 0; |
405 | } |
406 | |
407 | static int rt5190a_device_check(struct rt5190a_priv *priv) |
408 | { |
409 | u16 devid; |
410 | int ret; |
411 | |
412 | ret = regmap_raw_read(map: priv->regmap, RT5190A_REG_MANUFACTURE, val: &devid, |
413 | val_len: sizeof(devid)); |
414 | if (ret) |
415 | return ret; |
416 | |
417 | if (devid) { |
418 | dev_err(priv->dev, "Incorrect device id 0x%04x\n" , devid); |
419 | return -ENODEV; |
420 | } |
421 | |
422 | return 0; |
423 | } |
424 | |
425 | static const struct regmap_config rt5190a_regmap_config = { |
426 | .reg_bits = 8, |
427 | .val_bits = 8, |
428 | .max_register = RT5190A_REG_HOTDIEMASK, |
429 | }; |
430 | |
431 | static int rt5190a_probe(struct i2c_client *i2c) |
432 | { |
433 | struct rt5190a_priv *priv; |
434 | struct regulator_config cfg = {}; |
435 | int i, ret; |
436 | |
437 | priv = devm_kzalloc(dev: &i2c->dev, size: sizeof(*priv), GFP_KERNEL); |
438 | if (!priv) |
439 | return -ENOMEM; |
440 | |
441 | priv->dev = &i2c->dev; |
442 | |
443 | priv->regmap = devm_regmap_init_i2c(i2c, &rt5190a_regmap_config); |
444 | if (IS_ERR(ptr: priv->regmap)) { |
445 | dev_err(&i2c->dev, "Failed to allocate regmap\n" ); |
446 | return PTR_ERR(ptr: priv->regmap); |
447 | } |
448 | |
449 | ret = rt5190a_device_check(priv); |
450 | if (ret) { |
451 | dev_err(&i2c->dev, "Failed to check device %d\n" , ret); |
452 | return ret; |
453 | } |
454 | |
455 | ret = rt5190a_device_initialize(priv); |
456 | if (ret) { |
457 | dev_err(&i2c->dev, "Failed to initialize the device\n" ); |
458 | return ret; |
459 | } |
460 | |
461 | ret = rt5190a_parse_regulator_dt_data(priv); |
462 | if (ret) { |
463 | dev_err(&i2c->dev, "Failed to parse regulator dt\n" ); |
464 | return ret; |
465 | } |
466 | |
467 | cfg.dev = &i2c->dev; |
468 | cfg.regmap = priv->regmap; |
469 | |
470 | for (i = 0; i < RT5190A_MAX_IDX; i++) { |
471 | struct regulator_desc *desc = priv->rdesc + i; |
472 | struct of_regulator_match *match = rt5190a_regulator_match + i; |
473 | |
474 | cfg.init_data = match->init_data; |
475 | cfg.of_node = match->of_node; |
476 | |
477 | priv->rdev[i] = devm_regulator_register(dev: &i2c->dev, regulator_desc: desc, config: &cfg); |
478 | if (IS_ERR(ptr: priv->rdev[i])) { |
479 | dev_err(&i2c->dev, "Failed to register regulator %s\n" , |
480 | desc->name); |
481 | return PTR_ERR(ptr: priv->rdev[i]); |
482 | } |
483 | } |
484 | |
485 | if (i2c->irq) { |
486 | ret = devm_request_threaded_irq(dev: &i2c->dev, irq: i2c->irq, NULL, |
487 | thread_fn: rt5190a_irq_handler, |
488 | IRQF_ONESHOT, |
489 | devname: dev_name(dev: &i2c->dev), dev_id: priv); |
490 | if (ret) { |
491 | dev_err(&i2c->dev, "Failed to register interrupt\n" ); |
492 | return ret; |
493 | } |
494 | } |
495 | |
496 | return 0; |
497 | } |
498 | |
499 | static const struct of_device_id __maybe_unused rt5190a_device_table[] = { |
500 | { .compatible = "richtek,rt5190a" , }, |
501 | {} |
502 | }; |
503 | MODULE_DEVICE_TABLE(of, rt5190a_device_table); |
504 | |
505 | static struct i2c_driver rt5190a_driver = { |
506 | .driver = { |
507 | .name = "rt5190a" , |
508 | .probe_type = PROBE_PREFER_ASYNCHRONOUS, |
509 | .of_match_table = rt5190a_device_table, |
510 | }, |
511 | .probe = rt5190a_probe, |
512 | }; |
513 | module_i2c_driver(rt5190a_driver); |
514 | |
515 | MODULE_AUTHOR("ChiYuan Huang <cy_huang@richtek.com>" ); |
516 | MODULE_DESCRIPTION("Richtek RT5190A Regulator Driver" ); |
517 | MODULE_LICENSE("GPL v2" ); |
518 | |