1 From b740b1200958baf4b5675017531c773bad5b64d0 Mon Sep 17 00:00:00 2001
2 From: mokopatches <mokopatches@openmoko.org>
3 Date: Fri, 25 Jul 2008 22:21:23 +0100
4 Subject: [PATCH] introduce-fiq-migrate-vibrator-gta02-only.patch
6 On GTA02 we use FIQ to manage the vibrator IO now. That
7 is necessary because we stole timer3 from doing hw pwm
8 for vibrator. This keeps the same UI in /sys but does
9 "bitbang pwm" on the same vibrator GPIO
11 From: Andy Green <andy@openmoko.com>
12 Signed-off-by: Andy Green <andy@openmoko.com>
14 arch/arm/mach-s3c2440/fiq_c_isr.c | 13 +++++---
15 arch/arm/mach-s3c2440/mach-gta02.c | 38 ++++++++++++++++++++++++++
16 drivers/leds/Kconfig | 1 +
17 drivers/leds/leds-neo1973-vibrator.c | 24 +++++++++++++++-
18 include/asm-arm/arch-s3c2410/fiq_ipc_gta02.h | 9 +++++-
19 5 files changed, 77 insertions(+), 8 deletions(-)
21 diff --git a/arch/arm/mach-s3c2440/fiq_c_isr.c b/arch/arm/mach-s3c2440/fiq_c_isr.c
22 index a71a234..38692fc 100644
23 --- a/arch/arm/mach-s3c2440/fiq_c_isr.c
24 +++ b/arch/arm/mach-s3c2440/fiq_c_isr.c
25 @@ -79,6 +79,7 @@ u16 _fiq_timer_divisor;
27 extern void __attribute__ ((naked)) s3c2440_fiq_isr(void);
30 /* this is copied into the hard FIQ vector during init */
32 static void __attribute__ ((naked)) s3c2440_FIQ_Branch(void)
33 @@ -128,7 +129,7 @@ static int fiq_init_irq_source(int irq_index_fiq)
35 _fiq_irq = irq_index_fiq;
36 _fiq_ack_mask = 1 << (irq_index_fiq - S3C2410_CPUIRQ_OFFSET);
37 - timer_index = (irq_index_fiq - IRQ_TIMER0);
38 + _fiq_timer_index = (irq_index_fiq - IRQ_TIMER0);
40 /* set up the timer to operate as a pwm device */
42 @@ -136,12 +137,11 @@ static int fiq_init_irq_source(int irq_index_fiq)
46 - pwm_timer_fiq.timerid = PWM0 + timer_index;
47 + pwm_timer_fiq.timerid = PWM0 + _fiq_timer_index;
48 pwm_timer_fiq.prescaler = (6 - 1) / 2;
49 pwm_timer_fiq.divider = S3C2410_TCFG1_MUX3_DIV2;
50 /* default rate == ~32us */
51 - pwm_timer_fiq.counter = pwm_timer_fiq.comparer =
53 + pwm_timer_fiq.counter = pwm_timer_fiq.comparer = 3000;
55 rc = s3c2410_pwm_enable(&pwm_timer_fiq);
57 @@ -149,6 +149,8 @@ static int fiq_init_irq_source(int irq_index_fiq)
59 s3c2410_pwm_start(&pwm_timer_fiq);
61 + _fiq_timer_divisor = 0xffff; /* so kick will work initially */
63 /* let our selected interrupt be a magic FIQ interrupt */
64 __raw_writel(_fiq_ack_mask, S3C2410_INTMOD);
66 @@ -189,7 +191,7 @@ void fiq_kick(void)
68 tcon = __raw_readl(S3C2410_TCON) & ~S3C2410_TCON_T3START;
69 /* fake the timer to a count of 1 */
70 - __raw_writel(1, S3C2410_TCNTB(timer_index));
71 + __raw_writel(1, S3C2410_TCNTB(_fiq_timer_index));
72 __raw_writel(tcon | S3C2410_TCON_T3MANUALUPD, S3C2410_TCON);
73 __raw_writel(tcon | S3C2410_TCON_T3MANUALUPD | S3C2410_TCON_T3START,
75 @@ -207,6 +209,7 @@ static int __init sc32440_fiq_probe(struct platform_device *pdev)
80 /* configure for the interrupt we are meant to use */
81 printk(KERN_INFO"Enabling FIQ using irq %d\n", r->start);
83 diff --git a/arch/arm/mach-s3c2440/mach-gta02.c b/arch/arm/mach-s3c2440/mach-gta02.c
84 index cb839b2..8c7bbe7 100644
85 --- a/arch/arm/mach-s3c2440/mach-gta02.c
86 +++ b/arch/arm/mach-s3c2440/mach-gta02.c
87 @@ -95,12 +95,50 @@ static spinlock_t motion_irq_lock;
88 struct fiq_ipc fiq_ipc;
89 EXPORT_SYMBOL(fiq_ipc);
91 +#define DIVISOR_FROM_US(x) ((x) << 1)
93 +#define FIQ_DIVISOR_VIBRATOR DIVISOR_FROM_US(100)
98 /* define your locals here -- no initializers though */
100 FIQ_HANDLER_ENTRY(256, 512)
101 /* Your ISR here :-) */
104 + /* Vibrator servicing */
106 + if (fiq_ipc.vib_pwm_latched || fiq_ipc.vib_pwm) { /* not idle */
107 + if (((u8)_fiq_count_fiqs) == fiq_ipc.vib_pwm_latched)
108 + s3c2410_gpio_setpin(fiq_ipc.vib_gpio_pin, 0);
109 + if (((u8)_fiq_count_fiqs) == 0) {
110 + fiq_ipc.vib_pwm_latched = fiq_ipc.vib_pwm;
111 + if (fiq_ipc.vib_pwm_latched)
112 + s3c2410_gpio_setpin(fiq_ipc.vib_gpio_pin, 1);
114 + divisor = FIQ_DIVISOR_VIBRATOR;
117 + /* TODO: HDQ servicing */
121 + /* disable further timer interrupts if nobody has any work
122 + * or adjust rate according to who still has work
124 + * CAUTION: it means forground code must disable FIQ around
125 + * its own non-atomic S3C2410_INTMSK changes... not common
126 + * thankfully and taken care of by the fiq-basis patch
128 + if (divisor == 0xffff) /* mask the fiq irq source */
129 + __raw_writel(__raw_readl(S3C2410_INTMSK) | _fiq_ack_mask,
131 + else /* still working, maybe at a different rate */
132 + __raw_writel(divisor, S3C2410_TCNTB(_fiq_timer_index));
133 + _fiq_timer_divisor = divisor;
138 diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig
139 index b6b1211..5a0aa9c 100644
140 --- a/drivers/leds/Kconfig
141 +++ b/drivers/leds/Kconfig
142 @@ -150,6 +150,7 @@ config LEDS_CLEVO_MAIL
143 config LEDS_NEO1973_VIBRATOR
144 tristate "Vibrator Support for the FIC Neo1973 GSM phone"
145 depends on LEDS_CLASS && MACH_NEO1973
146 + select S3C2440_C_FIQ
148 This option enables support for the vibrator on the FIC Neo1973.
150 diff --git a/drivers/leds/leds-neo1973-vibrator.c b/drivers/leds/leds-neo1973-vibrator.c
151 index c943a6a..36ed216 100644
152 --- a/drivers/leds/leds-neo1973-vibrator.c
153 +++ b/drivers/leds/leds-neo1973-vibrator.c
155 #include <asm/arch/gta01.h>
156 #include <asm/plat-s3c/regs-timer.h>
158 +#include <asm/arch-s3c2410/fiq_ipc_gta02.h>
162 struct neo1973_vib_priv {
163 @@ -39,6 +41,11 @@ static void neo1973_vib_vib_set(struct led_classdev *led_cdev,
164 struct neo1973_vib_priv *vp =
165 container_of(led_cdev, struct neo1973_vib_priv, cdev);
167 + if (machine_is_neo1973_gta02()) { /* use FIQ to control GPIO */
168 + fiq_ipc.vib_pwm = value; /* set it for FIQ */
169 + fiq_kick(); /* start up FIQs if not already going */
173 * value == 255 -> 99% duty cycle (full power)
174 * value == 128 -> 50% duty cycle (medium power)
175 @@ -46,7 +53,7 @@ static void neo1973_vib_vib_set(struct led_classdev *led_cdev,
177 mutex_lock(&vp->mutex);
179 - s3c2410_pwm_duty_cycle(value/4, &vp->pwm);
180 + s3c2410_pwm_duty_cycle(value / 4, &vp->pwm);
183 s3c2410_gpio_setpin(vp->gpio, 1);
184 @@ -123,6 +130,15 @@ static int __init neo1973_vib_probe(struct platform_device *pdev)
185 neo1973_vib_led.gpio = r->start;
186 platform_set_drvdata(pdev, &neo1973_vib_led);
188 + if (machine_is_neo1973_gta02()) { /* use FIQ to control GPIO */
189 + s3c2410_gpio_setpin(neo1973_vib_led.gpio, 0); /* off */
190 + s3c2410_gpio_cfgpin(neo1973_vib_led.gpio, S3C2410_GPIO_OUTPUT);
191 + /* safe, kmalloc'd copy needed for FIQ ISR */
192 + fiq_ipc.vib_gpio_pin = neo1973_vib_led.gpio;
193 + fiq_ipc.vib_pwm = 0; /* off */
198 if (neo1973_vib_led.gpio == S3C2410_GPB3) {
199 rc = neo1973_vib_init_hw(&neo1973_vib_led);
200 @@ -133,7 +149,7 @@ static int __init neo1973_vib_probe(struct platform_device *pdev)
201 s3c2410_gpio_cfgpin(neo1973_vib_led.gpio, S3C2410_GPB3_TOUT3);
202 neo1973_vib_led.has_pwm = 1;
206 mutex_init(&neo1973_vib_led.mutex);
208 return led_classdev_register(&pdev->dev, &neo1973_vib_led.cdev);
209 @@ -141,6 +157,10 @@ static int __init neo1973_vib_probe(struct platform_device *pdev)
211 static int neo1973_vib_remove(struct platform_device *pdev)
213 + if (machine_is_neo1973_gta02()) /* use FIQ to control GPIO */
214 + fiq_ipc.vib_pwm = 0; /* off */
215 + /* would only need kick if already off so no kick needed */
217 if (neo1973_vib_led.has_pwm)
218 s3c2410_pwm_disable(&neo1973_vib_led.pwm);
220 diff --git a/include/asm-arm/arch-s3c2410/fiq_ipc_gta02.h b/include/asm-arm/arch-s3c2410/fiq_ipc_gta02.h
221 index 6cbd8e4..507d235 100644
222 --- a/include/asm-arm/arch-s3c2410/fiq_ipc_gta02.h
223 +++ b/include/asm-arm/arch-s3c2410/fiq_ipc_gta02.h
228 +#include <asm/arch/pwm.h>
229 +#include <asm/plat-s3c/regs-timer.h>
233 - u8 u8a[0]; /* placeholder */
235 + unsigned long vib_gpio_pin; /* which pin to meddle with */
236 + u8 vib_pwm; /* 0 = OFF -- will ensure GPIO deasserted and stop FIQ */
237 + u8 vib_pwm_latched;
240 /* actual definition lives in arch/arm/mach-s3c2440/fiq_c_isr.c */