mirror of
https://github.com/Rockbox/rockbox.git
synced 2025-12-08 12:45:26 -05:00
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:
parent
ee291a5e9b
commit
249aae587a
9 changed files with 242 additions and 58 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
/* acknowledge interrupt */
|
||||
GPIOA_IC = (1<<2);
|
||||
if (GPIOA_MIS & EXT_SD_BITS)
|
||||
timeout_register(&sd1_oneshot, sd1_oneshot_callback, (3*HZ/10), 0);
|
||||
/* acknowledge interrupt */
|
||||
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 */
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
/* acknowledge interrupt */
|
||||
GPIOA_IC = (1<<2);
|
||||
if (GPIOA_MIS & EXT_SD_BITS)
|
||||
timeout_register(&sd1_oneshot, sd1_oneshot_callback, (3*HZ/10), 0);
|
||||
/* acknowledge interrupt */
|
||||
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 */
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue