gta02: Add fiq handler
authorLars-Peter Clausen <lars@metafoo.de>
Mon, 5 Oct 2009 14:53:09 +0000 (16:53 +0200)
committerLars-Peter Clausen <lars@metafoo.de>
Mon, 17 May 2010 22:53:26 +0000 (00:53 +0200)
arch/arm/mach-s3c2440/Kconfig
arch/arm/mach-s3c2440/Makefile
arch/arm/mach-s3c2440/gta02-fiq.c [new file with mode: 0644]
arch/arm/mach-s3c2440/include/mach/gta02-fiq.h [new file with mode: 0644]
arch/arm/mach-s3c2440/mach-gta02.c

index ff06a7c..15bede3 100644 (file)
@@ -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
 
index dc29bee..6ce800d 100644 (file)
@@ -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 (file)
index 0000000..78a6501
--- /dev/null
@@ -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 (file)
index 0000000..90de353
--- /dev/null
@@ -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
index 3e9c7fb..be8782b 100644 (file)
 #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,