1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Copyright (C) 2021 ROHM Semiconductors
5 * ROHM BD9576MUF and BD9573MUF PMIC driver
9 #include <linux/interrupt.h>
10 #include <linux/ioport.h>
11 #include <linux/irq.h>
12 #include <linux/mfd/core.h>
13 #include <linux/mfd/rohm-bd957x.h>
14 #include <linux/mfd/rohm-generic.h>
15 #include <linux/module.h>
17 #include <linux/regmap.h>
18 #include <linux/types.h>
21 BD957X_REGULATOR_CELL
,
26 * Due to the BD9576MUF nasty IRQ behaviour we don't always populate IRQs.
27 * These will be added to regulator resources only if IRQ information for the
28 * PMIC is populated in device-tree.
30 static const struct resource bd9576_regulator_irqs
[] = {
31 DEFINE_RES_IRQ_NAMED(BD9576_INT_THERM
, "bd9576-temp"),
32 DEFINE_RES_IRQ_NAMED(BD9576_INT_OVD
, "bd9576-ovd"),
33 DEFINE_RES_IRQ_NAMED(BD9576_INT_UVD
, "bd9576-uvd"),
36 static struct mfd_cell bd9573_mfd_cells
[] = {
37 [BD957X_REGULATOR_CELL
] = { .name
= "bd9573-regulator", },
38 [BD957X_WDT_CELL
] = { .name
= "bd9576-wdt", },
41 static struct mfd_cell bd9576_mfd_cells
[] = {
42 [BD957X_REGULATOR_CELL
] = { .name
= "bd9576-regulator", },
43 [BD957X_WDT_CELL
] = { .name
= "bd9576-wdt", },
46 static const struct regmap_range volatile_ranges
[] = {
47 regmap_reg_range(BD957X_REG_SMRB_ASSERT
, BD957X_REG_SMRB_ASSERT
),
48 regmap_reg_range(BD957X_REG_PMIC_INTERNAL_STAT
,
49 BD957X_REG_PMIC_INTERNAL_STAT
),
50 regmap_reg_range(BD957X_REG_INT_THERM_STAT
, BD957X_REG_INT_THERM_STAT
),
51 regmap_reg_range(BD957X_REG_INT_OVP_STAT
, BD957X_REG_INT_SYS_STAT
),
52 regmap_reg_range(BD957X_REG_INT_MAIN_STAT
, BD957X_REG_INT_MAIN_STAT
),
55 static const struct regmap_access_table volatile_regs
= {
56 .yes_ranges
= &volatile_ranges
[0],
57 .n_yes_ranges
= ARRAY_SIZE(volatile_ranges
),
60 static const struct regmap_config bd957x_regmap
= {
63 .volatile_table
= &volatile_regs
,
64 .max_register
= BD957X_MAX_REGISTER
,
65 .cache_type
= REGCACHE_MAPLE
,
68 static const struct regmap_irq bd9576_irqs
[] = {
69 REGMAP_IRQ_REG(BD9576_INT_THERM
, 0, BD957X_MASK_INT_MAIN_THERM
),
70 REGMAP_IRQ_REG(BD9576_INT_OVP
, 0, BD957X_MASK_INT_MAIN_OVP
),
71 REGMAP_IRQ_REG(BD9576_INT_SCP
, 0, BD957X_MASK_INT_MAIN_SCP
),
72 REGMAP_IRQ_REG(BD9576_INT_OCP
, 0, BD957X_MASK_INT_MAIN_OCP
),
73 REGMAP_IRQ_REG(BD9576_INT_OVD
, 0, BD957X_MASK_INT_MAIN_OVD
),
74 REGMAP_IRQ_REG(BD9576_INT_UVD
, 0, BD957X_MASK_INT_MAIN_UVD
),
75 REGMAP_IRQ_REG(BD9576_INT_UVP
, 0, BD957X_MASK_INT_MAIN_UVP
),
76 REGMAP_IRQ_REG(BD9576_INT_SYS
, 0, BD957X_MASK_INT_MAIN_SYS
),
79 static const struct regmap_irq_chip bd9576_irq_chip
= {
81 .irqs
= &bd9576_irqs
[0],
82 .num_irqs
= ARRAY_SIZE(bd9576_irqs
),
83 .status_base
= BD957X_REG_INT_MAIN_STAT
,
84 .mask_base
= BD957X_REG_INT_MAIN_MASK
,
85 .ack_base
= BD957X_REG_INT_MAIN_STAT
,
86 .init_ack_masked
= true,
91 static int bd957x_i2c_probe(struct i2c_client
*i2c
)
94 struct regmap
*regmap
;
95 struct mfd_cell
*cells
;
97 unsigned long chip_type
;
98 struct irq_domain
*domain
;
101 chip_type
= (unsigned long)of_device_get_match_data(&i2c
->dev
);
104 case ROHM_CHIP_TYPE_BD9576
:
105 cells
= bd9576_mfd_cells
;
106 num_cells
= ARRAY_SIZE(bd9576_mfd_cells
);
107 usable_irqs
= !!i2c
->irq
;
109 case ROHM_CHIP_TYPE_BD9573
:
110 cells
= bd9573_mfd_cells
;
111 num_cells
= ARRAY_SIZE(bd9573_mfd_cells
);
113 * BD9573 only supports fatal IRQs which we can not handle
114 * because SoC is going to lose the power.
119 dev_err(&i2c
->dev
, "Unknown device type");
123 regmap
= devm_regmap_init_i2c(i2c
, &bd957x_regmap
);
125 return dev_err_probe(&i2c
->dev
, PTR_ERR(regmap
),
126 "Failed to initialize Regmap\n");
129 * BD9576 behaves badly. It kepts IRQ line asserted for the whole
130 * duration of detected HW condition (like over temperature). So we
131 * don't require IRQ to be populated.
132 * If IRQ information is not given, then we mask all IRQs and do not
133 * provide IRQ resources to regulator driver - which then just omits
137 struct regmap_irq_chip_data
*irq_data
;
138 struct mfd_cell
*regulators
;
140 regulators
= &bd9576_mfd_cells
[BD957X_REGULATOR_CELL
];
141 regulators
->resources
= bd9576_regulator_irqs
;
142 regulators
->num_resources
= ARRAY_SIZE(bd9576_regulator_irqs
);
144 ret
= devm_regmap_add_irq_chip(&i2c
->dev
, regmap
, i2c
->irq
,
146 &bd9576_irq_chip
, &irq_data
);
148 return dev_err_probe(&i2c
->dev
, ret
,
149 "Failed to add IRQ chip\n");
151 domain
= regmap_irq_get_domain(irq_data
);
153 ret
= regmap_update_bits(regmap
, BD957X_REG_INT_MAIN_MASK
,
155 BD957X_MASK_INT_ALL
);
161 ret
= devm_mfd_add_devices(&i2c
->dev
, PLATFORM_DEVID_AUTO
, cells
,
162 num_cells
, NULL
, 0, domain
);
164 dev_err_probe(&i2c
->dev
, ret
, "Failed to create subdevices\n");
169 static const struct of_device_id bd957x_of_match
[] = {
170 { .compatible
= "rohm,bd9576", .data
= (void *)ROHM_CHIP_TYPE_BD9576
, },
171 { .compatible
= "rohm,bd9573", .data
= (void *)ROHM_CHIP_TYPE_BD9573
, },
174 MODULE_DEVICE_TABLE(of
, bd957x_of_match
);
176 static struct i2c_driver bd957x_drv
= {
178 .name
= "rohm-bd957x",
179 .of_match_table
= bd957x_of_match
,
181 .probe
= bd957x_i2c_probe
,
183 module_i2c_driver(bd957x_drv
);
185 MODULE_AUTHOR("Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>");
186 MODULE_DESCRIPTION("ROHM BD9576MUF and BD9573MUF Power Management IC driver");
187 MODULE_LICENSE("GPL");