Commit 68ae89984710d2e9f3cf2005539c8f91bcce9d40

Authored by Kukjin Kim
1 parent bf46aaeacf

ARM: SAMSUNG: move interrupt part for common s5p into plat-samsung

Signed-off-by: Kukjin Kim <kgene.kim@samsung.com>

Showing 10 changed files with 487 additions and 485 deletions Side-by-side Diff

arch/arm/plat-s5p/Kconfig
... ... @@ -23,17 +23,6 @@
23 23 help
24 24 Base platform code for Samsung's S5P series SoC.
25 25  
26   -config S5P_EXT_INT
27   - bool
28   - help
29   - Use the external interrupts (other than GPIO interrupts.)
30   - Note: Do not choose this for S5P6440 and S5P6450.
31   -
32   -config S5P_GPIO_INT
33   - bool
34   - help
35   - Common code for the GPIO interrupts (other than external interrupts.)
36   -
37 26 config S5P_HRT
38 27 bool
39 28 select SAMSUNG_DEV_PWM
arch/arm/plat-s5p/Makefile
... ... @@ -12,9 +12,6 @@
12 12  
13 13 # Core files
14 14  
15   -obj-y += irq.o
16   -obj-$(CONFIG_S5P_EXT_INT) += irq-eint.o
17   -obj-$(CONFIG_S5P_GPIO_INT) += irq-gpioint.o
18 15 obj-$(CONFIG_S5P_PM) += pm.o irq-pm.o
19 16 obj-$(CONFIG_S5P_SLEEP) += sleep.o
20 17 obj-$(CONFIG_S5P_HRT) += s5p-time.o
arch/arm/plat-s5p/irq-eint.c
1   -/* linux/arch/arm/plat-s5p/irq-eint.c
2   - *
3   - * Copyright (c) 2010 Samsung Electronics Co., Ltd.
4   - * http://www.samsung.com
5   - *
6   - * S5P - IRQ EINT support
7   - *
8   - * This program is free software; you can redistribute it and/or modify
9   - * it under the terms of the GNU General Public License version 2 as
10   - * published by the Free Software Foundation.
11   -*/
12   -
13   -#include <linux/kernel.h>
14   -#include <linux/interrupt.h>
15   -#include <linux/irq.h>
16   -#include <linux/io.h>
17   -#include <linux/device.h>
18   -#include <linux/gpio.h>
19   -
20   -#include <asm/hardware/vic.h>
21   -
22   -#include <plat/regs-irqtype.h>
23   -
24   -#include <mach/map.h>
25   -#include <plat/cpu.h>
26   -#include <plat/pm.h>
27   -
28   -#include <plat/gpio-cfg.h>
29   -#include <mach/regs-gpio.h>
30   -
31   -static inline void s5p_irq_eint_mask(struct irq_data *data)
32   -{
33   - u32 mask;
34   -
35   - mask = __raw_readl(S5P_EINT_MASK(EINT_REG_NR(data->irq)));
36   - mask |= eint_irq_to_bit(data->irq);
37   - __raw_writel(mask, S5P_EINT_MASK(EINT_REG_NR(data->irq)));
38   -}
39   -
40   -static void s5p_irq_eint_unmask(struct irq_data *data)
41   -{
42   - u32 mask;
43   -
44   - mask = __raw_readl(S5P_EINT_MASK(EINT_REG_NR(data->irq)));
45   - mask &= ~(eint_irq_to_bit(data->irq));
46   - __raw_writel(mask, S5P_EINT_MASK(EINT_REG_NR(data->irq)));
47   -}
48   -
49   -static inline void s5p_irq_eint_ack(struct irq_data *data)
50   -{
51   - __raw_writel(eint_irq_to_bit(data->irq),
52   - S5P_EINT_PEND(EINT_REG_NR(data->irq)));
53   -}
54   -
55   -static void s5p_irq_eint_maskack(struct irq_data *data)
56   -{
57   - /* compiler should in-line these */
58   - s5p_irq_eint_mask(data);
59   - s5p_irq_eint_ack(data);
60   -}
61   -
62   -static int s5p_irq_eint_set_type(struct irq_data *data, unsigned int type)
63   -{
64   - int offs = EINT_OFFSET(data->irq);
65   - int shift;
66   - u32 ctrl, mask;
67   - u32 newvalue = 0;
68   -
69   - switch (type) {
70   - case IRQ_TYPE_EDGE_RISING:
71   - newvalue = S5P_IRQ_TYPE_EDGE_RISING;
72   - break;
73   -
74   - case IRQ_TYPE_EDGE_FALLING:
75   - newvalue = S5P_IRQ_TYPE_EDGE_FALLING;
76   - break;
77   -
78   - case IRQ_TYPE_EDGE_BOTH:
79   - newvalue = S5P_IRQ_TYPE_EDGE_BOTH;
80   - break;
81   -
82   - case IRQ_TYPE_LEVEL_LOW:
83   - newvalue = S5P_IRQ_TYPE_LEVEL_LOW;
84   - break;
85   -
86   - case IRQ_TYPE_LEVEL_HIGH:
87   - newvalue = S5P_IRQ_TYPE_LEVEL_HIGH;
88   - break;
89   -
90   - default:
91   - printk(KERN_ERR "No such irq type %d", type);
92   - return -EINVAL;
93   - }
94   -
95   - shift = (offs & 0x7) * 4;
96   - mask = 0x7 << shift;
97   -
98   - ctrl = __raw_readl(S5P_EINT_CON(EINT_REG_NR(data->irq)));
99   - ctrl &= ~mask;
100   - ctrl |= newvalue << shift;
101   - __raw_writel(ctrl, S5P_EINT_CON(EINT_REG_NR(data->irq)));
102   -
103   - if ((0 <= offs) && (offs < 8))
104   - s3c_gpio_cfgpin(EINT_GPIO_0(offs & 0x7), EINT_MODE);
105   -
106   - else if ((8 <= offs) && (offs < 16))
107   - s3c_gpio_cfgpin(EINT_GPIO_1(offs & 0x7), EINT_MODE);
108   -
109   - else if ((16 <= offs) && (offs < 24))
110   - s3c_gpio_cfgpin(EINT_GPIO_2(offs & 0x7), EINT_MODE);
111   -
112   - else if ((24 <= offs) && (offs < 32))
113   - s3c_gpio_cfgpin(EINT_GPIO_3(offs & 0x7), EINT_MODE);
114   -
115   - else
116   - printk(KERN_ERR "No such irq number %d", offs);
117   -
118   - return 0;
119   -}
120   -
121   -static struct irq_chip s5p_irq_eint = {
122   - .name = "s5p-eint",
123   - .irq_mask = s5p_irq_eint_mask,
124   - .irq_unmask = s5p_irq_eint_unmask,
125   - .irq_mask_ack = s5p_irq_eint_maskack,
126   - .irq_ack = s5p_irq_eint_ack,
127   - .irq_set_type = s5p_irq_eint_set_type,
128   -#ifdef CONFIG_PM
129   - .irq_set_wake = s3c_irqext_wake,
130   -#endif
131   -};
132   -
133   -/* s5p_irq_demux_eint
134   - *
135   - * This function demuxes the IRQ from the group0 external interrupts,
136   - * from EINTs 16 to 31. It is designed to be inlined into the specific
137   - * handler s5p_irq_demux_eintX_Y.
138   - *
139   - * Each EINT pend/mask registers handle eight of them.
140   - */
141   -static inline void s5p_irq_demux_eint(unsigned int start)
142   -{
143   - u32 status = __raw_readl(S5P_EINT_PEND(EINT_REG_NR(start)));
144   - u32 mask = __raw_readl(S5P_EINT_MASK(EINT_REG_NR(start)));
145   - unsigned int irq;
146   -
147   - status &= ~mask;
148   - status &= 0xff;
149   -
150   - while (status) {
151   - irq = fls(status) - 1;
152   - generic_handle_irq(irq + start);
153   - status &= ~(1 << irq);
154   - }
155   -}
156   -
157   -static void s5p_irq_demux_eint16_31(unsigned int irq, struct irq_desc *desc)
158   -{
159   - s5p_irq_demux_eint(IRQ_EINT(16));
160   - s5p_irq_demux_eint(IRQ_EINT(24));
161   -}
162   -
163   -static inline void s5p_irq_vic_eint_mask(struct irq_data *data)
164   -{
165   - void __iomem *base = irq_data_get_irq_chip_data(data);
166   -
167   - s5p_irq_eint_mask(data);
168   - writel(1 << EINT_OFFSET(data->irq), base + VIC_INT_ENABLE_CLEAR);
169   -}
170   -
171   -static void s5p_irq_vic_eint_unmask(struct irq_data *data)
172   -{
173   - void __iomem *base = irq_data_get_irq_chip_data(data);
174   -
175   - s5p_irq_eint_unmask(data);
176   - writel(1 << EINT_OFFSET(data->irq), base + VIC_INT_ENABLE);
177   -}
178   -
179   -static inline void s5p_irq_vic_eint_ack(struct irq_data *data)
180   -{
181   - __raw_writel(eint_irq_to_bit(data->irq),
182   - S5P_EINT_PEND(EINT_REG_NR(data->irq)));
183   -}
184   -
185   -static void s5p_irq_vic_eint_maskack(struct irq_data *data)
186   -{
187   - s5p_irq_vic_eint_mask(data);
188   - s5p_irq_vic_eint_ack(data);
189   -}
190   -
191   -static struct irq_chip s5p_irq_vic_eint = {
192   - .name = "s5p_vic_eint",
193   - .irq_mask = s5p_irq_vic_eint_mask,
194   - .irq_unmask = s5p_irq_vic_eint_unmask,
195   - .irq_mask_ack = s5p_irq_vic_eint_maskack,
196   - .irq_ack = s5p_irq_vic_eint_ack,
197   - .irq_set_type = s5p_irq_eint_set_type,
198   -#ifdef CONFIG_PM
199   - .irq_set_wake = s3c_irqext_wake,
200   -#endif
201   -};
202   -
203   -static int __init s5p_init_irq_eint(void)
204   -{
205   - int irq;
206   -
207   - for (irq = IRQ_EINT(0); irq <= IRQ_EINT(15); irq++)
208   - irq_set_chip(irq, &s5p_irq_vic_eint);
209   -
210   - for (irq = IRQ_EINT(16); irq <= IRQ_EINT(31); irq++) {
211   - irq_set_chip_and_handler(irq, &s5p_irq_eint, handle_level_irq);
212   - set_irq_flags(irq, IRQF_VALID);
213   - }
214   -
215   - irq_set_chained_handler(IRQ_EINT16_31, s5p_irq_demux_eint16_31);
216   - return 0;
217   -}
218   -
219   -arch_initcall(s5p_init_irq_eint);
arch/arm/plat-s5p/irq-gpioint.c
1   -/* linux/arch/arm/plat-s5p/irq-gpioint.c
2   - *
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>
7   - *
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.
12   - *
13   - */
14   -
15   -#include <linux/kernel.h>
16   -#include <linux/interrupt.h>
17   -#include <linux/irq.h>
18   -#include <linux/io.h>
19   -#include <linux/gpio.h>
20   -#include <linux/slab.h>
21   -
22   -#include <mach/map.h>
23   -#include <plat/gpio-core.h>
24   -#include <plat/gpio-cfg.h>
25   -
26   -#include <asm/mach/irq.h>
27   -
28   -#define GPIO_BASE(chip) (((unsigned long)(chip)->base) & 0xFFFFF000u)
29   -
30   -#define CON_OFFSET 0x700
31   -#define MASK_OFFSET 0x900
32   -#define PEND_OFFSET 0xA00
33   -#define REG_OFFSET(x) ((x) << 2)
34   -
35   -struct s5p_gpioint_bank {
36   - struct list_head list;
37   - int start;
38   - int nr_groups;
39   - int irq;
40   - struct samsung_gpio_chip **chips;
41   - void (*handler)(unsigned int, struct irq_desc *);
42   -};
43   -
44   -static LIST_HEAD(banks);
45   -
46   -static int s5p_gpioint_set_type(struct irq_data *d, unsigned int type)
47   -{
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;
51   -
52   - switch (type) {
53   - case IRQ_TYPE_EDGE_RISING:
54   - type = S5P_IRQ_TYPE_EDGE_RISING;
55   - break;
56   - case IRQ_TYPE_EDGE_FALLING:
57   - type = S5P_IRQ_TYPE_EDGE_FALLING;
58   - break;
59   - case IRQ_TYPE_EDGE_BOTH:
60   - type = S5P_IRQ_TYPE_EDGE_BOTH;
61   - break;
62   - case IRQ_TYPE_LEVEL_HIGH:
63   - type = S5P_IRQ_TYPE_LEVEL_HIGH;
64   - break;
65   - case IRQ_TYPE_LEVEL_LOW:
66   - type = S5P_IRQ_TYPE_LEVEL_LOW;
67   - break;
68   - case IRQ_TYPE_NONE:
69   - default:
70   - printk(KERN_WARNING "No irq type\n");
71   - return -EINVAL;
72   - }
73   -
74   - gc->type_cache &= ~(0x7 << shift);
75   - gc->type_cache |= type << shift;
76   - writel(gc->type_cache, gc->reg_base + ct->regs.type);
77   - return 0;
78   -}
79   -
80   -static void s5p_gpioint_handler(unsigned int irq, struct irq_desc *desc)
81   -{
82   - struct s5p_gpioint_bank *bank = irq_get_handler_data(irq);
83   - int group, pend_offset, mask_offset;
84   - unsigned int pend, mask;
85   -
86   - struct irq_chip *chip = irq_get_chip(irq);
87   - chained_irq_enter(chip, desc);
88   -
89   - for (group = 0; group < bank->nr_groups; group++) {
90   - struct samsung_gpio_chip *chip = bank->chips[group];
91   - if (!chip)
92   - continue;
93   -
94   - pend_offset = REG_OFFSET(group);
95   - pend = __raw_readl(GPIO_BASE(chip) + PEND_OFFSET + pend_offset);
96   - if (!pend)
97   - continue;
98   -
99   - mask_offset = REG_OFFSET(group);
100   - mask = __raw_readl(GPIO_BASE(chip) + MASK_OFFSET + mask_offset);
101   - pend &= ~mask;
102   -
103   - while (pend) {
104   - int offset = fls(pend) - 1;
105   - int real_irq = chip->irq_base + offset;
106   - generic_handle_irq(real_irq);
107   - pend &= ~BIT(offset);
108   - }
109   - }
110   - chained_irq_exit(chip, desc);
111   -}
112   -
113   -static __init int s5p_gpioint_add(struct samsung_gpio_chip *chip)
114   -{
115   - static int used_gpioint_groups = 0;
116   - int group = chip->group;
117   - struct s5p_gpioint_bank *b, *bank = NULL;
118   - struct irq_chip_generic *gc;
119   - struct irq_chip_type *ct;
120   -
121   - if (used_gpioint_groups >= S5P_GPIOINT_GROUP_COUNT)
122   - return -ENOMEM;
123   -
124   - list_for_each_entry(b, &banks, list) {
125   - if (group >= b->start && group < b->start + b->nr_groups) {
126   - bank = b;
127   - break;
128   - }
129   - }
130   - if (!bank)
131   - return -EINVAL;
132   -
133   - if (!bank->handler) {
134   - bank->chips = kzalloc(sizeof(struct samsung_gpio_chip *) *
135   - bank->nr_groups, GFP_KERNEL);
136   - if (!bank->chips)
137   - return -ENOMEM;
138   -
139   - irq_set_chained_handler(bank->irq, s5p_gpioint_handler);
140   - irq_set_handler_data(bank->irq, bank);
141   - bank->handler = s5p_gpioint_handler;
142   - printk(KERN_INFO "Registered chained gpio int handler for interrupt %d.\n",
143   - bank->irq);
144   - }
145   -
146   - /*
147   - * chained GPIO irq has been successfully registered, allocate new gpio
148   - * int group and assign irq nubmers
149   - */
150   - chip->irq_base = S5P_GPIOINT_BASE +
151   - used_gpioint_groups * S5P_GPIOINT_GROUP_SIZE;
152   - used_gpioint_groups++;
153   -
154   - bank->chips[group - bank->start] = chip;
155   -
156   - gc = irq_alloc_generic_chip("s5p_gpioint", 1, chip->irq_base,
157   - (void __iomem *)GPIO_BASE(chip),
158   - handle_level_irq);
159   - if (!gc)
160   - return -ENOMEM;
161   - ct = gc->chip_types;
162   - ct->chip.irq_ack = irq_gc_ack_set_bit;
163   - ct->chip.irq_mask = irq_gc_mask_set_bit;
164   - ct->chip.irq_unmask = irq_gc_mask_clr_bit;
165   - ct->chip.irq_set_type = s5p_gpioint_set_type,
166   - ct->regs.ack = PEND_OFFSET + REG_OFFSET(group - bank->start);
167   - ct->regs.mask = MASK_OFFSET + REG_OFFSET(group - bank->start);
168   - ct->regs.type = CON_OFFSET + REG_OFFSET(group - bank->start);
169   - irq_setup_generic_chip(gc, IRQ_MSK(chip->chip.ngpio),
170   - IRQ_GC_INIT_MASK_CACHE,
171   - IRQ_NOREQUEST | IRQ_NOPROBE, 0);
172   - return 0;
173   -}
174   -
175   -int __init s5p_register_gpio_interrupt(int pin)
176   -{
177   - struct samsung_gpio_chip *my_chip = samsung_gpiolib_getchip(pin);
178   - int offset, group;
179   - int ret;
180   -
181   - if (!my_chip)
182   - return -EINVAL;
183   -
184   - offset = pin - my_chip->chip.base;
185   - group = my_chip->group;
186   -
187   - /* check if the group has been already registered */
188   - if (my_chip->irq_base)
189   - return my_chip->irq_base + offset;
190   -
191   - /* register gpio group */
192   - ret = s5p_gpioint_add(my_chip);
193   - if (ret == 0) {
194   - my_chip->chip.to_irq = samsung_gpiolib_to_irq;
195   - printk(KERN_INFO "Registered interrupt support for gpio group %d.\n",
196   - group);
197   - return my_chip->irq_base + offset;
198   - }
199   - return ret;
200   -}
201   -
202   -int __init s5p_register_gpioint_bank(int chain_irq, int start, int nr_groups)
203   -{
204   - struct s5p_gpioint_bank *bank;
205   -
206   - bank = kzalloc(sizeof(*bank), GFP_KERNEL);
207   - if (!bank)
208   - return -ENOMEM;
209   -
210   - bank->start = start;
211   - bank->nr_groups = nr_groups;
212   - bank->irq = chain_irq;
213   -
214   - list_add_tail(&bank->list, &banks);
215   - return 0;
216   -}
arch/arm/plat-s5p/irq.c
1   -/* arch/arm/plat-s5p/irq.c
2   - *
3   - * Copyright (c) 2009 Samsung Electronics Co., Ltd.
4   - * http://www.samsung.com/
5   - *
6   - * S5P - Interrupt handling
7   - *
8   - * This program is free software; you can redistribute it and/or modify
9   - * it under the terms of the GNU General Public License version 2 as
10   - * published by the Free Software Foundation.
11   -*/
12   -
13   -#include <linux/kernel.h>
14   -#include <linux/interrupt.h>
15   -#include <linux/irq.h>
16   -#include <linux/io.h>
17   -
18   -#include <asm/hardware/vic.h>
19   -
20   -#include <mach/map.h>
21   -#include <plat/regs-timer.h>
22   -#include <plat/cpu.h>
23   -#include <plat/irq-vic-timer.h>
24   -
25   -void __init s5p_init_irq(u32 *vic, u32 num_vic)
26   -{
27   -#ifdef CONFIG_ARM_VIC
28   - int irq;
29   -
30   - /* initialize the VICs */
31   - for (irq = 0; irq < num_vic; irq++)
32   - vic_init(VA_VIC(irq), VIC_BASE(irq), vic[irq], 0);
33   -#endif
34   -
35   - s3c_init_vic_timer_irq(5, IRQ_TIMER0);
36   -}
arch/arm/plat-samsung/Kconfig
... ... @@ -70,6 +70,22 @@
70 70 help
71 71 Internal configuration to build the VIC timer interrupt code.
72 72  
  73 +config S5P_IRQ
  74 + def_bool (ARCH_S5P64X0 || ARCH_S5PC100 || ARCH_S5PV210 || ARCH_EXYNOS)
  75 + help
  76 + Support common interrup part for ARCH_S5P and ARCH_EXYNOS SoCs
  77 +
  78 +config S5P_EXT_INT
  79 + bool
  80 + help
  81 + Use the external interrupts (other than GPIO interrupts.)
  82 + Note: Do not choose this for S5P6440 and S5P6450.
  83 +
  84 +config S5P_GPIO_INT
  85 + bool
  86 + help
  87 + Common code for the GPIO interrupts (other than external interrupts.)
  88 +
73 89 # options for gpio configuration support
74 90  
75 91 config SAMSUNG_GPIOLIB_4BIT
arch/arm/plat-samsung/Makefile
... ... @@ -20,6 +20,9 @@
20 20 obj-$(CONFIG_S5P_CLOCK) += s5p-clock.o
21 21  
22 22 obj-$(CONFIG_SAMSUNG_IRQ_VIC_TIMER) += irq-vic-timer.o
  23 +obj-$(CONFIG_S5P_IRQ) += s5p-irq.o
  24 +obj-$(CONFIG_S5P_EXT_INT) += s5p-irq-eint.o
  25 +obj-$(CONFIG_S5P_GPIO_INT) += s5p-irq-gpioint.o
23 26  
24 27 # ADC
25 28  
arch/arm/plat-samsung/s5p-irq-eint.c
  1 +/*
  2 + * Copyright (c) 2010 Samsung Electronics Co., Ltd.
  3 + * http://www.samsung.com
  4 + *
  5 + * S5P - IRQ EINT support
  6 + *
  7 + * This program is free software; you can redistribute it and/or modify
  8 + * it under the terms of the GNU General Public License version 2 as
  9 + * published by the Free Software Foundation.
  10 +*/
  11 +
  12 +#include <linux/kernel.h>
  13 +#include <linux/interrupt.h>
  14 +#include <linux/irq.h>
  15 +#include <linux/io.h>
  16 +#include <linux/device.h>
  17 +#include <linux/gpio.h>
  18 +
  19 +#include <asm/hardware/vic.h>
  20 +
  21 +#include <plat/regs-irqtype.h>
  22 +
  23 +#include <mach/map.h>
  24 +#include <plat/cpu.h>
  25 +#include <plat/pm.h>
  26 +
  27 +#include <plat/gpio-cfg.h>
  28 +#include <mach/regs-gpio.h>
  29 +
  30 +static inline void s5p_irq_eint_mask(struct irq_data *data)
  31 +{
  32 + u32 mask;
  33 +
  34 + mask = __raw_readl(S5P_EINT_MASK(EINT_REG_NR(data->irq)));
  35 + mask |= eint_irq_to_bit(data->irq);
  36 + __raw_writel(mask, S5P_EINT_MASK(EINT_REG_NR(data->irq)));
  37 +}
  38 +
  39 +static void s5p_irq_eint_unmask(struct irq_data *data)
  40 +{
  41 + u32 mask;
  42 +
  43 + mask = __raw_readl(S5P_EINT_MASK(EINT_REG_NR(data->irq)));
  44 + mask &= ~(eint_irq_to_bit(data->irq));
  45 + __raw_writel(mask, S5P_EINT_MASK(EINT_REG_NR(data->irq)));
  46 +}
  47 +
  48 +static inline void s5p_irq_eint_ack(struct irq_data *data)
  49 +{
  50 + __raw_writel(eint_irq_to_bit(data->irq),
  51 + S5P_EINT_PEND(EINT_REG_NR(data->irq)));
  52 +}
  53 +
  54 +static void s5p_irq_eint_maskack(struct irq_data *data)
  55 +{
  56 + /* compiler should in-line these */
  57 + s5p_irq_eint_mask(data);
  58 + s5p_irq_eint_ack(data);
  59 +}
  60 +
  61 +static int s5p_irq_eint_set_type(struct irq_data *data, unsigned int type)
  62 +{
  63 + int offs = EINT_OFFSET(data->irq);
  64 + int shift;
  65 + u32 ctrl, mask;
  66 + u32 newvalue = 0;
  67 +
  68 + switch (type) {
  69 + case IRQ_TYPE_EDGE_RISING:
  70 + newvalue = S5P_IRQ_TYPE_EDGE_RISING;
  71 + break;
  72 +
  73 + case IRQ_TYPE_EDGE_FALLING:
  74 + newvalue = S5P_IRQ_TYPE_EDGE_FALLING;
  75 + break;
  76 +
  77 + case IRQ_TYPE_EDGE_BOTH:
  78 + newvalue = S5P_IRQ_TYPE_EDGE_BOTH;
  79 + break;
  80 +
  81 + case IRQ_TYPE_LEVEL_LOW:
  82 + newvalue = S5P_IRQ_TYPE_LEVEL_LOW;
  83 + break;
  84 +
  85 + case IRQ_TYPE_LEVEL_HIGH:
  86 + newvalue = S5P_IRQ_TYPE_LEVEL_HIGH;
  87 + break;
  88 +
  89 + default:
  90 + printk(KERN_ERR "No such irq type %d", type);
  91 + return -EINVAL;
  92 + }
  93 +
  94 + shift = (offs & 0x7) * 4;
  95 + mask = 0x7 << shift;
  96 +
  97 + ctrl = __raw_readl(S5P_EINT_CON(EINT_REG_NR(data->irq)));
  98 + ctrl &= ~mask;
  99 + ctrl |= newvalue << shift;
  100 + __raw_writel(ctrl, S5P_EINT_CON(EINT_REG_NR(data->irq)));
  101 +
  102 + if ((0 <= offs) && (offs < 8))
  103 + s3c_gpio_cfgpin(EINT_GPIO_0(offs & 0x7), EINT_MODE);
  104 +
  105 + else if ((8 <= offs) && (offs < 16))
  106 + s3c_gpio_cfgpin(EINT_GPIO_1(offs & 0x7), EINT_MODE);
  107 +
  108 + else if ((16 <= offs) && (offs < 24))
  109 + s3c_gpio_cfgpin(EINT_GPIO_2(offs & 0x7), EINT_MODE);
  110 +
  111 + else if ((24 <= offs) && (offs < 32))
  112 + s3c_gpio_cfgpin(EINT_GPIO_3(offs & 0x7), EINT_MODE);
  113 +
  114 + else
  115 + printk(KERN_ERR "No such irq number %d", offs);
  116 +
  117 + return 0;
  118 +}
  119 +
  120 +static struct irq_chip s5p_irq_eint = {
  121 + .name = "s5p-eint",
  122 + .irq_mask = s5p_irq_eint_mask,
  123 + .irq_unmask = s5p_irq_eint_unmask,
  124 + .irq_mask_ack = s5p_irq_eint_maskack,
  125 + .irq_ack = s5p_irq_eint_ack,
  126 + .irq_set_type = s5p_irq_eint_set_type,
  127 +#ifdef CONFIG_PM
  128 + .irq_set_wake = s3c_irqext_wake,
  129 +#endif
  130 +};
  131 +
  132 +/* s5p_irq_demux_eint
  133 + *
  134 + * This function demuxes the IRQ from the group0 external interrupts,
  135 + * from EINTs 16 to 31. It is designed to be inlined into the specific
  136 + * handler s5p_irq_demux_eintX_Y.
  137 + *
  138 + * Each EINT pend/mask registers handle eight of them.
  139 + */
  140 +static inline void s5p_irq_demux_eint(unsigned int start)
  141 +{
  142 + u32 status = __raw_readl(S5P_EINT_PEND(EINT_REG_NR(start)));
  143 + u32 mask = __raw_readl(S5P_EINT_MASK(EINT_REG_NR(start)));
  144 + unsigned int irq;
  145 +
  146 + status &= ~mask;
  147 + status &= 0xff;
  148 +
  149 + while (status) {
  150 + irq = fls(status) - 1;
  151 + generic_handle_irq(irq + start);
  152 + status &= ~(1 << irq);
  153 + }
  154 +}
  155 +
  156 +static void s5p_irq_demux_eint16_31(unsigned int irq, struct irq_desc *desc)
  157 +{
  158 + s5p_irq_demux_eint(IRQ_EINT(16));
  159 + s5p_irq_demux_eint(IRQ_EINT(24));
  160 +}
  161 +
  162 +static inline void s5p_irq_vic_eint_mask(struct irq_data *data)
  163 +{
  164 + void __iomem *base = irq_data_get_irq_chip_data(data);
  165 +
  166 + s5p_irq_eint_mask(data);
  167 + writel(1 << EINT_OFFSET(data->irq), base + VIC_INT_ENABLE_CLEAR);
  168 +}
  169 +
  170 +static void s5p_irq_vic_eint_unmask(struct irq_data *data)
  171 +{
  172 + void __iomem *base = irq_data_get_irq_chip_data(data);
  173 +
  174 + s5p_irq_eint_unmask(data);
  175 + writel(1 << EINT_OFFSET(data->irq), base + VIC_INT_ENABLE);
  176 +}
  177 +
  178 +static inline void s5p_irq_vic_eint_ack(struct irq_data *data)
  179 +{
  180 + __raw_writel(eint_irq_to_bit(data->irq),
  181 + S5P_EINT_PEND(EINT_REG_NR(data->irq)));
  182 +}
  183 +
  184 +static void s5p_irq_vic_eint_maskack(struct irq_data *data)
  185 +{
  186 + s5p_irq_vic_eint_mask(data);
  187 + s5p_irq_vic_eint_ack(data);
  188 +}
  189 +
  190 +static struct irq_chip s5p_irq_vic_eint = {
  191 + .name = "s5p_vic_eint",
  192 + .irq_mask = s5p_irq_vic_eint_mask,
  193 + .irq_unmask = s5p_irq_vic_eint_unmask,
  194 + .irq_mask_ack = s5p_irq_vic_eint_maskack,
  195 + .irq_ack = s5p_irq_vic_eint_ack,
  196 + .irq_set_type = s5p_irq_eint_set_type,
  197 +#ifdef CONFIG_PM
  198 + .irq_set_wake = s3c_irqext_wake,
  199 +#endif
  200 +};
  201 +
  202 +static int __init s5p_init_irq_eint(void)
  203 +{
  204 + int irq;
  205 +
  206 + for (irq = IRQ_EINT(0); irq <= IRQ_EINT(15); irq++)
  207 + irq_set_chip(irq, &s5p_irq_vic_eint);
  208 +
  209 + for (irq = IRQ_EINT(16); irq <= IRQ_EINT(31); irq++) {
  210 + irq_set_chip_and_handler(irq, &s5p_irq_eint, handle_level_irq);
  211 + set_irq_flags(irq, IRQF_VALID);
  212 + }
  213 +
  214 + irq_set_chained_handler(IRQ_EINT16_31, s5p_irq_demux_eint16_31);
  215 + return 0;
  216 +}
  217 +
  218 +arch_initcall(s5p_init_irq_eint);
arch/arm/plat-samsung/s5p-irq-gpioint.c
  1 +/*
  2 + * Copyright (c) 2010 Samsung Electronics Co., Ltd.
  3 + * Author: Kyungmin Park <kyungmin.park@samsung.com>
  4 + * Author: Joonyoung Shim <jy0922.shim@samsung.com>
  5 + * Author: Marek Szyprowski <m.szyprowski@samsung.com>
  6 + *
  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.
  11 + *
  12 + */
  13 +
  14 +#include <linux/kernel.h>
  15 +#include <linux/interrupt.h>
  16 +#include <linux/irq.h>
  17 +#include <linux/io.h>
  18 +#include <linux/gpio.h>
  19 +#include <linux/slab.h>
  20 +
  21 +#include <mach/map.h>
  22 +#include <plat/gpio-core.h>
  23 +#include <plat/gpio-cfg.h>
  24 +
  25 +#include <asm/mach/irq.h>
  26 +
  27 +#define GPIO_BASE(chip) (((unsigned long)(chip)->base) & 0xFFFFF000u)
  28 +
  29 +#define CON_OFFSET 0x700
  30 +#define MASK_OFFSET 0x900
  31 +#define PEND_OFFSET 0xA00
  32 +#define REG_OFFSET(x) ((x) << 2)
  33 +
  34 +struct s5p_gpioint_bank {
  35 + struct list_head list;
  36 + int start;
  37 + int nr_groups;
  38 + int irq;
  39 + struct samsung_gpio_chip **chips;
  40 + void (*handler)(unsigned int, struct irq_desc *);
  41 +};
  42 +
  43 +static LIST_HEAD(banks);
  44 +
  45 +static int s5p_gpioint_set_type(struct irq_data *d, unsigned int type)
  46 +{
  47 + struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
  48 + struct irq_chip_type *ct = gc->chip_types;
  49 + unsigned int shift = (d->irq - gc->irq_base) << 2;
  50 +
  51 + switch (type) {
  52 + case IRQ_TYPE_EDGE_RISING:
  53 + type = S5P_IRQ_TYPE_EDGE_RISING;
  54 + break;
  55 + case IRQ_TYPE_EDGE_FALLING:
  56 + type = S5P_IRQ_TYPE_EDGE_FALLING;
  57 + break;
  58 + case IRQ_TYPE_EDGE_BOTH:
  59 + type = S5P_IRQ_TYPE_EDGE_BOTH;
  60 + break;
  61 + case IRQ_TYPE_LEVEL_HIGH:
  62 + type = S5P_IRQ_TYPE_LEVEL_HIGH;
  63 + break;
  64 + case IRQ_TYPE_LEVEL_LOW:
  65 + type = S5P_IRQ_TYPE_LEVEL_LOW;
  66 + break;
  67 + case IRQ_TYPE_NONE:
  68 + default:
  69 + printk(KERN_WARNING "No irq type\n");
  70 + return -EINVAL;
  71 + }
  72 +
  73 + gc->type_cache &= ~(0x7 << shift);
  74 + gc->type_cache |= type << shift;
  75 + writel(gc->type_cache, gc->reg_base + ct->regs.type);
  76 + return 0;
  77 +}
  78 +
  79 +static void s5p_gpioint_handler(unsigned int irq, struct irq_desc *desc)
  80 +{
  81 + struct s5p_gpioint_bank *bank = irq_get_handler_data(irq);
  82 + int group, pend_offset, mask_offset;
  83 + unsigned int pend, mask;
  84 +
  85 + struct irq_chip *chip = irq_get_chip(irq);
  86 + chained_irq_enter(chip, desc);
  87 +
  88 + for (group = 0; group < bank->nr_groups; group++) {
  89 + struct samsung_gpio_chip *chip = bank->chips[group];
  90 + if (!chip)
  91 + continue;
  92 +
  93 + pend_offset = REG_OFFSET(group);
  94 + pend = __raw_readl(GPIO_BASE(chip) + PEND_OFFSET + pend_offset);
  95 + if (!pend)
  96 + continue;
  97 +
  98 + mask_offset = REG_OFFSET(group);
  99 + mask = __raw_readl(GPIO_BASE(chip) + MASK_OFFSET + mask_offset);
  100 + pend &= ~mask;
  101 +
  102 + while (pend) {
  103 + int offset = fls(pend) - 1;
  104 + int real_irq = chip->irq_base + offset;
  105 + generic_handle_irq(real_irq);
  106 + pend &= ~BIT(offset);
  107 + }
  108 + }
  109 + chained_irq_exit(chip, desc);
  110 +}
  111 +
  112 +static __init int s5p_gpioint_add(struct samsung_gpio_chip *chip)
  113 +{
  114 + static int used_gpioint_groups = 0;
  115 + int group = chip->group;
  116 + struct s5p_gpioint_bank *b, *bank = NULL;
  117 + struct irq_chip_generic *gc;
  118 + struct irq_chip_type *ct;
  119 +
  120 + if (used_gpioint_groups >= S5P_GPIOINT_GROUP_COUNT)
  121 + return -ENOMEM;
  122 +
  123 + list_for_each_entry(b, &banks, list) {
  124 + if (group >= b->start && group < b->start + b->nr_groups) {
  125 + bank = b;
  126 + break;
  127 + }
  128 + }
  129 + if (!bank)
  130 + return -EINVAL;
  131 +
  132 + if (!bank->handler) {
  133 + bank->chips = kzalloc(sizeof(struct samsung_gpio_chip *) *
  134 + bank->nr_groups, GFP_KERNEL);
  135 + if (!bank->chips)
  136 + return -ENOMEM;
  137 +
  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",
  142 + bank->irq);
  143 + }
  144 +
  145 + /*
  146 + * chained GPIO irq has been successfully registered, allocate new gpio
  147 + * int group and assign irq nubmers
  148 + */
  149 + chip->irq_base = S5P_GPIOINT_BASE +
  150 + used_gpioint_groups * S5P_GPIOINT_GROUP_SIZE;
  151 + used_gpioint_groups++;
  152 +
  153 + bank->chips[group - bank->start] = chip;
  154 +
  155 + gc = irq_alloc_generic_chip("s5p_gpioint", 1, chip->irq_base,
  156 + (void __iomem *)GPIO_BASE(chip),
  157 + handle_level_irq);
  158 + if (!gc)
  159 + return -ENOMEM;
  160 + ct = gc->chip_types;
  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(group - bank->start);
  166 + ct->regs.mask = MASK_OFFSET + REG_OFFSET(group - bank->start);
  167 + ct->regs.type = CON_OFFSET + REG_OFFSET(group - bank->start);
  168 + irq_setup_generic_chip(gc, IRQ_MSK(chip->chip.ngpio),
  169 + IRQ_GC_INIT_MASK_CACHE,
  170 + IRQ_NOREQUEST | IRQ_NOPROBE, 0);
  171 + return 0;
  172 +}
  173 +
  174 +int __init s5p_register_gpio_interrupt(int pin)
  175 +{
  176 + struct samsung_gpio_chip *my_chip = samsung_gpiolib_getchip(pin);
  177 + int offset, group;
  178 + int ret;
  179 +
  180 + if (!my_chip)
  181 + return -EINVAL;
  182 +
  183 + offset = pin - my_chip->chip.base;
  184 + group = my_chip->group;
  185 +
  186 + /* check if the group has been already registered */
  187 + if (my_chip->irq_base)
  188 + return my_chip->irq_base + offset;
  189 +
  190 + /* register gpio group */
  191 + ret = s5p_gpioint_add(my_chip);
  192 + if (ret == 0) {
  193 + my_chip->chip.to_irq = samsung_gpiolib_to_irq;
  194 + printk(KERN_INFO "Registered interrupt support for gpio group %d.\n",
  195 + group);
  196 + return my_chip->irq_base + offset;
  197 + }
  198 + return ret;
  199 +}
  200 +
  201 +int __init s5p_register_gpioint_bank(int chain_irq, int start, int nr_groups)
  202 +{
  203 + struct s5p_gpioint_bank *bank;
  204 +
  205 + bank = kzalloc(sizeof(*bank), GFP_KERNEL);
  206 + if (!bank)
  207 + return -ENOMEM;
  208 +
  209 + bank->start = start;
  210 + bank->nr_groups = nr_groups;
  211 + bank->irq = chain_irq;
  212 +
  213 + list_add_tail(&bank->list, &banks);
  214 + return 0;
  215 +}
arch/arm/plat-samsung/s5p-irq.c
  1 +/*
  2 + * Copyright (c) 2009 Samsung Electronics Co., Ltd.
  3 + * http://www.samsung.com/
  4 + *
  5 + * S5P - Interrupt handling
  6 + *
  7 + * This program is free software; you can redistribute it and/or modify
  8 + * it under the terms of the GNU General Public License version 2 as
  9 + * published by the Free Software Foundation.
  10 +*/
  11 +
  12 +#include <linux/kernel.h>
  13 +#include <linux/interrupt.h>
  14 +#include <linux/irq.h>
  15 +#include <linux/io.h>
  16 +
  17 +#include <asm/hardware/vic.h>
  18 +
  19 +#include <mach/map.h>
  20 +#include <plat/regs-timer.h>
  21 +#include <plat/cpu.h>
  22 +#include <plat/irq-vic-timer.h>
  23 +
  24 +void __init s5p_init_irq(u32 *vic, u32 num_vic)
  25 +{
  26 +#ifdef CONFIG_ARM_VIC
  27 + int irq;
  28 +
  29 + /* initialize the VICs */
  30 + for (irq = 0; irq < num_vic; irq++)
  31 + vic_init(VA_VIC(irq), VIC_BASE(irq), vic[irq], 0);
  32 +#endif
  33 +
  34 + s3c_init_vic_timer_irq(5, IRQ_TIMER0);
  35 +}