diff --git a/bootloader/sansa_as3525.c b/bootloader/sansa_as3525.c index 48f21bc..f010cf7 100644 --- a/bootloader/sansa_as3525.c +++ b/bootloader/sansa_as3525.c @@ -48,6 +48,8 @@ void main(void) system_init(); kernel_init(); + enable_irq(); + #ifdef SANSA_C200V2 /* stop here */ while(1); @@ -58,6 +60,10 @@ void main(void) _backlight_on(); button_init_device(); +#ifdef SANSA_CLIP + /* Clip button matrix has 3 rows, and the driver reads 1 row per tick */ + sleep(3); +#endif int btn = button_read_device(); #if !defined(SANSA_FUZE) && !defined(SANSA_CLIP) @@ -79,8 +85,6 @@ void main(void) verbose = true; } - enable_irq(); - ret = storage_init(); if(ret < 0) error(EATA,ret); diff --git a/firmware/target/arm/as3525/sansa-clip/button-clip.c b/firmware/target/arm/as3525/sansa-clip/button-clip.c index 2d2a3a6..6c252c4 100644 --- a/firmware/target/arm/as3525/sansa-clip/button-clip.c +++ b/firmware/target/arm/as3525/sansa-clip/button-clip.c @@ -7,6 +7,7 @@ * \/ \/ \/ \/ \/ * $Id$ * + * Copyright (C) 2009 Bertrik Sikken * Copyright (C) 2008 François Dinel * Copyright (C) 2008 Rafaël Carré * @@ -21,75 +22,116 @@ ****************************************************************************/ #include "button-target.h" #include "as3525.h" +#include "kernel.h" -void button_init_device(void) -{ - GPIOA_DIR &= ~((1<<7) | (1<<3)); - GPIOB_DIR &= ~((1<<2) | (1<<1) | (1<<0)); - GPIOC_PIN(4) = 0x00; - GPIOC_PIN(5) = 0x00; - GPIOC_PIN(6) = 0x00; - GPIOC_DIR |= ((1<<6) | (1<<5) | (1<<4)); -} +/* The Sansa Clip uses a button matrix that is scanned by selecting one of + three rows and reading back the button states from the columns. -int button_read_device(void) + In this driver, a kernel tick task is used to alternate between rows. + In one tick, column data from one row is read back and then the next row + is selected for the following tick. This mechanism ensures that there is + plenty time between selecting a row and reading the colums, avoiding the + need for explicit delays. +*/ + +static int buttons = 0; + +static void button_tick(void) { - int result = 0; + static int row = 0; + int temp; - if(button_hold()) - return result; + if(button_hold()) { + buttons = 0; + return; + } - /* direct GPIO connections */ + temp = buttons; + /* direct GPIO connections */ if (GPIOA_PIN(7)) - result |= BUTTON_POWER; + temp |= BUTTON_POWER; + else + temp &= ~BUTTON_POWER; /* This is a keypad using C4-C6 as columns and B0-B2 as rows */ - GPIOC_PIN(4) = (1<<4); - asm volatile("nop\nnop\nnop\nnop\nnop\n"); /* small delay */ + switch (row) { + + case 0: + temp &= ~(BUTTON_VOL_UP | BUTTON_UP); + + (void)GPIOB_PIN(0); /* C4B0 is unused */ - (void)GPIOB_PIN(0); /* C4B0 is unused */ + if (GPIOB_PIN(1)) + temp |= BUTTON_VOL_UP; - if (GPIOB_PIN(1)) - result |= BUTTON_VOL_UP; + if (GPIOB_PIN(2)) + temp |= BUTTON_UP; - if (GPIOB_PIN(2)) - result |= BUTTON_UP; + GPIOC_PIN(4) = 0; + GPIOC_PIN(5) = (1<<5); + row++; + break; - GPIOC_PIN(4) = 0x00; + case 1: + temp &= ~(BUTTON_LEFT | BUTTON_SELECT | BUTTON_RIGHT); - GPIOC_PIN(5) = (1<<5); - asm volatile("nop\nnop\nnop\nnop\nnop\n"); /* small delay */ + if (GPIOB_PIN(0)) + temp |= BUTTON_LEFT; - if (GPIOB_PIN(0)) - result |= BUTTON_LEFT; + if (GPIOB_PIN(1)) + temp |= BUTTON_SELECT; - if (GPIOB_PIN(1)) - result |= BUTTON_SELECT; + if (GPIOB_PIN(2)) + temp |= BUTTON_RIGHT; - if (GPIOB_PIN(2)) - result |= BUTTON_RIGHT; + GPIOC_PIN(5) = 0; + GPIOC_PIN(6) = (1<<6); + row++; + break; - GPIOC_PIN(5) = 0x00; + case 2: + temp &= ~(BUTTON_DOWN | BUTTON_VOL_DOWN | BUTTON_HOME); - GPIOC_PIN(6) = (1<<6); - asm volatile("nop\nnop\nnop\nnop\nnop\n"); /* small delay */ + if (GPIOB_PIN(0)) + temp |= BUTTON_DOWN; - if (GPIOB_PIN(0)) - result |= BUTTON_DOWN; + if (GPIOB_PIN(1)) + temp |= BUTTON_VOL_DOWN; - if (GPIOB_PIN(1)) - result |= BUTTON_VOL_DOWN; + if (GPIOB_PIN(2)) + temp |= BUTTON_HOME; - if (GPIOB_PIN(2)) - result |= BUTTON_HOME; + GPIOC_PIN(6) = 0; + GPIOC_PIN(4) = (1<<4); - GPIOC_PIN(6) = 0x00; + default: + row = 0; + break; + } - return result; + buttons = temp; +} + +int button_read_device(void) +{ + return buttons; } bool button_hold(void) { return (GPIOA_PIN(3) != 0); } + +void button_init_device(void) +{ + GPIOA_DIR &= ~((1<<7) | (1<<3)); + GPIOB_DIR &= ~((1<<2) | (1<<1) | (1<<0)); + GPIOC_PIN(4) = 0; + GPIOC_PIN(5) = 0; + GPIOC_PIN(6) = 0; + GPIOC_DIR |= ((1<<6) | (1<<5) | (1<<4)); + + tick_add_task(button_tick); +} +