1 // SPDX-License-Identifier: GPL-2.0+
2 //
3 // Copyright (c) 2011-2014 Samsung Electronics Co., Ltd
4 //              http://www.samsung.com
5 
6 #include <linux/device.h>
7 #include <linux/interrupt.h>
8 #include <linux/irq.h>
9 #include <linux/module.h>
10 #include <linux/regmap.h>
11 
12 #include <linux/mfd/samsung/core.h>
13 #include <linux/mfd/samsung/irq.h>
14 #include <linux/mfd/samsung/s2mps11.h>
15 #include <linux/mfd/samsung/s2mps14.h>
16 #include <linux/mfd/samsung/s2mpu02.h>
17 #include <linux/mfd/samsung/s2mpu05.h>
18 #include <linux/mfd/samsung/s5m8767.h>
19 
20 static const struct regmap_irq s2mps11_irqs[] = {
21 	[S2MPS11_IRQ_PWRONF] = {
22 		.reg_offset = 0,
23 		.mask = S2MPS11_IRQ_PWRONF_MASK,
24 	},
25 	[S2MPS11_IRQ_PWRONR] = {
26 		.reg_offset = 0,
27 		.mask = S2MPS11_IRQ_PWRONR_MASK,
28 	},
29 	[S2MPS11_IRQ_JIGONBF] = {
30 		.reg_offset = 0,
31 		.mask = S2MPS11_IRQ_JIGONBF_MASK,
32 	},
33 	[S2MPS11_IRQ_JIGONBR] = {
34 		.reg_offset = 0,
35 		.mask = S2MPS11_IRQ_JIGONBR_MASK,
36 	},
37 	[S2MPS11_IRQ_ACOKBF] = {
38 		.reg_offset = 0,
39 		.mask = S2MPS11_IRQ_ACOKBF_MASK,
40 	},
41 	[S2MPS11_IRQ_ACOKBR] = {
42 		.reg_offset = 0,
43 		.mask = S2MPS11_IRQ_ACOKBR_MASK,
44 	},
45 	[S2MPS11_IRQ_PWRON1S] = {
46 		.reg_offset = 0,
47 		.mask = S2MPS11_IRQ_PWRON1S_MASK,
48 	},
49 	[S2MPS11_IRQ_MRB] = {
50 		.reg_offset = 0,
51 		.mask = S2MPS11_IRQ_MRB_MASK,
52 	},
53 	[S2MPS11_IRQ_RTC60S] = {
54 		.reg_offset = 1,
55 		.mask = S2MPS11_IRQ_RTC60S_MASK,
56 	},
57 	[S2MPS11_IRQ_RTCA1] = {
58 		.reg_offset = 1,
59 		.mask = S2MPS11_IRQ_RTCA1_MASK,
60 	},
61 	[S2MPS11_IRQ_RTCA0] = {
62 		.reg_offset = 1,
63 		.mask = S2MPS11_IRQ_RTCA0_MASK,
64 	},
65 	[S2MPS11_IRQ_SMPL] = {
66 		.reg_offset = 1,
67 		.mask = S2MPS11_IRQ_SMPL_MASK,
68 	},
69 	[S2MPS11_IRQ_RTC1S] = {
70 		.reg_offset = 1,
71 		.mask = S2MPS11_IRQ_RTC1S_MASK,
72 	},
73 	[S2MPS11_IRQ_WTSR] = {
74 		.reg_offset = 1,
75 		.mask = S2MPS11_IRQ_WTSR_MASK,
76 	},
77 	[S2MPS11_IRQ_INT120C] = {
78 		.reg_offset = 2,
79 		.mask = S2MPS11_IRQ_INT120C_MASK,
80 	},
81 	[S2MPS11_IRQ_INT140C] = {
82 		.reg_offset = 2,
83 		.mask = S2MPS11_IRQ_INT140C_MASK,
84 	},
85 };
86 
87 static const struct regmap_irq s2mps14_irqs[] = {
88 	[S2MPS14_IRQ_PWRONF] = {
89 		.reg_offset = 0,
90 		.mask = S2MPS11_IRQ_PWRONF_MASK,
91 	},
92 	[S2MPS14_IRQ_PWRONR] = {
93 		.reg_offset = 0,
94 		.mask = S2MPS11_IRQ_PWRONR_MASK,
95 	},
96 	[S2MPS14_IRQ_JIGONBF] = {
97 		.reg_offset = 0,
98 		.mask = S2MPS11_IRQ_JIGONBF_MASK,
99 	},
100 	[S2MPS14_IRQ_JIGONBR] = {
101 		.reg_offset = 0,
102 		.mask = S2MPS11_IRQ_JIGONBR_MASK,
103 	},
104 	[S2MPS14_IRQ_ACOKBF] = {
105 		.reg_offset = 0,
106 		.mask = S2MPS11_IRQ_ACOKBF_MASK,
107 	},
108 	[S2MPS14_IRQ_ACOKBR] = {
109 		.reg_offset = 0,
110 		.mask = S2MPS11_IRQ_ACOKBR_MASK,
111 	},
112 	[S2MPS14_IRQ_PWRON1S] = {
113 		.reg_offset = 0,
114 		.mask = S2MPS11_IRQ_PWRON1S_MASK,
115 	},
116 	[S2MPS14_IRQ_MRB] = {
117 		.reg_offset = 0,
118 		.mask = S2MPS11_IRQ_MRB_MASK,
119 	},
120 	[S2MPS14_IRQ_RTC60S] = {
121 		.reg_offset = 1,
122 		.mask = S2MPS11_IRQ_RTC60S_MASK,
123 	},
124 	[S2MPS14_IRQ_RTCA1] = {
125 		.reg_offset = 1,
126 		.mask = S2MPS11_IRQ_RTCA1_MASK,
127 	},
128 	[S2MPS14_IRQ_RTCA0] = {
129 		.reg_offset = 1,
130 		.mask = S2MPS11_IRQ_RTCA0_MASK,
131 	},
132 	[S2MPS14_IRQ_SMPL] = {
133 		.reg_offset = 1,
134 		.mask = S2MPS11_IRQ_SMPL_MASK,
135 	},
136 	[S2MPS14_IRQ_RTC1S] = {
137 		.reg_offset = 1,
138 		.mask = S2MPS11_IRQ_RTC1S_MASK,
139 	},
140 	[S2MPS14_IRQ_WTSR] = {
141 		.reg_offset = 1,
142 		.mask = S2MPS11_IRQ_WTSR_MASK,
143 	},
144 	[S2MPS14_IRQ_INT120C] = {
145 		.reg_offset = 2,
146 		.mask = S2MPS11_IRQ_INT120C_MASK,
147 	},
148 	[S2MPS14_IRQ_INT140C] = {
149 		.reg_offset = 2,
150 		.mask = S2MPS11_IRQ_INT140C_MASK,
151 	},
152 	[S2MPS14_IRQ_TSD] = {
153 		.reg_offset = 2,
154 		.mask = S2MPS14_IRQ_TSD_MASK,
155 	},
156 };
157 
158 static const struct regmap_irq s2mpu02_irqs[] = {
159 	[S2MPU02_IRQ_PWRONF] = {
160 		.reg_offset = 0,
161 		.mask = S2MPS11_IRQ_PWRONF_MASK,
162 	},
163 	[S2MPU02_IRQ_PWRONR] = {
164 		.reg_offset = 0,
165 		.mask = S2MPS11_IRQ_PWRONR_MASK,
166 	},
167 	[S2MPU02_IRQ_JIGONBF] = {
168 		.reg_offset = 0,
169 		.mask = S2MPS11_IRQ_JIGONBF_MASK,
170 	},
171 	[S2MPU02_IRQ_JIGONBR] = {
172 		.reg_offset = 0,
173 		.mask = S2MPS11_IRQ_JIGONBR_MASK,
174 	},
175 	[S2MPU02_IRQ_ACOKBF] = {
176 		.reg_offset = 0,
177 		.mask = S2MPS11_IRQ_ACOKBF_MASK,
178 	},
179 	[S2MPU02_IRQ_ACOKBR] = {
180 		.reg_offset = 0,
181 		.mask = S2MPS11_IRQ_ACOKBR_MASK,
182 	},
183 	[S2MPU02_IRQ_PWRON1S] = {
184 		.reg_offset = 0,
185 		.mask = S2MPS11_IRQ_PWRON1S_MASK,
186 	},
187 	[S2MPU02_IRQ_MRB] = {
188 		.reg_offset = 0,
189 		.mask = S2MPS11_IRQ_MRB_MASK,
190 	},
191 	[S2MPU02_IRQ_RTC60S] = {
192 		.reg_offset = 1,
193 		.mask = S2MPS11_IRQ_RTC60S_MASK,
194 	},
195 	[S2MPU02_IRQ_RTCA1] = {
196 		.reg_offset = 1,
197 		.mask = S2MPS11_IRQ_RTCA1_MASK,
198 	},
199 	[S2MPU02_IRQ_RTCA0] = {
200 		.reg_offset = 1,
201 		.mask = S2MPS11_IRQ_RTCA0_MASK,
202 	},
203 	[S2MPU02_IRQ_SMPL] = {
204 		.reg_offset = 1,
205 		.mask = S2MPS11_IRQ_SMPL_MASK,
206 	},
207 	[S2MPU02_IRQ_RTC1S] = {
208 		.reg_offset = 1,
209 		.mask = S2MPS11_IRQ_RTC1S_MASK,
210 	},
211 	[S2MPU02_IRQ_WTSR] = {
212 		.reg_offset = 1,
213 		.mask = S2MPS11_IRQ_WTSR_MASK,
214 	},
215 	[S2MPU02_IRQ_INT120C] = {
216 		.reg_offset = 2,
217 		.mask = S2MPS11_IRQ_INT120C_MASK,
218 	},
219 	[S2MPU02_IRQ_INT140C] = {
220 		.reg_offset = 2,
221 		.mask = S2MPS11_IRQ_INT140C_MASK,
222 	},
223 	[S2MPU02_IRQ_TSD] = {
224 		.reg_offset = 2,
225 		.mask = S2MPS14_IRQ_TSD_MASK,
226 	},
227 };
228 
229 static const struct regmap_irq s2mpu05_irqs[] = {
230 	REGMAP_IRQ_REG(S2MPU05_IRQ_PWRONF, 0, S2MPU05_IRQ_PWRONF_MASK),
231 	REGMAP_IRQ_REG(S2MPU05_IRQ_PWRONR, 0, S2MPU05_IRQ_PWRONR_MASK),
232 	REGMAP_IRQ_REG(S2MPU05_IRQ_JIGONBF, 0, S2MPU05_IRQ_JIGONBF_MASK),
233 	REGMAP_IRQ_REG(S2MPU05_IRQ_JIGONBR, 0, S2MPU05_IRQ_JIGONBR_MASK),
234 	REGMAP_IRQ_REG(S2MPU05_IRQ_ACOKF, 0, S2MPU05_IRQ_ACOKF_MASK),
235 	REGMAP_IRQ_REG(S2MPU05_IRQ_ACOKR, 0, S2MPU05_IRQ_ACOKR_MASK),
236 	REGMAP_IRQ_REG(S2MPU05_IRQ_PWRON1S, 0, S2MPU05_IRQ_PWRON1S_MASK),
237 	REGMAP_IRQ_REG(S2MPU05_IRQ_MRB, 0, S2MPU05_IRQ_MRB_MASK),
238 	REGMAP_IRQ_REG(S2MPU05_IRQ_RTC60S, 1, S2MPU05_IRQ_RTC60S_MASK),
239 	REGMAP_IRQ_REG(S2MPU05_IRQ_RTCA1, 1, S2MPU05_IRQ_RTCA1_MASK),
240 	REGMAP_IRQ_REG(S2MPU05_IRQ_RTCA0, 1, S2MPU05_IRQ_RTCA0_MASK),
241 	REGMAP_IRQ_REG(S2MPU05_IRQ_SMPL, 1, S2MPU05_IRQ_SMPL_MASK),
242 	REGMAP_IRQ_REG(S2MPU05_IRQ_RTC1S, 1, S2MPU05_IRQ_RTC1S_MASK),
243 	REGMAP_IRQ_REG(S2MPU05_IRQ_WTSR, 1, S2MPU05_IRQ_WTSR_MASK),
244 	REGMAP_IRQ_REG(S2MPU05_IRQ_INT120C, 2, S2MPU05_IRQ_INT120C_MASK),
245 	REGMAP_IRQ_REG(S2MPU05_IRQ_INT140C, 2, S2MPU05_IRQ_INT140C_MASK),
246 	REGMAP_IRQ_REG(S2MPU05_IRQ_TSD, 2, S2MPU05_IRQ_TSD_MASK),
247 };
248 
249 static const struct regmap_irq s5m8767_irqs[] = {
250 	[S5M8767_IRQ_PWRR] = {
251 		.reg_offset = 0,
252 		.mask = S5M8767_IRQ_PWRR_MASK,
253 	},
254 	[S5M8767_IRQ_PWRF] = {
255 		.reg_offset = 0,
256 		.mask = S5M8767_IRQ_PWRF_MASK,
257 	},
258 	[S5M8767_IRQ_PWR1S] = {
259 		.reg_offset = 0,
260 		.mask = S5M8767_IRQ_PWR1S_MASK,
261 	},
262 	[S5M8767_IRQ_JIGR] = {
263 		.reg_offset = 0,
264 		.mask = S5M8767_IRQ_JIGR_MASK,
265 	},
266 	[S5M8767_IRQ_JIGF] = {
267 		.reg_offset = 0,
268 		.mask = S5M8767_IRQ_JIGF_MASK,
269 	},
270 	[S5M8767_IRQ_LOWBAT2] = {
271 		.reg_offset = 0,
272 		.mask = S5M8767_IRQ_LOWBAT2_MASK,
273 	},
274 	[S5M8767_IRQ_LOWBAT1] = {
275 		.reg_offset = 0,
276 		.mask = S5M8767_IRQ_LOWBAT1_MASK,
277 	},
278 	[S5M8767_IRQ_MRB] = {
279 		.reg_offset = 1,
280 		.mask = S5M8767_IRQ_MRB_MASK,
281 	},
282 	[S5M8767_IRQ_DVSOK2] = {
283 		.reg_offset = 1,
284 		.mask = S5M8767_IRQ_DVSOK2_MASK,
285 	},
286 	[S5M8767_IRQ_DVSOK3] = {
287 		.reg_offset = 1,
288 		.mask = S5M8767_IRQ_DVSOK3_MASK,
289 	},
290 	[S5M8767_IRQ_DVSOK4] = {
291 		.reg_offset = 1,
292 		.mask = S5M8767_IRQ_DVSOK4_MASK,
293 	},
294 	[S5M8767_IRQ_RTC60S] = {
295 		.reg_offset = 2,
296 		.mask = S5M8767_IRQ_RTC60S_MASK,
297 	},
298 	[S5M8767_IRQ_RTCA1] = {
299 		.reg_offset = 2,
300 		.mask = S5M8767_IRQ_RTCA1_MASK,
301 	},
302 	[S5M8767_IRQ_RTCA2] = {
303 		.reg_offset = 2,
304 		.mask = S5M8767_IRQ_RTCA2_MASK,
305 	},
306 	[S5M8767_IRQ_SMPL] = {
307 		.reg_offset = 2,
308 		.mask = S5M8767_IRQ_SMPL_MASK,
309 	},
310 	[S5M8767_IRQ_RTC1S] = {
311 		.reg_offset = 2,
312 		.mask = S5M8767_IRQ_RTC1S_MASK,
313 	},
314 	[S5M8767_IRQ_WTSR] = {
315 		.reg_offset = 2,
316 		.mask = S5M8767_IRQ_WTSR_MASK,
317 	},
318 };
319 
320 static const struct regmap_irq_chip s2mps11_irq_chip = {
321 	.name = "s2mps11",
322 	.irqs = s2mps11_irqs,
323 	.num_irqs = ARRAY_SIZE(s2mps11_irqs),
324 	.num_regs = 3,
325 	.status_base = S2MPS11_REG_INT1,
326 	.mask_base = S2MPS11_REG_INT1M,
327 	.ack_base = S2MPS11_REG_INT1,
328 };
329 
330 #define S2MPS1X_IRQ_CHIP_COMMON_DATA		\
331 	.irqs = s2mps14_irqs,			\
332 	.num_irqs = ARRAY_SIZE(s2mps14_irqs),	\
333 	.num_regs = 3,				\
334 	.status_base = S2MPS14_REG_INT1,	\
335 	.mask_base = S2MPS14_REG_INT1M,		\
336 	.ack_base = S2MPS14_REG_INT1		\
337 
338 static const struct regmap_irq_chip s2mps13_irq_chip = {
339 	.name = "s2mps13",
340 	S2MPS1X_IRQ_CHIP_COMMON_DATA,
341 };
342 
343 static const struct regmap_irq_chip s2mps14_irq_chip = {
344 	.name = "s2mps14",
345 	S2MPS1X_IRQ_CHIP_COMMON_DATA,
346 };
347 
348 static const struct regmap_irq_chip s2mps15_irq_chip = {
349 	.name = "s2mps15",
350 	S2MPS1X_IRQ_CHIP_COMMON_DATA,
351 };
352 
353 static const struct regmap_irq_chip s2mpu02_irq_chip = {
354 	.name = "s2mpu02",
355 	.irqs = s2mpu02_irqs,
356 	.num_irqs = ARRAY_SIZE(s2mpu02_irqs),
357 	.num_regs = 3,
358 	.status_base = S2MPU02_REG_INT1,
359 	.mask_base = S2MPU02_REG_INT1M,
360 	.ack_base = S2MPU02_REG_INT1,
361 };
362 
363 static const struct regmap_irq_chip s2mpu05_irq_chip = {
364 	.name = "s2mpu05",
365 	.irqs = s2mpu05_irqs,
366 	.num_irqs = ARRAY_SIZE(s2mpu05_irqs),
367 	.num_regs = 3,
368 	.status_base = S2MPU05_REG_INT1,
369 	.mask_base = S2MPU05_REG_INT1M,
370 	.ack_base = S2MPU05_REG_INT1,
371 };
372 
373 static const struct regmap_irq_chip s5m8767_irq_chip = {
374 	.name = "s5m8767",
375 	.irqs = s5m8767_irqs,
376 	.num_irqs = ARRAY_SIZE(s5m8767_irqs),
377 	.num_regs = 3,
378 	.status_base = S5M8767_REG_INT1,
379 	.mask_base = S5M8767_REG_INT1M,
380 	.ack_base = S5M8767_REG_INT1,
381 };
382 
sec_irq_init(struct sec_pmic_dev * sec_pmic)383 int sec_irq_init(struct sec_pmic_dev *sec_pmic)
384 {
385 	int ret = 0;
386 	int type = sec_pmic->device_type;
387 	const struct regmap_irq_chip *sec_irq_chip;
388 
389 	if (!sec_pmic->irq) {
390 		dev_warn(sec_pmic->dev,
391 			 "No interrupt specified, no interrupts\n");
392 		return 0;
393 	}
394 
395 	switch (type) {
396 	case S5M8767X:
397 		sec_irq_chip = &s5m8767_irq_chip;
398 		break;
399 	case S2MPA01:
400 		sec_irq_chip = &s2mps14_irq_chip;
401 		break;
402 	case S2MPS11X:
403 		sec_irq_chip = &s2mps11_irq_chip;
404 		break;
405 	case S2MPS13X:
406 		sec_irq_chip = &s2mps13_irq_chip;
407 		break;
408 	case S2MPS14X:
409 		sec_irq_chip = &s2mps14_irq_chip;
410 		break;
411 	case S2MPS15X:
412 		sec_irq_chip = &s2mps15_irq_chip;
413 		break;
414 	case S2MPU02:
415 		sec_irq_chip = &s2mpu02_irq_chip;
416 		break;
417 	case S2MPU05:
418 		sec_irq_chip = &s2mpu05_irq_chip;
419 		break;
420 	default:
421 		dev_err(sec_pmic->dev, "Unknown device type %lu\n",
422 			sec_pmic->device_type);
423 		return -EINVAL;
424 	}
425 
426 	ret = devm_regmap_add_irq_chip(sec_pmic->dev, sec_pmic->regmap_pmic,
427 				       sec_pmic->irq, IRQF_ONESHOT,
428 				       0, sec_irq_chip, &sec_pmic->irq_data);
429 	if (ret != 0) {
430 		dev_err(sec_pmic->dev, "Failed to register IRQ chip: %d\n", ret);
431 		return ret;
432 	}
433 
434 	/*
435 	 * The rtc-s5m driver requests S2MPS14_IRQ_RTCA0 also for S2MPS11
436 	 * so the interrupt number must be consistent.
437 	 */
438 	BUILD_BUG_ON(((enum s2mps14_irq)S2MPS11_IRQ_RTCA0) != S2MPS14_IRQ_RTCA0);
439 
440 	return 0;
441 }
442 EXPORT_SYMBOL_GPL(sec_irq_init);
443 
444 MODULE_AUTHOR("Sangbeom Kim <sbkim73@samsung.com>");
445 MODULE_AUTHOR("Chanwoo Choi <cw00.choi@samsung.com>");
446 MODULE_AUTHOR("Krzysztof Kozlowski <krzk@kernel.org>");
447 MODULE_DESCRIPTION("Interrupt support for the S5M MFD");
448 MODULE_LICENSE("GPL");
449