diff options
-rw-r--r-- | arch/arm/mach-s3c2440/fiq_c_isr.c | 13 | ||||
-rw-r--r-- | arch/arm/mach-s3c2440/mach-gta02.c | 38 | ||||
-rw-r--r-- | drivers/leds/Kconfig | 1 | ||||
-rw-r--r-- | drivers/leds/leds-neo1973-vibrator.c | 24 | ||||
-rw-r--r-- | 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 a71a234d86c..38692fcebf2 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 cb839b24b6d..8c7bbe733d9 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 4435859beca..6dad9d030e1 100644 --- a/drivers/leds/Kconfig +++ b/drivers/leds/Kconfig @@ -168,6 +168,7 @@ config LEDS_DA903X 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 c943a6a6988..36ed216a504 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 6cbd8e44710..507d23556b2 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 */ |