summaryrefslogtreecommitdiff
path: root/target/linux/s3c24xx/patches-2.6.26/0046-introduce-fiq-use-timer3-as-source.patch.patch
blob: ea8ae72fb0a6657c9cb6263fcd2ef1ed99b6a592 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
From 26fa0c816d5e1b593128477c7e200fafe3caae18 Mon Sep 17 00:00:00 2001
From: mokopatches <mokopatches@openmoko.org>
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 <andy@openmoko.com>
Signed-off-by: Andy Green <andy@openmoko.com>
---
 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 <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 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 <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 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