From d92e09556fdec3fbd65e153c6f41c31cb1e04c42 Mon Sep 17 00:00:00 2001 From: Michael Sevakis Date: Fri, 11 May 2007 08:09:49 +0000 Subject: GPIO IRQ ready button driver for e200 series. Can't actually use them yet but their status is polled. Easy to switch over once that works. Cheapo acceleration added or else it would be too fast for selecting items. Too much scrolling might cause the PCM buffer to empty out - beware. ) git-svn-id: svn://svn.rockbox.org/rockbox/trunk@13371 a1c6a512-1295-4272-9138-f99709370657 --- apps/keymaps/keymap-e200.c | 10 +- firmware/export/pp5024.h | 6 + .../target/arm/sandisk/sansa-e200/button-e200.c | 270 ++++++++++++++------- firmware/target/arm/system-pp502x.c | 30 ++- 4 files changed, 213 insertions(+), 103 deletions(-) diff --git a/apps/keymaps/keymap-e200.c b/apps/keymaps/keymap-e200.c index 8e11cadb8b..c946b5feca 100644 --- a/apps/keymaps/keymap-e200.c +++ b/apps/keymaps/keymap-e200.c @@ -31,9 +31,9 @@ * Insert LAST_ITEM_IN_LIST at the end of each mapping */ static const struct button_mapping button_context_standard[] = { - { ACTION_STD_PREV, BUTTON_SCROLL_UP|BUTTON_REL, BUTTON_NONE }, + { ACTION_STD_PREV, BUTTON_SCROLL_UP, BUTTON_NONE }, { ACTION_STD_PREVREPEAT, BUTTON_SCROLL_UP|BUTTON_REPEAT, BUTTON_NONE }, - { ACTION_STD_NEXT, BUTTON_SCROLL_DOWN|BUTTON_REL, BUTTON_NONE }, + { ACTION_STD_NEXT, BUTTON_SCROLL_DOWN, BUTTON_NONE }, { ACTION_STD_NEXTREPEAT, BUTTON_SCROLL_DOWN|BUTTON_REPEAT, BUTTON_NONE }, { ACTION_STD_MENU, BUTTON_POWER|BUTTON_REL, BUTTON_POWER }, @@ -159,9 +159,9 @@ static const struct button_mapping button_context_quickscreen[] = { }; /* button_context_quickscreen */ static const struct button_mapping button_context_settings_right_is_inc[] = { - { ACTION_SETTINGS_INC, BUTTON_SCROLL_DOWN|BUTTON_REL, BUTTON_NONE }, - { ACTION_SETTINGS_INCREPEAT, BUTTON_SCROLL_DOWN|BUTTON_REPEAT, BUTTON_NONE }, - { ACTION_SETTINGS_DEC, BUTTON_SCROLL_UP|BUTTON_REL, BUTTON_NONE }, + { ACTION_SETTINGS_INC, BUTTON_SCROLL_DOWN, BUTTON_NONE }, + { ACTION_SETTINGS_INCREPEAT, BUTTON_SCROLL_DOWN|BUTTON_REPEAT, BUTTON_NONE }, + { ACTION_SETTINGS_DEC, BUTTON_SCROLL_UP, BUTTON_NONE }, { ACTION_SETTINGS_DECREPEAT, BUTTON_SCROLL_UP|BUTTON_REPEAT,BUTTON_NONE }, { ACTION_STD_PREV, BUTTON_UP|BUTTON_REL, BUTTON_NONE }, diff --git a/firmware/export/pp5024.h b/firmware/export/pp5024.h index 3ed3d5dade..b9238ae98d 100644 --- a/firmware/export/pp5024.h +++ b/firmware/export/pp5024.h @@ -23,4 +23,10 @@ completely */ #include "pp5020.h" +#undef GPIO_IRQ +#define GPIO_IRQ (32+6) + +#undef GPIO_MASK +#define GPIO_MASK (1 << (GPIO_IRQ-32)) + #endif diff --git a/firmware/target/arm/sandisk/sansa-e200/button-e200.c b/firmware/target/arm/sandisk/sansa-e200/button-e200.c index 028a76f7a8..168332e3c1 100644 --- a/firmware/target/arm/sandisk/sansa-e200/button-e200.c +++ b/firmware/target/arm/sandisk/sansa-e200/button-e200.c @@ -23,26 +23,193 @@ #include "button.h" #include "backlight.h" -static unsigned int old_wheel_value = 0; -static unsigned int wheel_repeat = BUTTON_NONE; +#define WHEEL_REPEAT_INTERVAL 30 +#define WHEEL_FAST_ON_INTERVAL 2 +#define WHEEL_FAST_OFF_INTERVAL 6 + +/* Clickwheel */ +static unsigned int old_wheel_value = 0; +static unsigned int wheel_repeat = BUTTON_NONE; +static unsigned int wheel_click_count = 0; +static int wheel_fast_mode = 0; +static unsigned long last_wheel_tick = 0; +static unsigned long last_wheel_post = 0; +#ifndef BOOTLOADER +static unsigned long next_backlight_on = 0; +#endif +/* Buttons */ +static bool hold_button = false; +static bool hold_button_old = false; +static int int_btn = BUTTON_NONE; void button_init_device(void) { /* Enable all buttons */ + GPIOF_OUTPUT_EN &= ~0xff; GPIOF_ENABLE |= 0xff; - GPIOH_ENABLE |= 0xc0; /* Scrollwheel light - enable control through GPIOG pin 7 and set timeout */ - GPIOG_ENABLE = 0x80; GPIOG_OUTPUT_EN |= 0x80; - + GPIOG_ENABLE = 0x80; + + GPIOH_ENABLE |= 0xc0; + GPIOH_OUTPUT_EN &= ~0xc0; + +#if 0 + CPU_INT_PRIORITY &= ~HI_MASK; + CPU_HI_INT_PRIORITY &= ~GPIO_MASK; + + CPU_INT_CLR = HI_MASK; + CPU_HI_INT_CLR = GPIO_MASK; +#endif + GPIOF_INT_CLR = 0xff; + GPIOH_INT_CLR = 0xc0; + + /* Read initial buttons */ + old_wheel_value = GPIOF_INPUT_VAL & 0xff; + GPIOF_INT_LEV = (GPIOF_INT_LEV & ~0xff) | (old_wheel_value ^ 0xff); + hold_button = (GPIOF_INPUT_VAL & 0x80) != 0; + /* Read initial wheel value (bit 6-7 of GPIOH) */ old_wheel_value = GPIOH_INPUT_VAL & 0xc0; + GPIOH_INT_LEV = (GPIOH_INT_LEV & ~0xc0) | (old_wheel_value ^ 0xc0); + + GPIOF_INT_EN = 0xff; + GPIOH_INT_EN = 0xc0; +#if 0 + CPU_HI_INT_EN = GPIO_MASK; + CPU_INT_EN = HI_MASK; +#endif + + last_wheel_tick = current_tick; + last_wheel_post = current_tick; } bool button_hold(void) { - return (GPIOF_INPUT_VAL & 0x80)?true:false; + return hold_button; +} + +void clickwheel_int(void) +{ + /* Read wheel + * Bits 6 and 7 of GPIOH change as follows: + * Clockwise rotation 01 -> 00 -> 10 -> 11 + * Counter-clockwise 11 -> 10 -> 00 -> 01 + * + * This is equivalent to wheel_value of: + * Clockwise rotation 0x40 -> 0x00 -> 0x80 -> 0xc0 + * Counter-clockwise 0xc0 -> 0x80 -> 0x00 -> 0x40 + */ + static const unsigned char wheel_tbl[2][4] = + { + /* 0x00 0x40 0x80 0xc0 */ /* Wheel value */ + { 0x40, 0xc0, 0x00, 0x80 }, /* Clockwise rotation */ + { 0x80, 0x00, 0xc0, 0x40 }, /* Counter-clockwise */ + }; + + unsigned int wheel_value; + + GPIOH_INT_CLR = GPIOH_INT_STAT & 0xc0; + + wheel_value = GPIOH_INPUT_VAL & 0xc0; + GPIOH_INT_LEV = (GPIOH_INT_LEV & ~0xc0) | (wheel_value ^ 0xc0); + + if (!hold_button) + { + unsigned int btn = BUTTON_NONE; + + if (old_wheel_value == wheel_tbl[0][wheel_value >> 6]) + btn = BUTTON_SCROLL_DOWN; + else if (old_wheel_value == wheel_tbl[1][wheel_value >> 6]) + btn = BUTTON_SCROLL_UP; + + if (btn != BUTTON_NONE) + { + int repeat = 1; + + if (btn != wheel_repeat) + { + wheel_repeat = btn; + repeat = + wheel_fast_mode = + wheel_click_count = 0; + } + + if (wheel_fast_mode) + { + if (TIME_AFTER(current_tick, + last_wheel_tick + WHEEL_FAST_OFF_INTERVAL)) + { + if (++wheel_click_count < 2) + btn = BUTTON_NONE; + wheel_fast_mode = 0; + } + } + else + { + if (repeat && TIME_BEFORE(current_tick, + last_wheel_tick + WHEEL_FAST_ON_INTERVAL)) + wheel_fast_mode = 1; + else if (++wheel_click_count < 2) + btn = BUTTON_NONE; + } + +#ifndef BOOTLOADER + if (TIME_AFTER(current_tick, next_backlight_on)) + { + next_backlight_on = current_tick + HZ/4; + backlight_on(); + button_backlight_on(); + } +#endif + if (btn != BUTTON_NONE) + { + wheel_click_count = 0; + + if (repeat && TIME_BEFORE(current_tick, + last_wheel_post + WHEEL_REPEAT_INTERVAL)) + btn |= BUTTON_REPEAT; + + last_wheel_post = current_tick; + + if (queue_empty(&button_queue)) + queue_post(&button_queue, btn, 0); + } + + last_wheel_tick = current_tick; + } + } + + old_wheel_value = wheel_value; +} + +void button_int(void) +{ + unsigned char state; + + GPIOF_INT_CLR = GPIOF_INT_STAT; + + state = GPIOF_INPUT_VAL & 0xff; + + GPIOF_INT_LEV = (GPIOF_INT_LEV & ~0xff) | (state ^ 0xff); + + int_btn = BUTTON_NONE; + + hold_button = (state & 0x80) != 0; + + /* device buttons */ + if (!hold_button) + { + /* Read normal buttons */ + if ((state & 0x01) == 0) int_btn |= BUTTON_REC; + if ((state & 0x02) == 0) int_btn |= BUTTON_DOWN; + if ((state & 0x04) == 0) int_btn |= BUTTON_RIGHT; + if ((state & 0x08) == 0) int_btn |= BUTTON_LEFT; + if ((state & 0x10) == 0) int_btn |= BUTTON_SELECT; /* The centre button */ + if ((state & 0x20) == 0) int_btn |= BUTTON_UP; /* The "play" button */ + if ((state & 0x40) != 0) int_btn |= BUTTON_POWER; + } } /* @@ -50,101 +217,16 @@ bool button_hold(void) */ int button_read_device(void) { - int btn = BUTTON_NONE; - unsigned char state; - static bool hold_button = false; - bool hold_button_old; - unsigned int new_wheel_value = 0; /* read later, but this stops a warning */ - /* Hold */ - hold_button_old = hold_button; - hold_button = button_hold(); - #ifndef BOOTLOADER /* light handling */ if (hold_button != hold_button_old) { + hold_button_old = hold_button; backlight_hold_changed(hold_button); } #endif - /* device buttons */ - if (!hold_button) - { - /* Read normal buttons */ - state = GPIOF_INPUT_VAL & 0xff; - if ((state & 0x1) == 0) btn |= BUTTON_REC; - if ((state & 0x2) == 0) btn |= BUTTON_DOWN; - if ((state & 0x4) == 0) btn |= BUTTON_RIGHT; - if ((state & 0x8) == 0) btn |= BUTTON_LEFT; - if ((state & 0x10) == 0) btn |= BUTTON_SELECT; /* The centre button */ - if ((state & 0x20) == 0) btn |= BUTTON_UP; /* The "play" button */ - if ((state & 0x40) != 0) btn |= BUTTON_POWER; - - /* Read wheel - * Bits 6 and 7 of GPIOH change as follows: - * Clockwise rotation 01 -> 00 -> 10 -> 11 - * Counter-clockwise 11 -> 10 -> 00 -> 01 - * - * This is equivalent to wheel_value of: - * Clockwise rotation 0x40 -> 0x00 -> 0x80 -> 0xc0 - * Counter-clockwise 0xc0 -> 0x80 -> 0x00 -> 0x40 - */ - new_wheel_value = GPIOH_INPUT_VAL & 0xc0; - switch(new_wheel_value){ - case 0x00: - if(old_wheel_value==0x80) - btn |= BUTTON_SCROLL_UP; - else if (old_wheel_value==0x40) - btn |= BUTTON_SCROLL_DOWN; - break; - case 0x40: - if(old_wheel_value==0x00) - btn |= BUTTON_SCROLL_UP; - else if (old_wheel_value==0xc0) - btn |= BUTTON_SCROLL_DOWN; - break; - case 0x80: - if(old_wheel_value==0xc0) - btn |= BUTTON_SCROLL_UP; - else if (old_wheel_value==0x00) - btn |= BUTTON_SCROLL_DOWN; - break; - case 0xc0: - if(old_wheel_value==0x40) - btn |= BUTTON_SCROLL_UP; - else if (old_wheel_value==0x80) - btn |= BUTTON_SCROLL_DOWN; - break; - } - - if(wheel_repeat == BUTTON_NONE){ - if(btn & BUTTON_SCROLL_UP) - wheel_repeat = BUTTON_SCROLL_UP; - - if(btn & BUTTON_SCROLL_DOWN) - wheel_repeat = BUTTON_SCROLL_DOWN; - } else if (wheel_repeat == BUTTON_SCROLL_UP) { - btn |= BUTTON_SCROLL_UP; - wheel_repeat = BUTTON_NONE; - } else if (wheel_repeat == BUTTON_SCROLL_DOWN) { - btn |= BUTTON_SCROLL_DOWN; - wheel_repeat = BUTTON_NONE; - } - - old_wheel_value = new_wheel_value; - } - - if( (btn & BUTTON_SCROLL_UP) || (btn & BUTTON_SCROLL_DOWN) ){ - /* only trigger once per click */ - if ((new_wheel_value == 0x00) || (new_wheel_value == 0xc0)) - { - btn = btn&(~(BUTTON_SCROLL_UP|BUTTON_SCROLL_DOWN)); - } -#ifndef BOOTLOADER - button_backlight_on(); -#endif - } - - return btn; + /* The int_btn variable is set in the button interrupt handler */ + return int_btn; } diff --git a/firmware/target/arm/system-pp502x.c b/firmware/target/arm/system-pp502x.c index 1f1cdf47b6..72e3a9b361 100644 --- a/firmware/target/arm/system-pp502x.c +++ b/firmware/target/arm/system-pp502x.c @@ -56,12 +56,21 @@ void irq(void) /* TODO: this should really be in the target tree, but moving it there caused crt0.S not to find it while linking */ /* TODO: Even if it isn't in the target tree, this should be the default case */ +extern void button_int(void); +extern void clickwheel_int(void); + void irq(void) { - if(CURRENT_CORE == CPU) - { - if (CPU_INT_STAT & TIMER1_MASK) + if(CURRENT_CORE == CPU) { + if (CPU_INT_STAT & TIMER1_MASK) { +#ifdef SANSA_E200 + if (GPIOF_INT_STAT & 0xff) + button_int(); + if (GPIOH_INT_STAT & 0xc0) + clickwheel_int(); +#endif TIMER1(); + } else if (CPU_INT_STAT & TIMER2_MASK) TIMER2(); } else { @@ -222,7 +231,20 @@ void system_init(void) COP_INT_CLR = -1; CPU_INT_CLR = -1; INT_FORCED_CLR = -1; - + + GPIOA_INT_EN = 0; + GPIOB_INT_EN = 0; + GPIOC_INT_EN = 0; + GPIOD_INT_EN = 0; + GPIOE_INT_EN = 0; + GPIOF_INT_EN = 0; + GPIOG_INT_EN = 0; + GPIOH_INT_EN = 0; + GPIOI_INT_EN = 0; + GPIOJ_INT_EN = 0; + GPIOK_INT_EN = 0; + GPIOL_INT_EN = 0; + # if NUM_CORES > 1 && defined(HAVE_ADJUSTABLE_CPU_FREQ) spinlock_init(&boostctrl_mtx); # endif -- cgit v1.2.3