1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * Maxim MAX77620 MFD Driver |
4 | * |
5 | * Copyright (C) 2016 NVIDIA CORPORATION. All rights reserved. |
6 | * |
7 | * Author: |
8 | * Laxman Dewangan <ldewangan@nvidia.com> |
9 | * Chaitanya Bandi <bandik@nvidia.com> |
10 | * Mallikarjun Kasoju <mkasoju@nvidia.com> |
11 | */ |
12 | |
13 | /****************** Teminology used in driver ******************** |
14 | * Here are some terminology used from datasheet for quick reference: |
15 | * Flexible Power Sequence (FPS): |
16 | * The Flexible Power Sequencer (FPS) allows each regulator to power up under |
17 | * hardware or software control. Additionally, each regulator can power on |
18 | * independently or among a group of other regulators with an adjustable |
19 | * power-up and power-down delays (sequencing). GPIO1, GPIO2, and GPIO3 can |
20 | * be programmed to be part of a sequence allowing external regulators to be |
21 | * sequenced along with internal regulators. 32KHz clock can be programmed to |
22 | * be part of a sequence. |
23 | * There is 3 FPS confguration registers and all resources are configured to |
24 | * any of these FPS or no FPS. |
25 | */ |
26 | |
27 | #include <linux/i2c.h> |
28 | #include <linux/interrupt.h> |
29 | #include <linux/mfd/core.h> |
30 | #include <linux/mfd/max77620.h> |
31 | #include <linux/init.h> |
32 | #include <linux/of.h> |
33 | #include <linux/regmap.h> |
34 | #include <linux/slab.h> |
35 | |
36 | static struct max77620_chip *max77620_scratch; |
37 | |
38 | static const struct resource gpio_resources[] = { |
39 | DEFINE_RES_IRQ(MAX77620_IRQ_TOP_GPIO), |
40 | }; |
41 | |
42 | static const struct resource power_resources[] = { |
43 | DEFINE_RES_IRQ(MAX77620_IRQ_LBT_MBATLOW), |
44 | }; |
45 | |
46 | static const struct resource rtc_resources[] = { |
47 | DEFINE_RES_IRQ(MAX77620_IRQ_TOP_RTC), |
48 | }; |
49 | |
50 | static const struct resource thermal_resources[] = { |
51 | DEFINE_RES_IRQ(MAX77620_IRQ_LBT_TJALRM1), |
52 | DEFINE_RES_IRQ(MAX77620_IRQ_LBT_TJALRM2), |
53 | }; |
54 | |
55 | static const struct regmap_irq max77620_top_irqs[] = { |
56 | REGMAP_IRQ_REG(MAX77620_IRQ_TOP_GLBL, 0, MAX77620_IRQ_TOP_GLBL_MASK), |
57 | REGMAP_IRQ_REG(MAX77620_IRQ_TOP_SD, 0, MAX77620_IRQ_TOP_SD_MASK), |
58 | REGMAP_IRQ_REG(MAX77620_IRQ_TOP_LDO, 0, MAX77620_IRQ_TOP_LDO_MASK), |
59 | REGMAP_IRQ_REG(MAX77620_IRQ_TOP_GPIO, 0, MAX77620_IRQ_TOP_GPIO_MASK), |
60 | REGMAP_IRQ_REG(MAX77620_IRQ_TOP_RTC, 0, MAX77620_IRQ_TOP_RTC_MASK), |
61 | REGMAP_IRQ_REG(MAX77620_IRQ_TOP_32K, 0, MAX77620_IRQ_TOP_32K_MASK), |
62 | REGMAP_IRQ_REG(MAX77620_IRQ_TOP_ONOFF, 0, MAX77620_IRQ_TOP_ONOFF_MASK), |
63 | REGMAP_IRQ_REG(MAX77620_IRQ_LBT_MBATLOW, 1, MAX77620_IRQ_LBM_MASK), |
64 | REGMAP_IRQ_REG(MAX77620_IRQ_LBT_TJALRM1, 1, MAX77620_IRQ_TJALRM1_MASK), |
65 | REGMAP_IRQ_REG(MAX77620_IRQ_LBT_TJALRM2, 1, MAX77620_IRQ_TJALRM2_MASK), |
66 | }; |
67 | |
68 | static const struct mfd_cell max77620_children[] = { |
69 | { .name = "max77620-pinctrl" , }, |
70 | { .name = "max77620-clock" , }, |
71 | { .name = "max77620-pmic" , }, |
72 | { .name = "max77620-watchdog" , }, |
73 | { |
74 | .name = "max77620-gpio" , |
75 | .resources = gpio_resources, |
76 | .num_resources = ARRAY_SIZE(gpio_resources), |
77 | }, { |
78 | .name = "max77620-rtc" , |
79 | .resources = rtc_resources, |
80 | .num_resources = ARRAY_SIZE(rtc_resources), |
81 | }, { |
82 | .name = "max77620-power" , |
83 | .resources = power_resources, |
84 | .num_resources = ARRAY_SIZE(power_resources), |
85 | }, { |
86 | .name = "max77620-thermal" , |
87 | .resources = thermal_resources, |
88 | .num_resources = ARRAY_SIZE(thermal_resources), |
89 | }, |
90 | }; |
91 | |
92 | static const struct mfd_cell max20024_children[] = { |
93 | { .name = "max20024-pinctrl" , }, |
94 | { .name = "max77620-clock" , }, |
95 | { .name = "max20024-pmic" , }, |
96 | { .name = "max77620-watchdog" , }, |
97 | { |
98 | .name = "max77620-gpio" , |
99 | .resources = gpio_resources, |
100 | .num_resources = ARRAY_SIZE(gpio_resources), |
101 | }, { |
102 | .name = "max77620-rtc" , |
103 | .resources = rtc_resources, |
104 | .num_resources = ARRAY_SIZE(rtc_resources), |
105 | }, { |
106 | .name = "max20024-power" , |
107 | .resources = power_resources, |
108 | .num_resources = ARRAY_SIZE(power_resources), |
109 | }, |
110 | }; |
111 | |
112 | static const struct mfd_cell max77663_children[] = { |
113 | { .name = "max77620-pinctrl" , }, |
114 | { .name = "max77620-clock" , }, |
115 | { .name = "max77663-pmic" , }, |
116 | { .name = "max77620-watchdog" , }, |
117 | { |
118 | .name = "max77620-gpio" , |
119 | .resources = gpio_resources, |
120 | .num_resources = ARRAY_SIZE(gpio_resources), |
121 | }, { |
122 | .name = "max77620-rtc" , |
123 | .resources = rtc_resources, |
124 | .num_resources = ARRAY_SIZE(rtc_resources), |
125 | }, { |
126 | .name = "max77663-power" , |
127 | .resources = power_resources, |
128 | .num_resources = ARRAY_SIZE(power_resources), |
129 | }, |
130 | }; |
131 | |
132 | static const struct regmap_range max77620_readable_ranges[] = { |
133 | regmap_reg_range(MAX77620_REG_CNFGGLBL1, MAX77620_REG_DVSSD4), |
134 | }; |
135 | |
136 | static const struct regmap_access_table max77620_readable_table = { |
137 | .yes_ranges = max77620_readable_ranges, |
138 | .n_yes_ranges = ARRAY_SIZE(max77620_readable_ranges), |
139 | }; |
140 | |
141 | static const struct regmap_range max20024_readable_ranges[] = { |
142 | regmap_reg_range(MAX77620_REG_CNFGGLBL1, MAX77620_REG_DVSSD4), |
143 | regmap_reg_range(MAX20024_REG_MAX_ADD, MAX20024_REG_MAX_ADD), |
144 | }; |
145 | |
146 | static const struct regmap_access_table max20024_readable_table = { |
147 | .yes_ranges = max20024_readable_ranges, |
148 | .n_yes_ranges = ARRAY_SIZE(max20024_readable_ranges), |
149 | }; |
150 | |
151 | static const struct regmap_range max77620_writable_ranges[] = { |
152 | regmap_reg_range(MAX77620_REG_CNFGGLBL1, MAX77620_REG_DVSSD4), |
153 | }; |
154 | |
155 | static const struct regmap_access_table max77620_writable_table = { |
156 | .yes_ranges = max77620_writable_ranges, |
157 | .n_yes_ranges = ARRAY_SIZE(max77620_writable_ranges), |
158 | }; |
159 | |
160 | static const struct regmap_range max77620_cacheable_ranges[] = { |
161 | regmap_reg_range(MAX77620_REG_SD0_CFG, MAX77620_REG_LDO_CFG3), |
162 | regmap_reg_range(MAX77620_REG_FPS_CFG0, MAX77620_REG_FPS_SD3), |
163 | }; |
164 | |
165 | static const struct regmap_access_table max77620_volatile_table = { |
166 | .no_ranges = max77620_cacheable_ranges, |
167 | .n_no_ranges = ARRAY_SIZE(max77620_cacheable_ranges), |
168 | }; |
169 | |
170 | static const struct regmap_config max77620_regmap_config = { |
171 | .name = "power-slave" , |
172 | .reg_bits = 8, |
173 | .val_bits = 8, |
174 | .max_register = MAX77620_REG_DVSSD4 + 1, |
175 | .cache_type = REGCACHE_MAPLE, |
176 | .rd_table = &max77620_readable_table, |
177 | .wr_table = &max77620_writable_table, |
178 | .volatile_table = &max77620_volatile_table, |
179 | .use_single_write = true, |
180 | }; |
181 | |
182 | static const struct regmap_config max20024_regmap_config = { |
183 | .name = "power-slave" , |
184 | .reg_bits = 8, |
185 | .val_bits = 8, |
186 | .max_register = MAX20024_REG_MAX_ADD + 1, |
187 | .cache_type = REGCACHE_MAPLE, |
188 | .rd_table = &max20024_readable_table, |
189 | .wr_table = &max77620_writable_table, |
190 | .volatile_table = &max77620_volatile_table, |
191 | }; |
192 | |
193 | static const struct regmap_range max77663_readable_ranges[] = { |
194 | regmap_reg_range(MAX77620_REG_CNFGGLBL1, MAX77620_REG_CID5), |
195 | }; |
196 | |
197 | static const struct regmap_access_table max77663_readable_table = { |
198 | .yes_ranges = max77663_readable_ranges, |
199 | .n_yes_ranges = ARRAY_SIZE(max77663_readable_ranges), |
200 | }; |
201 | |
202 | static const struct regmap_range max77663_writable_ranges[] = { |
203 | regmap_reg_range(MAX77620_REG_CNFGGLBL1, MAX77620_REG_CID5), |
204 | }; |
205 | |
206 | static const struct regmap_access_table max77663_writable_table = { |
207 | .yes_ranges = max77663_writable_ranges, |
208 | .n_yes_ranges = ARRAY_SIZE(max77663_writable_ranges), |
209 | }; |
210 | |
211 | static const struct regmap_config max77663_regmap_config = { |
212 | .name = "power-slave" , |
213 | .reg_bits = 8, |
214 | .val_bits = 8, |
215 | .max_register = MAX77620_REG_CID5 + 1, |
216 | .cache_type = REGCACHE_MAPLE, |
217 | .rd_table = &max77663_readable_table, |
218 | .wr_table = &max77663_writable_table, |
219 | .volatile_table = &max77620_volatile_table, |
220 | }; |
221 | |
222 | /* |
223 | * MAX77620 and MAX20024 has the following steps of the interrupt handling |
224 | * for TOP interrupts: |
225 | * 1. When interrupt occurs from PMIC, mask the PMIC interrupt by setting GLBLM. |
226 | * 2. Read IRQTOP and service the interrupt. |
227 | * 3. Once all interrupts has been checked and serviced, the interrupt service |
228 | * routine un-masks the hardware interrupt line by clearing GLBLM. |
229 | */ |
230 | static int max77620_irq_global_mask(void *irq_drv_data) |
231 | { |
232 | struct max77620_chip *chip = irq_drv_data; |
233 | int ret; |
234 | |
235 | ret = regmap_update_bits(map: chip->rmap, MAX77620_REG_INTENLBT, |
236 | MAX77620_GLBLM_MASK, MAX77620_GLBLM_MASK); |
237 | if (ret < 0) |
238 | dev_err(chip->dev, "Failed to set GLBLM: %d\n" , ret); |
239 | |
240 | return ret; |
241 | } |
242 | |
243 | static int max77620_irq_global_unmask(void *irq_drv_data) |
244 | { |
245 | struct max77620_chip *chip = irq_drv_data; |
246 | int ret; |
247 | |
248 | ret = regmap_update_bits(map: chip->rmap, MAX77620_REG_INTENLBT, |
249 | MAX77620_GLBLM_MASK, val: 0); |
250 | if (ret < 0) |
251 | dev_err(chip->dev, "Failed to reset GLBLM: %d\n" , ret); |
252 | |
253 | return ret; |
254 | } |
255 | |
256 | static struct regmap_irq_chip max77620_top_irq_chip = { |
257 | .name = "max77620-top" , |
258 | .irqs = max77620_top_irqs, |
259 | .num_irqs = ARRAY_SIZE(max77620_top_irqs), |
260 | .num_regs = 2, |
261 | .status_base = MAX77620_REG_IRQTOP, |
262 | .mask_base = MAX77620_REG_IRQTOPM, |
263 | .handle_pre_irq = max77620_irq_global_mask, |
264 | .handle_post_irq = max77620_irq_global_unmask, |
265 | }; |
266 | |
267 | /* max77620_get_fps_period_reg_value: Get FPS bit field value from |
268 | * requested periods. |
269 | * MAX77620 supports the FPS period of 40, 80, 160, 320, 540, 1280, 2560 |
270 | * and 5120 microseconds. MAX20024 supports the FPS period of 20, 40, 80, |
271 | * 160, 320, 540, 1280 and 2560 microseconds. |
272 | * The FPS register has 3 bits field to set the FPS period as |
273 | * bits max77620 max20024 |
274 | * 000 40 20 |
275 | * 001 80 40 |
276 | * ::: |
277 | */ |
278 | static int max77620_get_fps_period_reg_value(struct max77620_chip *chip, |
279 | int tperiod) |
280 | { |
281 | int fps_min_period; |
282 | int i; |
283 | |
284 | switch (chip->chip_id) { |
285 | case MAX20024: |
286 | fps_min_period = MAX20024_FPS_PERIOD_MIN_US; |
287 | break; |
288 | case MAX77620: |
289 | fps_min_period = MAX77620_FPS_PERIOD_MIN_US; |
290 | break; |
291 | case MAX77663: |
292 | fps_min_period = MAX20024_FPS_PERIOD_MIN_US; |
293 | break; |
294 | default: |
295 | return -EINVAL; |
296 | } |
297 | |
298 | for (i = 0; i < 7; i++) { |
299 | if (fps_min_period >= tperiod) |
300 | return i; |
301 | fps_min_period *= 2; |
302 | } |
303 | |
304 | return i; |
305 | } |
306 | |
307 | /* max77620_config_fps: Configure FPS configuration registers |
308 | * based on platform specific information. |
309 | */ |
310 | static int max77620_config_fps(struct max77620_chip *chip, |
311 | struct device_node *fps_np) |
312 | { |
313 | struct device *dev = chip->dev; |
314 | unsigned int mask = 0, config = 0; |
315 | u32 fps_max_period; |
316 | u32 param_val; |
317 | int tperiod, fps_id; |
318 | int ret; |
319 | char fps_name[10]; |
320 | |
321 | switch (chip->chip_id) { |
322 | case MAX20024: |
323 | fps_max_period = MAX20024_FPS_PERIOD_MAX_US; |
324 | break; |
325 | case MAX77620: |
326 | fps_max_period = MAX77620_FPS_PERIOD_MAX_US; |
327 | break; |
328 | case MAX77663: |
329 | fps_max_period = MAX20024_FPS_PERIOD_MAX_US; |
330 | break; |
331 | default: |
332 | return -EINVAL; |
333 | } |
334 | |
335 | for (fps_id = 0; fps_id < MAX77620_FPS_COUNT; fps_id++) { |
336 | sprintf(buf: fps_name, fmt: "fps%d" , fps_id); |
337 | if (of_node_name_eq(np: fps_np, name: fps_name)) |
338 | break; |
339 | } |
340 | |
341 | if (fps_id == MAX77620_FPS_COUNT) { |
342 | dev_err(dev, "FPS node name %pOFn is not valid\n" , fps_np); |
343 | return -EINVAL; |
344 | } |
345 | |
346 | ret = of_property_read_u32(np: fps_np, propname: "maxim,shutdown-fps-time-period-us" , |
347 | out_value: ¶m_val); |
348 | if (!ret) { |
349 | mask |= MAX77620_FPS_TIME_PERIOD_MASK; |
350 | chip->shutdown_fps_period[fps_id] = min(param_val, |
351 | fps_max_period); |
352 | tperiod = max77620_get_fps_period_reg_value(chip, |
353 | tperiod: chip->shutdown_fps_period[fps_id]); |
354 | config |= tperiod << MAX77620_FPS_TIME_PERIOD_SHIFT; |
355 | } |
356 | |
357 | ret = of_property_read_u32(np: fps_np, propname: "maxim,suspend-fps-time-period-us" , |
358 | out_value: ¶m_val); |
359 | if (!ret) |
360 | chip->suspend_fps_period[fps_id] = min(param_val, |
361 | fps_max_period); |
362 | |
363 | ret = of_property_read_u32(np: fps_np, propname: "maxim,fps-event-source" , |
364 | out_value: ¶m_val); |
365 | if (!ret) { |
366 | if (param_val > 2) { |
367 | dev_err(dev, "FPS%d event-source invalid\n" , fps_id); |
368 | return -EINVAL; |
369 | } |
370 | mask |= MAX77620_FPS_EN_SRC_MASK; |
371 | config |= param_val << MAX77620_FPS_EN_SRC_SHIFT; |
372 | if (param_val == 2) { |
373 | mask |= MAX77620_FPS_ENFPS_SW_MASK; |
374 | config |= MAX77620_FPS_ENFPS_SW; |
375 | } |
376 | } |
377 | |
378 | if (!chip->sleep_enable && !chip->enable_global_lpm) { |
379 | ret = of_property_read_u32(np: fps_np, |
380 | propname: "maxim,device-state-on-disabled-event" , |
381 | out_value: ¶m_val); |
382 | if (!ret) { |
383 | if (param_val == 0) |
384 | chip->sleep_enable = true; |
385 | else if (param_val == 1) |
386 | chip->enable_global_lpm = true; |
387 | } |
388 | } |
389 | |
390 | ret = regmap_update_bits(map: chip->rmap, MAX77620_REG_FPS_CFG0 + fps_id, |
391 | mask, val: config); |
392 | if (ret < 0) { |
393 | dev_err(dev, "Failed to update FPS CFG: %d\n" , ret); |
394 | return ret; |
395 | } |
396 | |
397 | return 0; |
398 | } |
399 | |
400 | static int max77620_initialise_fps(struct max77620_chip *chip) |
401 | { |
402 | struct device *dev = chip->dev; |
403 | struct device_node *fps_np, *fps_child; |
404 | u8 config; |
405 | int fps_id; |
406 | int ret; |
407 | |
408 | for (fps_id = 0; fps_id < MAX77620_FPS_COUNT; fps_id++) { |
409 | chip->shutdown_fps_period[fps_id] = -1; |
410 | chip->suspend_fps_period[fps_id] = -1; |
411 | } |
412 | |
413 | fps_np = of_get_child_by_name(node: dev->of_node, name: "fps" ); |
414 | if (!fps_np) |
415 | goto skip_fps; |
416 | |
417 | for_each_child_of_node(fps_np, fps_child) { |
418 | ret = max77620_config_fps(chip, fps_np: fps_child); |
419 | if (ret < 0) { |
420 | of_node_put(node: fps_child); |
421 | of_node_put(node: fps_np); |
422 | return ret; |
423 | } |
424 | } |
425 | of_node_put(node: fps_np); |
426 | |
427 | config = chip->enable_global_lpm ? MAX77620_ONOFFCNFG2_SLP_LPM_MSK : 0; |
428 | ret = regmap_update_bits(map: chip->rmap, MAX77620_REG_ONOFFCNFG2, |
429 | MAX77620_ONOFFCNFG2_SLP_LPM_MSK, val: config); |
430 | if (ret < 0) { |
431 | dev_err(dev, "Failed to update SLP_LPM: %d\n" , ret); |
432 | return ret; |
433 | } |
434 | |
435 | skip_fps: |
436 | if (chip->chip_id == MAX77663) |
437 | return 0; |
438 | |
439 | /* Enable wake on EN0 pin */ |
440 | ret = regmap_update_bits(map: chip->rmap, MAX77620_REG_ONOFFCNFG2, |
441 | MAX77620_ONOFFCNFG2_WK_EN0, |
442 | MAX77620_ONOFFCNFG2_WK_EN0); |
443 | if (ret < 0) { |
444 | dev_err(dev, "Failed to update WK_EN0: %d\n" , ret); |
445 | return ret; |
446 | } |
447 | |
448 | /* For MAX20024, SLPEN will be POR reset if CLRSE is b11 */ |
449 | if ((chip->chip_id == MAX20024) && chip->sleep_enable) { |
450 | config = MAX77620_ONOFFCNFG1_SLPEN | MAX20024_ONOFFCNFG1_CLRSE; |
451 | ret = regmap_update_bits(map: chip->rmap, MAX77620_REG_ONOFFCNFG1, |
452 | mask: config, val: config); |
453 | if (ret < 0) { |
454 | dev_err(dev, "Failed to update SLPEN: %d\n" , ret); |
455 | return ret; |
456 | } |
457 | } |
458 | |
459 | return 0; |
460 | } |
461 | |
462 | static int max77620_read_es_version(struct max77620_chip *chip) |
463 | { |
464 | unsigned int val; |
465 | u8 cid_val[6]; |
466 | int i; |
467 | int ret; |
468 | |
469 | for (i = MAX77620_REG_CID0; i <= MAX77620_REG_CID5; i++) { |
470 | ret = regmap_read(map: chip->rmap, reg: i, val: &val); |
471 | if (ret < 0) { |
472 | dev_err(chip->dev, "Failed to read CID: %d\n" , ret); |
473 | return ret; |
474 | } |
475 | dev_dbg(chip->dev, "CID%d: 0x%02x\n" , |
476 | i - MAX77620_REG_CID0, val); |
477 | cid_val[i - MAX77620_REG_CID0] = val; |
478 | } |
479 | |
480 | /* CID4 is OTP Version and CID5 is ES version */ |
481 | dev_info(chip->dev, "PMIC Version OTP:0x%02X and ES:0x%X\n" , |
482 | cid_val[4], MAX77620_CID5_DIDM(cid_val[5])); |
483 | |
484 | return ret; |
485 | } |
486 | |
487 | static void max77620_pm_power_off(void) |
488 | { |
489 | struct max77620_chip *chip = max77620_scratch; |
490 | |
491 | regmap_update_bits(map: chip->rmap, MAX77620_REG_ONOFFCNFG1, |
492 | MAX77620_ONOFFCNFG1_SFT_RST, |
493 | MAX77620_ONOFFCNFG1_SFT_RST); |
494 | } |
495 | |
496 | static int max77620_probe(struct i2c_client *client) |
497 | { |
498 | const struct i2c_device_id *id = i2c_client_get_device_id(client); |
499 | const struct regmap_config *rmap_config; |
500 | struct max77620_chip *chip; |
501 | const struct mfd_cell *mfd_cells; |
502 | int n_mfd_cells; |
503 | bool pm_off; |
504 | int ret; |
505 | |
506 | chip = devm_kzalloc(dev: &client->dev, size: sizeof(*chip), GFP_KERNEL); |
507 | if (!chip) |
508 | return -ENOMEM; |
509 | |
510 | i2c_set_clientdata(client, data: chip); |
511 | chip->dev = &client->dev; |
512 | chip->chip_irq = client->irq; |
513 | chip->chip_id = (enum max77620_chip_id)id->driver_data; |
514 | |
515 | switch (chip->chip_id) { |
516 | case MAX77620: |
517 | mfd_cells = max77620_children; |
518 | n_mfd_cells = ARRAY_SIZE(max77620_children); |
519 | rmap_config = &max77620_regmap_config; |
520 | break; |
521 | case MAX20024: |
522 | mfd_cells = max20024_children; |
523 | n_mfd_cells = ARRAY_SIZE(max20024_children); |
524 | rmap_config = &max20024_regmap_config; |
525 | break; |
526 | case MAX77663: |
527 | mfd_cells = max77663_children; |
528 | n_mfd_cells = ARRAY_SIZE(max77663_children); |
529 | rmap_config = &max77663_regmap_config; |
530 | break; |
531 | default: |
532 | dev_err(chip->dev, "ChipID is invalid %d\n" , chip->chip_id); |
533 | return -EINVAL; |
534 | } |
535 | |
536 | chip->rmap = devm_regmap_init_i2c(client, rmap_config); |
537 | if (IS_ERR(ptr: chip->rmap)) { |
538 | ret = PTR_ERR(ptr: chip->rmap); |
539 | dev_err(chip->dev, "Failed to initialise regmap: %d\n" , ret); |
540 | return ret; |
541 | } |
542 | |
543 | ret = max77620_read_es_version(chip); |
544 | if (ret < 0) |
545 | return ret; |
546 | |
547 | max77620_top_irq_chip.irq_drv_data = chip; |
548 | ret = devm_regmap_add_irq_chip(dev: chip->dev, map: chip->rmap, irq: client->irq, |
549 | IRQF_ONESHOT | IRQF_SHARED, irq_base: 0, |
550 | chip: &max77620_top_irq_chip, |
551 | data: &chip->top_irq_data); |
552 | if (ret < 0) { |
553 | dev_err(chip->dev, "Failed to add regmap irq: %d\n" , ret); |
554 | return ret; |
555 | } |
556 | |
557 | ret = max77620_initialise_fps(chip); |
558 | if (ret < 0) |
559 | return ret; |
560 | |
561 | ret = devm_mfd_add_devices(dev: chip->dev, PLATFORM_DEVID_NONE, |
562 | cells: mfd_cells, n_devs: n_mfd_cells, NULL, irq_base: 0, |
563 | irq_domain: regmap_irq_get_domain(data: chip->top_irq_data)); |
564 | if (ret < 0) { |
565 | dev_err(chip->dev, "Failed to add MFD children: %d\n" , ret); |
566 | return ret; |
567 | } |
568 | |
569 | pm_off = of_device_is_system_power_controller(np: client->dev.of_node); |
570 | if (pm_off && !pm_power_off) { |
571 | max77620_scratch = chip; |
572 | pm_power_off = max77620_pm_power_off; |
573 | } |
574 | |
575 | return 0; |
576 | } |
577 | |
578 | static int max77620_set_fps_period(struct max77620_chip *chip, |
579 | int fps_id, int time_period) |
580 | { |
581 | int period = max77620_get_fps_period_reg_value(chip, tperiod: time_period); |
582 | int ret; |
583 | |
584 | ret = regmap_update_bits(map: chip->rmap, MAX77620_REG_FPS_CFG0 + fps_id, |
585 | MAX77620_FPS_TIME_PERIOD_MASK, |
586 | val: period << MAX77620_FPS_TIME_PERIOD_SHIFT); |
587 | if (ret < 0) { |
588 | dev_err(chip->dev, "Failed to update FPS period: %d\n" , ret); |
589 | return ret; |
590 | } |
591 | |
592 | return 0; |
593 | } |
594 | |
595 | static int max77620_i2c_suspend(struct device *dev) |
596 | { |
597 | struct max77620_chip *chip = dev_get_drvdata(dev); |
598 | struct i2c_client *client = to_i2c_client(dev); |
599 | unsigned int config; |
600 | int fps; |
601 | int ret; |
602 | |
603 | for (fps = 0; fps < MAX77620_FPS_COUNT; fps++) { |
604 | if (chip->suspend_fps_period[fps] < 0) |
605 | continue; |
606 | |
607 | ret = max77620_set_fps_period(chip, fps_id: fps, |
608 | time_period: chip->suspend_fps_period[fps]); |
609 | if (ret < 0) |
610 | return ret; |
611 | } |
612 | |
613 | /* |
614 | * For MAX20024: No need to configure SLPEN on suspend as |
615 | * it will be configured on Init. |
616 | */ |
617 | if (chip->chip_id == MAX20024) |
618 | goto out; |
619 | |
620 | config = (chip->sleep_enable) ? MAX77620_ONOFFCNFG1_SLPEN : 0; |
621 | ret = regmap_update_bits(map: chip->rmap, MAX77620_REG_ONOFFCNFG1, |
622 | MAX77620_ONOFFCNFG1_SLPEN, |
623 | val: config); |
624 | if (ret < 0) { |
625 | dev_err(dev, "Failed to configure sleep in suspend: %d\n" , ret); |
626 | return ret; |
627 | } |
628 | |
629 | if (chip->chip_id == MAX77663) |
630 | goto out; |
631 | |
632 | /* Disable WK_EN0 */ |
633 | ret = regmap_update_bits(map: chip->rmap, MAX77620_REG_ONOFFCNFG2, |
634 | MAX77620_ONOFFCNFG2_WK_EN0, val: 0); |
635 | if (ret < 0) { |
636 | dev_err(dev, "Failed to configure WK_EN in suspend: %d\n" , ret); |
637 | return ret; |
638 | } |
639 | |
640 | out: |
641 | disable_irq(irq: client->irq); |
642 | |
643 | return 0; |
644 | } |
645 | |
646 | static int max77620_i2c_resume(struct device *dev) |
647 | { |
648 | struct max77620_chip *chip = dev_get_drvdata(dev); |
649 | struct i2c_client *client = to_i2c_client(dev); |
650 | int ret; |
651 | int fps; |
652 | |
653 | for (fps = 0; fps < MAX77620_FPS_COUNT; fps++) { |
654 | if (chip->shutdown_fps_period[fps] < 0) |
655 | continue; |
656 | |
657 | ret = max77620_set_fps_period(chip, fps_id: fps, |
658 | time_period: chip->shutdown_fps_period[fps]); |
659 | if (ret < 0) |
660 | return ret; |
661 | } |
662 | |
663 | /* |
664 | * For MAX20024: No need to configure WKEN0 on resume as |
665 | * it is configured on Init. |
666 | */ |
667 | if (chip->chip_id == MAX20024 || chip->chip_id == MAX77663) |
668 | goto out; |
669 | |
670 | /* Enable WK_EN0 */ |
671 | ret = regmap_update_bits(map: chip->rmap, MAX77620_REG_ONOFFCNFG2, |
672 | MAX77620_ONOFFCNFG2_WK_EN0, |
673 | MAX77620_ONOFFCNFG2_WK_EN0); |
674 | if (ret < 0) { |
675 | dev_err(dev, "Failed to configure WK_EN0 n resume: %d\n" , ret); |
676 | return ret; |
677 | } |
678 | |
679 | out: |
680 | enable_irq(irq: client->irq); |
681 | |
682 | return 0; |
683 | } |
684 | |
685 | static const struct i2c_device_id max77620_id[] = { |
686 | {"max77620" , MAX77620}, |
687 | {"max20024" , MAX20024}, |
688 | {"max77663" , MAX77663}, |
689 | {}, |
690 | }; |
691 | |
692 | static DEFINE_SIMPLE_DEV_PM_OPS(max77620_pm_ops, |
693 | max77620_i2c_suspend, max77620_i2c_resume); |
694 | |
695 | static struct i2c_driver max77620_driver = { |
696 | .driver = { |
697 | .name = "max77620" , |
698 | .pm = pm_sleep_ptr(&max77620_pm_ops), |
699 | }, |
700 | .probe = max77620_probe, |
701 | .id_table = max77620_id, |
702 | }; |
703 | builtin_i2c_driver(max77620_driver); |
704 | |