2 * Core, IRQ and I2C device driver for DA9062 PMIC
3 * Copyright (C) 2015 Dialog Semiconductor Ltd.
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version 2
8 * of the License, or (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
16 #include <linux/kernel.h>
17 #include <linux/module.h>
18 #include <linux/init.h>
19 #include <linux/device.h>
20 #include <linux/interrupt.h>
21 #include <linux/regmap.h>
22 #include <linux/irq.h>
23 #include <linux/mfd/core.h>
24 #include <linux/i2c.h>
25 #include <linux/mfd/da9062/core.h>
26 #include <linux/mfd/da9062/registers.h>
27 #include <linux/regulator/of_regulator.h>
29 #define DA9062_REG_EVENT_A_OFFSET 0
30 #define DA9062_REG_EVENT_B_OFFSET 1
31 #define DA9062_REG_EVENT_C_OFFSET 2
33 static struct regmap_irq da9062_irqs
[] = {
35 [DA9062_IRQ_ONKEY
] = {
36 .reg_offset
= DA9062_REG_EVENT_A_OFFSET
,
37 .mask
= DA9062AA_M_NONKEY_MASK
,
39 [DA9062_IRQ_ALARM
] = {
40 .reg_offset
= DA9062_REG_EVENT_A_OFFSET
,
41 .mask
= DA9062AA_M_ALARM_MASK
,
44 .reg_offset
= DA9062_REG_EVENT_A_OFFSET
,
45 .mask
= DA9062AA_M_TICK_MASK
,
47 [DA9062_IRQ_WDG_WARN
] = {
48 .reg_offset
= DA9062_REG_EVENT_A_OFFSET
,
49 .mask
= DA9062AA_M_WDG_WARN_MASK
,
51 [DA9062_IRQ_SEQ_RDY
] = {
52 .reg_offset
= DA9062_REG_EVENT_A_OFFSET
,
53 .mask
= DA9062AA_M_SEQ_RDY_MASK
,
57 .reg_offset
= DA9062_REG_EVENT_B_OFFSET
,
58 .mask
= DA9062AA_M_TEMP_MASK
,
60 [DA9062_IRQ_LDO_LIM
] = {
61 .reg_offset
= DA9062_REG_EVENT_B_OFFSET
,
62 .mask
= DA9062AA_M_LDO_LIM_MASK
,
64 [DA9062_IRQ_DVC_RDY
] = {
65 .reg_offset
= DA9062_REG_EVENT_B_OFFSET
,
66 .mask
= DA9062AA_M_DVC_RDY_MASK
,
68 [DA9062_IRQ_VDD_WARN
] = {
69 .reg_offset
= DA9062_REG_EVENT_B_OFFSET
,
70 .mask
= DA9062AA_M_VDD_WARN_MASK
,
74 .reg_offset
= DA9062_REG_EVENT_C_OFFSET
,
75 .mask
= DA9062AA_M_GPI0_MASK
,
78 .reg_offset
= DA9062_REG_EVENT_C_OFFSET
,
79 .mask
= DA9062AA_M_GPI1_MASK
,
82 .reg_offset
= DA9062_REG_EVENT_C_OFFSET
,
83 .mask
= DA9062AA_M_GPI2_MASK
,
86 .reg_offset
= DA9062_REG_EVENT_C_OFFSET
,
87 .mask
= DA9062AA_M_GPI3_MASK
,
90 .reg_offset
= DA9062_REG_EVENT_C_OFFSET
,
91 .mask
= DA9062AA_M_GPI4_MASK
,
95 static struct regmap_irq_chip da9062_irq_chip
= {
98 .num_irqs
= DA9062_NUM_IRQ
,
100 .status_base
= DA9062AA_EVENT_A
,
101 .mask_base
= DA9062AA_IRQ_MASK_A
,
102 .ack_base
= DA9062AA_EVENT_A
,
105 static struct resource da9062_core_resources
[] = {
106 DEFINE_RES_NAMED(DA9062_IRQ_VDD_WARN
, 1, "VDD_WARN", IORESOURCE_IRQ
),
109 static struct resource da9062_regulators_resources
[] = {
110 DEFINE_RES_NAMED(DA9062_IRQ_LDO_LIM
, 1, "LDO_LIM", IORESOURCE_IRQ
),
113 static struct resource da9062_thermal_resources
[] = {
114 DEFINE_RES_NAMED(DA9062_IRQ_TEMP
, 1, "THERMAL", IORESOURCE_IRQ
),
117 static struct resource da9062_wdt_resources
[] = {
118 DEFINE_RES_NAMED(DA9062_IRQ_WDG_WARN
, 1, "WD_WARN", IORESOURCE_IRQ
),
121 static struct resource da9062_rtc_resources
[] = {
122 DEFINE_RES_NAMED(DA9062_IRQ_ALARM
, 1, "ALARM", IORESOURCE_IRQ
),
123 DEFINE_RES_NAMED(DA9062_IRQ_TICK
, 1, "TICK", IORESOURCE_IRQ
),
126 static struct resource da9062_onkey_resources
[] = {
127 DEFINE_RES_NAMED(DA9062_IRQ_ONKEY
, 1, "ONKEY", IORESOURCE_IRQ
),
130 static const struct mfd_cell da9062_devs
[] = {
132 .name
= "da9062-core",
133 .num_resources
= ARRAY_SIZE(da9062_core_resources
),
134 .resources
= da9062_core_resources
,
137 .name
= "da9062-regulators",
138 .num_resources
= ARRAY_SIZE(da9062_regulators_resources
),
139 .resources
= da9062_regulators_resources
,
142 .name
= "da9062-watchdog",
143 .num_resources
= ARRAY_SIZE(da9062_wdt_resources
),
144 .resources
= da9062_wdt_resources
,
145 .of_compatible
= "dlg,da9062-wdt",
148 .name
= "da9062-thermal",
149 .num_resources
= ARRAY_SIZE(da9062_thermal_resources
),
150 .resources
= da9062_thermal_resources
,
151 .of_compatible
= "dlg,da9062-thermal",
154 .name
= "da9062-rtc",
155 .num_resources
= ARRAY_SIZE(da9062_rtc_resources
),
156 .resources
= da9062_rtc_resources
,
157 .of_compatible
= "dlg,da9062-rtc",
160 .name
= "da9062-onkey",
161 .num_resources
= ARRAY_SIZE(da9062_onkey_resources
),
162 .resources
= da9062_onkey_resources
,
163 .of_compatible
= "dlg,da9062-onkey",
167 static int da9062_clear_fault_log(struct da9062
*chip
)
172 ret
= regmap_read(chip
->regmap
, DA9062AA_FAULT_LOG
, &fault_log
);
177 if (fault_log
& DA9062AA_TWD_ERROR_MASK
)
178 dev_dbg(chip
->dev
, "Fault log entry detected: TWD_ERROR\n");
179 if (fault_log
& DA9062AA_POR_MASK
)
180 dev_dbg(chip
->dev
, "Fault log entry detected: POR\n");
181 if (fault_log
& DA9062AA_VDD_FAULT_MASK
)
182 dev_dbg(chip
->dev
, "Fault log entry detected: VDD_FAULT\n");
183 if (fault_log
& DA9062AA_VDD_START_MASK
)
184 dev_dbg(chip
->dev
, "Fault log entry detected: VDD_START\n");
185 if (fault_log
& DA9062AA_TEMP_CRIT_MASK
)
186 dev_dbg(chip
->dev
, "Fault log entry detected: TEMP_CRIT\n");
187 if (fault_log
& DA9062AA_KEY_RESET_MASK
)
188 dev_dbg(chip
->dev
, "Fault log entry detected: KEY_RESET\n");
189 if (fault_log
& DA9062AA_NSHUTDOWN_MASK
)
190 dev_dbg(chip
->dev
, "Fault log entry detected: NSHUTDOWN\n");
191 if (fault_log
& DA9062AA_WAIT_SHUT_MASK
)
192 dev_dbg(chip
->dev
, "Fault log entry detected: WAIT_SHUT\n");
194 ret
= regmap_write(chip
->regmap
, DA9062AA_FAULT_LOG
,
201 static int da9062_get_device_type(struct da9062
*chip
)
203 int device_id
, variant_id
, variant_mrc
;
206 ret
= regmap_read(chip
->regmap
, DA9062AA_DEVICE_ID
, &device_id
);
208 dev_err(chip
->dev
, "Cannot read chip ID.\n");
211 if (device_id
!= DA9062_PMIC_DEVICE_ID
) {
212 dev_err(chip
->dev
, "Invalid device ID: 0x%02x\n", device_id
);
216 ret
= regmap_read(chip
->regmap
, DA9062AA_VARIANT_ID
, &variant_id
);
218 dev_err(chip
->dev
, "Cannot read chip variant id.\n");
223 "Device detected (device-ID: 0x%02X, var-ID: 0x%02X)\n",
224 device_id
, variant_id
);
226 variant_mrc
= (variant_id
& DA9062AA_MRC_MASK
) >> DA9062AA_MRC_SHIFT
;
228 if (variant_mrc
< DA9062_PMIC_VARIANT_MRC_AA
) {
230 "Cannot support variant MRC: 0x%02X\n", variant_mrc
);
237 static const struct regmap_range da9062_aa_readable_ranges
[] = {
239 .range_min
= DA9062AA_PAGE_CON
,
240 .range_max
= DA9062AA_STATUS_B
,
242 .range_min
= DA9062AA_STATUS_D
,
243 .range_max
= DA9062AA_EVENT_C
,
245 .range_min
= DA9062AA_IRQ_MASK_A
,
246 .range_max
= DA9062AA_IRQ_MASK_C
,
248 .range_min
= DA9062AA_CONTROL_A
,
249 .range_max
= DA9062AA_GPIO_4
,
251 .range_min
= DA9062AA_GPIO_WKUP_MODE
,
252 .range_max
= DA9062AA_BUCK4_CONT
,
254 .range_min
= DA9062AA_BUCK3_CONT
,
255 .range_max
= DA9062AA_BUCK3_CONT
,
257 .range_min
= DA9062AA_LDO1_CONT
,
258 .range_max
= DA9062AA_LDO4_CONT
,
260 .range_min
= DA9062AA_DVC_1
,
261 .range_max
= DA9062AA_DVC_1
,
263 .range_min
= DA9062AA_COUNT_S
,
264 .range_max
= DA9062AA_SECOND_D
,
266 .range_min
= DA9062AA_SEQ
,
267 .range_max
= DA9062AA_ID_4_3
,
269 .range_min
= DA9062AA_ID_12_11
,
270 .range_max
= DA9062AA_ID_16_15
,
272 .range_min
= DA9062AA_ID_22_21
,
273 .range_max
= DA9062AA_ID_32_31
,
275 .range_min
= DA9062AA_SEQ_A
,
276 .range_max
= DA9062AA_BUCK3_CFG
,
278 .range_min
= DA9062AA_VBUCK2_A
,
279 .range_max
= DA9062AA_VBUCK4_A
,
281 .range_min
= DA9062AA_VBUCK3_A
,
282 .range_max
= DA9062AA_VBUCK3_A
,
284 .range_min
= DA9062AA_VLDO1_A
,
285 .range_max
= DA9062AA_VLDO4_A
,
287 .range_min
= DA9062AA_VBUCK2_B
,
288 .range_max
= DA9062AA_VBUCK4_B
,
290 .range_min
= DA9062AA_VBUCK3_B
,
291 .range_max
= DA9062AA_VBUCK3_B
,
293 .range_min
= DA9062AA_VLDO1_B
,
294 .range_max
= DA9062AA_VLDO4_B
,
296 .range_min
= DA9062AA_BBAT_CONT
,
297 .range_max
= DA9062AA_BBAT_CONT
,
299 .range_min
= DA9062AA_INTERFACE
,
300 .range_max
= DA9062AA_CONFIG_E
,
302 .range_min
= DA9062AA_CONFIG_G
,
303 .range_max
= DA9062AA_CONFIG_K
,
305 .range_min
= DA9062AA_CONFIG_M
,
306 .range_max
= DA9062AA_CONFIG_M
,
308 .range_min
= DA9062AA_TRIM_CLDR
,
309 .range_max
= DA9062AA_GP_ID_19
,
311 .range_min
= DA9062AA_DEVICE_ID
,
312 .range_max
= DA9062AA_CONFIG_ID
,
316 static const struct regmap_range da9062_aa_writeable_ranges
[] = {
318 .range_min
= DA9062AA_PAGE_CON
,
319 .range_max
= DA9062AA_PAGE_CON
,
321 .range_min
= DA9062AA_FAULT_LOG
,
322 .range_max
= DA9062AA_EVENT_C
,
324 .range_min
= DA9062AA_IRQ_MASK_A
,
325 .range_max
= DA9062AA_IRQ_MASK_C
,
327 .range_min
= DA9062AA_CONTROL_A
,
328 .range_max
= DA9062AA_GPIO_4
,
330 .range_min
= DA9062AA_GPIO_WKUP_MODE
,
331 .range_max
= DA9062AA_BUCK4_CONT
,
333 .range_min
= DA9062AA_BUCK3_CONT
,
334 .range_max
= DA9062AA_BUCK3_CONT
,
336 .range_min
= DA9062AA_LDO1_CONT
,
337 .range_max
= DA9062AA_LDO4_CONT
,
339 .range_min
= DA9062AA_DVC_1
,
340 .range_max
= DA9062AA_DVC_1
,
342 .range_min
= DA9062AA_COUNT_S
,
343 .range_max
= DA9062AA_ALARM_Y
,
345 .range_min
= DA9062AA_SEQ
,
346 .range_max
= DA9062AA_ID_4_3
,
348 .range_min
= DA9062AA_ID_12_11
,
349 .range_max
= DA9062AA_ID_16_15
,
351 .range_min
= DA9062AA_ID_22_21
,
352 .range_max
= DA9062AA_ID_32_31
,
354 .range_min
= DA9062AA_SEQ_A
,
355 .range_max
= DA9062AA_BUCK3_CFG
,
357 .range_min
= DA9062AA_VBUCK2_A
,
358 .range_max
= DA9062AA_VBUCK4_A
,
360 .range_min
= DA9062AA_VBUCK3_A
,
361 .range_max
= DA9062AA_VBUCK3_A
,
363 .range_min
= DA9062AA_VLDO1_A
,
364 .range_max
= DA9062AA_VLDO4_A
,
366 .range_min
= DA9062AA_VBUCK2_B
,
367 .range_max
= DA9062AA_VBUCK4_B
,
369 .range_min
= DA9062AA_VBUCK3_B
,
370 .range_max
= DA9062AA_VBUCK3_B
,
372 .range_min
= DA9062AA_VLDO1_B
,
373 .range_max
= DA9062AA_VLDO4_B
,
375 .range_min
= DA9062AA_BBAT_CONT
,
376 .range_max
= DA9062AA_BBAT_CONT
,
378 .range_min
= DA9062AA_GP_ID_0
,
379 .range_max
= DA9062AA_GP_ID_19
,
383 static const struct regmap_range da9062_aa_volatile_ranges
[] = {
385 .range_min
= DA9062AA_PAGE_CON
,
386 .range_max
= DA9062AA_STATUS_B
,
388 .range_min
= DA9062AA_STATUS_D
,
389 .range_max
= DA9062AA_EVENT_C
,
391 .range_min
= DA9062AA_CONTROL_A
,
392 .range_max
= DA9062AA_CONTROL_B
,
394 .range_min
= DA9062AA_CONTROL_E
,
395 .range_max
= DA9062AA_CONTROL_F
,
397 .range_min
= DA9062AA_BUCK2_CONT
,
398 .range_max
= DA9062AA_BUCK4_CONT
,
400 .range_min
= DA9062AA_BUCK3_CONT
,
401 .range_max
= DA9062AA_BUCK3_CONT
,
403 .range_min
= DA9062AA_LDO1_CONT
,
404 .range_max
= DA9062AA_LDO4_CONT
,
406 .range_min
= DA9062AA_DVC_1
,
407 .range_max
= DA9062AA_DVC_1
,
409 .range_min
= DA9062AA_COUNT_S
,
410 .range_max
= DA9062AA_SECOND_D
,
412 .range_min
= DA9062AA_SEQ
,
413 .range_max
= DA9062AA_SEQ
,
415 .range_min
= DA9062AA_EN_32K
,
416 .range_max
= DA9062AA_EN_32K
,
420 static const struct regmap_access_table da9062_aa_readable_table
= {
421 .yes_ranges
= da9062_aa_readable_ranges
,
422 .n_yes_ranges
= ARRAY_SIZE(da9062_aa_readable_ranges
),
425 static const struct regmap_access_table da9062_aa_writeable_table
= {
426 .yes_ranges
= da9062_aa_writeable_ranges
,
427 .n_yes_ranges
= ARRAY_SIZE(da9062_aa_writeable_ranges
),
430 static const struct regmap_access_table da9062_aa_volatile_table
= {
431 .yes_ranges
= da9062_aa_volatile_ranges
,
432 .n_yes_ranges
= ARRAY_SIZE(da9062_aa_volatile_ranges
),
435 static const struct regmap_range_cfg da9062_range_cfg
[] = {
437 .range_min
= DA9062AA_PAGE_CON
,
438 .range_max
= DA9062AA_CONFIG_ID
,
439 .selector_reg
= DA9062AA_PAGE_CON
,
440 .selector_mask
= 1 << DA9062_I2C_PAGE_SEL_SHIFT
,
441 .selector_shift
= DA9062_I2C_PAGE_SEL_SHIFT
,
447 static struct regmap_config da9062_regmap_config
= {
450 .ranges
= da9062_range_cfg
,
451 .num_ranges
= ARRAY_SIZE(da9062_range_cfg
),
452 .max_register
= DA9062AA_CONFIG_ID
,
453 .cache_type
= REGCACHE_RBTREE
,
454 .rd_table
= &da9062_aa_readable_table
,
455 .wr_table
= &da9062_aa_writeable_table
,
456 .volatile_table
= &da9062_aa_volatile_table
,
459 static int da9062_i2c_probe(struct i2c_client
*i2c
,
460 const struct i2c_device_id
*id
)
463 unsigned int irq_base
;
466 chip
= devm_kzalloc(&i2c
->dev
, sizeof(*chip
), GFP_KERNEL
);
470 i2c_set_clientdata(i2c
, chip
);
471 chip
->dev
= &i2c
->dev
;
474 dev_err(chip
->dev
, "No IRQ configured\n");
478 chip
->regmap
= devm_regmap_init_i2c(i2c
, &da9062_regmap_config
);
479 if (IS_ERR(chip
->regmap
)) {
480 ret
= PTR_ERR(chip
->regmap
);
481 dev_err(chip
->dev
, "Failed to allocate register map: %d\n",
486 ret
= da9062_clear_fault_log(chip
);
488 dev_warn(chip
->dev
, "Cannot clear fault log\n");
490 ret
= da9062_get_device_type(chip
);
494 ret
= regmap_add_irq_chip(chip
->regmap
, i2c
->irq
,
495 IRQF_TRIGGER_LOW
| IRQF_ONESHOT
| IRQF_SHARED
,
496 -1, &da9062_irq_chip
,
499 dev_err(chip
->dev
, "Failed to request IRQ %d: %d\n",
504 irq_base
= regmap_irq_chip_get_base(chip
->regmap_irq
);
506 ret
= mfd_add_devices(chip
->dev
, PLATFORM_DEVID_NONE
, da9062_devs
,
507 ARRAY_SIZE(da9062_devs
), NULL
, irq_base
,
510 dev_err(chip
->dev
, "Cannot register child devices\n");
511 regmap_del_irq_chip(i2c
->irq
, chip
->regmap_irq
);
518 static int da9062_i2c_remove(struct i2c_client
*i2c
)
520 struct da9062
*chip
= i2c_get_clientdata(i2c
);
522 mfd_remove_devices(chip
->dev
);
523 regmap_del_irq_chip(i2c
->irq
, chip
->regmap_irq
);
528 static const struct i2c_device_id da9062_i2c_id
[] = {
532 MODULE_DEVICE_TABLE(i2c
, da9062_i2c_id
);
534 static const struct of_device_id da9062_dt_ids
[] = {
535 { .compatible
= "dlg,da9062", },
538 MODULE_DEVICE_TABLE(of
, da9062_dt_ids
);
540 static struct i2c_driver da9062_i2c_driver
= {
543 .of_match_table
= of_match_ptr(da9062_dt_ids
),
545 .probe
= da9062_i2c_probe
,
546 .remove
= da9062_i2c_remove
,
547 .id_table
= da9062_i2c_id
,
550 module_i2c_driver(da9062_i2c_driver
);
552 MODULE_DESCRIPTION("Core device driver for Dialog DA9062");
553 MODULE_AUTHOR("Steve Twiss <stwiss.opensource@diasemi.com>");
554 MODULE_LICENSE("GPL");