summaryrefslogtreecommitdiffstats
path: root/firmware/target/mips/ingenic_x1000/fiiom3k/button-fiiom3k.c
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/target/mips/ingenic_x1000/fiiom3k/button-fiiom3k.c')
-rw-r--r--firmware/target/mips/ingenic_x1000/fiiom3k/button-fiiom3k.c235
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;