1 /* linux/arch/arm/plat-s5p/irq-gpioint.c
3 * Copyright (c) 2010 Samsung Electronics Co., Ltd.
4 * Author: Kyungmin Park <kyungmin.park@samsung.com>
5 * Author: Joonyoung Shim <jy0922.shim@samsung.com>
6 * Author: Marek Szyprowski <m.szyprowski@samsung.com>
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation; either version 2 of the License, or (at your
11 * option) any later version.
15 #include <linux/kernel.h>
16 #include <linux/interrupt.h>
17 #include <linux/irq.h>
19 #include <linux/gpio.h>
20 #include <linux/slab.h>
23 #include <plat/gpio-core.h>
24 #include <plat/gpio-cfg.h>
26 #include <asm/mach/irq.h>
28 #define GPIO_BASE(chip) (((unsigned long)(chip)->base) & 0xFFFFF000u)
30 #define CON_OFFSET 0x700
31 #define MASK_OFFSET 0x900
32 #define PEND_OFFSET 0xA00
33 #define REG_OFFSET(x) ((x) << 2)
35 struct s5p_gpioint_bank
{
36 struct list_head list
;
40 struct s3c_gpio_chip
**chips
;
41 void (*handler
)(unsigned int, struct irq_desc
*);
46 static int s5p_gpioint_set_type(struct irq_data
*d
, unsigned int type
)
48 struct irq_chip_generic
*gc
= irq_data_get_irq_chip_data(d
);
49 struct irq_chip_type
*ct
= gc
->chip_types
;
50 unsigned int shift
= (d
->irq
- gc
->irq_base
) << 2;
53 case IRQ_TYPE_EDGE_RISING
:
54 type
= S5P_IRQ_TYPE_EDGE_RISING
;
56 case IRQ_TYPE_EDGE_FALLING
:
57 type
= S5P_IRQ_TYPE_EDGE_FALLING
;
59 case IRQ_TYPE_EDGE_BOTH
:
60 type
= S5P_IRQ_TYPE_EDGE_BOTH
;
62 case IRQ_TYPE_LEVEL_HIGH
:
63 type
= S5P_IRQ_TYPE_LEVEL_HIGH
;
65 case IRQ_TYPE_LEVEL_LOW
:
66 type
= S5P_IRQ_TYPE_LEVEL_LOW
;
70 printk(KERN_WARNING
"No irq type\n");
74 gc
->type_cache
&= ~(0x7 << shift
);
75 gc
->type_cache
|= type
<< shift
;
76 writel(gc
->type_cache
, gc
->reg_base
+ ct
->regs
.type
);
80 static void s5p_gpioint_handler(unsigned int irq
, struct irq_desc
*desc
)
82 struct s5p_gpioint_bank
*bank
= irq_get_handler_data(irq
);
83 int group
, pend_offset
, mask_offset
;
84 unsigned int pend
, mask
;
86 struct irq_chip
*chip
= irq_get_chip(irq
);
87 chained_irq_enter(chip
, desc
);
89 for (group
= 0; group
< bank
->nr_groups
; group
++) {
90 struct s3c_gpio_chip
*chip
= bank
->chips
[group
];
94 pend_offset
= REG_OFFSET(group
);
95 pend
= __raw_readl(GPIO_BASE(chip
) + PEND_OFFSET
+ pend_offset
);
99 mask_offset
= REG_OFFSET(group
);
100 mask
= __raw_readl(GPIO_BASE(chip
) + MASK_OFFSET
+ mask_offset
);
104 int offset
= fls(pend
) - 1;
105 int real_irq
= chip
->irq_base
+ offset
;
106 generic_handle_irq(real_irq
);
107 pend
&= ~BIT(offset
);
110 chained_irq_exit(chip
, desc
);
113 static __init
int s5p_gpioint_add(struct s3c_gpio_chip
*chip
)
115 static int used_gpioint_groups
= 0;
116 int group
= chip
->group
;
117 struct s5p_gpioint_bank
*bank
= NULL
;
118 struct irq_chip_generic
*gc
;
119 struct irq_chip_type
*ct
;
121 if (used_gpioint_groups
>= S5P_GPIOINT_GROUP_COUNT
)
124 list_for_each_entry(bank
, &banks
, list
) {
125 if (group
>= bank
->start
&&
126 group
< bank
->start
+ bank
->nr_groups
)
132 if (!bank
->handler
) {
133 bank
->chips
= kzalloc(sizeof(struct s3c_gpio_chip
*) *
134 bank
->nr_groups
, GFP_KERNEL
);
138 irq_set_chained_handler(bank
->irq
, s5p_gpioint_handler
);
139 irq_set_handler_data(bank
->irq
, bank
);
140 bank
->handler
= s5p_gpioint_handler
;
141 printk(KERN_INFO
"Registered chained gpio int handler for interrupt %d.\n",
146 * chained GPIO irq has been successfully registered, allocate new gpio
147 * int group and assign irq nubmers
149 chip
->irq_base
= S5P_GPIOINT_BASE
+
150 used_gpioint_groups
* S5P_GPIOINT_GROUP_SIZE
;
151 used_gpioint_groups
++;
153 bank
->chips
[group
- bank
->start
] = chip
;
155 gc
= irq_alloc_generic_chip("s5p_gpioint", 1, chip
->irq_base
,
156 (void __iomem
*)GPIO_BASE(chip
),
161 ct
->chip
.irq_ack
= irq_gc_ack_set_bit
;
162 ct
->chip
.irq_mask
= irq_gc_mask_set_bit
;
163 ct
->chip
.irq_unmask
= irq_gc_mask_clr_bit
;
164 ct
->chip
.irq_set_type
= s5p_gpioint_set_type
,
165 ct
->regs
.ack
= PEND_OFFSET
+ REG_OFFSET(chip
->group
);
166 ct
->regs
.mask
= MASK_OFFSET
+ REG_OFFSET(chip
->group
);
167 ct
->regs
.type
= CON_OFFSET
+ REG_OFFSET(chip
->group
);
168 irq_setup_generic_chip(gc
, IRQ_MSK(chip
->chip
.ngpio
),
169 IRQ_GC_INIT_MASK_CACHE
,
170 IRQ_NOREQUEST
| IRQ_NOPROBE
, 0);
174 int __init
s5p_register_gpio_interrupt(int pin
)
176 struct s3c_gpio_chip
*my_chip
= s3c_gpiolib_getchip(pin
);
183 offset
= pin
- my_chip
->chip
.base
;
184 group
= my_chip
->group
;
186 /* check if the group has been already registered */
187 if (my_chip
->irq_base
)
188 return my_chip
->irq_base
+ offset
;
190 /* register gpio group */
191 ret
= s5p_gpioint_add(my_chip
);
193 my_chip
->chip
.to_irq
= samsung_gpiolib_to_irq
;
194 printk(KERN_INFO
"Registered interrupt support for gpio group %d.\n",
196 return my_chip
->irq_base
+ offset
;
201 int __init
s5p_register_gpioint_bank(int chain_irq
, int start
, int nr_groups
)
203 struct s5p_gpioint_bank
*bank
;
205 bank
= kzalloc(sizeof(*bank
), GFP_KERNEL
);
210 bank
->nr_groups
= nr_groups
;
211 bank
->irq
= chain_irq
;
213 list_add_tail(&bank
->list
, &banks
);