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 #define GPIO_BASE(chip) (((unsigned long)(chip)->base) & 0xFFFFF000u)
28 #define CON_OFFSET 0x700
29 #define MASK_OFFSET 0x900
30 #define PEND_OFFSET 0xA00
31 #define REG_OFFSET(x) ((x) << 2)
33 struct s5p_gpioint_bank
{
34 struct list_head list
;
38 struct s3c_gpio_chip
**chips
;
39 void (*handler
)(unsigned int, struct irq_desc
*);
44 static int s5p_gpioint_set_type(struct irq_data
*d
, unsigned int type
)
46 struct irq_chip_generic
*gc
= irq_data_get_irq_chip_data(d
);
47 struct irq_chip_type
*ct
= gc
->chip_types
;
48 unsigned int shift
= (d
->irq
- gc
->irq_base
) << 2;
51 case IRQ_TYPE_EDGE_RISING
:
52 type
= S5P_IRQ_TYPE_EDGE_RISING
;
54 case IRQ_TYPE_EDGE_FALLING
:
55 type
= S5P_IRQ_TYPE_EDGE_FALLING
;
57 case IRQ_TYPE_EDGE_BOTH
:
58 type
= S5P_IRQ_TYPE_EDGE_BOTH
;
60 case IRQ_TYPE_LEVEL_HIGH
:
61 type
= S5P_IRQ_TYPE_LEVEL_HIGH
;
63 case IRQ_TYPE_LEVEL_LOW
:
64 type
= S5P_IRQ_TYPE_LEVEL_LOW
;
68 printk(KERN_WARNING
"No irq type\n");
72 gc
->type_cache
&= ~(0x7 << shift
);
73 gc
->type_cache
|= type
<< shift
;
74 writel(gc
->type_cache
, gc
->reg_base
+ ct
->regs
.type
);
78 static void s5p_gpioint_handler(unsigned int irq
, struct irq_desc
*desc
)
80 struct s5p_gpioint_bank
*bank
= irq_get_handler_data(irq
);
81 int group
, pend_offset
, mask_offset
;
82 unsigned int pend
, mask
;
84 for (group
= 0; group
< bank
->nr_groups
; group
++) {
85 struct s3c_gpio_chip
*chip
= bank
->chips
[group
];
89 pend_offset
= REG_OFFSET(group
);
90 pend
= __raw_readl(GPIO_BASE(chip
) + PEND_OFFSET
+ pend_offset
);
94 mask_offset
= REG_OFFSET(group
);
95 mask
= __raw_readl(GPIO_BASE(chip
) + MASK_OFFSET
+ mask_offset
);
99 int offset
= fls(pend
) - 1;
100 int real_irq
= chip
->irq_base
+ offset
;
101 generic_handle_irq(real_irq
);
102 pend
&= ~BIT(offset
);
107 static __init
int s5p_gpioint_add(struct s3c_gpio_chip
*chip
)
109 static int used_gpioint_groups
= 0;
110 int group
= chip
->group
;
111 struct s5p_gpioint_bank
*bank
= NULL
;
112 struct irq_chip_generic
*gc
;
113 struct irq_chip_type
*ct
;
115 if (used_gpioint_groups
>= S5P_GPIOINT_GROUP_COUNT
)
118 list_for_each_entry(bank
, &banks
, list
) {
119 if (group
>= bank
->start
&&
120 group
< bank
->start
+ bank
->nr_groups
)
126 if (!bank
->handler
) {
127 bank
->chips
= kzalloc(sizeof(struct s3c_gpio_chip
*) *
128 bank
->nr_groups
, GFP_KERNEL
);
132 irq_set_chained_handler(bank
->irq
, s5p_gpioint_handler
);
133 irq_set_handler_data(bank
->irq
, bank
);
134 bank
->handler
= s5p_gpioint_handler
;
135 printk(KERN_INFO
"Registered chained gpio int handler for interrupt %d.\n",
140 * chained GPIO irq has been successfully registered, allocate new gpio
141 * int group and assign irq nubmers
143 chip
->irq_base
= S5P_GPIOINT_BASE
+
144 used_gpioint_groups
* S5P_GPIOINT_GROUP_SIZE
;
145 used_gpioint_groups
++;
147 bank
->chips
[group
- bank
->start
] = chip
;
149 gc
= irq_alloc_generic_chip("s5p_gpioint", 1, chip
->irq_base
,
150 (void __iomem
*)GPIO_BASE(chip
),
155 ct
->chip
.irq_ack
= irq_gc_ack_set_bit
;
156 ct
->chip
.irq_mask
= irq_gc_mask_set_bit
;
157 ct
->chip
.irq_unmask
= irq_gc_mask_clr_bit
;
158 ct
->chip
.irq_set_type
= s5p_gpioint_set_type
,
159 ct
->regs
.ack
= PEND_OFFSET
+ REG_OFFSET(chip
->group
);
160 ct
->regs
.mask
= MASK_OFFSET
+ REG_OFFSET(chip
->group
);
161 ct
->regs
.type
= CON_OFFSET
+ REG_OFFSET(chip
->group
);
162 irq_setup_generic_chip(gc
, IRQ_MSK(chip
->chip
.ngpio
),
163 IRQ_GC_INIT_MASK_CACHE
,
164 IRQ_NOREQUEST
| IRQ_NOPROBE
, 0);
168 int __init
s5p_register_gpio_interrupt(int pin
)
170 struct s3c_gpio_chip
*my_chip
= s3c_gpiolib_getchip(pin
);
177 offset
= pin
- my_chip
->chip
.base
;
178 group
= my_chip
->group
;
180 /* check if the group has been already registered */
181 if (my_chip
->irq_base
)
182 return my_chip
->irq_base
+ offset
;
184 /* register gpio group */
185 ret
= s5p_gpioint_add(my_chip
);
187 my_chip
->chip
.to_irq
= samsung_gpiolib_to_irq
;
188 printk(KERN_INFO
"Registered interrupt support for gpio group %d.\n",
190 return my_chip
->irq_base
+ offset
;
195 int __init
s5p_register_gpioint_bank(int chain_irq
, int start
, int nr_groups
)
197 struct s5p_gpioint_bank
*bank
;
199 bank
= kzalloc(sizeof(*bank
), GFP_KERNEL
);
204 bank
->nr_groups
= nr_groups
;
205 bank
->irq
= chain_irq
;
207 list_add_tail(&bank
->list
, &banks
);