introduce-fiq-migrate-vibrator-gta02-only.patch From: warmcat 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 Signed-off-by: Andy Green 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 #include +#include + #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 +#include + + 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 */