2 * twl4030-irq.c - TWL4030/TPS659x0 irq support
4 * Copyright (C) 2005-2006 Texas Instruments, Inc.
6 * Modifications to defer interrupt handling to a kernel thread:
7 * Copyright (C) 2006 MontaVista Software, Inc.
9 * Based on tlv320aic23.c:
10 * Copyright (c) by Kai Svahn <kai.svahn@nokia.com>
12 * Code cleanup and modifications to IRQ handler.
13 * by syed khasim <x0khasim@ti.com>
15 * This program is free software; you can redistribute it and/or modify
16 * it under the terms of the GNU General Public License as published by
17 * the Free Software Foundation; either version 2 of the License, or
18 * (at your option) any later version.
20 * This program is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
25 * You should have received a copy of the GNU General Public License
26 * along with this program; if not, write to the Free Software
27 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
30 #include <linux/init.h>
31 #include <linux/interrupt.h>
32 #include <linux/irq.h>
33 #include <linux/kthread.h>
35 #include <linux/i2c/twl4030.h>
38 static inline void activate_irq(int irq)
41 /* ARM requires an extra step to clear IRQ_NOREQUEST, which it
42 * sets on behalf of every irq_chip. Also sets IRQ_NOPROBE.
44 set_irq_flags(irq, IRQF_VALID);
46 /* same effect on other architectures */
51 /* PIH register offsets */
52 #define REG_PIH_ISR_P1 0x01
53 #define REG_PIH_ISR_P2 0x02
54 #define REG_PIH_SIR 0x03 /* for testing */
56 /*----------------------------------------------------------------------*/
59 * struct twl4030_mod_iregs - TWL module IMR/ISR regs to mask/clear at init
60 * @mod_no: TWL4030 module number (e.g., TWL4030_MODULE_GPIO)
61 * @sih_ctrl: address of module SIH_CTRL register
62 * @reg_cnt: number of IMR/ISR regs
63 * @imrs: pointer to array of TWL module interrupt mask register indices
64 * @isrs: pointer to array of TWL module interrupt status register indices
66 * Ties together TWL4030 modules and lists of IMR/ISR registers to mask/clear
67 * during twl_init_irq().
69 struct twl4030_mod_iregs {
77 /* TWL4030 INT module interrupt mask registers */
78 static const u8 __initconst twl4030_int_imr_regs[] = {
83 /* TWL4030 INT module interrupt status registers */
84 static const u8 __initconst twl4030_int_isr_regs[] = {
89 /* TWL4030 INTERRUPTS module interrupt mask registers */
90 static const u8 __initconst twl4030_interrupts_imr_regs[] = {
91 TWL4030_INTERRUPTS_BCIIMR1A,
92 TWL4030_INTERRUPTS_BCIIMR1B,
93 TWL4030_INTERRUPTS_BCIIMR2A,
94 TWL4030_INTERRUPTS_BCIIMR2B,
97 /* TWL4030 INTERRUPTS module interrupt status registers */
98 static const u8 __initconst twl4030_interrupts_isr_regs[] = {
99 TWL4030_INTERRUPTS_BCIISR1A,
100 TWL4030_INTERRUPTS_BCIISR1B,
101 TWL4030_INTERRUPTS_BCIISR2A,
102 TWL4030_INTERRUPTS_BCIISR2B,
105 /* TWL4030 MADC module interrupt mask registers */
106 static const u8 __initconst twl4030_madc_imr_regs[] = {
111 /* TWL4030 MADC module interrupt status registers */
112 static const u8 __initconst twl4030_madc_isr_regs[] = {
117 /* TWL4030 keypad module interrupt mask registers */
118 static const u8 __initconst twl4030_keypad_imr_regs[] = {
119 TWL4030_KEYPAD_KEYP_IMR1,
120 TWL4030_KEYPAD_KEYP_IMR2,
123 /* TWL4030 keypad module interrupt status registers */
124 static const u8 __initconst twl4030_keypad_isr_regs[] = {
125 TWL4030_KEYPAD_KEYP_ISR1,
126 TWL4030_KEYPAD_KEYP_ISR2,
129 /* TWL4030 GPIO module interrupt mask registers */
130 static const u8 __initconst twl4030_gpio_imr_regs[] = {
139 /* TWL4030 GPIO module interrupt status registers */
140 static const u8 __initconst twl4030_gpio_isr_regs[] = {
149 /* TWL4030 modules that have IMR/ISR registers that must be masked/cleared */
150 static const struct twl4030_mod_iregs __initconst twl4030_mod_regs[] = {
152 .mod_no = TWL4030_MODULE_INT,
153 .sih_ctrl = TWL4030_INT_PWR_SIH_CTRL,
154 .reg_cnt = ARRAY_SIZE(twl4030_int_imr_regs),
155 .imrs = twl4030_int_imr_regs,
156 .isrs = twl4030_int_isr_regs,
159 .mod_no = TWL4030_MODULE_INTERRUPTS,
160 .sih_ctrl = TWL4030_INTERRUPTS_BCISIHCTRL,
161 .reg_cnt = ARRAY_SIZE(twl4030_interrupts_imr_regs),
162 .imrs = twl4030_interrupts_imr_regs,
163 .isrs = twl4030_interrupts_isr_regs,
166 .mod_no = TWL4030_MODULE_MADC,
167 .sih_ctrl = TWL4030_MADC_SIH_CTRL,
168 .reg_cnt = ARRAY_SIZE(twl4030_madc_imr_regs),
169 .imrs = twl4030_madc_imr_regs,
170 .isrs = twl4030_madc_isr_regs,
173 .mod_no = TWL4030_MODULE_KEYPAD,
174 .sih_ctrl = TWL4030_KEYPAD_KEYP_SIH_CTRL,
175 .reg_cnt = ARRAY_SIZE(twl4030_keypad_imr_regs),
176 .imrs = twl4030_keypad_imr_regs,
177 .isrs = twl4030_keypad_isr_regs,
180 .mod_no = TWL4030_MODULE_GPIO,
181 .sih_ctrl = REG_GPIO_SIH_CTRL,
182 .reg_cnt = ARRAY_SIZE(twl4030_gpio_imr_regs),
183 .imrs = twl4030_gpio_imr_regs,
184 .isrs = twl4030_gpio_isr_regs,
188 /*----------------------------------------------------------------------*/
190 static unsigned twl4030_irq_base;
192 static struct completion irq_event;
195 * This thread processes interrupts reported by the Primary Interrupt Handler.
197 static int twl4030_irq_thread(void *data)
199 long irq = (long)data;
200 irq_desc_t *desc = irq_desc + irq;
201 static unsigned i2c_errors;
202 const static unsigned max_i2c_errors = 100;
204 current->flags |= PF_NOFREEZE;
206 while (!kthread_should_stop()) {
211 /* Wait for IRQ, then read PIH irq status (also blocking) */
212 wait_for_completion_interruptible(&irq_event);
214 ret = twl4030_i2c_read_u8(TWL4030_MODULE_PIH, &pih_isr,
217 pr_warning("twl4030: I2C error %d reading PIH ISR\n",
219 if (++i2c_errors >= max_i2c_errors) {
220 printk(KERN_ERR "Maximum I2C error count"
221 " exceeded. Terminating %s.\n",
225 complete(&irq_event);
229 /* these handlers deal with the relevant SIH irq status */
231 for (module_irq = twl4030_irq_base;
233 pih_isr >>= 1, module_irq++) {
235 irq_desc_t *d = irq_desc + module_irq;
237 /* These can't be masked ... always warn
238 * if we get any surprises.
240 if (d->status & IRQ_DISABLED)
241 note_interrupt(module_irq, d,
244 d->handle_irq(module_irq, d);
249 desc->chip->unmask(irq);
256 * handle_twl4030_pih() is the desc->handle method for the twl4030 interrupt.
257 * This is a chained interrupt, so there is no desc->action method for it.
258 * Now we need to query the interrupt controller in the twl4030 to determine
259 * which module is generating the interrupt request. However, we can't do i2c
260 * transactions in interrupt context, so we must defer that work to a kernel
261 * thread. All we do here is acknowledge and mask the interrupt and wakeup
264 static void handle_twl4030_pih(unsigned int irq, irq_desc_t *desc)
266 /* Acknowledge, clear *AND* mask the interrupt... */
267 desc->chip->ack(irq);
268 complete(&irq_event);
271 static struct task_struct *start_twl4030_irq_thread(long irq)
273 struct task_struct *thread;
275 init_completion(&irq_event);
276 thread = kthread_run(twl4030_irq_thread, (void *)irq, "twl4030-irq");
278 pr_err("twl4030: could not create irq %ld thread!\n", irq);
283 /*----------------------------------------------------------------------*/
286 * twl4030_i2c_clear_isr - clear TWL4030 SIH ISR regs via read + write
287 * @mod_no: TWL4030 module number
288 * @reg: register index to clear
289 * @cor: value of the <module>_SIH_CTRL.COR bit (1 or 0)
291 * Either reads (cor == 1) or writes (cor == 0) to a TWL4030 interrupt
292 * status register to ensure that any prior interrupts are cleared.
293 * Returns the status from the I2C read operation.
295 static int __init twl4030_i2c_clear_isr(u8 mod_no, u8 reg, u8 cor)
299 return (cor) ? twl4030_i2c_read_u8(mod_no, &tmp, reg) :
300 twl4030_i2c_write_u8(mod_no, 0xff, reg);
304 * twl4030_read_cor_bit - are TWL module ISRs cleared by reads or writes?
305 * @mod_no: TWL4030 module number
306 * @reg: register index to clear
308 * Returns 1 if the TWL4030 SIH interrupt status registers (ISRs) for
309 * the specified TWL module are cleared by reads, or 0 if cleared by
312 static int twl4030_read_cor_bit(u8 mod_no, u8 reg)
316 WARN_ON(twl4030_i2c_read_u8(mod_no, &tmp, reg) < 0);
318 tmp &= TWL4030_SIH_CTRL_COR_MASK;
319 tmp >>= __ffs(TWL4030_SIH_CTRL_COR_MASK);
325 * twl4030_mask_clear_intrs - mask and clear all TWL4030 interrupts
326 * @t: pointer to twl4030_mod_iregs array
327 * @t_sz: ARRAY_SIZE(t) (starting at 1)
329 * Mask all TWL4030 interrupt mask registers (IMRs) and clear all
330 * interrupt status registers (ISRs). No return value, but will WARN if
331 * any I2C operations fail.
333 static void __init twl4030_mask_clear_intrs(const struct twl4030_mod_iregs *t,
339 * N.B. - further efficiency is possible here. Eight I2C
340 * operations on BCI and GPIO modules are avoidable if I2C
341 * burst read/write transactions were implemented. Would
342 * probably save about 1ms of boot time and a small amount of
345 for (i = 0; i < t_sz; i++) {
346 const struct twl4030_mod_iregs tmr = t[i];
349 /* Are ISRs cleared by reads or writes? */
350 cor = twl4030_read_cor_bit(tmr.mod_no, tmr.sih_ctrl);
352 for (j = 0; j < tmr.reg_cnt; j++) {
354 /* Mask interrupts at the TWL4030 */
355 WARN_ON(twl4030_i2c_write_u8(tmr.mod_no, 0xff,
358 /* Clear TWL4030 ISRs */
359 WARN_ON(twl4030_i2c_clear_isr(tmr.mod_no,
360 tmr.isrs[j], cor) < 0);
366 int twl_init_irq(int irq_num, unsigned irq_base, unsigned irq_end)
368 static struct irq_chip twl4030_irq_chip;
373 * Mask and clear all TWL4030 interrupts since initially we do
374 * not have any TWL4030 module interrupt handlers present
376 twl4030_mask_clear_intrs(twl4030_mod_regs,
377 ARRAY_SIZE(twl4030_mod_regs));
379 twl4030_irq_base = irq_base;
381 /* install an irq handler for each of the SIH modules;
382 * clone dummy irq_chip since PIH can't *do* anything
384 twl4030_irq_chip = dummy_irq_chip;
385 twl4030_irq_chip.name = "twl4030";
387 for (i = irq_base; i < irq_end; i++) {
388 set_irq_chip_and_handler(i, &twl4030_irq_chip,
393 /* install an irq handler to demultiplex the TWL4030 interrupt */
394 set_irq_data(irq_num, start_twl4030_irq_thread(irq_num));
395 set_irq_chained_handler(irq_num, handle_twl4030_pih);
400 int twl_exit_irq(void)
402 /* FIXME undo twl_init_irq() */
403 if (twl4030_irq_base) {
404 pr_err("twl4030: can't yet clean up IRQs?\n");