FS#11172 - Fuzev2: Read the scrollwheel scrollwheel via IRQ

git-svn-id: svn://svn.rockbox.org/rockbox/trunk@25736 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
Thomas Martitz 2010-04-27 10:11:52 +00:00
parent ee291a5e9b
commit 249aae587a
9 changed files with 242 additions and 58 deletions

View file

@ -407,11 +407,11 @@ target/arm/pnx0101/timer-pnx0101.c
target/arm/as3525/system-as3525.c
target/arm/as3525/kernel-as3525.c
target/arm/as3525/timer-as3525.c
#ifdef HAVE_SCROLLWHEEL
target/arm/as3525/scrollwheel-as3525.c
#endif
#if CONFIG_CPU == AS3525
target/arm/as3525/sd-as3525.c
#ifdef HAVE_SCROLLWHEEL
target/arm/as3525/scrollwheel-as3525.c
#endif /* HAVE_SCROLLWHEEL */
#else /* AS3535v2 */
target/arm/as3525/sd-as3525v2.c
#endif

View file

@ -68,6 +68,15 @@
/* There is no hardware tone control */
#define HAVE_SW_TONE_CONTROLS
/* define this if the unit uses a scrollwheel for navigation */
#define HAVE_SCROLLWHEEL
/* define to activate advanced wheel acceleration code */
#define HAVE_WHEEL_ACCELERATION
/* define from which rotation speed [degree/sec] on the acceleration starts */
#define WHEEL_ACCEL_START 540
/* define type of acceleration (1 = ^2, 2 = ^3, 3 = ^4) */
#define WHEEL_ACCELERATION 1
#endif /* !BOOTLOADER */
/* put the lcd frame buffer in IRAM */
@ -126,15 +135,6 @@
/* Which backlight fading type? */
#define CONFIG_BACKLIGHT_FADING BACKLIGHT_FADING_SW_SETTING
/* define this if the unit uses a scrollwheel for navigation */
#define HAVE_SCROLLWHEEL
/* define to activate advanced wheel acceleration code */
#define HAVE_WHEEL_ACCELERATION
/* define from which rotation speed [degree/sec] on the acceleration starts */
#define WHEEL_ACCEL_START 540
/* define type of acceleration (1 = ^2, 2 = ^3, 3 = ^4) */
#define WHEEL_ACCELERATION 1
/* define this if you have a flash memory storage */
#define HAVE_FLASH_STORAGE

View file

@ -24,7 +24,7 @@
#include "panic.h"
#include "timer.h"
#ifdef HAVE_SCROLLWHEEL
#if INCREASED_SCROLLWHEEL_POLLING
#include "button-target.h"
/* The scrollwheel is polled every 5 ms (the tick tasks only every 10) */
static int poll_scrollwheel = 0;

View file

@ -24,37 +24,198 @@
#include "button.h"
#include "backlight.h"
extern void scrollwheel(unsigned wheel_value);
#ifdef HAS_BUTTON_HOLD
static bool hold_button = false;
#endif
#ifdef HAVE_SCROLLWHEEL
#define SCROLLWHEEL_BITS (1<<7|1<<6)
/* TIMER units */
#define TIMER_TICK (TIMER_FREQ/HZ) /* how long a tick lasts */
#define TIMER_MS (TIMER_TICK/(1000/HZ))/* how long a ms lasts */
#define WHEEL_REPEAT_INTERVAL (300*TIMER_MS) /* 300ms */
#define WHEEL_FAST_ON_INTERVAL ( 20*TIMER_MS) /* 20ms */
#define WHEEL_FAST_OFF_INTERVAL ( 60*TIMER_MS) /* 60ms */
/* phsyical clicks per rotation * wheel value changes per phys click */
#define WHEEL_CHANGES_PER_CLICK 4
#define WHEELCLICKS_PER_ROTATION (12*WHEEL_CHANGES_PER_CLICK)
/*
* based on button-e200.c, adjusted to the AMS timers and fuzev2's
* scrollwheel and cleaned up a little
*/
static void scrollwheel(unsigned int wheel_value)
{
/* wheel values and times from the previous irq */
static unsigned int old_wheel_value = 0;
static unsigned int wheel_repeat = BUTTON_NONE;
static long last_wheel_post = 0;
/* We only post every 4th action, as this matches better with the physical
* clicks of the wheel */
static unsigned int wheel_click_count = 0;
/* number of items to skip in lists, 1 in slow mode */
static unsigned int wheel_delta = 0;
/* accumulated wheel rotations per second */
static unsigned long wheel_velocity = 0;
/* fast or slow mode? */
static int wheel_fast_mode = 0;
/* Read wheel
* Bits 6 and 7 of GPIOA change as follows (Gray Code):
* Clockwise rotation 00 -> 01 -> 11 -> 10 -> 00
* Counter-clockwise 00 -> 10 -> 11 -> 01 -> 00
*
* For easy look-up, actual wheel values act as indicies also,
* which is why the table seems to be not ordered correctly
*/
static const unsigned char wheel_tbl[2][4] =
{
{ 2, 0, 3, 1 }, /* Clockwise rotation */
{ 1, 3, 0, 2 }, /* Counter-clockwise */
};
unsigned int btn = BUTTON_NONE;
if (old_wheel_value == wheel_tbl[0][wheel_value])
btn = BUTTON_SCROLL_FWD;
else if (old_wheel_value == wheel_tbl[1][wheel_value])
btn = BUTTON_SCROLL_BACK;
if (btn == BUTTON_NONE)
{
old_wheel_value = wheel_value;
return;
}
int repeat = 1; /* assume repeat */
long time = TIMER1_VALUE + current_tick*TIMER_TICK; /* to timer unit */
long v = (time - last_wheel_post);
/* interpolate velocity in timer_freq/timer_unit == 1/s */
if (v) v = TIMER_FREQ / v;
/* accumulate velocities over time with each v */
wheel_velocity = (7*wheel_velocity + v) / 8;
if (btn != wheel_repeat)
{
/* direction reversals nullify all fast mode states */
wheel_repeat = btn;
repeat =
wheel_velocity =
wheel_click_count = 0;
}
if (wheel_fast_mode != 0)
{
/* fast OFF happens immediately when velocity drops below
threshold */
if (TIME_AFTER(time,
last_wheel_post + WHEEL_FAST_OFF_INTERVAL))
{
/* moving out of fast mode */
wheel_fast_mode = 0;
/* reset velocity */
wheel_velocity = 0;
/* wheel_delta is always 1 in slow mode */
wheel_delta = 1;
}
}
else
{
/* fast ON gets filtered to avoid inadvertent jumps to fast mode */
if (repeat && wheel_velocity > TIMER_FREQ/WHEEL_FAST_ON_INTERVAL)
{
/* moving into fast mode */
wheel_fast_mode = 1 << 31;
wheel_click_count = 0;
wheel_velocity = TIMER_FREQ/WHEEL_FAST_OFF_INTERVAL;
}
else if (++wheel_click_count < WHEEL_CHANGES_PER_CLICK)
{ /* skip some wheel changes, so that 1 post represents
* 1 item in lists */
btn = BUTTON_NONE;
}
/* wheel_delta is always 1 in slow mode */
wheel_delta = 1;
}
if (btn != BUTTON_NONE)
{
wheel_click_count = 0;
/* generate repeats if quick enough */
if (repeat && TIME_BEFORE(time,
last_wheel_post + WHEEL_REPEAT_INTERVAL))
btn |= BUTTON_REPEAT;
last_wheel_post = time;
if (queue_empty(&button_queue))
{
queue_post(&button_queue, btn, wheel_fast_mode |
(wheel_delta << 24) | wheel_velocity*360/WHEELCLICKS_PER_ROTATION);
/* message posted - reset delta and poke backlight on*/
wheel_delta = 1;
backlight_on();
buttonlight_on();
}
else
{
/* skipped post - increment delta */
if (++wheel_delta > 0x7f)
wheel_delta = 0x7f;
}
}
old_wheel_value = wheel_value;
}
#endif
void button_init_device(void)
{
#if defined(HAVE_SCROLLWHEEL)
GPIOA_DIR &= ~(1<<6|1<<7);
GPIOC_DIR = 0;
GPIOB_DIR |= (1<<4)|(1<<0);
GPIOB_PIN(4) = 1<<4; /* activate the wheel */
}
void get_scrollwheel(void)
{
#if defined(HAVE_SCROLLWHEEL) && !defined(BOOTLOADER)
/* scroll wheel handling */
#define GPIOA_PIN76_offset ((1<<(6+2)) | (1<<(7+2)))
#define GPIOA_PIN76 (*(volatile unsigned char*)(GPIOA_BASE+GPIOA_PIN76_offset))
scrollwheel(GPIOA_PIN76 >> 6);
/* setup scrollwheel isr */
/* clear previous irq if any */
GPIOA_IC = SCROLLWHEEL_BITS;
/* enable edge detecting */
GPIOA_IS &= ~SCROLLWHEEL_BITS;
/* detect both raising and falling edges */
GPIOA_IBE |= SCROLLWHEEL_BITS;
/* lastly, enable the interrupt */
GPIOA_IE |= SCROLLWHEEL_BITS;
#endif
}
/* read the 2 bits at the same time */
#define GPIOA_PIN76_offset ((1<<(6+2)) | (1<<(7+2)))
#define GPIOA_PIN76 (*(volatile unsigned char*)(GPIOA_BASE+GPIOA_PIN76_offset))
void button_gpioa_isr(void)
{
#if defined(HAVE_SCROLLWHEEL)
/* scroll wheel handling */
if (GPIOA_MIS & SCROLLWHEEL_BITS)
scrollwheel(GPIOA_PIN76 >> 6);
/* ack interrupt */
GPIOA_IC = SCROLLWHEEL_BITS;
#endif
}
/*
* Get button pressed from hardware
*/
int button_read_device(void)
{
int btn = 0;
@ -62,12 +223,12 @@ int button_read_device(void)
static long power_counter = 0;
unsigned gpiod6;
/* if we don't wait for the fifo to empty, we'll see screen corruption
* (the higher the CPU frequency the higher the corruption) */
while ((DBOP_STAT & (1<<10)) == 0);
get_scrollwheel();
int delay = 30;
while(delay--) nop;
CCU_IO &= ~(1<<12);
@ -77,6 +238,7 @@ int button_read_device(void)
gpiod6 = GPIOD_PIN(6);
GPIOB_PIN(0) = 0;
udelay(1);
if (GPIOC_PIN(1) & 1<<1)
@ -114,6 +276,12 @@ int button_read_device(void)
{
hold_button_old = hold_button;
backlight_hold_changed(hold_button);
/* mask scrollwheel irq so we don't need to check for
* the hold button in the isr */
if (hold_button)
GPIOA_IE &= ~SCROLLWHEEL_BITS;
else
GPIOA_IE |= SCROLLWHEEL_BITS;
}
#else
(void)hold_button_old;

View file

@ -30,12 +30,6 @@
void button_init_device(void);
bool button_hold(void);
int button_read_device(void);
void get_scrollwheel(void);
#define WHEEL_REPEAT_INTERVAL (HZ/5)
#define WHEEL_COUNTER_DIV 4
#define ACCEL_INCREMENT 2
#define ACCEL_SHIFT 2
/* Sandisk Sansa Fuze button codes */
/* Main unit's buttons */

View file

@ -131,6 +131,7 @@ bool sd_enabled = false;
#if defined(HAVE_MULTIDRIVE)
static bool hs_card = false;
#define EXT_SD_BITS (1<<2)
#endif
static struct wakeup transfer_completion_signal;
@ -172,12 +173,13 @@ static int sd1_oneshot_callback(struct timeout *tmo)
return 0;
}
void INT_GPIOA(void)
void sd_gpioa_isr(void)
{
static struct timeout sd1_oneshot;
if (GPIOA_MIS & EXT_SD_BITS)
timeout_register(&sd1_oneshot, sd1_oneshot_callback, (3*HZ/10), 0);
/* acknowledge interrupt */
GPIOA_IC = (1<<2);
timeout_register(&sd1_oneshot, sd1_oneshot_callback, (3*HZ/10), 0);
GPIOA_IC = EXT_SD_BITS;
}
#endif /* HAVE_HOTSWAP */
@ -479,15 +481,12 @@ static void init_pl180_controller(const int drive)
#ifdef HAVE_MULTIDRIVE
VIC_INT_ENABLE =
(drive == INTERNAL_AS3525) ? INTERRUPT_NAND : INTERRUPT_MCI0;
/* setup isr for microsd monitoring */
VIC_INT_ENABLE = (INTERRUPT_GPIOA);
/* clear previous irq */
GPIOA_IC = (1<<2);
GPIOA_IC = EXT_SD_BITS;
/* enable edge detecting */
GPIOA_IS &= ~(1<<2);
GPIOA_IS &= ~EXT_SD_BITS;
/* detect both raising and falling edges */
GPIOA_IBE |= (1<<2);
GPIOA_IBE |= EXT_SD_BITS;
#else
VIC_INT_ENABLE = INTERRUPT_NAND;
@ -910,9 +909,9 @@ tCardInfo *card_get_info_target(int card_no)
void card_enable_monitoring_target(bool on)
{
if (on) /* enable interrupt */
GPIOA_IE |= (1<<2);
GPIOA_IE |= EXT_SD_BITS;
else /* disable interrupt */
GPIOA_IE &= ~(1<<2);
GPIOA_IE &= ~EXT_SD_BITS;
}
#endif /* HAVE_HOTSWAP */

View file

@ -342,6 +342,7 @@ static volatile bool retry;
#if defined(HAVE_MULTIDRIVE)
int active_card = 0;
#define EXT_SD_BITS (1<<2)
#endif
static inline void mci_delay(void) { udelay(1000); }
@ -687,14 +688,12 @@ int sd_init(void)
wakeup_init(&transfer_completion_signal);
#ifdef HAVE_MULTIDRIVE
/* setup isr for microsd monitoring */
VIC_INT_ENABLE = (INTERRUPT_GPIOA);
/* clear previous irq */
GPIOA_IC = (1<<2);
GPIOA_IC = EXT_SD_BITS;
/* enable edge detecting */
GPIOA_IS &= ~(1<<2);
GPIOA_IS &= ~EXT_SD_BITS;
/* detect both raising and falling edges */
GPIOA_IBE |= (1<<2);
GPIOA_IBE |= EXT_SD_BITS;
/* Configure XPD for SD-MCI interface */
CCU_IO |= (1<<2);
#endif
@ -961,20 +960,21 @@ static int sd1_oneshot_callback(struct timeout *tmo)
return 0;
}
void INT_GPIOA(void)
void sd_gpioa_isr(void)
{
static struct timeout sd1_oneshot;
if (GPIOA_MIS & EXT_SD_BITS)
timeout_register(&sd1_oneshot, sd1_oneshot_callback, (3*HZ/10), 0);
/* acknowledge interrupt */
GPIOA_IC = (1<<2);
timeout_register(&sd1_oneshot, sd1_oneshot_callback, (3*HZ/10), 0);
GPIOA_IC = EXT_SD_BITS;
}
void card_enable_monitoring_target(bool on)
{
if (on) /* enable interrupt */
GPIOA_IE |= (1<<2);
GPIOA_IE |= EXT_SD_BITS;
else /* disable interrupt */
GPIOA_IE &= ~(1<<2);
GPIOA_IE &= ~EXT_SD_BITS;
}
#endif /* HAVE_HOTSWAP */

View file

@ -70,7 +70,8 @@ default_interrupt(RESERVED6); /* Interrupt 25 : unused */
default_interrupt(RESERVED7); /* Interrupt 26 : unused */
default_interrupt(RESERVED8); /* Interrupt 27 : unused */
default_interrupt(RESERVED9); /* Interrupt 28 : unused */
default_interrupt(INT_GPIOA);
/* INT_GPIOA is declared in this file */
void INT_GPIOA(void);
default_interrupt(INT_GPIOB);
default_interrupt(INT_GPIOC);
@ -144,6 +145,18 @@ static void setup_vic(void)
}
}
void INT_GPIOA(void)
{
#ifdef HAVE_MULTIDRIVE
void sd_gpioa_isr(void);
sd_gpioa_isr();
#endif
#if (defined(HAVE_SCROLLWHEEL) && CONFIG_CPU != AS3525)
void button_gpioa_isr(void);
button_gpioa_isr();
#endif
}
void irq_handler(void)
{
asm volatile( "stmfd sp!, {r0-r5,ip,lr} \n" /* Store context */
@ -348,6 +361,12 @@ void system_init(void)
ascodec_init();
#ifndef BOOTLOADER
/* setup isr for microsd monitoring and for scrollwheel irq */
#if defined(HAVE_MULTIDRIVE) || (defined(HAVE_SCROLLWHEEL) && CONFIG_CPU != AS3525)
VIC_INT_ENABLE = (INTERRUPT_GPIOA);
/* pin selection for irq happens in the drivers */
#endif
/* Initialize power management settings */
ascodec_write(AS3514_CVDD_DCDC3, AS314_CP_DCDC3_SETTING);
#if CONFIG_TUNER

View file

@ -27,7 +27,11 @@
#include "clock-target.h" /* CPUFREQ_* are defined here */
#ifdef HAVE_SCROLLWHEEL
/* We can use a interrupt-based mechanism on the fuzev2 */
#define INCREASED_SCROLLWHEEL_POLLING \
(defined(HAVE_SCROLLWHEEL) && (CONFIG_CPU == AS3525))
#if INCREASED_SCROLLWHEEL_POLLING
/* let the timer interrupt twice as often for the scrollwheel polling */
#define KERNEL_TIMER_FREQ (TIMER_FREQ/2)
#else