openwrt/target/linux/s3c24xx/patches-2.6.24/1055-introduce-fiq-migrate-vibrator-gta02-only.patch.patch

244 lines
8.1 KiB
Diff

From b1b2748dd58ae925df4b4e98921db373a7777e9b Mon Sep 17 00:00:00 2001
From: mokopatches <mokopatches@openmoko.org>
Date: Sun, 13 Apr 2008 07:23:52 +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 2f95707..77aa3bd 100644
--- a/drivers/leds/Kconfig
+++ b/drivers/leds/Kconfig
@@ -117,6 +117,7 @@ config LEDS_CM_X270
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.5