diff options
Diffstat (limited to 'firmware/target/mips/ingenic_x1000/fiiom3k/button-fiiom3k.c')
-rw-r--r-- | firmware/target/mips/ingenic_x1000/fiiom3k/button-fiiom3k.c | 235 |
1 files changed, 126 insertions, 109 deletions
diff --git a/firmware/target/mips/ingenic_x1000/fiiom3k/button-fiiom3k.c b/firmware/target/mips/ingenic_x1000/fiiom3k/button-fiiom3k.c index db5ece10b0..24daf2ef69 100644 --- a/firmware/target/mips/ingenic_x1000/fiiom3k/button-fiiom3k.c +++ b/firmware/target/mips/ingenic_x1000/fiiom3k/button-fiiom3k.c @@ -22,27 +22,21 @@ #include "button.h" #include "kernel.h" #include "backlight.h" +#include "powermgmt.h" #include "panic.h" -#include "lcd.h" +#include "axp-pmu.h" +#include "ft6x06.h" #include "gpio-x1000.h" +#include "irq-x1000.h" #include "i2c-x1000.h" #include <string.h> #include <stdbool.h> #ifndef BOOTLOADER +# include "lcd.h" # include "font.h" #endif -#define FT_RST_PIN (1 << 15) -#define FT_INT_PIN (1 << 12) -#define ft_interrupt GPIOB12 - -/* Touch event types */ -#define EVENT_NONE (-1) -#define EVENT_PRESS 0 -#define EVENT_RELEASE 1 -#define EVENT_CONTACT 2 - /* FSM states */ #define STATE_IDLE 0 #define STATE_PRESS 1 @@ -51,11 +45,11 @@ #define STATE_SCROLLING 4 /* Assume there's no active touch if no event is reported in this time */ -#define AUTORELEASE_TIME (10000 * OST_TICKS_PER_US) +#define AUTORELEASE_TIME (40 * 1000 * OST_TICKS_PER_US) /* If there's no significant motion on the scrollbar for this time, * then report it as a button press instead */ -#define SCROLL_PRESS_TIME (100000 * OST_TICKS_PER_US) +#define SCROLL_PRESS_TIME (400 * 1000 * OST_TICKS_PER_US) /* If a press on the scrollbar moves more than this during SCROLL_PRESS_TIME, * then we enter scrolling mode. */ @@ -68,17 +62,6 @@ /* Number of touch samples to smooth before reading */ #define TOUCH_SAMPLES 3 -static struct ft_driver { - int i2c_cookie; - i2c_descriptor i2c_desc; - uint8_t raw_data[6]; - bool active; - - /* Number of pixels squared which must be moved before - * a scrollbar pulse is generated */ - int scroll_thresh_sqr; -} ftd; - static struct ft_state_machine { /* Current button state, used by button_read_device() */ int buttons; @@ -107,8 +90,27 @@ static struct ft_state_machine { /* Current touch position */ int cur_x, cur_y; + + /* Motion threshold squared, in 'pixels', required to trigger scrolling */ + int scroll_thresh_sqr; + + /* Touchpad enabled state */ + bool active; } fsm; +/* coordinates below this are the left hand buttons, + * coordinates above this are part of the scrollbar */ +#define SCROLLSTRIP_LEFT_X 80 + +/* top and bottom cutoffs for the center of the strip, + * divides it into top/middle/bottom zones */ +#define SCROLLSTRIP_TOP_Y 105 +#define SCROLLSTRIP_BOT_Y 185 + +/* cutoffs for the menu/left button zones */ +#define MENUBUTTON_Y 80 +#define LEFTBUTTON_Y 190 + static int touch_to_button(int x, int y) { if(x == 900) { @@ -119,19 +121,19 @@ static int touch_to_button(int x, int y) return BUTTON_RIGHT; else return 0; - } else if(x < 80) { + } else if(x < SCROLLSTRIP_LEFT_X) { /* Left strip */ - if(y < 80) + if(y < MENUBUTTON_Y) return BUTTON_MENU; - else if(y > 190) + else if(y > LEFTBUTTON_Y) return BUTTON_LEFT; else return 0; } else { /* Middle strip */ - if(y < 100) + if(y < SCROLLSTRIP_TOP_Y) return BUTTON_UP; - else if(y > 220) + else if(y > SCROLLSTRIP_BOT_Y) return BUTTON_DOWN; else return BUTTON_SELECT; @@ -199,9 +201,9 @@ static void ft_start_report_or_scroll(void) static void ft_step_state(uint32_t t, int evt, int tx, int ty) { /* Generate a release event automatically in case we missed it */ - if(evt == EVENT_NONE) { + if(evt == FT6x06_EVT_NONE) { if(TICKS_SINCE(t, fsm.last_event_t) >= AUTORELEASE_TIME) { - evt = EVENT_RELEASE; + evt = FT6x06_EVT_RELEASE; tx = fsm.cur_x; ty = fsm.cur_y; } @@ -209,7 +211,7 @@ static void ft_step_state(uint32_t t, int evt, int tx, int ty) switch(fsm.state) { case STATE_IDLE: { - if(evt == EVENT_PRESS || evt == EVENT_CONTACT) { + if(evt == FT6x06_EVT_PRESS || evt == FT6x06_EVT_CONTACT) { /* Move to REPORT or PRESS state */ if(ft_accum_touch(t, tx, ty)) ft_start_report_or_scroll(); @@ -219,10 +221,10 @@ static void ft_step_state(uint32_t t, int evt, int tx, int ty) } break; case STATE_PRESS: { - if(evt == EVENT_RELEASE) { + if(evt == FT6x06_EVT_RELEASE) { /* Ignore if the number of samples is too low */ ft_go_idle(); - } else if(evt == EVENT_PRESS || evt == EVENT_CONTACT) { + } else if(evt == FT6x06_EVT_PRESS || evt == FT6x06_EVT_CONTACT) { /* Accumulate the touch position in the filter */ if(ft_accum_touch(t, tx, ty)) ft_start_report_or_scroll(); @@ -230,14 +232,14 @@ static void ft_step_state(uint32_t t, int evt, int tx, int ty) } break; case STATE_REPORT: { - if(evt == EVENT_RELEASE) + if(evt == FT6x06_EVT_RELEASE) ft_go_idle(); - else if(evt == EVENT_PRESS || evt == EVENT_CONTACT) + else if(evt == FT6x06_EVT_PRESS || evt == FT6x06_EVT_CONTACT) ft_accum_touch(t, tx, ty); } break; case STATE_SCROLL_PRESS: { - if(evt == EVENT_RELEASE) { + if(evt == FT6x06_EVT_RELEASE) { /* This _should_ synthesize a button press. * * - ft_start_report() will set the button bit based on the @@ -246,10 +248,10 @@ static void ft_step_state(uint32_t t, int evt, int tx, int ty) * * - The next button_read_device() will see the button bit * and report it back to Rockbox, then step the FSM with - * EVENT_NONE. + * FT6x06_EVT_NONE. * - * - The EVENT_NONE stepping will eventually autogenerate a - * RELEASE event and restore the button state back to 0 + * - The FT6x06_EVT_NONE stepping will eventually autogenerate + * a RELEASE event and restore the button state back to 0 * * - There's a small logic hole in the REPORT state which * could cause it to miss an immediately repeated PRESS @@ -260,7 +262,7 @@ static void ft_step_state(uint32_t t, int evt, int tx, int ty) break; } - if(evt == EVENT_PRESS || evt == EVENT_CONTACT) + if(evt == FT6x06_EVT_PRESS || evt == FT6x06_EVT_CONTACT) ft_accum_touch(t, tx, ty); int dx = fsm.cur_x - fsm.orig_x; @@ -278,28 +280,33 @@ static void ft_step_state(uint32_t t, int evt, int tx, int ty) } break; case STATE_SCROLLING: { - if(evt == EVENT_RELEASE) { + if(evt == FT6x06_EVT_RELEASE) { ft_go_idle(); break; } - if(evt == EVENT_PRESS || evt == EVENT_CONTACT) + if(evt == FT6x06_EVT_PRESS || evt == FT6x06_EVT_CONTACT) ft_accum_touch(t, tx, ty); int dx = fsm.cur_x - fsm.orig_x; int dy = fsm.cur_y - fsm.orig_y; int dp = (dx*dx) + (dy*dy); - if(dp >= ftd.scroll_thresh_sqr) { - if(dy < 0) { - queue_post(&button_queue, BUTTON_SCROLL_BACK, 0); - } else { - queue_post(&button_queue, BUTTON_SCROLL_FWD, 0); + if(dp >= fsm.scroll_thresh_sqr) { + /* avoid generating events if we're supposed to be inactive... + * should not be necessary but better to be safe. */ + if(fsm.active) { + if(dy < 0) { + queue_post(&button_queue, BUTTON_SCROLL_BACK, 0); + } else { + queue_post(&button_queue, BUTTON_SCROLL_FWD, 0); + } + + /* Poke the backlight */ + backlight_on(); + buttonlight_on(); + reset_poweroff_timer(); } - /* Poke the backlight */ - backlight_on(); - buttonlight_on(); - fsm.orig_x = fsm.cur_x; fsm.orig_y = fsm.cur_y; } @@ -311,18 +318,8 @@ static void ft_step_state(uint32_t t, int evt, int tx, int ty) } } -static void ft_i2c_callback(int status, i2c_descriptor* desc) +static void ft_event_cb(struct ft6x06_state* state) { - (void)desc; - if(status != I2C_STATUS_OK) - return; - - /* The panel is oriented such that its X axis is vertical, - * so swap the axes for reporting */ - int evt = ftd.raw_data[1] >> 6; - int ty = ftd.raw_data[2] | ((ftd.raw_data[1] & 0xf) << 8); - int tx = ftd.raw_data[4] | ((ftd.raw_data[3] & 0xf) << 8); - /* TODO: convert the touch positions to linear positions. * * Points reported by the touch controller are distorted and non-linear, @@ -330,35 +327,12 @@ static void ft_i2c_callback(int status, i2c_descriptor* desc) * the middle of the touchpad than on the edges, so scrolling feels slow * in the middle and faster near the edge. */ - - ft_step_state(__ost_read32(), evt, tx, ty); -} - -void ft_interrupt(void) -{ - /* We don't care if this fails */ - i2c_async_queue(FT6x06_BUS, TIMEOUT_NOBLOCK, I2C_Q_ONCE, - ftd.i2c_cookie, &ftd.i2c_desc); + struct ft6x06_point* pt = &state->points[0]; + ft_step_state(__ost_read32(), pt->event, pt->pos_x, pt->pos_y); } static void ft_init(void) { - /* Initialize the driver state */ - ftd.i2c_cookie = i2c_async_reserve_cookies(FT6x06_BUS, 1); - ftd.i2c_desc.slave_addr = FT6x06_ADDR; - ftd.i2c_desc.bus_cond = I2C_START | I2C_STOP; - ftd.i2c_desc.tran_mode = I2C_READ; - ftd.i2c_desc.buffer[0] = &ftd.raw_data[5]; - ftd.i2c_desc.count[0] = 1; - ftd.i2c_desc.buffer[1] = &ftd.raw_data[0]; - ftd.i2c_desc.count[1] = 5; - ftd.i2c_desc.callback = ft_i2c_callback; - ftd.i2c_desc.arg = 0; - ftd.i2c_desc.next = NULL; - ftd.raw_data[5] = 0x02; - ftd.active = true; - touchpad_set_sensitivity(DEFAULT_TOUCHPAD_SENSITIVITY_SETTING); - /* Initialize the state machine */ fsm.buttons = 0; fsm.state = STATE_IDLE; @@ -368,29 +342,39 @@ static void ft_init(void) fsm.sum_x = fsm.sum_y = 0; fsm.orig_x = fsm.orig_y = 0; fsm.cur_x = fsm.cur_y = 0; + fsm.active = true; + touchpad_set_sensitivity(DEFAULT_TOUCHPAD_SENSITIVITY_SETTING); /* Bring up I2C bus */ i2c_x1000_set_freq(FT6x06_BUS, I2C_FREQ_400K); + /* Driver init */ + ft6x06_init(); + ft6x06_set_event_cb(ft_event_cb); + /* Reset chip */ - gpio_config(GPIO_B, FT_RST_PIN|FT_INT_PIN, GPIO_OUTPUT(0)); + gpio_set_level(GPIO_FT6x06_RESET, 0); mdelay(5); - gpio_out_level(GPIO_B, FT_RST_PIN, 1); - gpio_config(GPIO_B, FT_INT_PIN, GPIO_IRQ_EDGE(0)); - gpio_enable_irq(GPIO_B, FT_INT_PIN); + gpio_set_level(GPIO_FT6x06_RESET, 1); + + /* Configure the interrupt pin */ + system_set_irq_handler(GPIO_TO_IRQ(GPIO_FT6x06_INTERRUPT), + ft6x06_irq_handler); + gpio_set_function(GPIO_FT6x06_INTERRUPT, GPIOF_IRQ_EDGE(0)); + gpio_enable_irq(GPIO_FT6x06_INTERRUPT); } void touchpad_set_sensitivity(int level) { int pixels = 40; pixels -= level; - ftd.scroll_thresh_sqr = pixels * pixels; + fsm.scroll_thresh_sqr = pixels * pixels; } void touchpad_enable_device(bool en) { - i2c_reg_write1(FT6x06_BUS, FT6x06_ADDR, 0xa5, en ? 0 : 3); - ftd.active = en; + ft6x06_enable(en); + fsm.active = en; } /* Value of headphone detect register */ @@ -402,16 +386,16 @@ static uint8_t hp_detect_reg = 0x00; static int hp_detect_tmo_cb(struct timeout* tmo) { i2c_descriptor* d = (i2c_descriptor*)tmo->data; - i2c_async_queue(AXP173_BUS, TIMEOUT_NOBLOCK, I2C_Q_ADD, 0, d); + i2c_async_queue(AXP_PMU_BUS, TIMEOUT_NOBLOCK, I2C_Q_ADD, 0, d); return HPD_POLL_TIME; } static void hp_detect_init(void) { static struct timeout tmo; - static const uint8_t gpio_reg = 0x94; + static const uint8_t gpio_reg = AXP192_REG_GPIOSTATE1; static i2c_descriptor desc = { - .slave_addr = AXP173_ADDR, + .slave_addr = AXP_PMU_ADDR, .bus_cond = I2C_START | I2C_STOP, .tran_mode = I2C_READ, .buffer[0] = (void*)&gpio_reg, @@ -423,12 +407,11 @@ static void hp_detect_init(void) .next = NULL, }; - /* Headphone detect is wired to an undocumented GPIO on the AXP173. - * This sets it to input mode so we can see the pin state. */ - i2c_reg_write1(AXP173_BUS, AXP173_ADDR, 0x93, 0x01); + /* Headphone detect is wired to AXP192 GPIO: set it to input state */ + i2c_reg_write1(AXP_PMU_BUS, AXP_PMU_ADDR, AXP192_REG_GPIO2FUNCTION, 0x01); /* Get an initial reading before startup */ - int r = i2c_reg_read1(AXP173_BUS, AXP173_ADDR, gpio_reg); + int r = i2c_reg_read1(AXP_PMU_BUS, AXP_PMU_ADDR, gpio_reg); if(r >= 0) hp_detect_reg = r; @@ -439,10 +422,6 @@ static void hp_detect_init(void) /* Rockbox interface */ void button_init_device(void) { - /* Configure physical button GPIOs */ - gpio_config(GPIO_A, (1 << 17) | (1 << 19), GPIO_INPUT); - gpio_config(GPIO_B, (1 << 28) | (1 << 31), GPIO_INPUT); - /* Initialize touchpad */ ft_init(); @@ -453,7 +432,7 @@ void button_init_device(void) int button_read_device(void) { int r = fsm.buttons; - ft_step_state(__ost_read32(), EVENT_NONE, 0, 0); + ft_step_state(__ost_read32(), FT6x06_EVT_NONE, 0, 0); /* Read GPIOs for physical buttons */ uint32_t a = REG_GPIO_PIN(GPIO_A); @@ -465,10 +444,10 @@ int button_read_device(void) if((b & (1 << 28)) == 0) r |= BUTTON_VOL_DOWN; if((b & (1 << 31)) == 0) r |= BUTTON_POWER; - return r; + return touchpad_filter(r); } -bool headphones_inserted() +bool headphones_inserted(void) { return hp_detect_reg & 0x40 ? true : false; } @@ -489,6 +468,24 @@ bool dbg_fiiom3k_touchpad(void) "IDLE", "PRESS", "REPORT", "SCROLL_PRESS", "SCROLLING" }; + /* definition of box used to represent the touchpad */ + const int pad_w = LCD_WIDTH; + const int pad_h = LCD_HEIGHT; + const int box_h = pad_h - SYSFONT_HEIGHT*5; + const int box_w = pad_w * box_h / pad_h; + const int box_x = (LCD_WIDTH - box_w) / 2; + const int box_y = SYSFONT_HEIGHT * 9 / 2; + + /* cutoffs converted to box coordinates */ + const int ss_left_x = box_x + SCROLLSTRIP_LEFT_X * box_w / pad_w; + const int ss_top_y = box_y + SCROLLSTRIP_TOP_Y * box_h / pad_h; + const int ss_bot_y = box_y + SCROLLSTRIP_BOT_Y * box_h / pad_h; + const int menubtn_y = box_y + MENUBUTTON_Y * box_h / pad_h; + const int leftbtn_y = box_y + LEFTBUTTON_Y * box_h / pad_h; + + bool draw_areas = true; + bool draw_border = true; + do { int line = 0; lcd_clear_display(); @@ -496,6 +493,26 @@ bool dbg_fiiom3k_touchpad(void) lcd_putsf(0, line++, "button: %08x", fsm.buttons); lcd_putsf(0, line++, "pos x: %4d orig x: %4d", fsm.cur_x, fsm.orig_x); lcd_putsf(0, line++, "pos y: %4d orig y: %4d", fsm.cur_y, fsm.orig_y); + + /* draw touchpad box borders */ + if(draw_border) + lcd_drawrect(box_x, box_y, box_w, box_h); + + /* draw crosshair */ + int tx = box_x + fsm.cur_x * box_w / pad_w; + int ty = box_y + fsm.cur_y * box_h / pad_h; + lcd_hline(tx-2, tx+2, ty); + lcd_vline(tx, ty-2, ty+2); + + /* draw the button areas */ + if(draw_areas) { + lcd_vline(ss_left_x, box_y, box_y+box_h); + lcd_hline(ss_left_x, box_x+box_w, ss_top_y); + lcd_hline(ss_left_x, box_x+box_w, ss_bot_y); + lcd_hline(box_x, ss_left_x, menubtn_y); + lcd_hline(box_x, ss_left_x, leftbtn_y); + } + lcd_update(); } while(getbtn() != BUTTON_POWER); return false; |