summaryrefslogtreecommitdiff
path: root/firmware/target/arm
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/target/arm')
-rw-r--r--firmware/target/arm/as3525/kernel-as3525.c2
-rw-r--r--firmware/target/arm/as3525/sansa-fuzev2/button-fuzev2.c192
-rw-r--r--firmware/target/arm/as3525/sansa-fuzev2/button-target.h6
-rw-r--r--firmware/target/arm/as3525/sd-as3525.c21
-rw-r--r--firmware/target/arm/as3525/sd-as3525v2.c20
-rw-r--r--firmware/target/arm/as3525/system-as3525.c21
-rw-r--r--firmware/target/arm/as3525/system-target.h6
7 files changed, 226 insertions, 42 deletions
diff --git a/firmware/target/arm/as3525/kernel-as3525.c b/firmware/target/arm/as3525/kernel-as3525.c
index 4ae1a03809..ff489a86e8 100644
--- a/firmware/target/arm/as3525/kernel-as3525.c
+++ b/firmware/target/arm/as3525/kernel-as3525.c
@@ -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;
diff --git a/firmware/target/arm/as3525/sansa-fuzev2/button-fuzev2.c b/firmware/target/arm/as3525/sansa-fuzev2/button-fuzev2.c
index db08414ae5..9421076cce 100644
--- a/firmware/target/arm/as3525/sansa-fuzev2/button-fuzev2.c
+++ b/firmware/target/arm/as3525/sansa-fuzev2/button-fuzev2.c
@@ -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 */
+ /* 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))
- scrollwheel(GPIOA_PIN76 >> 6);
+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;
diff --git a/firmware/target/arm/as3525/sansa-fuzev2/button-target.h b/firmware/target/arm/as3525/sansa-fuzev2/button-target.h
index d7ef9623f9..c64c68f951 100644
--- a/firmware/target/arm/as3525/sansa-fuzev2/button-target.h
+++ b/firmware/target/arm/as3525/sansa-fuzev2/button-target.h
@@ -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 */
diff --git a/firmware/target/arm/as3525/sd-as3525.c b/firmware/target/arm/as3525/sd-as3525.c
index 1cf7e51cf8..9c3ff0b5fe 100644
--- a/firmware/target/arm/as3525/sd-as3525.c
+++ b/firmware/target/arm/as3525/sd-as3525.c
@@ -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 */
diff --git a/firmware/target/arm/as3525/sd-as3525v2.c b/firmware/target/arm/as3525/sd-as3525v2.c
index 2f263f7378..65fc13feae 100644
--- a/firmware/target/arm/as3525/sd-as3525v2.c
+++ b/firmware/target/arm/as3525/sd-as3525v2.c
@@ -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 */
diff --git a/firmware/target/arm/as3525/system-as3525.c b/firmware/target/arm/as3525/system-as3525.c
index 0b1884aa16..e3e41998ce 100644
--- a/firmware/target/arm/as3525/system-as3525.c
+++ b/firmware/target/arm/as3525/system-as3525.c
@@ -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
diff --git a/firmware/target/arm/as3525/system-target.h b/firmware/target/arm/as3525/system-target.h
index 1ccd3282db..d2cf99499d 100644
--- a/firmware/target/arm/as3525/system-target.h
+++ b/firmware/target/arm/as3525/system-target.h
@@ -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