aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLars-Peter Clausen <lars@metafoo.de>2009-10-05 16:53:09 +0200
committerLars-Peter Clausen <lars@metafoo.de>2010-05-18 00:53:26 +0200
commit487349e69fa5737e9370c889acc350890a25c10b (patch)
tree794d58b5ed13874386373e7a824ee9877ec5984d
parent7cf0d44116947a1077d58bb837b29e510cc07121 (diff)
gta02: Add fiq handler
-rw-r--r--arch/arm/mach-s3c2440/Kconfig1
-rw-r--r--arch/arm/mach-s3c2440/Makefile1
-rw-r--r--arch/arm/mach-s3c2440/gta02-fiq.c126
-rw-r--r--arch/arm/mach-s3c2440/include/mach/gta02-fiq.h9
-rw-r--r--arch/arm/mach-s3c2440/mach-gta02.c3
5 files changed, 140 insertions, 0 deletions
diff --git a/arch/arm/mach-s3c2440/Kconfig b/arch/arm/mach-s3c2440/Kconfig
index ff06a7c5e46..15bede380cc 100644
--- a/arch/arm/mach-s3c2440/Kconfig
+++ b/arch/arm/mach-s3c2440/Kconfig
@@ -101,6 +101,7 @@ config MACH_NEO1973_GTA02
select S3C2410_PWM
select S3C_DEV_USB_HOST
select S3C_DEV_NAND
+ select FIQ
help
Say Y here if you are using the Openmoko GTA02 / Freerunner GSM Phone
diff --git a/arch/arm/mach-s3c2440/Makefile b/arch/arm/mach-s3c2440/Makefile
index dc29bee1039..6ce800d220f 100644
--- a/arch/arm/mach-s3c2440/Makefile
+++ b/arch/arm/mach-s3c2440/Makefile
@@ -38,6 +38,7 @@ obj-$(CONFIG_MACH_NEO1973_GTA02) += mach-gta02.o \
gta02-pm-gps.o \
gta02-pm-gsm.o \
gta02-pm-wlan.o \
+ gta02-fiq.o \
# extra machine support
diff --git a/arch/arm/mach-s3c2440/gta02-fiq.c b/arch/arm/mach-s3c2440/gta02-fiq.c
new file mode 100644
index 00000000000..78a6501d5be
--- /dev/null
+++ b/arch/arm/mach-s3c2440/gta02-fiq.c
@@ -0,0 +1,126 @@
+#include <linux/kernel.h>
+
+#include <asm/fiq.h>
+#include <mach/regs-irq.h>
+#include <plat/regs-timer.h>
+#include <mach/irqs.h>
+#include <linux/io.h>
+#include <linux/pwm.h>
+#include <linux/err.h>
+
+/* -------------------------------------------------------------------------------
+ * GTA02 FIQ related
+ *
+ * Calls into vibrator and hdq and based on the return values
+ * determines if we the FIQ source be kept alive
+ */
+
+#define DIVISOR_FROM_US(x) ((x) << 3)
+
+/* Global data related to our fiq source */
+static uint32_t gta02_fiq_ack_mask;
+static const int gta02_gta02_fiq_timer_id = 2;
+
+struct pwm_device* gta02_fiq_timer;
+
+void gta02_fiq_handler(void)
+{
+ unsigned long intmask;
+ int keep_running = 0;
+ /* disable further timer interrupts if nobody has any work
+ * or adjust rate according to who still has work
+ *
+ * CAUTION: it means forground code must disable FIQ around
+ * its own non-atomic S3C2410_INTMSK changes... not common
+ * thankfully and taken care of by the fiq-basis patch
+ */
+
+ if (!keep_running) {
+ /* Disable irq */
+ intmask = __raw_readl(S3C2410_INTMSK);
+ intmask |= (gta02_fiq_ack_mask);
+ __raw_writel(intmask, S3C2410_INTMSK);
+ }
+
+ __raw_writel(gta02_fiq_ack_mask, S3C2410_SRCPND);
+}
+
+void gta02_fiq_kick(void)
+{
+ unsigned long flags;
+ unsigned long intmask;
+ /* we have to take care about FIQ because this modification is
+ * non-atomic, FIQ could come in after the read and before the
+ * writeback and its changes to the register would be lost
+ * (platform INTMSK mod code is taken care of already)
+ */
+ local_save_flags(flags);
+ local_fiq_disable();
+
+ /* allow FIQs to resume */
+ intmask = __raw_readl(S3C2410_INTMSK);
+ intmask &= ~(gta02_fiq_ack_mask);
+ __raw_writel(intmask, S3C2410_INTMSK);
+
+ local_irq_restore(flags);
+
+}
+
+int gta02_fiq_enable(void)
+{
+ int ret = 0;
+
+ local_fiq_disable();
+
+ gta02_fiq_timer = pwm_request(gta02_gta02_fiq_timer_id, "fiq timer");
+
+ if (IS_ERR(gta02_fiq_timer)) {
+ ret = PTR_ERR(gta02_fiq_timer);
+ printk("GTA02 FIQ: Could not request fiq timer: %d\n", ret);
+ return ret;
+ }
+
+ gta02_fiq_ack_mask = 1 << (IRQ_TIMER0 + gta02_gta02_fiq_timer_id
+ - S3C2410_CPUIRQ_OFFSET);
+
+
+ ret = pwm_config(gta02_fiq_timer, HDQ_SAMPLE_PERIOD_US * 1000,
+ HDQ_SAMPLE_PERIOD_US * 1000);
+ if (ret) {
+ printk("GTA02 FIQ: Could not configure fiq timer: %d\n", ret);
+ goto err;
+ }
+
+ set_fiq_c_handler(gta02_fiq_handler);
+
+ __raw_writel(gta02_fiq_ack_mask, S3C2410_INTMOD);
+
+ pwm_enable(gta02_fiq_timer);
+
+ local_fiq_enable();
+
+ return 0;
+
+err:
+ pwm_free(gta02_fiq_timer);
+
+ return ret;
+}
+
+void gta02_fiq_disable(void)
+{
+ local_fiq_disable();
+
+ if (!gta02_fiq_timer)
+ return;
+
+ __raw_writel(0, S3C2410_INTMOD);
+ set_fiq_c_handler(NULL);
+
+ pwm_disable(gta02_fiq_timer);
+
+ pwm_free(gta02_fiq_timer);
+
+ gta02_fiq_timer = NULL;
+}
+/* -------------------- /GTA02 FIQ Handler ------------------------------------- */
diff --git a/arch/arm/mach-s3c2440/include/mach/gta02-fiq.h b/arch/arm/mach-s3c2440/include/mach/gta02-fiq.h
new file mode 100644
index 00000000000..90de3530595
--- /dev/null
+++ b/arch/arm/mach-s3c2440/include/mach/gta02-fiq.h
@@ -0,0 +1,9 @@
+#ifndef __GTA02_FIQ_H
+#define __GTA02_FIQ_H
+
+extern void gta02_fiq_handler(void);
+extern void gta02_fiq_kick(void);
+extern int gta02_fiq_enable(void);
+extern void gta02_fiq_disable(void);
+
+#endif
diff --git a/arch/arm/mach-s3c2440/mach-gta02.c b/arch/arm/mach-s3c2440/mach-gta02.c
index 3e9c7fb377d..be8782b80e5 100644
--- a/arch/arm/mach-s3c2440/mach-gta02.c
+++ b/arch/arm/mach-s3c2440/mach-gta02.c
@@ -101,6 +101,8 @@
#include <mach/gta02-pm-gps.h>
#include <mach/gta02-pm-wlan.h>
+#include <mach/gta02-fiq.h>
+
#include <linux/jbt6k74.h>
#include <linux/glamofb.h>
#include <linux/mfd/glamo.h>
@@ -886,6 +888,7 @@ static struct platform_device *gta02_devices[] __initdata = {
&gta02_nor_flash,
&s3c_device_timer[0],
&s3c_device_timer[1],
+ &s3c_device_timer[2],
&s3c_device_timer[3],
&s3c_device_iis,
&s3c_device_i2c0,