1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | // |
3 | // Copyright (C) 2019 ROHM Semiconductors |
4 | // |
5 | // ROHM BD71828/BD71815 PMIC driver |
6 | |
7 | #include <linux/gpio_keys.h> |
8 | #include <linux/i2c.h> |
9 | #include <linux/input.h> |
10 | #include <linux/interrupt.h> |
11 | #include <linux/ioport.h> |
12 | #include <linux/irq.h> |
13 | #include <linux/mfd/core.h> |
14 | #include <linux/mfd/rohm-bd71815.h> |
15 | #include <linux/mfd/rohm-bd71828.h> |
16 | #include <linux/mfd/rohm-generic.h> |
17 | #include <linux/module.h> |
18 | #include <linux/of.h> |
19 | #include <linux/regmap.h> |
20 | #include <linux/types.h> |
21 | |
22 | static struct gpio_keys_button button = { |
23 | .code = KEY_POWER, |
24 | .gpio = -1, |
25 | .type = EV_KEY, |
26 | }; |
27 | |
28 | static struct gpio_keys_platform_data bd71828_powerkey_data = { |
29 | .buttons = &button, |
30 | .nbuttons = 1, |
31 | .name = "bd71828-pwrkey" , |
32 | }; |
33 | |
34 | static const struct resource bd71815_rtc_irqs[] = { |
35 | DEFINE_RES_IRQ_NAMED(BD71815_INT_RTC0, "bd71815-rtc-alm-0" ), |
36 | DEFINE_RES_IRQ_NAMED(BD71815_INT_RTC1, "bd71815-rtc-alm-1" ), |
37 | DEFINE_RES_IRQ_NAMED(BD71815_INT_RTC2, "bd71815-rtc-alm-2" ), |
38 | }; |
39 | |
40 | static const struct resource bd71828_rtc_irqs[] = { |
41 | DEFINE_RES_IRQ_NAMED(BD71828_INT_RTC0, "bd71828-rtc-alm-0" ), |
42 | DEFINE_RES_IRQ_NAMED(BD71828_INT_RTC1, "bd71828-rtc-alm-1" ), |
43 | DEFINE_RES_IRQ_NAMED(BD71828_INT_RTC2, "bd71828-rtc-alm-2" ), |
44 | }; |
45 | |
46 | static struct resource bd71815_power_irqs[] = { |
47 | DEFINE_RES_IRQ_NAMED(BD71815_INT_DCIN_RMV, "bd71815-dcin-rmv" ), |
48 | DEFINE_RES_IRQ_NAMED(BD71815_INT_CLPS_OUT, "bd71815-clps-out" ), |
49 | DEFINE_RES_IRQ_NAMED(BD71815_INT_CLPS_IN, "bd71815-clps-in" ), |
50 | DEFINE_RES_IRQ_NAMED(BD71815_INT_DCIN_OVP_RES, "bd71815-dcin-ovp-res" ), |
51 | DEFINE_RES_IRQ_NAMED(BD71815_INT_DCIN_OVP_DET, "bd71815-dcin-ovp-det" ), |
52 | DEFINE_RES_IRQ_NAMED(BD71815_INT_DCIN_MON_RES, "bd71815-dcin-mon-res" ), |
53 | DEFINE_RES_IRQ_NAMED(BD71815_INT_DCIN_MON_DET, "bd71815-dcin-mon-det" ), |
54 | DEFINE_RES_IRQ_NAMED(BD71815_INT_VSYS_UV_RES, "bd71815-vsys-uv-res" ), |
55 | DEFINE_RES_IRQ_NAMED(BD71815_INT_VSYS_UV_DET, "bd71815-vsys-uv-det" ), |
56 | DEFINE_RES_IRQ_NAMED(BD71815_INT_VSYS_LOW_RES, "bd71815-vsys-low-res" ), |
57 | DEFINE_RES_IRQ_NAMED(BD71815_INT_VSYS_LOW_DET, "bd71815-vsys-low-det" ), |
58 | DEFINE_RES_IRQ_NAMED(BD71815_INT_VSYS_MON_RES, "bd71815-vsys-mon-res" ), |
59 | DEFINE_RES_IRQ_NAMED(BD71815_INT_VSYS_MON_RES, "bd71815-vsys-mon-det" ), |
60 | DEFINE_RES_IRQ_NAMED(BD71815_INT_CHG_WDG_TEMP, "bd71815-chg-wdg-temp" ), |
61 | DEFINE_RES_IRQ_NAMED(BD71815_INT_CHG_WDG_TIME, "bd71815-chg-wdg" ), |
62 | DEFINE_RES_IRQ_NAMED(BD71815_INT_CHG_RECHARGE_RES, "bd71815-rechg-res" ), |
63 | DEFINE_RES_IRQ_NAMED(BD71815_INT_CHG_RECHARGE_DET, "bd71815-rechg-det" ), |
64 | DEFINE_RES_IRQ_NAMED(BD71815_INT_CHG_RANGED_TEMP_TRANSITION, "bd71815-ranged-temp-transit" ), |
65 | DEFINE_RES_IRQ_NAMED(BD71815_INT_CHG_STATE_TRANSITION, "bd71815-chg-state-change" ), |
66 | DEFINE_RES_IRQ_NAMED(BD71815_INT_BAT_TEMP_NORMAL, "bd71815-bat-temp-normal" ), |
67 | DEFINE_RES_IRQ_NAMED(BD71815_INT_BAT_TEMP_ERANGE, "bd71815-bat-temp-erange" ), |
68 | DEFINE_RES_IRQ_NAMED(BD71815_INT_BAT_REMOVED, "bd71815-bat-rmv" ), |
69 | DEFINE_RES_IRQ_NAMED(BD71815_INT_BAT_DETECTED, "bd71815-bat-det" ), |
70 | DEFINE_RES_IRQ_NAMED(BD71815_INT_THERM_REMOVED, "bd71815-therm-rmv" ), |
71 | DEFINE_RES_IRQ_NAMED(BD71815_INT_THERM_DETECTED, "bd71815-therm-det" ), |
72 | DEFINE_RES_IRQ_NAMED(BD71815_INT_BAT_DEAD, "bd71815-bat-dead" ), |
73 | DEFINE_RES_IRQ_NAMED(BD71815_INT_BAT_SHORTC_RES, "bd71815-bat-short-res" ), |
74 | DEFINE_RES_IRQ_NAMED(BD71815_INT_BAT_SHORTC_DET, "bd71815-bat-short-det" ), |
75 | DEFINE_RES_IRQ_NAMED(BD71815_INT_BAT_LOW_VOLT_RES, "bd71815-bat-low-res" ), |
76 | DEFINE_RES_IRQ_NAMED(BD71815_INT_BAT_LOW_VOLT_DET, "bd71815-bat-low-det" ), |
77 | DEFINE_RES_IRQ_NAMED(BD71815_INT_BAT_OVER_VOLT_RES, "bd71815-bat-over-res" ), |
78 | DEFINE_RES_IRQ_NAMED(BD71815_INT_BAT_OVER_VOLT_DET, "bd71815-bat-over-det" ), |
79 | DEFINE_RES_IRQ_NAMED(BD71815_INT_BAT_MON_RES, "bd71815-bat-mon-res" ), |
80 | DEFINE_RES_IRQ_NAMED(BD71815_INT_BAT_MON_DET, "bd71815-bat-mon-det" ), |
81 | DEFINE_RES_IRQ_NAMED(BD71815_INT_BAT_CC_MON1, "bd71815-bat-cc-mon1" ), |
82 | DEFINE_RES_IRQ_NAMED(BD71815_INT_BAT_CC_MON2, "bd71815-bat-cc-mon2" ), |
83 | DEFINE_RES_IRQ_NAMED(BD71815_INT_BAT_CC_MON3, "bd71815-bat-cc-mon3" ), |
84 | DEFINE_RES_IRQ_NAMED(BD71815_INT_BAT_OVER_CURR_1_RES, "bd71815-bat-oc1-res" ), |
85 | DEFINE_RES_IRQ_NAMED(BD71815_INT_BAT_OVER_CURR_1_DET, "bd71815-bat-oc1-det" ), |
86 | DEFINE_RES_IRQ_NAMED(BD71815_INT_BAT_OVER_CURR_2_RES, "bd71815-bat-oc2-res" ), |
87 | DEFINE_RES_IRQ_NAMED(BD71815_INT_BAT_OVER_CURR_2_DET, "bd71815-bat-oc2-det" ), |
88 | DEFINE_RES_IRQ_NAMED(BD71815_INT_BAT_OVER_CURR_3_RES, "bd71815-bat-oc3-res" ), |
89 | DEFINE_RES_IRQ_NAMED(BD71815_INT_BAT_OVER_CURR_3_DET, "bd71815-bat-oc3-det" ), |
90 | DEFINE_RES_IRQ_NAMED(BD71815_INT_TEMP_BAT_LOW_RES, "bd71815-bat-low-res" ), |
91 | DEFINE_RES_IRQ_NAMED(BD71815_INT_TEMP_BAT_LOW_DET, "bd71815-bat-low-det" ), |
92 | DEFINE_RES_IRQ_NAMED(BD71815_INT_TEMP_BAT_HI_RES, "bd71815-bat-hi-res" ), |
93 | DEFINE_RES_IRQ_NAMED(BD71815_INT_TEMP_BAT_HI_DET, "bd71815-bat-hi-det" ), |
94 | }; |
95 | |
96 | static struct mfd_cell bd71815_mfd_cells[] = { |
97 | { .name = "bd71815-pmic" , }, |
98 | { .name = "bd71815-clk" , }, |
99 | { .name = "bd71815-gpo" , }, |
100 | { |
101 | .name = "bd71815-power" , |
102 | .num_resources = ARRAY_SIZE(bd71815_power_irqs), |
103 | .resources = &bd71815_power_irqs[0], |
104 | }, |
105 | { |
106 | .name = "bd71815-rtc" , |
107 | .num_resources = ARRAY_SIZE(bd71815_rtc_irqs), |
108 | .resources = &bd71815_rtc_irqs[0], |
109 | }, |
110 | }; |
111 | |
112 | static struct mfd_cell bd71828_mfd_cells[] = { |
113 | { .name = "bd71828-pmic" , }, |
114 | { .name = "bd71828-gpio" , }, |
115 | { .name = "bd71828-led" , .of_compatible = "rohm,bd71828-leds" }, |
116 | /* |
117 | * We use BD71837 driver to drive the clock block. Only differences to |
118 | * BD70528 clock gate are the register address and mask. |
119 | */ |
120 | { .name = "bd71828-clk" , }, |
121 | { .name = "bd71827-power" , }, |
122 | { |
123 | .name = "bd71828-rtc" , |
124 | .resources = bd71828_rtc_irqs, |
125 | .num_resources = ARRAY_SIZE(bd71828_rtc_irqs), |
126 | }, { |
127 | .name = "gpio-keys" , |
128 | .platform_data = &bd71828_powerkey_data, |
129 | .pdata_size = sizeof(bd71828_powerkey_data), |
130 | }, |
131 | }; |
132 | |
133 | static const struct regmap_range bd71815_volatile_ranges[] = { |
134 | { |
135 | .range_min = BD71815_REG_SEC, |
136 | .range_max = BD71815_REG_YEAR, |
137 | }, { |
138 | .range_min = BD71815_REG_CONF, |
139 | .range_max = BD71815_REG_BAT_TEMP, |
140 | }, { |
141 | .range_min = BD71815_REG_VM_IBAT_U, |
142 | .range_max = BD71815_REG_CC_CTRL, |
143 | }, { |
144 | .range_min = BD71815_REG_CC_STAT, |
145 | .range_max = BD71815_REG_CC_CURCD_L, |
146 | }, { |
147 | .range_min = BD71815_REG_VM_BTMP_MON, |
148 | .range_max = BD71815_REG_VM_BTMP_MON, |
149 | }, { |
150 | .range_min = BD71815_REG_INT_STAT, |
151 | .range_max = BD71815_REG_INT_UPDATE, |
152 | }, { |
153 | .range_min = BD71815_REG_VM_VSYS_U, |
154 | .range_max = BD71815_REG_REX_CTRL_1, |
155 | }, { |
156 | .range_min = BD71815_REG_FULL_CCNTD_3, |
157 | .range_max = BD71815_REG_CCNTD_CHG_2, |
158 | }, |
159 | }; |
160 | |
161 | static const struct regmap_range bd71828_volatile_ranges[] = { |
162 | { |
163 | .range_min = BD71828_REG_PS_CTRL_1, |
164 | .range_max = BD71828_REG_PS_CTRL_1, |
165 | }, { |
166 | .range_min = BD71828_REG_PS_CTRL_3, |
167 | .range_max = BD71828_REG_PS_CTRL_3, |
168 | }, { |
169 | .range_min = BD71828_REG_RTC_SEC, |
170 | .range_max = BD71828_REG_RTC_YEAR, |
171 | }, { |
172 | /* |
173 | * For now make all charger registers volatile because many |
174 | * needs to be and because the charger block is not that |
175 | * performance critical. |
176 | */ |
177 | .range_min = BD71828_REG_CHG_STATE, |
178 | .range_max = BD71828_REG_CHG_FULL, |
179 | }, { |
180 | .range_min = BD71828_REG_INT_MAIN, |
181 | .range_max = BD71828_REG_IO_STAT, |
182 | }, |
183 | }; |
184 | |
185 | static const struct regmap_access_table bd71815_volatile_regs = { |
186 | .yes_ranges = &bd71815_volatile_ranges[0], |
187 | .n_yes_ranges = ARRAY_SIZE(bd71815_volatile_ranges), |
188 | }; |
189 | |
190 | static const struct regmap_access_table bd71828_volatile_regs = { |
191 | .yes_ranges = &bd71828_volatile_ranges[0], |
192 | .n_yes_ranges = ARRAY_SIZE(bd71828_volatile_ranges), |
193 | }; |
194 | |
195 | static const struct regmap_config bd71815_regmap = { |
196 | .reg_bits = 8, |
197 | .val_bits = 8, |
198 | .volatile_table = &bd71815_volatile_regs, |
199 | .max_register = BD71815_MAX_REGISTER - 1, |
200 | .cache_type = REGCACHE_MAPLE, |
201 | }; |
202 | |
203 | static const struct regmap_config bd71828_regmap = { |
204 | .reg_bits = 8, |
205 | .val_bits = 8, |
206 | .volatile_table = &bd71828_volatile_regs, |
207 | .max_register = BD71828_MAX_REGISTER, |
208 | .cache_type = REGCACHE_MAPLE, |
209 | }; |
210 | |
211 | /* |
212 | * Mapping of main IRQ register bits to sub-IRQ register offsets so that we can |
213 | * access corect sub-IRQ registers based on bits that are set in main IRQ |
214 | * register. BD71815 and BD71828 have same sub-register-block offests. |
215 | */ |
216 | |
217 | static unsigned int bit0_offsets[] = {11}; /* RTC IRQ */ |
218 | static unsigned int bit1_offsets[] = {10}; /* TEMP IRQ */ |
219 | static unsigned int bit2_offsets[] = {6, 7, 8, 9}; /* BAT MON IRQ */ |
220 | static unsigned int bit3_offsets[] = {5}; /* BAT IRQ */ |
221 | static unsigned int bit4_offsets[] = {4}; /* CHG IRQ */ |
222 | static unsigned int bit5_offsets[] = {3}; /* VSYS IRQ */ |
223 | static unsigned int bit6_offsets[] = {1, 2}; /* DCIN IRQ */ |
224 | static unsigned int bit7_offsets[] = {0}; /* BUCK IRQ */ |
225 | |
226 | static struct regmap_irq_sub_irq_map bd718xx_sub_irq_offsets[] = { |
227 | REGMAP_IRQ_MAIN_REG_OFFSET(bit0_offsets), |
228 | REGMAP_IRQ_MAIN_REG_OFFSET(bit1_offsets), |
229 | REGMAP_IRQ_MAIN_REG_OFFSET(bit2_offsets), |
230 | REGMAP_IRQ_MAIN_REG_OFFSET(bit3_offsets), |
231 | REGMAP_IRQ_MAIN_REG_OFFSET(bit4_offsets), |
232 | REGMAP_IRQ_MAIN_REG_OFFSET(bit5_offsets), |
233 | REGMAP_IRQ_MAIN_REG_OFFSET(bit6_offsets), |
234 | REGMAP_IRQ_MAIN_REG_OFFSET(bit7_offsets), |
235 | }; |
236 | |
237 | static const struct regmap_irq bd71815_irqs[] = { |
238 | REGMAP_IRQ_REG(BD71815_INT_BUCK1_OCP, 0, BD71815_INT_BUCK1_OCP_MASK), |
239 | REGMAP_IRQ_REG(BD71815_INT_BUCK2_OCP, 0, BD71815_INT_BUCK2_OCP_MASK), |
240 | REGMAP_IRQ_REG(BD71815_INT_BUCK3_OCP, 0, BD71815_INT_BUCK3_OCP_MASK), |
241 | REGMAP_IRQ_REG(BD71815_INT_BUCK4_OCP, 0, BD71815_INT_BUCK4_OCP_MASK), |
242 | REGMAP_IRQ_REG(BD71815_INT_BUCK5_OCP, 0, BD71815_INT_BUCK5_OCP_MASK), |
243 | REGMAP_IRQ_REG(BD71815_INT_LED_OVP, 0, BD71815_INT_LED_OVP_MASK), |
244 | REGMAP_IRQ_REG(BD71815_INT_LED_OCP, 0, BD71815_INT_LED_OCP_MASK), |
245 | REGMAP_IRQ_REG(BD71815_INT_LED_SCP, 0, BD71815_INT_LED_SCP_MASK), |
246 | /* DCIN1 interrupts */ |
247 | REGMAP_IRQ_REG(BD71815_INT_DCIN_RMV, 1, BD71815_INT_DCIN_RMV_MASK), |
248 | REGMAP_IRQ_REG(BD71815_INT_CLPS_OUT, 1, BD71815_INT_CLPS_OUT_MASK), |
249 | REGMAP_IRQ_REG(BD71815_INT_CLPS_IN, 1, BD71815_INT_CLPS_IN_MASK), |
250 | REGMAP_IRQ_REG(BD71815_INT_DCIN_OVP_RES, 1, BD71815_INT_DCIN_OVP_RES_MASK), |
251 | REGMAP_IRQ_REG(BD71815_INT_DCIN_OVP_DET, 1, BD71815_INT_DCIN_OVP_DET_MASK), |
252 | /* DCIN2 interrupts */ |
253 | REGMAP_IRQ_REG(BD71815_INT_DCIN_MON_RES, 2, BD71815_INT_DCIN_MON_RES_MASK), |
254 | REGMAP_IRQ_REG(BD71815_INT_DCIN_MON_DET, 2, BD71815_INT_DCIN_MON_DET_MASK), |
255 | REGMAP_IRQ_REG(BD71815_INT_WDOG, 2, BD71815_INT_WDOG_MASK), |
256 | /* Vsys */ |
257 | REGMAP_IRQ_REG(BD71815_INT_VSYS_UV_RES, 3, BD71815_INT_VSYS_UV_RES_MASK), |
258 | REGMAP_IRQ_REG(BD71815_INT_VSYS_UV_DET, 3, BD71815_INT_VSYS_UV_DET_MASK), |
259 | REGMAP_IRQ_REG(BD71815_INT_VSYS_LOW_RES, 3, BD71815_INT_VSYS_LOW_RES_MASK), |
260 | REGMAP_IRQ_REG(BD71815_INT_VSYS_LOW_DET, 3, BD71815_INT_VSYS_LOW_DET_MASK), |
261 | REGMAP_IRQ_REG(BD71815_INT_VSYS_MON_RES, 3, BD71815_INT_VSYS_MON_RES_MASK), |
262 | REGMAP_IRQ_REG(BD71815_INT_VSYS_MON_DET, 3, BD71815_INT_VSYS_MON_DET_MASK), |
263 | /* Charger */ |
264 | REGMAP_IRQ_REG(BD71815_INT_CHG_WDG_TEMP, 4, BD71815_INT_CHG_WDG_TEMP_MASK), |
265 | REGMAP_IRQ_REG(BD71815_INT_CHG_WDG_TIME, 4, BD71815_INT_CHG_WDG_TIME_MASK), |
266 | REGMAP_IRQ_REG(BD71815_INT_CHG_RECHARGE_RES, 4, BD71815_INT_CHG_RECHARGE_RES_MASK), |
267 | REGMAP_IRQ_REG(BD71815_INT_CHG_RECHARGE_DET, 4, BD71815_INT_CHG_RECHARGE_DET_MASK), |
268 | REGMAP_IRQ_REG(BD71815_INT_CHG_RANGED_TEMP_TRANSITION, 4, |
269 | BD71815_INT_CHG_RANGED_TEMP_TRANSITION_MASK), |
270 | REGMAP_IRQ_REG(BD71815_INT_CHG_STATE_TRANSITION, 4, BD71815_INT_CHG_STATE_TRANSITION_MASK), |
271 | /* Battery */ |
272 | REGMAP_IRQ_REG(BD71815_INT_BAT_TEMP_NORMAL, 5, BD71815_INT_BAT_TEMP_NORMAL_MASK), |
273 | REGMAP_IRQ_REG(BD71815_INT_BAT_TEMP_ERANGE, 5, BD71815_INT_BAT_TEMP_ERANGE_MASK), |
274 | REGMAP_IRQ_REG(BD71815_INT_BAT_REMOVED, 5, BD71815_INT_BAT_REMOVED_MASK), |
275 | REGMAP_IRQ_REG(BD71815_INT_BAT_DETECTED, 5, BD71815_INT_BAT_DETECTED_MASK), |
276 | REGMAP_IRQ_REG(BD71815_INT_THERM_REMOVED, 5, BD71815_INT_THERM_REMOVED_MASK), |
277 | REGMAP_IRQ_REG(BD71815_INT_THERM_DETECTED, 5, BD71815_INT_THERM_DETECTED_MASK), |
278 | /* Battery Mon 1 */ |
279 | REGMAP_IRQ_REG(BD71815_INT_BAT_DEAD, 6, BD71815_INT_BAT_DEAD_MASK), |
280 | REGMAP_IRQ_REG(BD71815_INT_BAT_SHORTC_RES, 6, BD71815_INT_BAT_SHORTC_RES_MASK), |
281 | REGMAP_IRQ_REG(BD71815_INT_BAT_SHORTC_DET, 6, BD71815_INT_BAT_SHORTC_DET_MASK), |
282 | REGMAP_IRQ_REG(BD71815_INT_BAT_LOW_VOLT_RES, 6, BD71815_INT_BAT_LOW_VOLT_RES_MASK), |
283 | REGMAP_IRQ_REG(BD71815_INT_BAT_LOW_VOLT_DET, 6, BD71815_INT_BAT_LOW_VOLT_DET_MASK), |
284 | REGMAP_IRQ_REG(BD71815_INT_BAT_OVER_VOLT_RES, 6, BD71815_INT_BAT_OVER_VOLT_RES_MASK), |
285 | REGMAP_IRQ_REG(BD71815_INT_BAT_OVER_VOLT_DET, 6, BD71815_INT_BAT_OVER_VOLT_DET_MASK), |
286 | /* Battery Mon 2 */ |
287 | REGMAP_IRQ_REG(BD71815_INT_BAT_MON_RES, 7, BD71815_INT_BAT_MON_RES_MASK), |
288 | REGMAP_IRQ_REG(BD71815_INT_BAT_MON_DET, 7, BD71815_INT_BAT_MON_DET_MASK), |
289 | /* Battery Mon 3 (Coulomb counter) */ |
290 | REGMAP_IRQ_REG(BD71815_INT_BAT_CC_MON1, 8, BD71815_INT_BAT_CC_MON1_MASK), |
291 | REGMAP_IRQ_REG(BD71815_INT_BAT_CC_MON2, 8, BD71815_INT_BAT_CC_MON2_MASK), |
292 | REGMAP_IRQ_REG(BD71815_INT_BAT_CC_MON3, 8, BD71815_INT_BAT_CC_MON3_MASK), |
293 | /* Battery Mon 4 */ |
294 | REGMAP_IRQ_REG(BD71815_INT_BAT_OVER_CURR_1_RES, 9, BD71815_INT_BAT_OVER_CURR_1_RES_MASK), |
295 | REGMAP_IRQ_REG(BD71815_INT_BAT_OVER_CURR_1_DET, 9, BD71815_INT_BAT_OVER_CURR_1_DET_MASK), |
296 | REGMAP_IRQ_REG(BD71815_INT_BAT_OVER_CURR_2_RES, 9, BD71815_INT_BAT_OVER_CURR_2_RES_MASK), |
297 | REGMAP_IRQ_REG(BD71815_INT_BAT_OVER_CURR_2_DET, 9, BD71815_INT_BAT_OVER_CURR_2_DET_MASK), |
298 | REGMAP_IRQ_REG(BD71815_INT_BAT_OVER_CURR_3_RES, 9, BD71815_INT_BAT_OVER_CURR_3_RES_MASK), |
299 | REGMAP_IRQ_REG(BD71815_INT_BAT_OVER_CURR_3_DET, 9, BD71815_INT_BAT_OVER_CURR_3_DET_MASK), |
300 | /* Temperature */ |
301 | REGMAP_IRQ_REG(BD71815_INT_TEMP_BAT_LOW_RES, 10, BD71815_INT_TEMP_BAT_LOW_RES_MASK), |
302 | REGMAP_IRQ_REG(BD71815_INT_TEMP_BAT_LOW_DET, 10, BD71815_INT_TEMP_BAT_LOW_DET_MASK), |
303 | REGMAP_IRQ_REG(BD71815_INT_TEMP_BAT_HI_RES, 10, BD71815_INT_TEMP_BAT_HI_RES_MASK), |
304 | REGMAP_IRQ_REG(BD71815_INT_TEMP_BAT_HI_DET, 10, BD71815_INT_TEMP_BAT_HI_DET_MASK), |
305 | REGMAP_IRQ_REG(BD71815_INT_TEMP_CHIP_OVER_125_RES, 10, |
306 | BD71815_INT_TEMP_CHIP_OVER_125_RES_MASK), |
307 | REGMAP_IRQ_REG(BD71815_INT_TEMP_CHIP_OVER_125_DET, 10, |
308 | BD71815_INT_TEMP_CHIP_OVER_125_DET_MASK), |
309 | REGMAP_IRQ_REG(BD71815_INT_TEMP_CHIP_OVER_VF_RES, 10, |
310 | BD71815_INT_TEMP_CHIP_OVER_VF_RES_MASK), |
311 | REGMAP_IRQ_REG(BD71815_INT_TEMP_CHIP_OVER_VF_DET, 10, |
312 | BD71815_INT_TEMP_CHIP_OVER_VF_DET_MASK), |
313 | /* RTC Alarm */ |
314 | REGMAP_IRQ_REG(BD71815_INT_RTC0, 11, BD71815_INT_RTC0_MASK), |
315 | REGMAP_IRQ_REG(BD71815_INT_RTC1, 11, BD71815_INT_RTC1_MASK), |
316 | REGMAP_IRQ_REG(BD71815_INT_RTC2, 11, BD71815_INT_RTC2_MASK), |
317 | }; |
318 | |
319 | static struct regmap_irq bd71828_irqs[] = { |
320 | REGMAP_IRQ_REG(BD71828_INT_BUCK1_OCP, 0, BD71828_INT_BUCK1_OCP_MASK), |
321 | REGMAP_IRQ_REG(BD71828_INT_BUCK2_OCP, 0, BD71828_INT_BUCK2_OCP_MASK), |
322 | REGMAP_IRQ_REG(BD71828_INT_BUCK3_OCP, 0, BD71828_INT_BUCK3_OCP_MASK), |
323 | REGMAP_IRQ_REG(BD71828_INT_BUCK4_OCP, 0, BD71828_INT_BUCK4_OCP_MASK), |
324 | REGMAP_IRQ_REG(BD71828_INT_BUCK5_OCP, 0, BD71828_INT_BUCK5_OCP_MASK), |
325 | REGMAP_IRQ_REG(BD71828_INT_BUCK6_OCP, 0, BD71828_INT_BUCK6_OCP_MASK), |
326 | REGMAP_IRQ_REG(BD71828_INT_BUCK7_OCP, 0, BD71828_INT_BUCK7_OCP_MASK), |
327 | REGMAP_IRQ_REG(BD71828_INT_PGFAULT, 0, BD71828_INT_PGFAULT_MASK), |
328 | /* DCIN1 interrupts */ |
329 | REGMAP_IRQ_REG(BD71828_INT_DCIN_DET, 1, BD71828_INT_DCIN_DET_MASK), |
330 | REGMAP_IRQ_REG(BD71828_INT_DCIN_RMV, 1, BD71828_INT_DCIN_RMV_MASK), |
331 | REGMAP_IRQ_REG(BD71828_INT_CLPS_OUT, 1, BD71828_INT_CLPS_OUT_MASK), |
332 | REGMAP_IRQ_REG(BD71828_INT_CLPS_IN, 1, BD71828_INT_CLPS_IN_MASK), |
333 | /* DCIN2 interrupts */ |
334 | REGMAP_IRQ_REG(BD71828_INT_DCIN_MON_RES, 2, BD71828_INT_DCIN_MON_RES_MASK), |
335 | REGMAP_IRQ_REG(BD71828_INT_DCIN_MON_DET, 2, BD71828_INT_DCIN_MON_DET_MASK), |
336 | REGMAP_IRQ_REG(BD71828_INT_LONGPUSH, 2, BD71828_INT_LONGPUSH_MASK), |
337 | REGMAP_IRQ_REG(BD71828_INT_MIDPUSH, 2, BD71828_INT_MIDPUSH_MASK), |
338 | REGMAP_IRQ_REG(BD71828_INT_SHORTPUSH, 2, BD71828_INT_SHORTPUSH_MASK), |
339 | REGMAP_IRQ_REG(BD71828_INT_PUSH, 2, BD71828_INT_PUSH_MASK), |
340 | REGMAP_IRQ_REG(BD71828_INT_WDOG, 2, BD71828_INT_WDOG_MASK), |
341 | REGMAP_IRQ_REG(BD71828_INT_SWRESET, 2, BD71828_INT_SWRESET_MASK), |
342 | /* Vsys */ |
343 | REGMAP_IRQ_REG(BD71828_INT_VSYS_UV_RES, 3, BD71828_INT_VSYS_UV_RES_MASK), |
344 | REGMAP_IRQ_REG(BD71828_INT_VSYS_UV_DET, 3, BD71828_INT_VSYS_UV_DET_MASK), |
345 | REGMAP_IRQ_REG(BD71828_INT_VSYS_LOW_RES, 3, BD71828_INT_VSYS_LOW_RES_MASK), |
346 | REGMAP_IRQ_REG(BD71828_INT_VSYS_LOW_DET, 3, BD71828_INT_VSYS_LOW_DET_MASK), |
347 | REGMAP_IRQ_REG(BD71828_INT_VSYS_HALL_IN, 3, BD71828_INT_VSYS_HALL_IN_MASK), |
348 | REGMAP_IRQ_REG(BD71828_INT_VSYS_HALL_TOGGLE, 3, BD71828_INT_VSYS_HALL_TOGGLE_MASK), |
349 | REGMAP_IRQ_REG(BD71828_INT_VSYS_MON_RES, 3, BD71828_INT_VSYS_MON_RES_MASK), |
350 | REGMAP_IRQ_REG(BD71828_INT_VSYS_MON_DET, 3, BD71828_INT_VSYS_MON_DET_MASK), |
351 | /* Charger */ |
352 | REGMAP_IRQ_REG(BD71828_INT_CHG_DCIN_ILIM, 4, BD71828_INT_CHG_DCIN_ILIM_MASK), |
353 | REGMAP_IRQ_REG(BD71828_INT_CHG_TOPOFF_TO_DONE, 4, BD71828_INT_CHG_TOPOFF_TO_DONE_MASK), |
354 | REGMAP_IRQ_REG(BD71828_INT_CHG_WDG_TEMP, 4, BD71828_INT_CHG_WDG_TEMP_MASK), |
355 | REGMAP_IRQ_REG(BD71828_INT_CHG_WDG_TIME, 4, BD71828_INT_CHG_WDG_TIME_MASK), |
356 | REGMAP_IRQ_REG(BD71828_INT_CHG_RECHARGE_RES, 4, BD71828_INT_CHG_RECHARGE_RES_MASK), |
357 | REGMAP_IRQ_REG(BD71828_INT_CHG_RECHARGE_DET, 4, BD71828_INT_CHG_RECHARGE_DET_MASK), |
358 | REGMAP_IRQ_REG(BD71828_INT_CHG_RANGED_TEMP_TRANSITION, 4, |
359 | BD71828_INT_CHG_RANGED_TEMP_TRANSITION_MASK), |
360 | REGMAP_IRQ_REG(BD71828_INT_CHG_STATE_TRANSITION, 4, BD71828_INT_CHG_STATE_TRANSITION_MASK), |
361 | /* Battery */ |
362 | REGMAP_IRQ_REG(BD71828_INT_BAT_TEMP_NORMAL, 5, BD71828_INT_BAT_TEMP_NORMAL_MASK), |
363 | REGMAP_IRQ_REG(BD71828_INT_BAT_TEMP_ERANGE, 5, BD71828_INT_BAT_TEMP_ERANGE_MASK), |
364 | REGMAP_IRQ_REG(BD71828_INT_BAT_TEMP_WARN, 5, BD71828_INT_BAT_TEMP_WARN_MASK), |
365 | REGMAP_IRQ_REG(BD71828_INT_BAT_REMOVED, 5, BD71828_INT_BAT_REMOVED_MASK), |
366 | REGMAP_IRQ_REG(BD71828_INT_BAT_DETECTED, 5, BD71828_INT_BAT_DETECTED_MASK), |
367 | REGMAP_IRQ_REG(BD71828_INT_THERM_REMOVED, 5, BD71828_INT_THERM_REMOVED_MASK), |
368 | REGMAP_IRQ_REG(BD71828_INT_THERM_DETECTED, 5, BD71828_INT_THERM_DETECTED_MASK), |
369 | /* Battery Mon 1 */ |
370 | REGMAP_IRQ_REG(BD71828_INT_BAT_DEAD, 6, BD71828_INT_BAT_DEAD_MASK), |
371 | REGMAP_IRQ_REG(BD71828_INT_BAT_SHORTC_RES, 6, BD71828_INT_BAT_SHORTC_RES_MASK), |
372 | REGMAP_IRQ_REG(BD71828_INT_BAT_SHORTC_DET, 6, BD71828_INT_BAT_SHORTC_DET_MASK), |
373 | REGMAP_IRQ_REG(BD71828_INT_BAT_LOW_VOLT_RES, 6, BD71828_INT_BAT_LOW_VOLT_RES_MASK), |
374 | REGMAP_IRQ_REG(BD71828_INT_BAT_LOW_VOLT_DET, 6, BD71828_INT_BAT_LOW_VOLT_DET_MASK), |
375 | REGMAP_IRQ_REG(BD71828_INT_BAT_OVER_VOLT_RES, 6, BD71828_INT_BAT_OVER_VOLT_RES_MASK), |
376 | REGMAP_IRQ_REG(BD71828_INT_BAT_OVER_VOLT_DET, 6, BD71828_INT_BAT_OVER_VOLT_DET_MASK), |
377 | /* Battery Mon 2 */ |
378 | REGMAP_IRQ_REG(BD71828_INT_BAT_MON_RES, 7, BD71828_INT_BAT_MON_RES_MASK), |
379 | REGMAP_IRQ_REG(BD71828_INT_BAT_MON_DET, 7, BD71828_INT_BAT_MON_DET_MASK), |
380 | /* Battery Mon 3 (Coulomb counter) */ |
381 | REGMAP_IRQ_REG(BD71828_INT_BAT_CC_MON1, 8, BD71828_INT_BAT_CC_MON1_MASK), |
382 | REGMAP_IRQ_REG(BD71828_INT_BAT_CC_MON2, 8, BD71828_INT_BAT_CC_MON2_MASK), |
383 | REGMAP_IRQ_REG(BD71828_INT_BAT_CC_MON3, 8, BD71828_INT_BAT_CC_MON3_MASK), |
384 | /* Battery Mon 4 */ |
385 | REGMAP_IRQ_REG(BD71828_INT_BAT_OVER_CURR_1_RES, 9, BD71828_INT_BAT_OVER_CURR_1_RES_MASK), |
386 | REGMAP_IRQ_REG(BD71828_INT_BAT_OVER_CURR_1_DET, 9, BD71828_INT_BAT_OVER_CURR_1_DET_MASK), |
387 | REGMAP_IRQ_REG(BD71828_INT_BAT_OVER_CURR_2_RES, 9, BD71828_INT_BAT_OVER_CURR_2_RES_MASK), |
388 | REGMAP_IRQ_REG(BD71828_INT_BAT_OVER_CURR_2_DET, 9, BD71828_INT_BAT_OVER_CURR_2_DET_MASK), |
389 | REGMAP_IRQ_REG(BD71828_INT_BAT_OVER_CURR_3_RES, 9, BD71828_INT_BAT_OVER_CURR_3_RES_MASK), |
390 | REGMAP_IRQ_REG(BD71828_INT_BAT_OVER_CURR_3_DET, 9, BD71828_INT_BAT_OVER_CURR_3_DET_MASK), |
391 | /* Temperature */ |
392 | REGMAP_IRQ_REG(BD71828_INT_TEMP_BAT_LOW_RES, 10, BD71828_INT_TEMP_BAT_LOW_RES_MASK), |
393 | REGMAP_IRQ_REG(BD71828_INT_TEMP_BAT_LOW_DET, 10, BD71828_INT_TEMP_BAT_LOW_DET_MASK), |
394 | REGMAP_IRQ_REG(BD71828_INT_TEMP_BAT_HI_RES, 10, BD71828_INT_TEMP_BAT_HI_RES_MASK), |
395 | REGMAP_IRQ_REG(BD71828_INT_TEMP_BAT_HI_DET, 10, BD71828_INT_TEMP_BAT_HI_DET_MASK), |
396 | REGMAP_IRQ_REG(BD71828_INT_TEMP_CHIP_OVER_125_RES, 10, |
397 | BD71828_INT_TEMP_CHIP_OVER_125_RES_MASK), |
398 | REGMAP_IRQ_REG(BD71828_INT_TEMP_CHIP_OVER_125_DET, 10, |
399 | BD71828_INT_TEMP_CHIP_OVER_125_DET_MASK), |
400 | REGMAP_IRQ_REG(BD71828_INT_TEMP_CHIP_OVER_VF_DET, 10, |
401 | BD71828_INT_TEMP_CHIP_OVER_VF_DET_MASK), |
402 | REGMAP_IRQ_REG(BD71828_INT_TEMP_CHIP_OVER_VF_RES, 10, |
403 | BD71828_INT_TEMP_CHIP_OVER_VF_RES_MASK), |
404 | /* RTC Alarm */ |
405 | REGMAP_IRQ_REG(BD71828_INT_RTC0, 11, BD71828_INT_RTC0_MASK), |
406 | REGMAP_IRQ_REG(BD71828_INT_RTC1, 11, BD71828_INT_RTC1_MASK), |
407 | REGMAP_IRQ_REG(BD71828_INT_RTC2, 11, BD71828_INT_RTC2_MASK), |
408 | }; |
409 | |
410 | static struct regmap_irq_chip bd71828_irq_chip = { |
411 | .name = "bd71828_irq" , |
412 | .main_status = BD71828_REG_INT_MAIN, |
413 | .irqs = &bd71828_irqs[0], |
414 | .num_irqs = ARRAY_SIZE(bd71828_irqs), |
415 | .status_base = BD71828_REG_INT_BUCK, |
416 | .unmask_base = BD71828_REG_INT_MASK_BUCK, |
417 | .ack_base = BD71828_REG_INT_BUCK, |
418 | .init_ack_masked = true, |
419 | .num_regs = 12, |
420 | .num_main_regs = 1, |
421 | .sub_reg_offsets = &bd718xx_sub_irq_offsets[0], |
422 | .num_main_status_bits = 8, |
423 | .irq_reg_stride = 1, |
424 | }; |
425 | |
426 | static struct regmap_irq_chip bd71815_irq_chip = { |
427 | .name = "bd71815_irq" , |
428 | .main_status = BD71815_REG_INT_STAT, |
429 | .irqs = &bd71815_irqs[0], |
430 | .num_irqs = ARRAY_SIZE(bd71815_irqs), |
431 | .status_base = BD71815_REG_INT_STAT_01, |
432 | .unmask_base = BD71815_REG_INT_EN_01, |
433 | .ack_base = BD71815_REG_INT_STAT_01, |
434 | .init_ack_masked = true, |
435 | .num_regs = 12, |
436 | .num_main_regs = 1, |
437 | .sub_reg_offsets = &bd718xx_sub_irq_offsets[0], |
438 | .num_main_status_bits = 8, |
439 | .irq_reg_stride = 1, |
440 | }; |
441 | |
442 | static int set_clk_mode(struct device *dev, struct regmap *regmap, |
443 | int clkmode_reg) |
444 | { |
445 | int ret; |
446 | unsigned int open_drain; |
447 | |
448 | ret = of_property_read_u32(np: dev->of_node, propname: "rohm,clkout-open-drain" , out_value: &open_drain); |
449 | if (ret) { |
450 | if (ret == -EINVAL) |
451 | return 0; |
452 | return ret; |
453 | } |
454 | if (open_drain > 1) { |
455 | dev_err(dev, "bad clk32kout mode configuration" ); |
456 | return -EINVAL; |
457 | } |
458 | |
459 | if (open_drain) |
460 | return regmap_update_bits(map: regmap, reg: clkmode_reg, OUT32K_MODE, |
461 | OUT32K_MODE_OPEN_DRAIN); |
462 | |
463 | return regmap_update_bits(map: regmap, reg: clkmode_reg, OUT32K_MODE, |
464 | OUT32K_MODE_CMOS); |
465 | } |
466 | |
467 | static int bd71828_i2c_probe(struct i2c_client *i2c) |
468 | { |
469 | struct regmap_irq_chip_data *irq_data; |
470 | int ret; |
471 | struct regmap *regmap; |
472 | const struct regmap_config *regmap_config; |
473 | struct regmap_irq_chip *irqchip; |
474 | unsigned int chip_type; |
475 | struct mfd_cell *mfd; |
476 | int cells; |
477 | int button_irq; |
478 | int clkmode_reg; |
479 | |
480 | if (!i2c->irq) { |
481 | dev_err(&i2c->dev, "No IRQ configured\n" ); |
482 | return -EINVAL; |
483 | } |
484 | |
485 | chip_type = (unsigned int)(uintptr_t) |
486 | of_device_get_match_data(dev: &i2c->dev); |
487 | switch (chip_type) { |
488 | case ROHM_CHIP_TYPE_BD71828: |
489 | mfd = bd71828_mfd_cells; |
490 | cells = ARRAY_SIZE(bd71828_mfd_cells); |
491 | regmap_config = &bd71828_regmap; |
492 | irqchip = &bd71828_irq_chip; |
493 | clkmode_reg = BD71828_REG_OUT32K; |
494 | button_irq = BD71828_INT_SHORTPUSH; |
495 | break; |
496 | case ROHM_CHIP_TYPE_BD71815: |
497 | mfd = bd71815_mfd_cells; |
498 | cells = ARRAY_SIZE(bd71815_mfd_cells); |
499 | regmap_config = &bd71815_regmap; |
500 | irqchip = &bd71815_irq_chip; |
501 | clkmode_reg = BD71815_REG_OUT32K; |
502 | /* |
503 | * If BD71817 support is needed we should be able to handle it |
504 | * with proper DT configs + BD71815 drivers + power-button. |
505 | * BD71815 data-sheet does not list the power-button IRQ so we |
506 | * don't use it. |
507 | */ |
508 | button_irq = 0; |
509 | break; |
510 | default: |
511 | dev_err(&i2c->dev, "Unknown device type" ); |
512 | return -EINVAL; |
513 | } |
514 | |
515 | regmap = devm_regmap_init_i2c(i2c, regmap_config); |
516 | if (IS_ERR(ptr: regmap)) |
517 | return dev_err_probe(dev: &i2c->dev, err: PTR_ERR(ptr: regmap), |
518 | fmt: "Failed to initialize Regmap\n" ); |
519 | |
520 | ret = devm_regmap_add_irq_chip(dev: &i2c->dev, map: regmap, irq: i2c->irq, |
521 | IRQF_ONESHOT, irq_base: 0, chip: irqchip, data: &irq_data); |
522 | if (ret) |
523 | return dev_err_probe(dev: &i2c->dev, err: ret, |
524 | fmt: "Failed to add IRQ chip\n" ); |
525 | |
526 | dev_dbg(&i2c->dev, "Registered %d IRQs for chip\n" , |
527 | irqchip->num_irqs); |
528 | |
529 | if (button_irq) { |
530 | ret = regmap_irq_get_virq(data: irq_data, irq: button_irq); |
531 | if (ret < 0) |
532 | return dev_err_probe(dev: &i2c->dev, err: ret, |
533 | fmt: "Failed to get the power-key IRQ\n" ); |
534 | |
535 | button.irq = ret; |
536 | } |
537 | |
538 | ret = set_clk_mode(dev: &i2c->dev, regmap, clkmode_reg); |
539 | if (ret) |
540 | return ret; |
541 | |
542 | ret = devm_mfd_add_devices(dev: &i2c->dev, PLATFORM_DEVID_AUTO, cells: mfd, n_devs: cells, |
543 | NULL, irq_base: 0, irq_domain: regmap_irq_get_domain(data: irq_data)); |
544 | if (ret) |
545 | dev_err_probe(dev: &i2c->dev, err: ret, fmt: "Failed to create subdevices\n" ); |
546 | |
547 | return ret; |
548 | } |
549 | |
550 | static const struct of_device_id bd71828_of_match[] = { |
551 | { |
552 | .compatible = "rohm,bd71828" , |
553 | .data = (void *)ROHM_CHIP_TYPE_BD71828, |
554 | }, { |
555 | .compatible = "rohm,bd71815" , |
556 | .data = (void *)ROHM_CHIP_TYPE_BD71815, |
557 | }, |
558 | { }, |
559 | }; |
560 | MODULE_DEVICE_TABLE(of, bd71828_of_match); |
561 | |
562 | static struct i2c_driver bd71828_drv = { |
563 | .driver = { |
564 | .name = "rohm-bd71828" , |
565 | .of_match_table = bd71828_of_match, |
566 | }, |
567 | .probe = bd71828_i2c_probe, |
568 | }; |
569 | module_i2c_driver(bd71828_drv); |
570 | |
571 | MODULE_AUTHOR("Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>" ); |
572 | MODULE_DESCRIPTION("ROHM BD71828 Power Management IC driver" ); |
573 | MODULE_LICENSE("GPL" ); |
574 | |