aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormokopatches <mokopatches@openmoko.org>2008-11-19 17:03:18 +0000
committerwarmcat <andy@warmcat.com>2008-11-19 17:03:18 +0000
commit81487a2b118cee39ed13586b17c394935d799216 (patch)
tree646638c5c2f25c9180af1239f20ae1b8a45af76a
parent8fd8547b742a608695823e38ca7cfc531d50f341 (diff)
introduce-fiq-use-timer3-as-source.patch
This makes the FIQ stuff specific to one of the timers on the s3c244x and adds the platform stuff for fiq in the gta02 init Currently one sysfs node is exposed, a count of FIQ events cat /sys/devices/platform/sc32440_fiq.0/fiq/count From: Andy Green <andy@openmoko.com> Signed-off-by: Andy Green <andy@openmoko.com>
-rw-r--r--arch/arm/mach-s3c2440/fiq_c_isr.c56
-rw-r--r--arch/arm/mach-s3c2440/fiq_c_isr.h2
-rw-r--r--arch/arm/mach-s3c2440/mach-gta02.c17
-rw-r--r--include/asm-arm/arch-s3c2410/fiq_ipc_gta02.h2
4 files changed, 67 insertions, 10 deletions
diff --git a/arch/arm/mach-s3c2440/fiq_c_isr.c b/arch/arm/mach-s3c2440/fiq_c_isr.c
index 12f45276b03..a71a234d86c 100644
--- a/arch/arm/mach-s3c2440/fiq_c_isr.c
+++ b/arch/arm/mach-s3c2440/fiq_c_isr.c
@@ -18,6 +18,9 @@
#include <asm/plat-s3c24xx/cpu.h>
#include <asm/plat-s3c24xx/irq.h>
+#include <asm/arch/pwm.h>
+#include <asm/plat-s3c/regs-timer.h>
+
/*
* Major Caveats for using FIQ
* ---------------------------
@@ -66,6 +69,10 @@ static u8 u8aFiqStack[4096];
u32 _fiq_ack_mask; /* used by isr exit define */
unsigned long _fiq_count_fiqs; /* used by isr exit define */
static int _fiq_irq; /* private ; irq index we were started with, or 0 */
+struct s3c2410_pwm pwm_timer_fiq;
+int _fiq_timer_index;
+u16 _fiq_timer_divisor;
+
/* this function must live in the monolithic kernel somewhere! A module is
* NOT good enough!
@@ -110,23 +117,45 @@ static struct attribute_group s3c2440_fiq_attr_group = {
* you still need to clear the source interrupt in S3C2410_INTMSK to get
* anything good happening
*/
-static void fiq_init_irq_source(int irq_index_fiq)
+static int fiq_init_irq_source(int irq_index_fiq)
{
+ int rc = 0;
+
if (!irq_index_fiq) /* no interrupt */
- return;
+ goto bail;
- printk(KERN_INFO"Enabling FIQ using int idx %d\n",
- irq_index_fiq - S3C2410_CPUIRQ_OFFSET);
local_fiq_disable();
_fiq_irq = irq_index_fiq;
_fiq_ack_mask = 1 << (irq_index_fiq - S3C2410_CPUIRQ_OFFSET);
+ timer_index = (irq_index_fiq - IRQ_TIMER0);
+
+ /* set up the timer to operate as a pwm device */
+
+ rc = s3c2410_pwm_init(&pwm_timer_fiq);
+ if (rc)
+ goto bail;
+
+ pwm_timer_fiq.timerid = PWM0 + timer_index;
+ pwm_timer_fiq.prescaler = (6 - 1) / 2;
+ pwm_timer_fiq.divider = S3C2410_TCFG1_MUX3_DIV2;
+ /* default rate == ~32us */
+ pwm_timer_fiq.counter = pwm_timer_fiq.comparer =
+ timer_divisor = 64;
+
+ rc = s3c2410_pwm_enable(&pwm_timer_fiq);
+ if (rc)
+ goto bail;
+
+ s3c2410_pwm_start(&pwm_timer_fiq);
/* let our selected interrupt be a magic FIQ interrupt */
__raw_writel(_fiq_ack_mask, S3C2410_INTMOD);
/* it's ready to go as soon as we unmask the source in S3C2410_INTMSK */
local_fiq_enable();
+bail:
+ return rc;
}
@@ -139,15 +168,13 @@ static void fiq_disable_irq_source(void)
_fiq_irq = 0; /* no active source interrupt now either */
}
-/* this starts FIQ timer events... they continue until the FIQ ISR sees that
- * its work is done and it turns off the timer. After setting up the fiq_ipc
- * struct with new work, you call this to start FIQ timer actions up again.
- * Only the FIQ ISR decides when it is done and controls turning off the
- * timer events.
+/*
+ * fiq_kick() forces a FIQ event to happen shortly after leaving the routine
*/
void fiq_kick(void)
{
unsigned long flags;
+ u32 tcon;
/* we have to take care about FIQ because this modification is
* non-atomic, FIQ could come in after the read and before the
@@ -156,15 +183,24 @@ void fiq_kick(void)
*/
local_save_flags(flags);
local_fiq_disable();
+ /* allow FIQs to resume */
__raw_writel(__raw_readl(S3C2410_INTMSK) &
~(1 << (_fiq_irq - S3C2410_CPUIRQ_OFFSET)),
S3C2410_INTMSK);
+ tcon = __raw_readl(S3C2410_TCON) & ~S3C2410_TCON_T3START;
+ /* fake the timer to a count of 1 */
+ __raw_writel(1, S3C2410_TCNTB(timer_index));
+ __raw_writel(tcon | S3C2410_TCON_T3MANUALUPD, S3C2410_TCON);
+ __raw_writel(tcon | S3C2410_TCON_T3MANUALUPD | S3C2410_TCON_T3START,
+ S3C2410_TCON);
+ __raw_writel(tcon | S3C2410_TCON_T3START, S3C2410_TCON);
local_irq_restore(flags);
}
EXPORT_SYMBOL_GPL(fiq_kick);
+
static int __init sc32440_fiq_probe(struct platform_device *pdev)
{
struct resource *r = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
@@ -172,6 +208,8 @@ static int __init sc32440_fiq_probe(struct platform_device *pdev)
if (!r)
return -EIO;
/* configure for the interrupt we are meant to use */
+ printk(KERN_INFO"Enabling FIQ using irq %d\n", r->start);
+
fiq_init_irq_source(r->start);
return sysfs_create_group(&pdev->dev.kobj, &s3c2440_fiq_attr_group);
diff --git a/arch/arm/mach-s3c2440/fiq_c_isr.h b/arch/arm/mach-s3c2440/fiq_c_isr.h
index f08740ee8d3..0c45eb780ed 100644
--- a/arch/arm/mach-s3c2440/fiq_c_isr.h
+++ b/arch/arm/mach-s3c2440/fiq_c_isr.h
@@ -5,6 +5,8 @@
extern unsigned long _fiq_count_fiqs;
extern u32 _fiq_ack_mask;
+extern int _fiq_timer_index;
+extern u16 _fiq_timer_divisor;
/* This CANNOT be implemented in a module -- it has to be used in code
* included in the monolithic kernel
diff --git a/arch/arm/mach-s3c2440/mach-gta02.c b/arch/arm/mach-s3c2440/mach-gta02.c
index 0bdd0e02010..cb839b24b6d 100644
--- a/arch/arm/mach-s3c2440/mach-gta02.c
+++ b/arch/arm/mach-s3c2440/mach-gta02.c
@@ -57,6 +57,7 @@
#include <asm/irq.h>
#include <asm/mach-types.h>
+#include <asm/arch-s3c2410/regs-irq.h>
#include <asm/arch/regs-gpio.h>
#include <asm/arch/regs-gpioj.h>
#include <asm/arch/fb.h>
@@ -336,6 +337,21 @@ struct platform_device gta02_pmu_dev = {
},
};
+/* FIQ */
+
+static struct resource sc32440_fiq_resources[] = {
+ [0] = {
+ .flags = IORESOURCE_IRQ,
+ .start = IRQ_TIMER3,
+ .end = IRQ_TIMER3,
+ },
+};
+
+struct platform_device sc32440_fiq_device = {
+ .name = "sc32440_fiq",
+ .num_resources = 1,
+ .resource = sc32440_fiq_resources,
+};
/* NOR Flash */
@@ -403,6 +419,7 @@ static struct platform_device *gta02_devices[] __initdata = {
&s3c_device_nand,
&s3c_device_ts,
&gta02_nor_flash,
+ &sc32440_fiq_device,
};
static struct s3c2410_nand_set gta02_nand_sets[] = {
diff --git a/include/asm-arm/arch-s3c2410/fiq_ipc_gta02.h b/include/asm-arm/arch-s3c2410/fiq_ipc_gta02.h
index 341f2bbd22b..6cbd8e44710 100644
--- a/include/asm-arm/arch-s3c2410/fiq_ipc_gta02.h
+++ b/include/asm-arm/arch-s3c2410/fiq_ipc_gta02.h
@@ -22,7 +22,7 @@ struct fiq_ipc {
/* actual definition lives in arch/arm/mach-s3c2440/fiq_c_isr.c */
extern struct fiq_ipc fiq_ipc;
-
+extern unsigned long _fiq_count_fiqs;
extern void fiq_kick(void); /* provoke a FIQ "immediately" */
#endif /* _LINUX_FIQ_IPC_H */