summaryrefslogtreecommitdiff
path: root/target/linux/s3c24xx/patches-2.6.26/0047-introduce-fiq-migrate-vibrator-gta02-only.patch.patch
blob: f179555d1bd9add9116580354f0aba2cc00fcfbd (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
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
From b740b1200958baf4b5675017531c773bad5b64d0 Mon Sep 17 00:00:00 2001
From: mokopatches <mokopatches@openmoko.org>
Date: Fri, 25 Jul 2008 22:21:23 +0100
Subject: [PATCH] introduce-fiq-migrate-vibrator-gta02-only.patch

On GTA02 we use FIQ to manage the vibrator IO now.  That
is necessary because we stole timer3 from doing hw pwm
for vibrator.  This keeps the same UI in /sys but does
"bitbang pwm" on the same vibrator GPIO

From: Andy Green <andy@openmoko.com>
Signed-off-by: Andy Green <andy@openmoko.com>
---
 arch/arm/mach-s3c2440/fiq_c_isr.c            |   13 +++++---
 arch/arm/mach-s3c2440/mach-gta02.c           |   38 ++++++++++++++++++++++++++
 drivers/leds/Kconfig                         |    1 +
 drivers/leds/leds-neo1973-vibrator.c         |   24 +++++++++++++++-
 include/asm-arm/arch-s3c2410/fiq_ipc_gta02.h |    9 +++++-
 5 files changed, 77 insertions(+), 8 deletions(-)

diff --git a/arch/arm/mach-s3c2440/fiq_c_isr.c b/arch/arm/mach-s3c2440/fiq_c_isr.c
index a71a234..38692fc 100644
--- a/arch/arm/mach-s3c2440/fiq_c_isr.c
+++ b/arch/arm/mach-s3c2440/fiq_c_isr.c
@@ -79,6 +79,7 @@ u16 _fiq_timer_divisor;
  */
 extern void __attribute__ ((naked)) s3c2440_fiq_isr(void);
 
+
 /* this is copied into the hard FIQ vector during init */
 
 static void __attribute__ ((naked)) s3c2440_FIQ_Branch(void)
@@ -128,7 +129,7 @@ static int fiq_init_irq_source(int irq_index_fiq)
 
 	_fiq_irq = irq_index_fiq;
 	_fiq_ack_mask = 1 << (irq_index_fiq - S3C2410_CPUIRQ_OFFSET);
-	timer_index = (irq_index_fiq - IRQ_TIMER0);
+	_fiq_timer_index = (irq_index_fiq - IRQ_TIMER0);
 
 	/* set up the timer to operate as a pwm device */
 
@@ -136,12 +137,11 @@ static int fiq_init_irq_source(int irq_index_fiq)
 	if (rc)
 		goto bail;
 
-	pwm_timer_fiq.timerid = PWM0 + timer_index;
+	pwm_timer_fiq.timerid = PWM0 + _fiq_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;
+	pwm_timer_fiq.counter = pwm_timer_fiq.comparer = 3000;
 
 	rc = s3c2410_pwm_enable(&pwm_timer_fiq);
 	if (rc)
@@ -149,6 +149,8 @@ static int fiq_init_irq_source(int irq_index_fiq)
 
 	s3c2410_pwm_start(&pwm_timer_fiq);
 
+	_fiq_timer_divisor = 0xffff; /* so kick will work initially */
+
 	/* let our selected interrupt be a magic FIQ interrupt */
 	__raw_writel(_fiq_ack_mask, S3C2410_INTMOD);
 
@@ -189,7 +191,7 @@ void fiq_kick(void)
 		     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(1, S3C2410_TCNTB(_fiq_timer_index));
 	__raw_writel(tcon | S3C2410_TCON_T3MANUALUPD, S3C2410_TCON);
 	__raw_writel(tcon | S3C2410_TCON_T3MANUALUPD | S3C2410_TCON_T3START,
 		     S3C2410_TCON);
@@ -207,6 +209,7 @@ 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);
 
diff --git a/arch/arm/mach-s3c2440/mach-gta02.c b/arch/arm/mach-s3c2440/mach-gta02.c
index cb839b2..8c7bbe7 100644
--- a/arch/arm/mach-s3c2440/mach-gta02.c
+++ b/arch/arm/mach-s3c2440/mach-gta02.c
@@ -95,12 +95,50 @@ static spinlock_t motion_irq_lock;
 struct fiq_ipc fiq_ipc;
 EXPORT_SYMBOL(fiq_ipc);
 
+#define DIVISOR_FROM_US(x) ((x) << 1)
+
+#define FIQ_DIVISOR_VIBRATOR DIVISOR_FROM_US(100)
+
 /* define FIQ ISR */
 
 FIQ_HANDLER_START()
 /* define your locals here -- no initializers though */
+	u16 divisor;
 FIQ_HANDLER_ENTRY(256, 512)
 /* Your ISR here :-) */
+	divisor = 0xffff;
+
+	/* Vibrator servicing */
+
+	if (fiq_ipc.vib_pwm_latched || fiq_ipc.vib_pwm) { /* not idle */
+		if (((u8)_fiq_count_fiqs) == fiq_ipc.vib_pwm_latched)
+			s3c2410_gpio_setpin(fiq_ipc.vib_gpio_pin, 0);
+		if (((u8)_fiq_count_fiqs) == 0) {
+			fiq_ipc.vib_pwm_latched = fiq_ipc.vib_pwm;
+			if (fiq_ipc.vib_pwm_latched)
+				s3c2410_gpio_setpin(fiq_ipc.vib_gpio_pin, 1);
+		}
+		divisor = FIQ_DIVISOR_VIBRATOR;
+	}
+
+	/* TODO: HDQ servicing */
+
+
+
+	/* 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 (divisor == 0xffff) /* mask the fiq irq source */
+		__raw_writel(__raw_readl(S3C2410_INTMSK) | _fiq_ack_mask,
+			     S3C2410_INTMSK);
+	else /* still working, maybe at a different rate */
+		__raw_writel(divisor, S3C2410_TCNTB(_fiq_timer_index));
+	_fiq_timer_divisor = divisor;
+
 FIQ_HANDLER_END()
 
 
diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig
index b6b1211..5a0aa9c 100644
--- a/drivers/leds/Kconfig
+++ b/drivers/leds/Kconfig
@@ -150,6 +150,7 @@ config LEDS_CLEVO_MAIL
 config LEDS_NEO1973_VIBRATOR
 	tristate "Vibrator Support for the FIC Neo1973 GSM phone"
 	depends on LEDS_CLASS && MACH_NEO1973
+	select S3C2440_C_FIQ
 	help
 	  This option enables support for the vibrator on the FIC Neo1973.
 
diff --git a/drivers/leds/leds-neo1973-vibrator.c b/drivers/leds/leds-neo1973-vibrator.c
index c943a6a..36ed216 100644
--- a/drivers/leds/leds-neo1973-vibrator.c
+++ b/drivers/leds/leds-neo1973-vibrator.c
@@ -23,6 +23,8 @@
 #include <asm/arch/gta01.h>
 #include <asm/plat-s3c/regs-timer.h>
 
+#include <asm/arch-s3c2410/fiq_ipc_gta02.h>
+
 #define COUNTER 64
 
 struct neo1973_vib_priv {
@@ -39,6 +41,11 @@ static void neo1973_vib_vib_set(struct led_classdev *led_cdev,
 	struct neo1973_vib_priv *vp =
 		container_of(led_cdev, struct neo1973_vib_priv, cdev);
 
+	if (machine_is_neo1973_gta02()) { /* use FIQ to control GPIO */
+		fiq_ipc.vib_pwm = value; /* set it for FIQ */
+		fiq_kick(); /* start up FIQs if not already going */
+		return;
+	}
 	/*
 	 * value == 255 -> 99% duty cycle (full power)
 	 * value == 128 -> 50% duty cycle (medium power)
@@ -46,7 +53,7 @@ static void neo1973_vib_vib_set(struct led_classdev *led_cdev,
 	 */
 	mutex_lock(&vp->mutex);
 	if (vp->has_pwm)
-		s3c2410_pwm_duty_cycle(value/4, &vp->pwm);
+		s3c2410_pwm_duty_cycle(value / 4, &vp->pwm);
 	else {
 		if (value)
 			s3c2410_gpio_setpin(vp->gpio, 1);
@@ -123,6 +130,15 @@ static int __init neo1973_vib_probe(struct platform_device *pdev)
 	neo1973_vib_led.gpio = r->start;
 	platform_set_drvdata(pdev, &neo1973_vib_led);
 
+	if (machine_is_neo1973_gta02()) { /* use FIQ to control GPIO */
+		s3c2410_gpio_setpin(neo1973_vib_led.gpio, 0); /* off */
+		s3c2410_gpio_cfgpin(neo1973_vib_led.gpio, S3C2410_GPIO_OUTPUT);
+		/* safe, kmalloc'd copy needed for FIQ ISR */
+		fiq_ipc.vib_gpio_pin = neo1973_vib_led.gpio;
+		fiq_ipc.vib_pwm = 0; /* off */
+		goto configured;
+	}
+
 	/* TOUT3 */
 	if (neo1973_vib_led.gpio == S3C2410_GPB3) {
 		rc = neo1973_vib_init_hw(&neo1973_vib_led);
@@ -133,7 +149,7 @@ static int __init neo1973_vib_probe(struct platform_device *pdev)
 		s3c2410_gpio_cfgpin(neo1973_vib_led.gpio, S3C2410_GPB3_TOUT3);
 		neo1973_vib_led.has_pwm = 1;
 	}
-
+configured:
 	mutex_init(&neo1973_vib_led.mutex);
 
 	return led_classdev_register(&pdev->dev, &neo1973_vib_led.cdev);
@@ -141,6 +157,10 @@ static int __init neo1973_vib_probe(struct platform_device *pdev)
 
 static int neo1973_vib_remove(struct platform_device *pdev)
 {
+	if (machine_is_neo1973_gta02()) /* use FIQ to control GPIO */
+		fiq_ipc.vib_pwm = 0; /* off */
+	/* would only need kick if already off so no kick needed */
+
 	if (neo1973_vib_led.has_pwm)
 		s3c2410_pwm_disable(&neo1973_vib_led.pwm);
 
diff --git a/include/asm-arm/arch-s3c2410/fiq_ipc_gta02.h b/include/asm-arm/arch-s3c2410/fiq_ipc_gta02.h
index 6cbd8e4..507d235 100644
--- a/include/asm-arm/arch-s3c2410/fiq_ipc_gta02.h
+++ b/include/asm-arm/arch-s3c2410/fiq_ipc_gta02.h
@@ -16,8 +16,15 @@
  * for testing
  */
 
+#include <asm/arch/pwm.h>
+#include <asm/plat-s3c/regs-timer.h>
+
+
 struct fiq_ipc {
-	u8 u8a[0]; /* placeholder */
+	/* vibrator */
+	unsigned long vib_gpio_pin; /* which pin to meddle with */
+	u8 vib_pwm; /* 0 = OFF -- will ensure GPIO deasserted and stop FIQ */
+	u8 vib_pwm_latched;
 };
 
 /* actual definition lives in arch/arm/mach-s3c2440/fiq_c_isr.c */
-- 
1.5.6.3