]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blob - drivers/mfd/twl4030-irq.c
create twl4030-irq.c
[linux-2.6-omap-h63xx.git] / drivers / mfd / twl4030-irq.c
1 /*
2  * twl4030-irq.c - TWL4030/TPS659x0 irq support
3  *
4  * Copyright (C) 2005-2006 Texas Instruments, Inc.
5  *
6  * Modifications to defer interrupt handling to a kernel thread:
7  * Copyright (C) 2006 MontaVista Software, Inc.
8  *
9  * Based on tlv320aic23.c:
10  * Copyright (c) by Kai Svahn <kai.svahn@nokia.com>
11  *
12  * Code cleanup and modifications to IRQ handler.
13  * by syed khasim <x0khasim@ti.com>
14  *
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.
19  *
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.
24  *
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
28  */
29
30 #include <linux/init.h>
31 #include <linux/interrupt.h>
32 #include <linux/irq.h>
33 #include <linux/kthread.h>
34
35 #include <linux/i2c/twl4030.h>
36
37
38 static inline void activate_irq(int irq)
39 {
40 #ifdef CONFIG_ARM
41         /* ARM requires an extra step to clear IRQ_NOREQUEST, which it
42          * sets on behalf of every irq_chip.  Also sets IRQ_NOPROBE.
43          */
44         set_irq_flags(irq, IRQF_VALID);
45 #else
46         /* same effect on other architectures */
47         set_irq_noprobe(irq);
48 #endif
49 }
50
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 */
55
56 /*----------------------------------------------------------------------*/
57
58 /**
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
65  *
66  * Ties together TWL4030 modules and lists of IMR/ISR registers to mask/clear
67  * during twl_init_irq().
68  */
69 struct twl4030_mod_iregs {
70         const u8 mod_no;
71         const u8 sih_ctrl;
72         const u8 reg_cnt;
73         const u8 *imrs;
74         const u8 *isrs;
75 };
76
77 /* TWL4030 INT module interrupt mask registers */
78 static const u8 __initconst twl4030_int_imr_regs[] = {
79         TWL4030_INT_PWR_IMR1,
80         TWL4030_INT_PWR_IMR2,
81 };
82
83 /* TWL4030 INT module interrupt status registers */
84 static const u8 __initconst twl4030_int_isr_regs[] = {
85         TWL4030_INT_PWR_ISR1,
86         TWL4030_INT_PWR_ISR2,
87 };
88
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,
95 };
96
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,
103 };
104
105 /* TWL4030 MADC module interrupt mask registers */
106 static const u8 __initconst twl4030_madc_imr_regs[] = {
107         TWL4030_MADC_IMR1,
108         TWL4030_MADC_IMR2,
109 };
110
111 /* TWL4030 MADC module interrupt status registers */
112 static const u8 __initconst twl4030_madc_isr_regs[] = {
113         TWL4030_MADC_ISR1,
114         TWL4030_MADC_ISR2,
115 };
116
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,
121 };
122
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,
127 };
128
129 /* TWL4030 GPIO module interrupt mask registers */
130 static const u8 __initconst twl4030_gpio_imr_regs[] = {
131         REG_GPIO_IMR1A,
132         REG_GPIO_IMR1B,
133         REG_GPIO_IMR2A,
134         REG_GPIO_IMR2B,
135         REG_GPIO_IMR3A,
136         REG_GPIO_IMR3B,
137 };
138
139 /* TWL4030 GPIO module interrupt status registers */
140 static const u8 __initconst twl4030_gpio_isr_regs[] = {
141         REG_GPIO_ISR1A,
142         REG_GPIO_ISR1B,
143         REG_GPIO_ISR2A,
144         REG_GPIO_ISR2B,
145         REG_GPIO_ISR3A,
146         REG_GPIO_ISR3B,
147 };
148
149 /* TWL4030 modules that have IMR/ISR registers that must be masked/cleared */
150 static const struct twl4030_mod_iregs __initconst twl4030_mod_regs[] = {
151         {
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,
157         },
158         {
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,
164         },
165         {
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,
171         },
172         {
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,
178         },
179         {
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,
185         },
186 };
187
188 /*----------------------------------------------------------------------*/
189
190 static unsigned twl4030_irq_base;
191
192 static struct completion irq_event;
193
194 /*
195  * This thread processes interrupts reported by the Primary Interrupt Handler.
196  */
197 static int twl4030_irq_thread(void *data)
198 {
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;
203
204         current->flags |= PF_NOFREEZE;
205
206         while (!kthread_should_stop()) {
207                 int ret;
208                 int module_irq;
209                 u8 pih_isr;
210
211                 /* Wait for IRQ, then read PIH irq status (also blocking) */
212                 wait_for_completion_interruptible(&irq_event);
213
214                 ret = twl4030_i2c_read_u8(TWL4030_MODULE_PIH, &pih_isr,
215                                           REG_PIH_ISR_P1);
216                 if (ret) {
217                         pr_warning("twl4030: I2C error %d reading PIH ISR\n",
218                                         ret);
219                         if (++i2c_errors >= max_i2c_errors) {
220                                 printk(KERN_ERR "Maximum I2C error count"
221                                                 " exceeded.  Terminating %s.\n",
222                                                 __func__);
223                                 break;
224                         }
225                         complete(&irq_event);
226                         continue;
227                 }
228
229                 /* these handlers deal with the relevant SIH irq status */
230                 local_irq_disable();
231                 for (module_irq = twl4030_irq_base;
232                                 pih_isr;
233                                 pih_isr >>= 1, module_irq++) {
234                         if (pih_isr & 0x1) {
235                                 irq_desc_t *d = irq_desc + module_irq;
236
237                                 /* These can't be masked ... always warn
238                                  * if we get any surprises.
239                                  */
240                                 if (d->status & IRQ_DISABLED)
241                                         note_interrupt(module_irq, d,
242                                                         IRQ_NONE);
243                                 else
244                                         d->handle_irq(module_irq, d);
245                         }
246                 }
247                 local_irq_enable();
248
249                 desc->chip->unmask(irq);
250         }
251
252         return 0;
253 }
254
255 /*
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
262  * the kernel thread.
263  */
264 static void handle_twl4030_pih(unsigned int irq, irq_desc_t *desc)
265 {
266         /* Acknowledge, clear *AND* mask the interrupt... */
267         desc->chip->ack(irq);
268         complete(&irq_event);
269 }
270
271 static struct task_struct *start_twl4030_irq_thread(long irq)
272 {
273         struct task_struct *thread;
274
275         init_completion(&irq_event);
276         thread = kthread_run(twl4030_irq_thread, (void *)irq, "twl4030-irq");
277         if (!thread)
278                 pr_err("twl4030: could not create irq %ld thread!\n", irq);
279
280         return thread;
281 }
282
283 /*----------------------------------------------------------------------*/
284
285 /**
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)
290  *
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.
294  */
295 static int __init twl4030_i2c_clear_isr(u8 mod_no, u8 reg, u8 cor)
296 {
297         u8 tmp;
298
299         return (cor) ? twl4030_i2c_read_u8(mod_no, &tmp, reg) :
300                 twl4030_i2c_write_u8(mod_no, 0xff, reg);
301 }
302
303 /**
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
307  *
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
310  * writes.
311  */
312 static int twl4030_read_cor_bit(u8 mod_no, u8 reg)
313 {
314         u8 tmp = 0;
315
316         WARN_ON(twl4030_i2c_read_u8(mod_no, &tmp, reg) < 0);
317
318         tmp &= TWL4030_SIH_CTRL_COR_MASK;
319         tmp >>= __ffs(TWL4030_SIH_CTRL_COR_MASK);
320
321         return tmp;
322 }
323
324 /**
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)
328  *
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.
332  */
333 static void __init twl4030_mask_clear_intrs(const struct twl4030_mod_iregs *t,
334                                             const u8 t_sz)
335 {
336         int i, j;
337
338         /*
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
343          * power.
344          */
345         for (i = 0; i < t_sz; i++) {
346                 const struct twl4030_mod_iregs tmr = t[i];
347                 int cor;
348
349                 /* Are ISRs cleared by reads or writes? */
350                 cor = twl4030_read_cor_bit(tmr.mod_no, tmr.sih_ctrl);
351
352                 for (j = 0; j < tmr.reg_cnt; j++) {
353
354                         /* Mask interrupts at the TWL4030 */
355                         WARN_ON(twl4030_i2c_write_u8(tmr.mod_no, 0xff,
356                                                      tmr.imrs[j]) < 0);
357
358                         /* Clear TWL4030 ISRs */
359                         WARN_ON(twl4030_i2c_clear_isr(tmr.mod_no,
360                                                       tmr.isrs[j], cor) < 0);
361                 }
362         }
363 }
364
365
366 int twl_init_irq(int irq_num, unsigned irq_base, unsigned irq_end)
367 {
368         static struct irq_chip  twl4030_irq_chip;
369
370         int                     i;
371
372         /*
373          * Mask and clear all TWL4030 interrupts since initially we do
374          * not have any TWL4030 module interrupt handlers present
375          */
376         twl4030_mask_clear_intrs(twl4030_mod_regs,
377                                  ARRAY_SIZE(twl4030_mod_regs));
378
379         twl4030_irq_base = irq_base;
380
381         /* install an irq handler for each of the SIH modules;
382          * clone dummy irq_chip since PIH can't *do* anything
383          */
384         twl4030_irq_chip = dummy_irq_chip;
385         twl4030_irq_chip.name = "twl4030";
386
387         for (i = irq_base; i < irq_end; i++) {
388                 set_irq_chip_and_handler(i, &twl4030_irq_chip,
389                                 handle_simple_irq);
390                 activate_irq(i);
391         }
392
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);
396
397         return 0;
398 }
399
400 int twl_exit_irq(void)
401 {
402         /* FIXME undo twl_init_irq() */
403         if (twl4030_irq_base) {
404                 pr_err("twl4030: can't yet clean up IRQs?\n");
405                 return -ENOSYS;
406         }
407         return 0;
408 }