Index: firmware/target/arm/as3525/sansa-e200v2/lcd-e200v2.c =================================================================== --- firmware/target/arm/as3525/sansa-e200v2/lcd-e200v2.c (revision 22658) +++ firmware/target/arm/as3525/sansa-e200v2/lcd-e200v2.c (working copy) @@ -39,6 +39,7 @@ * (see lcd_button_support()), but that must not happen while the lcd is * updating so block lcd_button_support the during updates */ static volatile bool lcd_busy = false; +static volatile unsigned short int dbop_input = 0xFFFF; /* register defines */ #define R_START_OSC 0x00 @@ -98,6 +99,8 @@ #define R_DISP_CONTROL_REV 0x0000 static unsigned short r_disp_control_rev = R_DISP_CONTROL_NORMAL; +static unsigned short lcd_dbop_read(void); + /* TODO: Implement this function */ static void lcd_delay(int x) { @@ -502,9 +505,13 @@ if (!display_on) return; + lcd_busy = true; + + /* do a DBOP read before doing a possibly length LCD write */ + dbop_input = lcd_dbop_read(); + lcd_write_reg(R_ENTRY_MODE, r_entry_mode); - lcd_busy = true; /* Set start position and window */ lcd_window(0, 0, LCD_WIDTH-1, LCD_HEIGHT-1); @@ -544,8 +551,12 @@ if (y >= ymax) return; /* nothing left to do */ + lcd_busy = true; + + /* do a DBOP read before doing a possibly length LCD write */ + dbop_input = lcd_dbop_read(); + lcd_write_reg(R_ENTRY_MODE, r_entry_mode); - lcd_busy = true; lcd_window(x, y, xmax, ymax); lcd_write_cmd(R_WRITE_DATA_2_GRAM); @@ -561,21 +572,43 @@ lcd_busy = false; } /* lcd_update_rect */ -/* writes one red pixel outside the visible area, needed for correct - * dbop reads */ -bool lcd_button_support(void) + +static unsigned short lcd_dbop_read(void) { - fb_data data = (0xf<<12); + unsigned int dbop_ctrl_old = DBOP_CTRL; + unsigned int dbop_timpol23_old = DBOP_TIMPOL_23; + unsigned int value; - if (lcd_busy) - return false; + /* make sure that the DBOP FIFO is empty */ + while ((DBOP_STAT & (1<<10)) == 0); - lcd_write_reg(R_ENTRY_MODE, r_entry_mode); - /* Set start position and window */ - lcd_window(LCD_WIDTH+1, LCD_HEIGHT+1, LCD_WIDTH+2, LCD_HEIGHT+2); + /* write DBOP_DOUT to pre-charge DBOP data lines with a high level */ + DBOP_TIMPOL_23 = 0xe167e167; /* no strobe towards lcd */ + DBOP_CTRL = (1 << 16) | /* enw=1 (enable write) */ + (1 << 12); /* ow=1 (16-bit data width) */ + DBOP_DOUT = 0xFFFF; /* all pins high */ + while ((DBOP_STAT & (1<<10)) == 0); - lcd_write_cmd(R_WRITE_DATA_2_GRAM); + /* perform a DBOP read */ + DBOP_CTRL = (1 << 15) | /* strd=1 (start read) */ + (1 << 12) | /* ow=1 (16-bit data width) */ + (31 << 0); /* rs_t=31 (read DBOP at end of cycle) */ + while ((DBOP_STAT & (1<<16)) == 0); + value = DBOP_DIN; - lcd_write_single_data16(data); - return true; + /* restore previous values */ + DBOP_TIMPOL_23 = dbop_timpol23_old; + DBOP_CTRL = dbop_ctrl_old; + + return value; } + +/* get the DBOP input value, either directly or cached if DBOP is busy */ +unsigned short int lcd_dbop_input(void) +{ + if (!lcd_busy) { + dbop_input = lcd_dbop_read(); + } + return dbop_input; +} + Index: firmware/target/arm/as3525/kernel-as3525.c =================================================================== --- firmware/target/arm/as3525/kernel-as3525.c (revision 22658) +++ firmware/target/arm/as3525/kernel-as3525.c (working copy) @@ -24,40 +24,14 @@ #include "panic.h" #include "timer.h" -#ifdef HAVE_SCROLLWHEEL -/* let the timer interrupt twice as often for the scrollwheel polling */ -#define KERNEL_TIMER_FREQ (TIMER_FREQ/2) -#else #define KERNEL_TIMER_FREQ TIMER_FREQ -#endif -#ifdef HAVE_SCROLLWHEEL -#include "button-target.h" -/* The scrollwheel is polled every 5 ms (the tick tasks only every 10) */ -static int poll_scrollwheel = 0; - void INT_TIMER2(void) { - if (!poll_scrollwheel) - call_tick_tasks(); /* Run through the list of tick tasks - * (that includes reading the scrollwheel) */ - else - { - if (!button_hold()) - button_read_dbop(); /* Read the scrollwheel */ - } - - poll_scrollwheel ^= 1; - TIMER2_INTCLR = 0; /* clear interrupt */ -} -#else -void INT_TIMER2(void) -{ call_tick_tasks(); /* Run through the list of tick tasks */ TIMER2_INTCLR = 0; /* clear interrupt */ } -#endif void tick_start(unsigned int interval_in_ms) { Index: firmware/target/arm/as3525/button-e200v2-fuze.c =================================================================== --- firmware/target/arm/as3525/button-e200v2-fuze.c (revision 22658) +++ firmware/target/arm/as3525/button-e200v2-fuze.c (working copy) @@ -32,7 +32,6 @@ #define WHEEL_COUNTER_DIV 4 #define ACCEL_INCREMENT 2 #define ACCEL_SHIFT 2 -#define BUTTON_DELAY 60 #endif #ifdef SANSA_E200V2 @@ -41,12 +40,6 @@ #define WHEEL_COUNTER_DIV 2 #define ACCEL_INCREMENT 3 #define ACCEL_SHIFT 1 -#define BUTTON_DELAY 20 - -/* read_missed is true if buttons could not - * be read (see lcd_button_support) */ -static bool read_missed = false; - #endif /* Buttons */ @@ -57,19 +50,18 @@ static unsigned short _dbop_din = BUTTON_NONE; /* in the lcd driver */ -extern bool lcd_button_support(void); +extern unsigned short int lcd_dbop_input(void); void button_init_device(void) { - GPIOA_DIR |= (1<<1); + GPIOA_DIR |= (1<<1); GPIOA_PIN(1) = (1<<1); } #if !defined(BOOTLOADER) && defined(HAVE_SCROLLWHEEL) -static void scrollwheel(unsigned short dbop_din) +static void scrollwheel(unsigned int wheel_value) { /* current wheel values, parsed from dbop and the resulting button */ - unsigned wheel_value = 0; unsigned btn = BUTTON_NONE; /* old wheel values */ static unsigned old_wheel_value = 0; @@ -92,7 +84,7 @@ /* We only post every 4th action, as this matches better with the physical * clicks of the wheel */ static int counter = 0; - /* Read wheel + /* Read wheel * Bits 13 and 14 of DBOP_DIN change as follows: * Clockwise rotation 00 -> 01 -> 11 -> 10 -> 00 * Counter-clockwise 00 -> 10 -> 11 -> 01 -> 00 @@ -100,7 +92,7 @@ static const unsigned char wheel_tbl[2][4] = { { 2, 0, 3, 1 }, /* Clockwise rotation */ - { 1, 3, 0, 2 }, /* Counter-clockwise */ + { 1, 3, 0, 2 }, /* Counter-clockwise */ }; if(hold_button) @@ -109,9 +101,6 @@ return; } - wheel_value = dbop_din & (1<<13|1<<14); - wheel_value >>= 13; - if (old_wheel_value == wheel_tbl[0][wheel_value]) btn = BUTTON_SCROLL_FWD; else if (old_wheel_value == wheel_tbl[1][wheel_value]) @@ -139,7 +128,7 @@ accel += ACCEL_INCREMENT; /* the wheel is more reliable if we don't send every change, - * every WHEEL_COUNTER_DIVth is basically one "physical click" + * every WHEEL_COUNTER_DIVth is basically one "physical click" * which should make up 1 item in lists */ if (++counter >= WHEEL_COUNTER_DIV && queue_empty(&button_queue)) { @@ -151,11 +140,7 @@ last_wheel_post = current_tick; } } - if (accel > 0 -#ifdef SANSA_E200V2 - && !read_missed /* decrement only if reading buttons was successful */ -#endif - ) + if (accel > 0) accel--; old_wheel_value = wheel_value; @@ -167,167 +152,26 @@ return hold_button; } -static void button_delay(void) -{ - int i = BUTTON_DELAY; - while(i--) asm volatile ("nop\n"); -} - -unsigned short button_read_dbop(void) -{ -#ifdef SANSA_FUZE - /* skip home and power reading if lcd_button_support was blocked, - * since the dbop bit 15 is invalid then, and use the old value instead - * -20 (arbitary value) indicates valid home&power button read - * (fuze only) */ - int old_home_power = -20; -#endif - if(!lcd_button_support()) - { -#if defined(SANSA_FUZE) - old_home_power = (_dbop_din & (1<<15|1<<8)); -#elif defined(SANSA_E200V2) - read_missed = true; -#endif - } - -#ifdef SANSA_E200V2 - if (!read_missed) /* read buttons only if lcd_button_support was not blocked */ -#endif - { - /* Set up dbop for input */ - DBOP_CTRL |= (1<<19); /* Tri-state DBOP on read cycle */ - DBOP_CTRL &= ~(1<<16); /* disable output (1:write enabled) */ - DBOP_TIMPOL_01 = 0xe167e167; /* Set Timing & Polarity regs 0 & 1 */ - DBOP_TIMPOL_23 = 0xe167006e; /* Set Timing & Polarity regs 2 & 3 */ - - button_delay(); - DBOP_CTRL |= (1<<15); /* start read */ - while (!(DBOP_STAT & (1<<16))); /* wait for valid data */ - - _dbop_din = DBOP_DIN; /* Read dbop data*/ - - /* Reset dbop for output */ - DBOP_TIMPOL_01 = 0x6e167; /* Set Timing & Polarity regs 0 & 1 */ - DBOP_TIMPOL_23 = 0xa167e06f; /* Set Timing & Polarity regs 2 & 3 */ - DBOP_CTRL |= (1<<16); /* Enable output (0:write disable) */ - DBOP_CTRL &= ~(1<<19); /* Tri-state when no active write */ - } - -#ifdef SANSA_FUZE - /* write back old values if blocked */ - if (old_home_power != -20) - { - _dbop_din |= old_home_power & 1<<15; - _dbop_din &= 0xfeff|(old_home_power & 1<<8); - } -#endif - -#if defined(HAVE_SCROLLWHEEL) && !defined(BOOTLOADER) - /* read wheel on bit 13 & 14, but sent to the button queue seperately */ - scrollwheel(_dbop_din); -#endif - -#ifdef SANSA_E200V2 - read_missed = false; -#endif - - return _dbop_din; -} - /* for the debug menu */ unsigned short button_dbop_data(void) { return _dbop_din; } -static int button_gpio(void) -{ - int btn = BUTTON_NONE; - if(hold_button) - return btn; - - /* disable DBOP output while changing GPIO pins that share lines with it */ - DBOP_CTRL &= ~(1<<16); - button_delay(); - - /* set afsel, so that we can read our buttons */ - GPIOC_AFSEL &= ~(1<<2|1<<3|1<<4|1<<5|1<<6); - /* set dir so we can read our buttons (but reset the C pins first) */ - GPIOB_DIR &= ~(1<<4); - GPIOC_DIR |= (1<<2|1<<3|1<<4|1<<5|1<<6); - GPIOC_PIN(2) = (1<<2); - GPIOC_PIN(3) = (1<<3); - GPIOC_PIN(4) = (1<<4); - GPIOC_PIN(5) = (1<<5); - GPIOC_PIN(6) = (1<<6); - - GPIOC_DIR &= ~(1<<2|1<<3|1<<4|1<<5|1<<6); - - /* small delay needed to read buttons correctly */ - button_delay(); - - /* direct GPIO connections */ - if (!GPIOC_PIN(3)) - btn |= BUTTON_LEFT; - if (!GPIOC_PIN(2)) - btn |= BUTTON_UP; - if (!GPIOC_PIN(6)) - btn |= BUTTON_DOWN; - if (!GPIOC_PIN(5)) - btn |= BUTTON_RIGHT; - if (!GPIOC_PIN(4)) - btn |= BUTTON_SELECT; - /* return to settings needed for lcd */ - GPIOC_DIR |= (1<<2|1<<3|1<<4|1<<5|1<<6); - GPIOC_AFSEL |= (1<<2|1<<3|1<<4|1<<5|1<<6); - - DBOP_CTRL |= (1<<16); /* enable output again */ - return btn; -} - /* * Get button pressed from hardware */ int button_read_device(void) { - int btn = BUTTON_NONE; - unsigned short dbop = button_read_dbop(); #ifdef SANSA_FUZE static unsigned power_counter = 0; #endif - /* hold button */ - if(dbop & (1<<12)) - { -#ifdef SANSA_FUZE - power_counter = HZ; -#endif - hold_button = true; - } - else - { - hold_button = false; -#ifdef SANSA_FUZE - /* read power on bit 8, but not if hold button was just released, since - * you basically always hit power due to the slider mechanism after releasing - * (fuze only) - * hold (wait 1 sec) */ - if (power_counter) - power_counter--; -#endif - if (dbop & (1<<8) -#ifdef SANSA_FUZE - && !power_counter -#endif - ) - btn |= BUTTON_POWER; - /* read home on bit 15 */ - if (!(dbop & (1<<15))) - btn |= DBOP_BIT15_BUTTON; + int btn = BUTTON_NONE; - btn |= button_gpio(); - } + _dbop_din = lcd_dbop_input(); + /* hold button handling */ + hold_button = ((_dbop_din && (1<<12)) == 0); #ifndef BOOTLOADER /* light handling */ if (hold_button != hold_button_old) @@ -336,6 +180,45 @@ backlight_hold_changed(hold_button); } #endif /* BOOTLOADER */ + if (hold_button) { +#ifdef SANSA_FUZE + power_counter = HZ; +#endif + return 0; + } + /* push button handling */ + if ((_dbop_din & (1 << 2)) == 0) + btn |= BUTTON_UP; + if ((_dbop_din & (1 << 3)) == 0) + btn |= BUTTON_LEFT; + if ((_dbop_din & (1 << 4)) == 0) + btn |= BUTTON_SELECT; + if ((_dbop_din & (1 << 5)) == 0) + btn |= BUTTON_RIGHT; + if ((_dbop_din & (1 << 6)) == 0) + btn |= BUTTON_DOWN; + if ((_dbop_din & (1 << 8)) == 0) + btn |= BUTTON_POWER; + if ((_dbop_din & (1 << 15)) == 0) + btn |= DBOP_BIT15_BUTTON; + +#ifdef SANSA_FUZE + /* read power on bit 8, but not if hold button was just released, since + * you basically always hit power due to the slider mechanism after releasing + * (fuze only) + */ + if (power_counter > 0) { + power_counter--; + btn &= ~BUTTON_POWER; + } +#endif + +#if defined(HAVE_SCROLLWHEEL) && !defined(BOOTLOADER) + /* scroll wheel handling */ + scrollwheel((_dbop_din >> 13) & 3); +#endif + return btn; } +