Commit | Line | Data |
---|---|---|
760423df CH |
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(regmap, RT5190A_REG_PGSTAT, &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(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(regmap, RT5190A_REG_DCDCCNTL, &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(priv->regmap, RT5190A_REG_OVINT, &raws, | |
162 | 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(priv->regmap, RT5190A_REG_OVINT, &raws, | |
171 | 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(priv->rdev[j], | |
185 | 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(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 | ||
5f7202d8 CH |
227 | if (!init_data) |
228 | return 0; | |
229 | ||
760423df CH |
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, "richtek,latchup-enable"); | |
250 | ||
251 | /* latchup: 0, default hiccup: 1 */ | |
252 | val = !latchup_enable ? mask : 0; | |
253 | ||
254 | return regmap_update_bits(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(reg_desc, i); | |
332 | ||
333 | match->desc = reg_desc; | |
334 | } | |
335 | ||
336 | regulator_np = of_get_child_by_name(priv->dev->of_node, "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(priv->dev, regulator_np, | |
343 | rt5190a_regulator_match, | |
344 | ARRAY_SIZE(rt5190a_regulator_match)); | |
345 | ||
346 | of_node_put(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, 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(priv->regmap, 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(priv->dev, | |
394 | "richtek,mute-enable"); | |
395 | ||
396 | if (mute_enable) { | |
397 | ret = regmap_write(priv->regmap, RT5190A_REG_MUTECNTL, 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(priv->regmap, RT5190A_REG_MANUFACTURE, &devid, | |
413 | 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(&i2c->dev, 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(priv->regmap)) { | |
445 | dev_err(&i2c->dev, "Failed to allocate regmap\n"); | |
446 | return PTR_ERR(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(&i2c->dev, desc, &cfg); | |
478 | if (IS_ERR(priv->rdev[i])) { | |
479 | dev_err(&i2c->dev, "Failed to register regulator %s\n", | |
480 | desc->name); | |
481 | return PTR_ERR(priv->rdev[i]); | |
482 | } | |
483 | } | |
484 | ||
485 | if (i2c->irq) { | |
486 | ret = devm_request_threaded_irq(&i2c->dev, i2c->irq, NULL, | |
487 | rt5190a_irq_handler, | |
488 | IRQF_ONESHOT, | |
489 | dev_name(&i2c->dev), 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", | |
41cff178 | 508 | .probe_type = PROBE_PREFER_ASYNCHRONOUS, |
760423df CH |
509 | .of_match_table = rt5190a_device_table, |
510 | }, | |
964e1865 | 511 | .probe = rt5190a_probe, |
760423df CH |
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"); |