ARM: SAMSUNG: move interrupt part for common s5p into plat-samsung
authorKukjin Kim <kgene.kim@samsung.com>
Mon, 16 Apr 2012 04:40:33 +0000 (21:40 -0700)
committerKukjin Kim <kgene.kim@samsung.com>
Sat, 12 May 2012 22:01:27 +0000 (07:01 +0900)
Signed-off-by: Kukjin Kim <kgene.kim@samsung.com>
arch/arm/plat-s5p/Kconfig
arch/arm/plat-s5p/Makefile
arch/arm/plat-s5p/irq-eint.c [deleted file]
arch/arm/plat-s5p/irq-gpioint.c [deleted file]
arch/arm/plat-s5p/irq.c [deleted file]
arch/arm/plat-samsung/Kconfig
arch/arm/plat-samsung/Makefile
arch/arm/plat-samsung/s5p-irq-eint.c [new file with mode: 0644]
arch/arm/plat-samsung/s5p-irq-gpioint.c [new file with mode: 0644]
arch/arm/plat-samsung/s5p-irq.c [new file with mode: 0644]

index 2c1193c5992884ad0a624dc463bcccfc1d372e9b..efff0a30da4a3eb8c5d1d701867bfbdc4b6e4117 100644 (file)
@@ -23,17 +23,6 @@ config PLAT_S5P
        help
          Base platform code for Samsung's S5P series SoC.
 
-config S5P_EXT_INT
-       bool
-       help
-         Use the external interrupts (other than GPIO interrupts.)
-         Note: Do not choose this for S5P6440 and S5P6450.
-
-config S5P_GPIO_INT
-       bool
-       help
-         Common code for the GPIO interrupts (other than external interrupts.)
-
 config S5P_HRT
        bool
        select SAMSUNG_DEV_PWM
index 83152108af3de3a214b9702e8f12f186cfd8b44e..8701c3c36d6a0f8d53d9cf4749d1986a0dfa1d63 100644 (file)
@@ -12,9 +12,6 @@ obj-                          :=
 
 # Core files
 
-obj-y                          += irq.o
-obj-$(CONFIG_S5P_EXT_INT)      += irq-eint.o
-obj-$(CONFIG_S5P_GPIO_INT)     += irq-gpioint.o
 obj-$(CONFIG_S5P_PM)           += pm.o irq-pm.o
 obj-$(CONFIG_S5P_SLEEP)                += sleep.o
 obj-$(CONFIG_S5P_HRT)          += s5p-time.o
diff --git a/arch/arm/plat-s5p/irq-eint.c b/arch/arm/plat-s5p/irq-eint.c
deleted file mode 100644 (file)
index 139c050..0000000
+++ /dev/null
@@ -1,219 +0,0 @@
-/* linux/arch/arm/plat-s5p/irq-eint.c
- *
- * Copyright (c) 2010 Samsung Electronics Co., Ltd.
- *             http://www.samsung.com
- *
- * S5P - IRQ EINT support
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
-*/
-
-#include <linux/kernel.h>
-#include <linux/interrupt.h>
-#include <linux/irq.h>
-#include <linux/io.h>
-#include <linux/device.h>
-#include <linux/gpio.h>
-
-#include <asm/hardware/vic.h>
-
-#include <plat/regs-irqtype.h>
-
-#include <mach/map.h>
-#include <plat/cpu.h>
-#include <plat/pm.h>
-
-#include <plat/gpio-cfg.h>
-#include <mach/regs-gpio.h>
-
-static inline void s5p_irq_eint_mask(struct irq_data *data)
-{
-       u32 mask;
-
-       mask = __raw_readl(S5P_EINT_MASK(EINT_REG_NR(data->irq)));
-       mask |= eint_irq_to_bit(data->irq);
-       __raw_writel(mask, S5P_EINT_MASK(EINT_REG_NR(data->irq)));
-}
-
-static void s5p_irq_eint_unmask(struct irq_data *data)
-{
-       u32 mask;
-
-       mask = __raw_readl(S5P_EINT_MASK(EINT_REG_NR(data->irq)));
-       mask &= ~(eint_irq_to_bit(data->irq));
-       __raw_writel(mask, S5P_EINT_MASK(EINT_REG_NR(data->irq)));
-}
-
-static inline void s5p_irq_eint_ack(struct irq_data *data)
-{
-       __raw_writel(eint_irq_to_bit(data->irq),
-                    S5P_EINT_PEND(EINT_REG_NR(data->irq)));
-}
-
-static void s5p_irq_eint_maskack(struct irq_data *data)
-{
-       /* compiler should in-line these */
-       s5p_irq_eint_mask(data);
-       s5p_irq_eint_ack(data);
-}
-
-static int s5p_irq_eint_set_type(struct irq_data *data, unsigned int type)
-{
-       int offs = EINT_OFFSET(data->irq);
-       int shift;
-       u32 ctrl, mask;
-       u32 newvalue = 0;
-
-       switch (type) {
-       case IRQ_TYPE_EDGE_RISING:
-               newvalue = S5P_IRQ_TYPE_EDGE_RISING;
-               break;
-
-       case IRQ_TYPE_EDGE_FALLING:
-               newvalue = S5P_IRQ_TYPE_EDGE_FALLING;
-               break;
-
-       case IRQ_TYPE_EDGE_BOTH:
-               newvalue = S5P_IRQ_TYPE_EDGE_BOTH;
-               break;
-
-       case IRQ_TYPE_LEVEL_LOW:
-               newvalue = S5P_IRQ_TYPE_LEVEL_LOW;
-               break;
-
-       case IRQ_TYPE_LEVEL_HIGH:
-               newvalue = S5P_IRQ_TYPE_LEVEL_HIGH;
-               break;
-
-       default:
-               printk(KERN_ERR "No such irq type %d", type);
-               return -EINVAL;
-       }
-
-       shift = (offs & 0x7) * 4;
-       mask = 0x7 << shift;
-
-       ctrl = __raw_readl(S5P_EINT_CON(EINT_REG_NR(data->irq)));
-       ctrl &= ~mask;
-       ctrl |= newvalue << shift;
-       __raw_writel(ctrl, S5P_EINT_CON(EINT_REG_NR(data->irq)));
-
-       if ((0 <= offs) && (offs < 8))
-               s3c_gpio_cfgpin(EINT_GPIO_0(offs & 0x7), EINT_MODE);
-
-       else if ((8 <= offs) && (offs < 16))
-               s3c_gpio_cfgpin(EINT_GPIO_1(offs & 0x7), EINT_MODE);
-
-       else if ((16 <= offs) && (offs < 24))
-               s3c_gpio_cfgpin(EINT_GPIO_2(offs & 0x7), EINT_MODE);
-
-       else if ((24 <= offs) && (offs < 32))
-               s3c_gpio_cfgpin(EINT_GPIO_3(offs & 0x7), EINT_MODE);
-
-       else
-               printk(KERN_ERR "No such irq number %d", offs);
-
-       return 0;
-}
-
-static struct irq_chip s5p_irq_eint = {
-       .name           = "s5p-eint",
-       .irq_mask       = s5p_irq_eint_mask,
-       .irq_unmask     = s5p_irq_eint_unmask,
-       .irq_mask_ack   = s5p_irq_eint_maskack,
-       .irq_ack        = s5p_irq_eint_ack,
-       .irq_set_type   = s5p_irq_eint_set_type,
-#ifdef CONFIG_PM
-       .irq_set_wake   = s3c_irqext_wake,
-#endif
-};
-
-/* s5p_irq_demux_eint
- *
- * This function demuxes the IRQ from the group0 external interrupts,
- * from EINTs 16 to 31. It is designed to be inlined into the specific
- * handler s5p_irq_demux_eintX_Y.
- *
- * Each EINT pend/mask registers handle eight of them.
- */
-static inline void s5p_irq_demux_eint(unsigned int start)
-{
-       u32 status = __raw_readl(S5P_EINT_PEND(EINT_REG_NR(start)));
-       u32 mask = __raw_readl(S5P_EINT_MASK(EINT_REG_NR(start)));
-       unsigned int irq;
-
-       status &= ~mask;
-       status &= 0xff;
-
-       while (status) {
-               irq = fls(status) - 1;
-               generic_handle_irq(irq + start);
-               status &= ~(1 << irq);
-       }
-}
-
-static void s5p_irq_demux_eint16_31(unsigned int irq, struct irq_desc *desc)
-{
-       s5p_irq_demux_eint(IRQ_EINT(16));
-       s5p_irq_demux_eint(IRQ_EINT(24));
-}
-
-static inline void s5p_irq_vic_eint_mask(struct irq_data *data)
-{
-       void __iomem *base = irq_data_get_irq_chip_data(data);
-
-       s5p_irq_eint_mask(data);
-       writel(1 << EINT_OFFSET(data->irq), base + VIC_INT_ENABLE_CLEAR);
-}
-
-static void s5p_irq_vic_eint_unmask(struct irq_data *data)
-{
-       void __iomem *base = irq_data_get_irq_chip_data(data);
-
-       s5p_irq_eint_unmask(data);
-       writel(1 << EINT_OFFSET(data->irq), base + VIC_INT_ENABLE);
-}
-
-static inline void s5p_irq_vic_eint_ack(struct irq_data *data)
-{
-       __raw_writel(eint_irq_to_bit(data->irq),
-                    S5P_EINT_PEND(EINT_REG_NR(data->irq)));
-}
-
-static void s5p_irq_vic_eint_maskack(struct irq_data *data)
-{
-       s5p_irq_vic_eint_mask(data);
-       s5p_irq_vic_eint_ack(data);
-}
-
-static struct irq_chip s5p_irq_vic_eint = {
-       .name           = "s5p_vic_eint",
-       .irq_mask       = s5p_irq_vic_eint_mask,
-       .irq_unmask     = s5p_irq_vic_eint_unmask,
-       .irq_mask_ack   = s5p_irq_vic_eint_maskack,
-       .irq_ack        = s5p_irq_vic_eint_ack,
-       .irq_set_type   = s5p_irq_eint_set_type,
-#ifdef CONFIG_PM
-       .irq_set_wake   = s3c_irqext_wake,
-#endif
-};
-
-static int __init s5p_init_irq_eint(void)
-{
-       int irq;
-
-       for (irq = IRQ_EINT(0); irq <= IRQ_EINT(15); irq++)
-               irq_set_chip(irq, &s5p_irq_vic_eint);
-
-       for (irq = IRQ_EINT(16); irq <= IRQ_EINT(31); irq++) {
-               irq_set_chip_and_handler(irq, &s5p_irq_eint, handle_level_irq);
-               set_irq_flags(irq, IRQF_VALID);
-       }
-
-       irq_set_chained_handler(IRQ_EINT16_31, s5p_irq_demux_eint16_31);
-       return 0;
-}
-
-arch_initcall(s5p_init_irq_eint);
diff --git a/arch/arm/plat-s5p/irq-gpioint.c b/arch/arm/plat-s5p/irq-gpioint.c
deleted file mode 100644 (file)
index 82c7311..0000000
+++ /dev/null
@@ -1,216 +0,0 @@
-/* linux/arch/arm/plat-s5p/irq-gpioint.c
- *
- * Copyright (c) 2010 Samsung Electronics Co., Ltd.
- * Author: Kyungmin Park <kyungmin.park@samsung.com>
- * Author: Joonyoung Shim <jy0922.shim@samsung.com>
- * Author: Marek Szyprowski <m.szyprowski@samsung.com>
- *
- *  This program is free software; you can redistribute  it and/or modify it
- *  under  the terms of  the GNU General  Public License as published by the
- *  Free Software Foundation;  either version 2 of the  License, or (at your
- *  option) any later version.
- *
- */
-
-#include <linux/kernel.h>
-#include <linux/interrupt.h>
-#include <linux/irq.h>
-#include <linux/io.h>
-#include <linux/gpio.h>
-#include <linux/slab.h>
-
-#include <mach/map.h>
-#include <plat/gpio-core.h>
-#include <plat/gpio-cfg.h>
-
-#include <asm/mach/irq.h>
-
-#define GPIO_BASE(chip)                (((unsigned long)(chip)->base) & 0xFFFFF000u)
-
-#define CON_OFFSET             0x700
-#define MASK_OFFSET            0x900
-#define PEND_OFFSET            0xA00
-#define REG_OFFSET(x)          ((x) << 2)
-
-struct s5p_gpioint_bank {
-       struct list_head        list;
-       int                     start;
-       int                     nr_groups;
-       int                     irq;
-       struct samsung_gpio_chip        **chips;
-       void                    (*handler)(unsigned int, struct irq_desc *);
-};
-
-static LIST_HEAD(banks);
-
-static int s5p_gpioint_set_type(struct irq_data *d, unsigned int type)
-{
-       struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
-       struct irq_chip_type *ct = gc->chip_types;
-       unsigned int shift = (d->irq - gc->irq_base) << 2;
-
-       switch (type) {
-       case IRQ_TYPE_EDGE_RISING:
-               type = S5P_IRQ_TYPE_EDGE_RISING;
-               break;
-       case IRQ_TYPE_EDGE_FALLING:
-               type = S5P_IRQ_TYPE_EDGE_FALLING;
-               break;
-       case IRQ_TYPE_EDGE_BOTH:
-               type = S5P_IRQ_TYPE_EDGE_BOTH;
-               break;
-       case IRQ_TYPE_LEVEL_HIGH:
-               type = S5P_IRQ_TYPE_LEVEL_HIGH;
-               break;
-       case IRQ_TYPE_LEVEL_LOW:
-               type = S5P_IRQ_TYPE_LEVEL_LOW;
-               break;
-       case IRQ_TYPE_NONE:
-       default:
-               printk(KERN_WARNING "No irq type\n");
-               return -EINVAL;
-       }
-
-       gc->type_cache &= ~(0x7 << shift);
-       gc->type_cache |= type << shift;
-       writel(gc->type_cache, gc->reg_base + ct->regs.type);
-       return 0;
-}
-
-static void s5p_gpioint_handler(unsigned int irq, struct irq_desc *desc)
-{
-       struct s5p_gpioint_bank *bank = irq_get_handler_data(irq);
-       int group, pend_offset, mask_offset;
-       unsigned int pend, mask;
-
-       struct irq_chip *chip = irq_get_chip(irq);
-       chained_irq_enter(chip, desc);
-
-       for (group = 0; group < bank->nr_groups; group++) {
-               struct samsung_gpio_chip *chip = bank->chips[group];
-               if (!chip)
-                       continue;
-
-               pend_offset = REG_OFFSET(group);
-               pend = __raw_readl(GPIO_BASE(chip) + PEND_OFFSET + pend_offset);
-               if (!pend)
-                       continue;
-
-               mask_offset = REG_OFFSET(group);
-               mask = __raw_readl(GPIO_BASE(chip) + MASK_OFFSET + mask_offset);
-               pend &= ~mask;
-
-               while (pend) {
-                       int offset = fls(pend) - 1;
-                       int real_irq = chip->irq_base + offset;
-                       generic_handle_irq(real_irq);
-                       pend &= ~BIT(offset);
-               }
-       }
-       chained_irq_exit(chip, desc);
-}
-
-static __init int s5p_gpioint_add(struct samsung_gpio_chip *chip)
-{
-       static int used_gpioint_groups = 0;
-       int group = chip->group;
-       struct s5p_gpioint_bank *b, *bank = NULL;
-       struct irq_chip_generic *gc;
-       struct irq_chip_type *ct;
-
-       if (used_gpioint_groups >= S5P_GPIOINT_GROUP_COUNT)
-               return -ENOMEM;
-
-       list_for_each_entry(b, &banks, list) {
-               if (group >= b->start && group < b->start + b->nr_groups) {
-                       bank = b;
-                       break;
-               }
-       }
-       if (!bank)
-               return -EINVAL;
-
-       if (!bank->handler) {
-               bank->chips = kzalloc(sizeof(struct samsung_gpio_chip *) *
-                                     bank->nr_groups, GFP_KERNEL);
-               if (!bank->chips)
-                       return -ENOMEM;
-
-               irq_set_chained_handler(bank->irq, s5p_gpioint_handler);
-               irq_set_handler_data(bank->irq, bank);
-               bank->handler = s5p_gpioint_handler;
-               printk(KERN_INFO "Registered chained gpio int handler for interrupt %d.\n",
-                      bank->irq);
-       }
-
-       /*
-        * chained GPIO irq has been successfully registered, allocate new gpio
-        * int group and assign irq nubmers
-        */
-       chip->irq_base = S5P_GPIOINT_BASE +
-                        used_gpioint_groups * S5P_GPIOINT_GROUP_SIZE;
-       used_gpioint_groups++;
-
-       bank->chips[group - bank->start] = chip;
-
-       gc = irq_alloc_generic_chip("s5p_gpioint", 1, chip->irq_base,
-                                   (void __iomem *)GPIO_BASE(chip),
-                                   handle_level_irq);
-       if (!gc)
-               return -ENOMEM;
-       ct = gc->chip_types;
-       ct->chip.irq_ack = irq_gc_ack_set_bit;
-       ct->chip.irq_mask = irq_gc_mask_set_bit;
-       ct->chip.irq_unmask = irq_gc_mask_clr_bit;
-       ct->chip.irq_set_type = s5p_gpioint_set_type,
-       ct->regs.ack = PEND_OFFSET + REG_OFFSET(group - bank->start);
-       ct->regs.mask = MASK_OFFSET + REG_OFFSET(group - bank->start);
-       ct->regs.type = CON_OFFSET + REG_OFFSET(group - bank->start);
-       irq_setup_generic_chip(gc, IRQ_MSK(chip->chip.ngpio),
-                              IRQ_GC_INIT_MASK_CACHE,
-                              IRQ_NOREQUEST | IRQ_NOPROBE, 0);
-       return 0;
-}
-
-int __init s5p_register_gpio_interrupt(int pin)
-{
-       struct samsung_gpio_chip *my_chip = samsung_gpiolib_getchip(pin);
-       int offset, group;
-       int ret;
-
-       if (!my_chip)
-               return -EINVAL;
-
-       offset = pin - my_chip->chip.base;
-       group = my_chip->group;
-
-       /* check if the group has been already registered */
-       if (my_chip->irq_base)
-               return my_chip->irq_base + offset;
-
-       /* register gpio group */
-       ret = s5p_gpioint_add(my_chip);
-       if (ret == 0) {
-               my_chip->chip.to_irq = samsung_gpiolib_to_irq;
-               printk(KERN_INFO "Registered interrupt support for gpio group %d.\n",
-                      group);
-               return my_chip->irq_base + offset;
-       }
-       return ret;
-}
-
-int __init s5p_register_gpioint_bank(int chain_irq, int start, int nr_groups)
-{
-       struct s5p_gpioint_bank *bank;
-
-       bank = kzalloc(sizeof(*bank), GFP_KERNEL);
-       if (!bank)
-               return -ENOMEM;
-
-       bank->start = start;
-       bank->nr_groups = nr_groups;
-       bank->irq = chain_irq;
-
-       list_add_tail(&bank->list, &banks);
-       return 0;
-}
diff --git a/arch/arm/plat-s5p/irq.c b/arch/arm/plat-s5p/irq.c
deleted file mode 100644 (file)
index afdaa10..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-/* arch/arm/plat-s5p/irq.c
- *
- * Copyright (c) 2009 Samsung Electronics Co., Ltd.
- *             http://www.samsung.com/
- *
- * S5P - Interrupt handling
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
-*/
-
-#include <linux/kernel.h>
-#include <linux/interrupt.h>
-#include <linux/irq.h>
-#include <linux/io.h>
-
-#include <asm/hardware/vic.h>
-
-#include <mach/map.h>
-#include <plat/regs-timer.h>
-#include <plat/cpu.h>
-#include <plat/irq-vic-timer.h>
-
-void __init s5p_init_irq(u32 *vic, u32 num_vic)
-{
-#ifdef CONFIG_ARM_VIC
-       int irq;
-
-       /* initialize the VICs */
-       for (irq = 0; irq < num_vic; irq++)
-               vic_init(VA_VIC(irq), VIC_BASE(irq), vic[irq], 0);
-#endif
-
-       s3c_init_vic_timer_irq(5, IRQ_TIMER0);
-}
index 3a48d9de22a88171781340e05fdf21d0460f75fe..e09dd4f9dc3138f1bb0d0f95f0fe2b9789d6e0da 100644 (file)
@@ -70,6 +70,22 @@ config SAMSUNG_IRQ_VIC_TIMER
        help
          Internal configuration to build the VIC timer interrupt code.
 
+config S5P_IRQ
+       def_bool (ARCH_S5P64X0 || ARCH_S5PC100 || ARCH_S5PV210 || ARCH_EXYNOS)
+       help
+         Support common interrup part for ARCH_S5P and ARCH_EXYNOS SoCs
+
+config S5P_EXT_INT
+       bool
+       help
+         Use the external interrupts (other than GPIO interrupts.)
+         Note: Do not choose this for S5P6440 and S5P6450.
+
+config S5P_GPIO_INT
+       bool
+       help
+         Common code for the GPIO interrupts (other than external interrupts.)
+
 # options for gpio configuration support
 
 config SAMSUNG_GPIOLIB_4BIT
index 997ce1005700e9f7de913b9d5a0adf4c7afd2d71..5b650094628fd0ac11a0cde9266b13daf70e0007 100644 (file)
@@ -20,6 +20,9 @@ obj-$(CONFIG_SAMSUNG_CLKSRC)  += clock-clksrc.o
 obj-$(CONFIG_S5P_CLOCK)                += s5p-clock.o
 
 obj-$(CONFIG_SAMSUNG_IRQ_VIC_TIMER) += irq-vic-timer.o
+obj-$(CONFIG_S5P_IRQ)          += s5p-irq.o
+obj-$(CONFIG_S5P_EXT_INT)      += s5p-irq-eint.o
+obj-$(CONFIG_S5P_GPIO_INT)     += s5p-irq-gpioint.o
 
 # ADC
 
diff --git a/arch/arm/plat-samsung/s5p-irq-eint.c b/arch/arm/plat-samsung/s5p-irq-eint.c
new file mode 100644 (file)
index 0000000..33bd3f3
--- /dev/null
@@ -0,0 +1,218 @@
+/*
+ * Copyright (c) 2010 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com
+ *
+ * S5P - IRQ EINT support
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/io.h>
+#include <linux/device.h>
+#include <linux/gpio.h>
+
+#include <asm/hardware/vic.h>
+
+#include <plat/regs-irqtype.h>
+
+#include <mach/map.h>
+#include <plat/cpu.h>
+#include <plat/pm.h>
+
+#include <plat/gpio-cfg.h>
+#include <mach/regs-gpio.h>
+
+static inline void s5p_irq_eint_mask(struct irq_data *data)
+{
+       u32 mask;
+
+       mask = __raw_readl(S5P_EINT_MASK(EINT_REG_NR(data->irq)));
+       mask |= eint_irq_to_bit(data->irq);
+       __raw_writel(mask, S5P_EINT_MASK(EINT_REG_NR(data->irq)));
+}
+
+static void s5p_irq_eint_unmask(struct irq_data *data)
+{
+       u32 mask;
+
+       mask = __raw_readl(S5P_EINT_MASK(EINT_REG_NR(data->irq)));
+       mask &= ~(eint_irq_to_bit(data->irq));
+       __raw_writel(mask, S5P_EINT_MASK(EINT_REG_NR(data->irq)));
+}
+
+static inline void s5p_irq_eint_ack(struct irq_data *data)
+{
+       __raw_writel(eint_irq_to_bit(data->irq),
+                    S5P_EINT_PEND(EINT_REG_NR(data->irq)));
+}
+
+static void s5p_irq_eint_maskack(struct irq_data *data)
+{
+       /* compiler should in-line these */
+       s5p_irq_eint_mask(data);
+       s5p_irq_eint_ack(data);
+}
+
+static int s5p_irq_eint_set_type(struct irq_data *data, unsigned int type)
+{
+       int offs = EINT_OFFSET(data->irq);
+       int shift;
+       u32 ctrl, mask;
+       u32 newvalue = 0;
+
+       switch (type) {
+       case IRQ_TYPE_EDGE_RISING:
+               newvalue = S5P_IRQ_TYPE_EDGE_RISING;
+               break;
+
+       case IRQ_TYPE_EDGE_FALLING:
+               newvalue = S5P_IRQ_TYPE_EDGE_FALLING;
+               break;
+
+       case IRQ_TYPE_EDGE_BOTH:
+               newvalue = S5P_IRQ_TYPE_EDGE_BOTH;
+               break;
+
+       case IRQ_TYPE_LEVEL_LOW:
+               newvalue = S5P_IRQ_TYPE_LEVEL_LOW;
+               break;
+
+       case IRQ_TYPE_LEVEL_HIGH:
+               newvalue = S5P_IRQ_TYPE_LEVEL_HIGH;
+               break;
+
+       default:
+               printk(KERN_ERR "No such irq type %d", type);
+               return -EINVAL;
+       }
+
+       shift = (offs & 0x7) * 4;
+       mask = 0x7 << shift;
+
+       ctrl = __raw_readl(S5P_EINT_CON(EINT_REG_NR(data->irq)));
+       ctrl &= ~mask;
+       ctrl |= newvalue << shift;
+       __raw_writel(ctrl, S5P_EINT_CON(EINT_REG_NR(data->irq)));
+
+       if ((0 <= offs) && (offs < 8))
+               s3c_gpio_cfgpin(EINT_GPIO_0(offs & 0x7), EINT_MODE);
+
+       else if ((8 <= offs) && (offs < 16))
+               s3c_gpio_cfgpin(EINT_GPIO_1(offs & 0x7), EINT_MODE);
+
+       else if ((16 <= offs) && (offs < 24))
+               s3c_gpio_cfgpin(EINT_GPIO_2(offs & 0x7), EINT_MODE);
+
+       else if ((24 <= offs) && (offs < 32))
+               s3c_gpio_cfgpin(EINT_GPIO_3(offs & 0x7), EINT_MODE);
+
+       else
+               printk(KERN_ERR "No such irq number %d", offs);
+
+       return 0;
+}
+
+static struct irq_chip s5p_irq_eint = {
+       .name           = "s5p-eint",
+       .irq_mask       = s5p_irq_eint_mask,
+       .irq_unmask     = s5p_irq_eint_unmask,
+       .irq_mask_ack   = s5p_irq_eint_maskack,
+       .irq_ack        = s5p_irq_eint_ack,
+       .irq_set_type   = s5p_irq_eint_set_type,
+#ifdef CONFIG_PM
+       .irq_set_wake   = s3c_irqext_wake,
+#endif
+};
+
+/* s5p_irq_demux_eint
+ *
+ * This function demuxes the IRQ from the group0 external interrupts,
+ * from EINTs 16 to 31. It is designed to be inlined into the specific
+ * handler s5p_irq_demux_eintX_Y.
+ *
+ * Each EINT pend/mask registers handle eight of them.
+ */
+static inline void s5p_irq_demux_eint(unsigned int start)
+{
+       u32 status = __raw_readl(S5P_EINT_PEND(EINT_REG_NR(start)));
+       u32 mask = __raw_readl(S5P_EINT_MASK(EINT_REG_NR(start)));
+       unsigned int irq;
+
+       status &= ~mask;
+       status &= 0xff;
+
+       while (status) {
+               irq = fls(status) - 1;
+               generic_handle_irq(irq + start);
+               status &= ~(1 << irq);
+       }
+}
+
+static void s5p_irq_demux_eint16_31(unsigned int irq, struct irq_desc *desc)
+{
+       s5p_irq_demux_eint(IRQ_EINT(16));
+       s5p_irq_demux_eint(IRQ_EINT(24));
+}
+
+static inline void s5p_irq_vic_eint_mask(struct irq_data *data)
+{
+       void __iomem *base = irq_data_get_irq_chip_data(data);
+
+       s5p_irq_eint_mask(data);
+       writel(1 << EINT_OFFSET(data->irq), base + VIC_INT_ENABLE_CLEAR);
+}
+
+static void s5p_irq_vic_eint_unmask(struct irq_data *data)
+{
+       void __iomem *base = irq_data_get_irq_chip_data(data);
+
+       s5p_irq_eint_unmask(data);
+       writel(1 << EINT_OFFSET(data->irq), base + VIC_INT_ENABLE);
+}
+
+static inline void s5p_irq_vic_eint_ack(struct irq_data *data)
+{
+       __raw_writel(eint_irq_to_bit(data->irq),
+                    S5P_EINT_PEND(EINT_REG_NR(data->irq)));
+}
+
+static void s5p_irq_vic_eint_maskack(struct irq_data *data)
+{
+       s5p_irq_vic_eint_mask(data);
+       s5p_irq_vic_eint_ack(data);
+}
+
+static struct irq_chip s5p_irq_vic_eint = {
+       .name           = "s5p_vic_eint",
+       .irq_mask       = s5p_irq_vic_eint_mask,
+       .irq_unmask     = s5p_irq_vic_eint_unmask,
+       .irq_mask_ack   = s5p_irq_vic_eint_maskack,
+       .irq_ack        = s5p_irq_vic_eint_ack,
+       .irq_set_type   = s5p_irq_eint_set_type,
+#ifdef CONFIG_PM
+       .irq_set_wake   = s3c_irqext_wake,
+#endif
+};
+
+static int __init s5p_init_irq_eint(void)
+{
+       int irq;
+
+       for (irq = IRQ_EINT(0); irq <= IRQ_EINT(15); irq++)
+               irq_set_chip(irq, &s5p_irq_vic_eint);
+
+       for (irq = IRQ_EINT(16); irq <= IRQ_EINT(31); irq++) {
+               irq_set_chip_and_handler(irq, &s5p_irq_eint, handle_level_irq);
+               set_irq_flags(irq, IRQF_VALID);
+       }
+
+       irq_set_chained_handler(IRQ_EINT16_31, s5p_irq_demux_eint16_31);
+       return 0;
+}
+
+arch_initcall(s5p_init_irq_eint);
diff --git a/arch/arm/plat-samsung/s5p-irq-gpioint.c b/arch/arm/plat-samsung/s5p-irq-gpioint.c
new file mode 100644 (file)
index 0000000..f9431fe
--- /dev/null
@@ -0,0 +1,215 @@
+/*
+ * Copyright (c) 2010 Samsung Electronics Co., Ltd.
+ * Author: Kyungmin Park <kyungmin.park@samsung.com>
+ * Author: Joonyoung Shim <jy0922.shim@samsung.com>
+ * Author: Marek Szyprowski <m.szyprowski@samsung.com>
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/io.h>
+#include <linux/gpio.h>
+#include <linux/slab.h>
+
+#include <mach/map.h>
+#include <plat/gpio-core.h>
+#include <plat/gpio-cfg.h>
+
+#include <asm/mach/irq.h>
+
+#define GPIO_BASE(chip)                (((unsigned long)(chip)->base) & 0xFFFFF000u)
+
+#define CON_OFFSET             0x700
+#define MASK_OFFSET            0x900
+#define PEND_OFFSET            0xA00
+#define REG_OFFSET(x)          ((x) << 2)
+
+struct s5p_gpioint_bank {
+       struct list_head        list;
+       int                     start;
+       int                     nr_groups;
+       int                     irq;
+       struct samsung_gpio_chip        **chips;
+       void                    (*handler)(unsigned int, struct irq_desc *);
+};
+
+static LIST_HEAD(banks);
+
+static int s5p_gpioint_set_type(struct irq_data *d, unsigned int type)
+{
+       struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
+       struct irq_chip_type *ct = gc->chip_types;
+       unsigned int shift = (d->irq - gc->irq_base) << 2;
+
+       switch (type) {
+       case IRQ_TYPE_EDGE_RISING:
+               type = S5P_IRQ_TYPE_EDGE_RISING;
+               break;
+       case IRQ_TYPE_EDGE_FALLING:
+               type = S5P_IRQ_TYPE_EDGE_FALLING;
+               break;
+       case IRQ_TYPE_EDGE_BOTH:
+               type = S5P_IRQ_TYPE_EDGE_BOTH;
+               break;
+       case IRQ_TYPE_LEVEL_HIGH:
+               type = S5P_IRQ_TYPE_LEVEL_HIGH;
+               break;
+       case IRQ_TYPE_LEVEL_LOW:
+               type = S5P_IRQ_TYPE_LEVEL_LOW;
+               break;
+       case IRQ_TYPE_NONE:
+       default:
+               printk(KERN_WARNING "No irq type\n");
+               return -EINVAL;
+       }
+
+       gc->type_cache &= ~(0x7 << shift);
+       gc->type_cache |= type << shift;
+       writel(gc->type_cache, gc->reg_base + ct->regs.type);
+       return 0;
+}
+
+static void s5p_gpioint_handler(unsigned int irq, struct irq_desc *desc)
+{
+       struct s5p_gpioint_bank *bank = irq_get_handler_data(irq);
+       int group, pend_offset, mask_offset;
+       unsigned int pend, mask;
+
+       struct irq_chip *chip = irq_get_chip(irq);
+       chained_irq_enter(chip, desc);
+
+       for (group = 0; group < bank->nr_groups; group++) {
+               struct samsung_gpio_chip *chip = bank->chips[group];
+               if (!chip)
+                       continue;
+
+               pend_offset = REG_OFFSET(group);
+               pend = __raw_readl(GPIO_BASE(chip) + PEND_OFFSET + pend_offset);
+               if (!pend)
+                       continue;
+
+               mask_offset = REG_OFFSET(group);
+               mask = __raw_readl(GPIO_BASE(chip) + MASK_OFFSET + mask_offset);
+               pend &= ~mask;
+
+               while (pend) {
+                       int offset = fls(pend) - 1;
+                       int real_irq = chip->irq_base + offset;
+                       generic_handle_irq(real_irq);
+                       pend &= ~BIT(offset);
+               }
+       }
+       chained_irq_exit(chip, desc);
+}
+
+static __init int s5p_gpioint_add(struct samsung_gpio_chip *chip)
+{
+       static int used_gpioint_groups = 0;
+       int group = chip->group;
+       struct s5p_gpioint_bank *b, *bank = NULL;
+       struct irq_chip_generic *gc;
+       struct irq_chip_type *ct;
+
+       if (used_gpioint_groups >= S5P_GPIOINT_GROUP_COUNT)
+               return -ENOMEM;
+
+       list_for_each_entry(b, &banks, list) {
+               if (group >= b->start && group < b->start + b->nr_groups) {
+                       bank = b;
+                       break;
+               }
+       }
+       if (!bank)
+               return -EINVAL;
+
+       if (!bank->handler) {
+               bank->chips = kzalloc(sizeof(struct samsung_gpio_chip *) *
+                                     bank->nr_groups, GFP_KERNEL);
+               if (!bank->chips)
+                       return -ENOMEM;
+
+               irq_set_chained_handler(bank->irq, s5p_gpioint_handler);
+               irq_set_handler_data(bank->irq, bank);
+               bank->handler = s5p_gpioint_handler;
+               printk(KERN_INFO "Registered chained gpio int handler for interrupt %d.\n",
+                      bank->irq);
+       }
+
+       /*
+        * chained GPIO irq has been successfully registered, allocate new gpio
+        * int group and assign irq nubmers
+        */
+       chip->irq_base = S5P_GPIOINT_BASE +
+                        used_gpioint_groups * S5P_GPIOINT_GROUP_SIZE;
+       used_gpioint_groups++;
+
+       bank->chips[group - bank->start] = chip;
+
+       gc = irq_alloc_generic_chip("s5p_gpioint", 1, chip->irq_base,
+                                   (void __iomem *)GPIO_BASE(chip),
+                                   handle_level_irq);
+       if (!gc)
+               return -ENOMEM;
+       ct = gc->chip_types;
+       ct->chip.irq_ack = irq_gc_ack_set_bit;
+       ct->chip.irq_mask = irq_gc_mask_set_bit;
+       ct->chip.irq_unmask = irq_gc_mask_clr_bit;
+       ct->chip.irq_set_type = s5p_gpioint_set_type,
+       ct->regs.ack = PEND_OFFSET + REG_OFFSET(group - bank->start);
+       ct->regs.mask = MASK_OFFSET + REG_OFFSET(group - bank->start);
+       ct->regs.type = CON_OFFSET + REG_OFFSET(group - bank->start);
+       irq_setup_generic_chip(gc, IRQ_MSK(chip->chip.ngpio),
+                              IRQ_GC_INIT_MASK_CACHE,
+                              IRQ_NOREQUEST | IRQ_NOPROBE, 0);
+       return 0;
+}
+
+int __init s5p_register_gpio_interrupt(int pin)
+{
+       struct samsung_gpio_chip *my_chip = samsung_gpiolib_getchip(pin);
+       int offset, group;
+       int ret;
+
+       if (!my_chip)
+               return -EINVAL;
+
+       offset = pin - my_chip->chip.base;
+       group = my_chip->group;
+
+       /* check if the group has been already registered */
+       if (my_chip->irq_base)
+               return my_chip->irq_base + offset;
+
+       /* register gpio group */
+       ret = s5p_gpioint_add(my_chip);
+       if (ret == 0) {
+               my_chip->chip.to_irq = samsung_gpiolib_to_irq;
+               printk(KERN_INFO "Registered interrupt support for gpio group %d.\n",
+                      group);
+               return my_chip->irq_base + offset;
+       }
+       return ret;
+}
+
+int __init s5p_register_gpioint_bank(int chain_irq, int start, int nr_groups)
+{
+       struct s5p_gpioint_bank *bank;
+
+       bank = kzalloc(sizeof(*bank), GFP_KERNEL);
+       if (!bank)
+               return -ENOMEM;
+
+       bank->start = start;
+       bank->nr_groups = nr_groups;
+       bank->irq = chain_irq;
+
+       list_add_tail(&bank->list, &banks);
+       return 0;
+}
diff --git a/arch/arm/plat-samsung/s5p-irq.c b/arch/arm/plat-samsung/s5p-irq.c
new file mode 100644 (file)
index 0000000..dfb47d6
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2009 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com/
+ *
+ * S5P - Interrupt handling
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/io.h>
+
+#include <asm/hardware/vic.h>
+
+#include <mach/map.h>
+#include <plat/regs-timer.h>
+#include <plat/cpu.h>
+#include <plat/irq-vic-timer.h>
+
+void __init s5p_init_irq(u32 *vic, u32 num_vic)
+{
+#ifdef CONFIG_ARM_VIC
+       int irq;
+
+       /* initialize the VICs */
+       for (irq = 0; irq < num_vic; irq++)
+               vic_init(VA_VIC(irq), VIC_BASE(irq), vic[irq], 0);
+#endif
+
+       s3c_init_vic_timer_irq(5, IRQ_TIMER0);
+}
This page took 0.037193 seconds and 5 git commands to generate.