From 26fa0c816d5e1b593128477c7e200fafe3caae18 Mon Sep 17 00:00:00 2001 From: mokopatches Date: Fri, 25 Jul 2008 22:21:22 +0100 Subject: [PATCH] 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 Signed-off-by: Andy Green --- arch/arm/mach-s3c2440/fiq_c_isr.c | 56 +++++++++++++++++++++---- arch/arm/mach-s3c2440/fiq_c_isr.h | 2 + arch/arm/mach-s3c2440/mach-gta02.c | 17 ++++++++ include/asm-arm/arch-s3c2410/fiq_ipc_gta02.h | 2 +- 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 12f4527..a71a234 100644 --- a/arch/arm/mach-s3c2440/fiq_c_isr.c +++ b/arch/arm/mach-s3c2440/fiq_c_isr.c @@ -18,6 +18,9 @@ #include #include +#include +#include + /* * 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 f08740e..0c45eb7 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 0bdd0e0..cb839b2 100644 --- a/arch/arm/mach-s3c2440/mach-gta02.c +++ b/arch/arm/mach-s3c2440/mach-gta02.c @@ -57,6 +57,7 @@ #include #include +#include #include #include #include @@ -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, >a02_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 341f2bb..6cbd8e4 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 */ -- 1.5.6.3