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 | ||
227 | switch (rid) { | |
228 | case RT5190A_IDX_BUCK1: | |
229 | case RT5190A_IDX_BUCK4: | |
230 | case RT5190A_IDX_LDO: | |
231 | init_data->constraints.apply_uV = 0; | |
232 | ||
233 | if (init_data->constraints.min_uV == | |
234 | init_data->constraints.max_uV) | |
235 | desc->fixed_uV = init_data->constraints.min_uV; | |
236 | else { | |
237 | dev_err(priv->dev, | |
238 | "Variable voltage for fixed regulator\n"); | |
239 | return -EINVAL; | |
240 | } | |
241 | break; | |
242 | default: | |
243 | break; | |
244 | } | |
245 | ||
246 | latchup_enable = of_property_read_bool(np, "richtek,latchup-enable"); | |
247 | ||
248 | /* latchup: 0, default hiccup: 1 */ | |
249 | val = !latchup_enable ? mask : 0; | |
250 | ||
251 | return regmap_update_bits(priv->regmap, RT5190A_REG_PROTMODE, mask, val); | |
252 | } | |
253 | ||
254 | static void rt5190a_fillin_regulator_desc(struct regulator_desc *desc, int rid) | |
255 | { | |
256 | static const char * const regu_name[] = { "buck1", "buck2", | |
257 | "buck3", "buck4", | |
258 | "ldo" }; | |
259 | static const char * const supply[] = { NULL, "vin2", "vin3", "vin4", | |
260 | "vinldo" }; | |
261 | ||
262 | desc->name = regu_name[rid]; | |
263 | desc->supply_name = supply[rid]; | |
264 | desc->owner = THIS_MODULE; | |
265 | desc->type = REGULATOR_VOLTAGE; | |
266 | desc->id = rid; | |
267 | desc->enable_reg = RT5190A_REG_ENABLE; | |
268 | desc->enable_mask = RT5190A_RID_BITMASK(rid); | |
269 | desc->active_discharge_reg = RT5190A_REG_DISCHARGE; | |
270 | desc->active_discharge_mask = RT5190A_RID_BITMASK(rid); | |
271 | desc->active_discharge_on = RT5190A_RID_BITMASK(rid); | |
272 | ||
273 | switch (rid) { | |
274 | case RT5190A_IDX_BUCK1: | |
275 | desc->active_discharge_mask = RT5190A_BUCK1_DISCHG_MASK; | |
276 | desc->active_discharge_on = RT5190A_BUCK1_DISCHG_ONVAL; | |
277 | desc->n_voltages = 1; | |
278 | desc->ops = &rt5190a_fixed_buck_ops; | |
279 | desc->of_map_mode = rt5190a_of_map_mode; | |
280 | break; | |
281 | case RT5190A_IDX_BUCK2: | |
282 | desc->vsel_reg = RT5190A_REG_BUCK2VSEL; | |
283 | desc->vsel_mask = RT5190A_VSEL_MASK; | |
284 | desc->min_uV = RT5190A_BUCK23_MINUV; | |
285 | desc->uV_step = RT5190A_BUCK23_STEPUV; | |
286 | desc->n_voltages = RT5190A_BUCK23_STEPNUM; | |
287 | desc->ops = &rt5190a_ranged_buck_ops; | |
288 | break; | |
289 | case RT5190A_IDX_BUCK3: | |
290 | desc->vsel_reg = RT5190A_REG_BUCK3VSEL; | |
291 | desc->vsel_mask = RT5190A_VSEL_MASK; | |
292 | desc->min_uV = RT5190A_BUCK23_MINUV; | |
293 | desc->uV_step = RT5190A_BUCK23_STEPUV; | |
294 | desc->n_voltages = RT5190A_BUCK23_STEPNUM; | |
295 | desc->ops = &rt5190a_ranged_buck_ops; | |
296 | break; | |
297 | case RT5190A_IDX_BUCK4: | |
298 | desc->n_voltages = 1; | |
299 | desc->ops = &rt5190a_fixed_buck_ops; | |
300 | desc->of_map_mode = rt5190a_of_map_mode; | |
301 | break; | |
302 | case RT5190A_IDX_LDO: | |
303 | desc->n_voltages = 1; | |
304 | desc->ops = &rt5190a_fixed_ldo_ops; | |
305 | break; | |
306 | } | |
307 | } | |
308 | ||
309 | static struct of_regulator_match rt5190a_regulator_match[] = { | |
310 | { .name = "buck1", }, | |
311 | { .name = "buck2", }, | |
312 | { .name = "buck3", }, | |
313 | { .name = "buck4", }, | |
314 | { .name = "ldo", } | |
315 | }; | |
316 | ||
317 | static int rt5190a_parse_regulator_dt_data(struct rt5190a_priv *priv) | |
318 | { | |
319 | struct device_node *regulator_np; | |
320 | struct regulator_desc *reg_desc; | |
321 | struct of_regulator_match *match; | |
322 | int i, ret; | |
323 | ||
324 | for (i = 0; i < RT5190A_MAX_IDX; i++) { | |
325 | reg_desc = priv->rdesc + i; | |
326 | match = rt5190a_regulator_match + i; | |
327 | ||
328 | rt5190a_fillin_regulator_desc(reg_desc, i); | |
329 | ||
330 | match->desc = reg_desc; | |
331 | } | |
332 | ||
333 | regulator_np = of_get_child_by_name(priv->dev->of_node, "regulators"); | |
334 | if (!regulator_np) { | |
335 | dev_err(priv->dev, "Could not find 'regulators' node\n"); | |
336 | return -ENODEV; | |
337 | } | |
338 | ||
339 | ret = of_regulator_match(priv->dev, regulator_np, | |
340 | rt5190a_regulator_match, | |
341 | ARRAY_SIZE(rt5190a_regulator_match)); | |
342 | ||
343 | of_node_put(regulator_np); | |
344 | ||
345 | if (ret < 0) { | |
346 | dev_err(priv->dev, | |
347 | "Error parsing regulator init data: %d\n", ret); | |
348 | return ret; | |
349 | } | |
350 | ||
351 | for (i = 0; i < RT5190A_MAX_IDX; i++) { | |
352 | match = rt5190a_regulator_match + i; | |
353 | ||
354 | ret = rt5190a_of_parse_cb(priv, i, match); | |
355 | if (ret) { | |
356 | dev_err(priv->dev, "Failed in [%d] of_parse_cb\n", i); | |
357 | return ret; | |
358 | } | |
359 | } | |
360 | ||
361 | return 0; | |
362 | } | |
363 | ||
364 | static const struct reg_sequence rt5190a_init_patch[] = { | |
365 | { 0x09, 0x3d, }, | |
366 | { 0x0a, 0x3e, }, | |
367 | { 0x0b, 0x01, }, | |
368 | { 0x10, 0xff, }, | |
369 | { 0x11, 0xff, }, | |
370 | { 0x12, 0xff, }, | |
371 | { 0x13, 0xff, }, | |
372 | { 0x14, 0, }, | |
373 | { 0x15, 0, }, | |
374 | { 0x16, 0x3e, }, | |
375 | { 0x17, 0, } | |
376 | }; | |
377 | ||
378 | static int rt5190a_device_initialize(struct rt5190a_priv *priv) | |
379 | { | |
380 | bool mute_enable; | |
381 | int ret; | |
382 | ||
383 | ret = regmap_register_patch(priv->regmap, rt5190a_init_patch, | |
384 | ARRAY_SIZE(rt5190a_init_patch)); | |
385 | if (ret) { | |
386 | dev_err(priv->dev, "Failed to do register patch\n"); | |
387 | return ret; | |
388 | } | |
389 | ||
390 | mute_enable = device_property_read_bool(priv->dev, | |
391 | "richtek,mute-enable"); | |
392 | ||
393 | if (mute_enable) { | |
394 | ret = regmap_write(priv->regmap, RT5190A_REG_MUTECNTL, 0x00); | |
395 | if (ret) { | |
396 | dev_err(priv->dev, "Failed to enable mute function\n"); | |
397 | return ret; | |
398 | } | |
399 | } | |
400 | ||
401 | return 0; | |
402 | } | |
403 | ||
404 | static int rt5190a_device_check(struct rt5190a_priv *priv) | |
405 | { | |
406 | u16 devid; | |
407 | int ret; | |
408 | ||
409 | ret = regmap_raw_read(priv->regmap, RT5190A_REG_MANUFACTURE, &devid, | |
410 | sizeof(devid)); | |
411 | if (ret) | |
412 | return ret; | |
413 | ||
414 | if (devid) { | |
415 | dev_err(priv->dev, "Incorrect device id 0x%04x\n", devid); | |
416 | return -ENODEV; | |
417 | } | |
418 | ||
419 | return 0; | |
420 | } | |
421 | ||
422 | static const struct regmap_config rt5190a_regmap_config = { | |
423 | .reg_bits = 8, | |
424 | .val_bits = 8, | |
425 | .max_register = RT5190A_REG_HOTDIEMASK, | |
426 | }; | |
427 | ||
428 | static int rt5190a_probe(struct i2c_client *i2c) | |
429 | { | |
430 | struct rt5190a_priv *priv; | |
431 | struct regulator_config cfg = {}; | |
432 | int i, ret; | |
433 | ||
434 | priv = devm_kzalloc(&i2c->dev, sizeof(*priv), GFP_KERNEL); | |
435 | if (!priv) | |
436 | return -ENOMEM; | |
437 | ||
438 | priv->dev = &i2c->dev; | |
439 | ||
440 | priv->regmap = devm_regmap_init_i2c(i2c, &rt5190a_regmap_config); | |
441 | if (IS_ERR(priv->regmap)) { | |
442 | dev_err(&i2c->dev, "Failed to allocate regmap\n"); | |
443 | return PTR_ERR(priv->regmap); | |
444 | } | |
445 | ||
446 | ret = rt5190a_device_check(priv); | |
447 | if (ret) { | |
448 | dev_err(&i2c->dev, "Failed to check device %d\n", ret); | |
449 | return ret; | |
450 | } | |
451 | ||
452 | ret = rt5190a_device_initialize(priv); | |
453 | if (ret) { | |
454 | dev_err(&i2c->dev, "Failed to initialize the device\n"); | |
455 | return ret; | |
456 | } | |
457 | ||
458 | ret = rt5190a_parse_regulator_dt_data(priv); | |
459 | if (ret) { | |
460 | dev_err(&i2c->dev, "Failed to parse regulator dt\n"); | |
461 | return ret; | |
462 | } | |
463 | ||
464 | cfg.dev = &i2c->dev; | |
465 | cfg.regmap = priv->regmap; | |
466 | ||
467 | for (i = 0; i < RT5190A_MAX_IDX; i++) { | |
468 | struct regulator_desc *desc = priv->rdesc + i; | |
469 | struct of_regulator_match *match = rt5190a_regulator_match + i; | |
470 | ||
471 | cfg.init_data = match->init_data; | |
472 | cfg.of_node = match->of_node; | |
473 | ||
474 | priv->rdev[i] = devm_regulator_register(&i2c->dev, desc, &cfg); | |
475 | if (IS_ERR(priv->rdev[i])) { | |
476 | dev_err(&i2c->dev, "Failed to register regulator %s\n", | |
477 | desc->name); | |
478 | return PTR_ERR(priv->rdev[i]); | |
479 | } | |
480 | } | |
481 | ||
482 | if (i2c->irq) { | |
483 | ret = devm_request_threaded_irq(&i2c->dev, i2c->irq, NULL, | |
484 | rt5190a_irq_handler, | |
485 | IRQF_ONESHOT, | |
486 | dev_name(&i2c->dev), priv); | |
487 | if (ret) { | |
488 | dev_err(&i2c->dev, "Failed to register interrupt\n"); | |
489 | return ret; | |
490 | } | |
491 | } | |
492 | ||
493 | return 0; | |
494 | } | |
495 | ||
496 | static const struct of_device_id __maybe_unused rt5190a_device_table[] = { | |
497 | { .compatible = "richtek,rt5190a", }, | |
498 | {} | |
499 | }; | |
500 | MODULE_DEVICE_TABLE(of, rt5190a_device_table); | |
501 | ||
502 | static struct i2c_driver rt5190a_driver = { | |
503 | .driver = { | |
504 | .name = "rt5190a", | |
505 | .of_match_table = rt5190a_device_table, | |
506 | }, | |
507 | .probe_new = rt5190a_probe, | |
508 | }; | |
509 | module_i2c_driver(rt5190a_driver); | |
510 | ||
511 | MODULE_AUTHOR("ChiYuan Huang <cy_huang@richtek.com>"); | |
512 | MODULE_DESCRIPTION("Richtek RT5190A Regulator Driver"); | |
513 | MODULE_LICENSE("GPL v2"); |