4 * Copyright (c) 2011 Samsung Electronics Co., Ltd
5 * http://www.samsung.com
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation; either version 2 of the License, or (at your
10 * option) any later version.
14 #include <linux/device.h>
15 #include <linux/interrupt.h>
16 #include <linux/irq.h>
17 #include <linux/mfd/s5m87xx/s5m-core.h>
24 static struct s5m_irq_data s5m8767_irqs
[] = {
25 [S5M8767_IRQ_PWRR
] = {
27 .mask
= S5M8767_IRQ_PWRR_MASK
,
29 [S5M8767_IRQ_PWRF
] = {
31 .mask
= S5M8767_IRQ_PWRF_MASK
,
33 [S5M8767_IRQ_PWR1S
] = {
35 .mask
= S5M8767_IRQ_PWR1S_MASK
,
37 [S5M8767_IRQ_JIGR
] = {
39 .mask
= S5M8767_IRQ_JIGR_MASK
,
41 [S5M8767_IRQ_JIGF
] = {
43 .mask
= S5M8767_IRQ_JIGF_MASK
,
45 [S5M8767_IRQ_LOWBAT2
] = {
47 .mask
= S5M8767_IRQ_LOWBAT2_MASK
,
49 [S5M8767_IRQ_LOWBAT1
] = {
51 .mask
= S5M8767_IRQ_LOWBAT1_MASK
,
55 .mask
= S5M8767_IRQ_MRB_MASK
,
57 [S5M8767_IRQ_DVSOK2
] = {
59 .mask
= S5M8767_IRQ_DVSOK2_MASK
,
61 [S5M8767_IRQ_DVSOK3
] = {
63 .mask
= S5M8767_IRQ_DVSOK3_MASK
,
65 [S5M8767_IRQ_DVSOK4
] = {
67 .mask
= S5M8767_IRQ_DVSOK4_MASK
,
69 [S5M8767_IRQ_RTC60S
] = {
71 .mask
= S5M8767_IRQ_RTC60S_MASK
,
73 [S5M8767_IRQ_RTCA1
] = {
75 .mask
= S5M8767_IRQ_RTCA1_MASK
,
77 [S5M8767_IRQ_RTCA2
] = {
79 .mask
= S5M8767_IRQ_RTCA2_MASK
,
81 [S5M8767_IRQ_SMPL
] = {
83 .mask
= S5M8767_IRQ_SMPL_MASK
,
85 [S5M8767_IRQ_RTC1S
] = {
87 .mask
= S5M8767_IRQ_RTC1S_MASK
,
89 [S5M8767_IRQ_WTSR
] = {
91 .mask
= S5M8767_IRQ_WTSR_MASK
,
95 static struct s5m_irq_data s5m8763_irqs
[] = {
96 [S5M8763_IRQ_DCINF
] = {
98 .mask
= S5M8763_IRQ_DCINF_MASK
,
100 [S5M8763_IRQ_DCINR
] = {
102 .mask
= S5M8763_IRQ_DCINR_MASK
,
104 [S5M8763_IRQ_JIGF
] = {
106 .mask
= S5M8763_IRQ_JIGF_MASK
,
108 [S5M8763_IRQ_JIGR
] = {
110 .mask
= S5M8763_IRQ_JIGR_MASK
,
112 [S5M8763_IRQ_PWRONF
] = {
114 .mask
= S5M8763_IRQ_PWRONF_MASK
,
116 [S5M8763_IRQ_PWRONR
] = {
118 .mask
= S5M8763_IRQ_PWRONR_MASK
,
120 [S5M8763_IRQ_WTSREVNT
] = {
122 .mask
= S5M8763_IRQ_WTSREVNT_MASK
,
124 [S5M8763_IRQ_SMPLEVNT
] = {
126 .mask
= S5M8763_IRQ_SMPLEVNT_MASK
,
128 [S5M8763_IRQ_ALARM1
] = {
130 .mask
= S5M8763_IRQ_ALARM1_MASK
,
132 [S5M8763_IRQ_ALARM0
] = {
134 .mask
= S5M8763_IRQ_ALARM0_MASK
,
136 [S5M8763_IRQ_ONKEY1S
] = {
138 .mask
= S5M8763_IRQ_ONKEY1S_MASK
,
140 [S5M8763_IRQ_TOPOFFR
] = {
142 .mask
= S5M8763_IRQ_TOPOFFR_MASK
,
144 [S5M8763_IRQ_DCINOVPR
] = {
146 .mask
= S5M8763_IRQ_DCINOVPR_MASK
,
148 [S5M8763_IRQ_CHGRSTF
] = {
150 .mask
= S5M8763_IRQ_CHGRSTF_MASK
,
152 [S5M8763_IRQ_DONER
] = {
154 .mask
= S5M8763_IRQ_DONER_MASK
,
156 [S5M8763_IRQ_CHGFAULT
] = {
158 .mask
= S5M8763_IRQ_CHGFAULT_MASK
,
160 [S5M8763_IRQ_LOBAT1
] = {
162 .mask
= S5M8763_IRQ_LOBAT1_MASK
,
164 [S5M8763_IRQ_LOBAT2
] = {
166 .mask
= S5M8763_IRQ_LOBAT2_MASK
,
170 static inline struct s5m_irq_data
*
171 irq_to_s5m8767_irq(struct s5m87xx_dev
*s5m87xx
, int irq
)
173 return &s5m8767_irqs
[irq
- s5m87xx
->irq_base
];
176 static void s5m8767_irq_lock(struct irq_data
*data
)
178 struct s5m87xx_dev
*s5m87xx
= irq_data_get_irq_chip_data(data
);
180 mutex_lock(&s5m87xx
->irqlock
);
183 static void s5m8767_irq_sync_unlock(struct irq_data
*data
)
185 struct s5m87xx_dev
*s5m87xx
= irq_data_get_irq_chip_data(data
);
188 for (i
= 0; i
< ARRAY_SIZE(s5m87xx
->irq_masks_cur
); i
++) {
189 if (s5m87xx
->irq_masks_cur
[i
] != s5m87xx
->irq_masks_cache
[i
]) {
190 s5m87xx
->irq_masks_cache
[i
] = s5m87xx
->irq_masks_cur
[i
];
191 s5m_reg_write(s5m87xx
, S5M8767_REG_INT1M
+ i
,
192 s5m87xx
->irq_masks_cur
[i
]);
196 mutex_unlock(&s5m87xx
->irqlock
);
199 static void s5m8767_irq_unmask(struct irq_data
*data
)
201 struct s5m87xx_dev
*s5m87xx
= irq_data_get_irq_chip_data(data
);
202 struct s5m_irq_data
*irq_data
= irq_to_s5m8767_irq(s5m87xx
,
205 s5m87xx
->irq_masks_cur
[irq_data
->reg
- 1] &= ~irq_data
->mask
;
208 static void s5m8767_irq_mask(struct irq_data
*data
)
210 struct s5m87xx_dev
*s5m87xx
= irq_data_get_irq_chip_data(data
);
211 struct s5m_irq_data
*irq_data
= irq_to_s5m8767_irq(s5m87xx
,
214 s5m87xx
->irq_masks_cur
[irq_data
->reg
- 1] |= irq_data
->mask
;
217 static struct irq_chip s5m8767_irq_chip
= {
219 .irq_bus_lock
= s5m8767_irq_lock
,
220 .irq_bus_sync_unlock
= s5m8767_irq_sync_unlock
,
221 .irq_mask
= s5m8767_irq_mask
,
222 .irq_unmask
= s5m8767_irq_unmask
,
225 static inline struct s5m_irq_data
*
226 irq_to_s5m8763_irq(struct s5m87xx_dev
*s5m87xx
, int irq
)
228 return &s5m8763_irqs
[irq
- s5m87xx
->irq_base
];
231 static void s5m8763_irq_lock(struct irq_data
*data
)
233 struct s5m87xx_dev
*s5m87xx
= irq_data_get_irq_chip_data(data
);
235 mutex_lock(&s5m87xx
->irqlock
);
238 static void s5m8763_irq_sync_unlock(struct irq_data
*data
)
240 struct s5m87xx_dev
*s5m87xx
= irq_data_get_irq_chip_data(data
);
243 for (i
= 0; i
< ARRAY_SIZE(s5m87xx
->irq_masks_cur
); i
++) {
244 if (s5m87xx
->irq_masks_cur
[i
] != s5m87xx
->irq_masks_cache
[i
]) {
245 s5m87xx
->irq_masks_cache
[i
] = s5m87xx
->irq_masks_cur
[i
];
246 s5m_reg_write(s5m87xx
, S5M8763_REG_IRQM1
+ i
,
247 s5m87xx
->irq_masks_cur
[i
]);
251 mutex_unlock(&s5m87xx
->irqlock
);
254 static void s5m8763_irq_unmask(struct irq_data
*data
)
256 struct s5m87xx_dev
*s5m87xx
= irq_data_get_irq_chip_data(data
);
257 struct s5m_irq_data
*irq_data
= irq_to_s5m8763_irq(s5m87xx
,
260 s5m87xx
->irq_masks_cur
[irq_data
->reg
- 1] &= ~irq_data
->mask
;
263 static void s5m8763_irq_mask(struct irq_data
*data
)
265 struct s5m87xx_dev
*s5m87xx
= irq_data_get_irq_chip_data(data
);
266 struct s5m_irq_data
*irq_data
= irq_to_s5m8763_irq(s5m87xx
,
269 s5m87xx
->irq_masks_cur
[irq_data
->reg
- 1] |= irq_data
->mask
;
272 static struct irq_chip s5m8763_irq_chip
= {
274 .irq_bus_lock
= s5m8763_irq_lock
,
275 .irq_bus_sync_unlock
= s5m8763_irq_sync_unlock
,
276 .irq_mask
= s5m8763_irq_mask
,
277 .irq_unmask
= s5m8763_irq_unmask
,
281 static irqreturn_t
s5m8767_irq_thread(int irq
, void *data
)
283 struct s5m87xx_dev
*s5m87xx
= data
;
284 u8 irq_reg
[NUM_IRQ_REGS
-1];
289 ret
= s5m_bulk_read(s5m87xx
, S5M8767_REG_INT1
,
290 NUM_IRQ_REGS
- 1, irq_reg
);
292 dev_err(s5m87xx
->dev
, "Failed to read interrupt register: %d\n",
297 for (i
= 0; i
< NUM_IRQ_REGS
- 1; i
++)
298 irq_reg
[i
] &= ~s5m87xx
->irq_masks_cur
[i
];
300 for (i
= 0; i
< S5M8767_IRQ_NR
; i
++) {
301 if (irq_reg
[s5m8767_irqs
[i
].reg
- 1] & s5m8767_irqs
[i
].mask
)
302 handle_nested_irq(s5m87xx
->irq_base
+ i
);
308 static irqreturn_t
s5m8763_irq_thread(int irq
, void *data
)
310 struct s5m87xx_dev
*s5m87xx
= data
;
311 u8 irq_reg
[NUM_IRQ_REGS
];
315 ret
= s5m_bulk_read(s5m87xx
, S5M8763_REG_IRQ1
,
316 NUM_IRQ_REGS
, irq_reg
);
318 dev_err(s5m87xx
->dev
, "Failed to read interrupt register: %d\n",
323 for (i
= 0; i
< NUM_IRQ_REGS
; i
++)
324 irq_reg
[i
] &= ~s5m87xx
->irq_masks_cur
[i
];
326 for (i
= 0; i
< S5M8763_IRQ_NR
; i
++) {
327 if (irq_reg
[s5m8763_irqs
[i
].reg
- 1] & s5m8763_irqs
[i
].mask
)
328 handle_nested_irq(s5m87xx
->irq_base
+ i
);
334 int s5m_irq_resume(struct s5m87xx_dev
*s5m87xx
)
336 if (s5m87xx
->irq
&& s5m87xx
->irq_base
){
337 switch (s5m87xx
->device_type
) {
339 s5m8763_irq_thread(s5m87xx
->irq_base
, s5m87xx
);
342 s5m8767_irq_thread(s5m87xx
->irq_base
, s5m87xx
);
352 int s5m_irq_init(struct s5m87xx_dev
*s5m87xx
)
357 int type
= s5m87xx
->device_type
;
360 dev_warn(s5m87xx
->dev
,
361 "No interrupt specified, no interrupts\n");
362 s5m87xx
->irq_base
= 0;
366 if (!s5m87xx
->irq_base
) {
367 dev_err(s5m87xx
->dev
,
368 "No interrupt base specified, no interrupts\n");
372 mutex_init(&s5m87xx
->irqlock
);
376 for (i
= 0; i
< NUM_IRQ_REGS
; i
++) {
377 s5m87xx
->irq_masks_cur
[i
] = 0xff;
378 s5m87xx
->irq_masks_cache
[i
] = 0xff;
379 s5m_reg_write(s5m87xx
, S5M8763_REG_IRQM1
+ i
,
383 s5m_reg_write(s5m87xx
, S5M8763_REG_STATUSM1
, 0xff);
384 s5m_reg_write(s5m87xx
, S5M8763_REG_STATUSM2
, 0xff);
386 for (i
= 0; i
< S5M8763_IRQ_NR
; i
++) {
387 cur_irq
= i
+ s5m87xx
->irq_base
;
388 irq_set_chip_data(cur_irq
, s5m87xx
);
389 irq_set_chip_and_handler(cur_irq
, &s5m8763_irq_chip
,
391 irq_set_nested_thread(cur_irq
, 1);
393 set_irq_flags(cur_irq
, IRQF_VALID
);
395 irq_set_noprobe(cur_irq
);
399 ret
= request_threaded_irq(s5m87xx
->irq
, NULL
,
401 IRQF_TRIGGER_FALLING
| IRQF_ONESHOT
,
402 "s5m87xx-irq", s5m87xx
);
404 dev_err(s5m87xx
->dev
, "Failed to request IRQ %d: %d\n",
410 for (i
= 0; i
< NUM_IRQ_REGS
- 1; i
++) {
411 s5m87xx
->irq_masks_cur
[i
] = 0xff;
412 s5m87xx
->irq_masks_cache
[i
] = 0xff;
413 s5m_reg_write(s5m87xx
, S5M8767_REG_INT1M
+ i
,
416 for (i
= 0; i
< S5M8767_IRQ_NR
; i
++) {
417 cur_irq
= i
+ s5m87xx
->irq_base
;
418 irq_set_chip_data(cur_irq
, s5m87xx
);
420 dev_err(s5m87xx
->dev
,
421 "Failed to irq_set_chip_data %d: %d\n",
426 irq_set_chip_and_handler(cur_irq
, &s5m8767_irq_chip
,
428 irq_set_nested_thread(cur_irq
, 1);
430 set_irq_flags(cur_irq
, IRQF_VALID
);
432 irq_set_noprobe(cur_irq
);
436 ret
= request_threaded_irq(s5m87xx
->irq
, NULL
,
438 IRQF_TRIGGER_FALLING
| IRQF_ONESHOT
,
439 "s5m87xx-irq", s5m87xx
);
441 dev_err(s5m87xx
->dev
, "Failed to request IRQ %d: %d\n",
455 ret
= request_threaded_irq(s5m87xx
->ono
, NULL
,
457 IRQF_TRIGGER_FALLING
|
458 IRQF_TRIGGER_RISING
|
459 IRQF_ONESHOT
, "s5m87xx-ono",
463 ret
= request_threaded_irq(s5m87xx
->ono
, NULL
,
465 IRQF_TRIGGER_FALLING
|
466 IRQF_TRIGGER_RISING
|
467 IRQF_ONESHOT
, "s5m87xx-ono", s5m87xx
);
474 dev_err(s5m87xx
->dev
, "Failed to request IRQ %d: %d\n",
480 void s5m_irq_exit(struct s5m87xx_dev
*s5m87xx
)
483 free_irq(s5m87xx
->ono
, s5m87xx
);
486 free_irq(s5m87xx
->irq
, s5m87xx
);