introduce-fiq-migrate-vibrator-gta02-only.patch

From: warmcat <andy@openmoko.com>

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>

Index: linux-2.6.24/arch/arm/mach-s3c2440/fiq_c_isr.c
===================================================================
--- linux-2.6.24.orig/arch/arm/mach-s3c2440/fiq_c_isr.c
+++ linux-2.6.24/arch/arm/mach-s3c2440/fiq_c_isr.c
@@ -79,6 +79,7 @@
  */
 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 @@
 
 	_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 @@
 	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 @@
 
 	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 @@
 		     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 @@
 
 	if (!r)
 		return -EIO;
+
 	/* configure for the interrupt we are meant to use */
 	printk(KERN_INFO"Enabling FIQ using irq %d\n", r->start);
 
Index: linux-2.6.24/arch/arm/mach-s3c2440/mach-gta02.c
===================================================================
--- linux-2.6.24.orig/arch/arm/mach-s3c2440/mach-gta02.c
+++ linux-2.6.24/arch/arm/mach-s3c2440/mach-gta02.c
@@ -92,12 +92,50 @@
 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()
 
 
Index: linux-2.6.24/drivers/leds/Kconfig
===================================================================
--- linux-2.6.24.orig/drivers/leds/Kconfig
+++ linux-2.6.24/drivers/leds/Kconfig
@@ -117,6 +117,7 @@
 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.
 
Index: linux-2.6.24/drivers/leds/leds-neo1973-vibrator.c
===================================================================
--- linux-2.6.24.orig/drivers/leds/leds-neo1973-vibrator.c
+++ linux-2.6.24/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 @@
 	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 @@
 	 */
 	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 @@
 	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 @@
 		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 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);
 
Index: linux-2.6.24/include/asm-arm/arch-s3c2410/fiq_ipc_gta02.h
===================================================================
--- linux-2.6.24.orig/include/asm-arm/arch-s3c2410/fiq_ipc_gta02.h
+++ linux-2.6.24/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 */
