aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-s3c24xx/irq-s3c2412.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2012-03-27 16:03:32 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2012-03-27 16:03:32 -0700
commitd61b7a572b292e2be409e13b4b3adf475f18fb29 (patch)
treee9d30390860147136c05e66abf1edda1bc5b0562 /arch/arm/mach-s3c24xx/irq-s3c2412.c
parentMerge tag 'maintainers' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc (diff)
parentMerge branch 'ep93xx-for-arm-soc' of git://github.com/RyanMallon/linux-2.6 into next/cleanup (diff)
downloadlinux-dev-d61b7a572b292e2be409e13b4b3adf475f18fb29.tar.xz
linux-dev-d61b7a572b292e2be409e13b4b3adf475f18fb29.zip
Merge tag 'cleanup' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc
Pull "ARM: global cleanups" from Arnd Bergmann: "Quite a bit of code gets removed, and some stuff moved around, mostly the old samsung s3c24xx stuff. There should be no functional changes in this series otherwise. Some cleanups have dependencies on other arm-soc branches and will be sent in the second round. Signed-off-by: Arnd Bergmann <arnd@arndb.de>" Fixed up trivial conflicts mainly due to #include's being changes on both sides. * tag 'cleanup' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc: (121 commits) ep93xx: Remove unnecessary includes of ep93xx-regs.h ep93xx: Move EP93XX_SYSCON defines to SoC private header ep93xx: Move crunch code to mach-ep93xx directory ep93xx: Make syscon access functions private to SoC ep93xx: Configure GPIO ports in core code ep93xx: Move peripheral defines to local SoC header ep93xx: Convert the watchdog driver into a platform device. ep93xx: Use ioremap for backlight driver ep93xx: Move GPIO defines to gpio-ep93xx.h ep93xx: Don't use system controller defines in audio drivers ep93xx: Move PHYS_BASE defines to local SoC header file ARM: EXYNOS: Add clock register addresses for EXYNOS4X12 bus devfreq driver ARM: EXYNOS: add clock registers for exynos4x12-cpufreq PM / devfreq: update the name of EXYNOS clock registers that were omitted PM / devfreq: update the name of EXYNOS clock register ARM: EXYNOS: change the prefix S5P_ to EXYNOS4_ for clock ARM: EXYNOS: use static declaration on regarding clock ARM: EXYNOS: replace clock.c for other new EXYNOS SoCs ARM: OMAP2+: Fix build error after merge ARM: S3C24XX: remove call to s3c24xx_setup_clocks ...
Diffstat (limited to 'arch/arm/mach-s3c24xx/irq-s3c2412.c')
-rw-r--r--arch/arm/mach-s3c24xx/irq-s3c2412.c214
1 files changed, 214 insertions, 0 deletions
diff --git a/arch/arm/mach-s3c24xx/irq-s3c2412.c b/arch/arm/mach-s3c24xx/irq-s3c2412.c
new file mode 100644
index 000000000000..e65619ddbccc
--- /dev/null
+++ b/arch/arm/mach-s3c24xx/irq-s3c2412.c
@@ -0,0 +1,214 @@
+/* linux/arch/arm/mach-s3c2412/irq.c
+ *
+ * Copyright (c) 2006 Simtec Electronics
+ * Ben Dooks <ben@simtec.co.uk>
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+*/
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/device.h>
+#include <linux/io.h>
+
+#include <mach/hardware.h>
+#include <asm/irq.h>
+
+#include <asm/mach/irq.h>
+
+#include <mach/regs-irq.h>
+#include <mach/regs-gpio.h>
+#include <mach/regs-power.h>
+
+#include <plat/cpu.h>
+#include <plat/irq.h>
+#include <plat/pm.h>
+
+#define INTMSK(start, end) ((1 << ((end) + 1 - (start))) - 1)
+#define INTMSK_SUB(start, end) (INTMSK(start, end) << ((start - S3C2410_IRQSUB(0))))
+
+/* the s3c2412 changes the behaviour of IRQ_EINT0 through IRQ_EINT3 by
+ * having them turn up in both the INT* and the EINT* registers. Whilst
+ * both show the status, they both now need to be acked when the IRQs
+ * go off.
+*/
+
+static void
+s3c2412_irq_mask(struct irq_data *data)
+{
+ unsigned long bitval = 1UL << (data->irq - IRQ_EINT0);
+ unsigned long mask;
+
+ mask = __raw_readl(S3C2410_INTMSK);
+ __raw_writel(mask | bitval, S3C2410_INTMSK);
+
+ mask = __raw_readl(S3C2412_EINTMASK);
+ __raw_writel(mask | bitval, S3C2412_EINTMASK);
+}
+
+static inline void
+s3c2412_irq_ack(struct irq_data *data)
+{
+ unsigned long bitval = 1UL << (data->irq - IRQ_EINT0);
+
+ __raw_writel(bitval, S3C2412_EINTPEND);
+ __raw_writel(bitval, S3C2410_SRCPND);
+ __raw_writel(bitval, S3C2410_INTPND);
+}
+
+static inline void
+s3c2412_irq_maskack(struct irq_data *data)
+{
+ unsigned long bitval = 1UL << (data->irq - IRQ_EINT0);
+ unsigned long mask;
+
+ mask = __raw_readl(S3C2410_INTMSK);
+ __raw_writel(mask|bitval, S3C2410_INTMSK);
+
+ mask = __raw_readl(S3C2412_EINTMASK);
+ __raw_writel(mask | bitval, S3C2412_EINTMASK);
+
+ __raw_writel(bitval, S3C2412_EINTPEND);
+ __raw_writel(bitval, S3C2410_SRCPND);
+ __raw_writel(bitval, S3C2410_INTPND);
+}
+
+static void
+s3c2412_irq_unmask(struct irq_data *data)
+{
+ unsigned long bitval = 1UL << (data->irq - IRQ_EINT0);
+ unsigned long mask;
+
+ mask = __raw_readl(S3C2412_EINTMASK);
+ __raw_writel(mask & ~bitval, S3C2412_EINTMASK);
+
+ mask = __raw_readl(S3C2410_INTMSK);
+ __raw_writel(mask & ~bitval, S3C2410_INTMSK);
+}
+
+static struct irq_chip s3c2412_irq_eint0t4 = {
+ .irq_ack = s3c2412_irq_ack,
+ .irq_mask = s3c2412_irq_mask,
+ .irq_unmask = s3c2412_irq_unmask,
+ .irq_set_wake = s3c_irq_wake,
+ .irq_set_type = s3c_irqext_type,
+};
+
+#define INTBIT(x) (1 << ((x) - S3C2410_IRQSUB(0)))
+
+/* CF and SDI sub interrupts */
+
+static void s3c2412_irq_demux_cfsdi(unsigned int irq, struct irq_desc *desc)
+{
+ unsigned int subsrc, submsk;
+
+ subsrc = __raw_readl(S3C2410_SUBSRCPND);
+ submsk = __raw_readl(S3C2410_INTSUBMSK);
+
+ subsrc &= ~submsk;
+
+ if (subsrc & INTBIT(IRQ_S3C2412_SDI))
+ generic_handle_irq(IRQ_S3C2412_SDI);
+
+ if (subsrc & INTBIT(IRQ_S3C2412_CF))
+ generic_handle_irq(IRQ_S3C2412_CF);
+}
+
+#define INTMSK_CFSDI (1UL << (IRQ_S3C2412_CFSDI - IRQ_EINT0))
+#define SUBMSK_CFSDI INTMSK_SUB(IRQ_S3C2412_SDI, IRQ_S3C2412_CF)
+
+static void s3c2412_irq_cfsdi_mask(struct irq_data *data)
+{
+ s3c_irqsub_mask(data->irq, INTMSK_CFSDI, SUBMSK_CFSDI);
+}
+
+static void s3c2412_irq_cfsdi_unmask(struct irq_data *data)
+{
+ s3c_irqsub_unmask(data->irq, INTMSK_CFSDI);
+}
+
+static void s3c2412_irq_cfsdi_ack(struct irq_data *data)
+{
+ s3c_irqsub_maskack(data->irq, INTMSK_CFSDI, SUBMSK_CFSDI);
+}
+
+static struct irq_chip s3c2412_irq_cfsdi = {
+ .name = "s3c2412-cfsdi",
+ .irq_ack = s3c2412_irq_cfsdi_ack,
+ .irq_mask = s3c2412_irq_cfsdi_mask,
+ .irq_unmask = s3c2412_irq_cfsdi_unmask,
+};
+
+static int s3c2412_irq_rtc_wake(struct irq_data *data, unsigned int state)
+{
+ unsigned long pwrcfg;
+
+ pwrcfg = __raw_readl(S3C2412_PWRCFG);
+ if (state)
+ pwrcfg &= ~S3C2412_PWRCFG_RTC_MASKIRQ;
+ else
+ pwrcfg |= S3C2412_PWRCFG_RTC_MASKIRQ;
+ __raw_writel(pwrcfg, S3C2412_PWRCFG);
+
+ return s3c_irq_chip.irq_set_wake(data, state);
+}
+
+static struct irq_chip s3c2412_irq_rtc_chip;
+
+static int s3c2412_irq_add(struct device *dev, struct subsys_interface *sif)
+{
+ unsigned int irqno;
+
+ for (irqno = IRQ_EINT0; irqno <= IRQ_EINT3; irqno++) {
+ irq_set_chip_and_handler(irqno, &s3c2412_irq_eint0t4,
+ handle_edge_irq);
+ set_irq_flags(irqno, IRQF_VALID);
+ }
+
+ /* add demux support for CF/SDI */
+
+ irq_set_chained_handler(IRQ_S3C2412_CFSDI, s3c2412_irq_demux_cfsdi);
+
+ for (irqno = IRQ_S3C2412_SDI; irqno <= IRQ_S3C2412_CF; irqno++) {
+ irq_set_chip_and_handler(irqno, &s3c2412_irq_cfsdi,
+ handle_level_irq);
+ set_irq_flags(irqno, IRQF_VALID);
+ }
+
+ /* change RTC IRQ's set wake method */
+
+ s3c2412_irq_rtc_chip = s3c_irq_chip;
+ s3c2412_irq_rtc_chip.irq_set_wake = s3c2412_irq_rtc_wake;
+
+ irq_set_chip(IRQ_RTC, &s3c2412_irq_rtc_chip);
+
+ return 0;
+}
+
+static struct subsys_interface s3c2412_irq_interface = {
+ .name = "s3c2412_irq",
+ .subsys = &s3c2412_subsys,
+ .add_dev = s3c2412_irq_add,
+};
+
+static int s3c2412_irq_init(void)
+{
+ return subsys_interface_register(&s3c2412_irq_interface);
+}
+
+arch_initcall(s3c2412_irq_init);