diff options
author | Aidan MacDonald <amachronic@protonmail.com> | 2021-06-11 16:22:12 +0100 |
---|---|---|
committer | Aidan MacDonald <amachronic@protonmail.com> | 2021-06-11 20:09:38 +0100 |
commit | d01f3192f2a1a34d28ee701e8c397cd7f1827b88 (patch) | |
tree | a59688babe7fe4d62857a36af7c38ca2348ab7b5 /firmware/target/mips/ingenic_x1000/fiiom3k/button-fiiom3k.c | |
parent | 551c74da55dc15238e76713d7477e7e4bfda60ef (diff) | |
download | rockbox-d01f3192f2a1a34d28ee701e8c397cd7f1827b88.tar.gz rockbox-d01f3192f2a1a34d28ee701e8c397cd7f1827b88.zip |
Spin off common ft6x06 code to a driver
Allows for the i2c boilerplate to be shared between the M3K and
Shanling Q1 ports. M3K-specific quirks remain in button-fiiom3k.
Change-Id: I8879b603cefc16416bb200f1c484ca916d935c6a
Diffstat (limited to 'firmware/target/mips/ingenic_x1000/fiiom3k/button-fiiom3k.c')
-rw-r--r-- | firmware/target/mips/ingenic_x1000/fiiom3k/button-fiiom3k.c | 110 |
1 files changed, 37 insertions, 73 deletions
diff --git a/firmware/target/mips/ingenic_x1000/fiiom3k/button-fiiom3k.c b/firmware/target/mips/ingenic_x1000/fiiom3k/button-fiiom3k.c index 4a853cd88f..4354257f7b 100644 --- a/firmware/target/mips/ingenic_x1000/fiiom3k/button-fiiom3k.c +++ b/firmware/target/mips/ingenic_x1000/fiiom3k/button-fiiom3k.c | |||
@@ -25,7 +25,9 @@ | |||
25 | #include "powermgmt.h" | 25 | #include "powermgmt.h" |
26 | #include "panic.h" | 26 | #include "panic.h" |
27 | #include "axp-pmu.h" | 27 | #include "axp-pmu.h" |
28 | #include "ft6x06.h" | ||
28 | #include "gpio-x1000.h" | 29 | #include "gpio-x1000.h" |
30 | #include "irq-x1000.h" | ||
29 | #include "i2c-x1000.h" | 31 | #include "i2c-x1000.h" |
30 | #include <string.h> | 32 | #include <string.h> |
31 | #include <stdbool.h> | 33 | #include <stdbool.h> |
@@ -35,12 +37,6 @@ | |||
35 | # include "font.h" | 37 | # include "font.h" |
36 | #endif | 38 | #endif |
37 | 39 | ||
38 | /* Touch event types */ | ||
39 | #define EVENT_NONE (-1) | ||
40 | #define EVENT_PRESS 0 | ||
41 | #define EVENT_RELEASE 1 | ||
42 | #define EVENT_CONTACT 2 | ||
43 | |||
44 | /* FSM states */ | 40 | /* FSM states */ |
45 | #define STATE_IDLE 0 | 41 | #define STATE_IDLE 0 |
46 | #define STATE_PRESS 1 | 42 | #define STATE_PRESS 1 |
@@ -66,17 +62,6 @@ | |||
66 | /* Number of touch samples to smooth before reading */ | 62 | /* Number of touch samples to smooth before reading */ |
67 | #define TOUCH_SAMPLES 3 | 63 | #define TOUCH_SAMPLES 3 |
68 | 64 | ||
69 | static struct ft_driver { | ||
70 | int i2c_cookie; | ||
71 | i2c_descriptor i2c_desc; | ||
72 | uint8_t raw_data[6]; | ||
73 | bool active; | ||
74 | |||
75 | /* Number of pixels squared which must be moved before | ||
76 | * a scrollbar pulse is generated */ | ||
77 | int scroll_thresh_sqr; | ||
78 | } ftd; | ||
79 | |||
80 | static struct ft_state_machine { | 65 | static struct ft_state_machine { |
81 | /* Current button state, used by button_read_device() */ | 66 | /* Current button state, used by button_read_device() */ |
82 | int buttons; | 67 | int buttons; |
@@ -105,6 +90,12 @@ static struct ft_state_machine { | |||
105 | 90 | ||
106 | /* Current touch position */ | 91 | /* Current touch position */ |
107 | int cur_x, cur_y; | 92 | int cur_x, cur_y; |
93 | |||
94 | /* Motion threshold squared, in 'pixels', required to trigger scrolling */ | ||
95 | int scroll_thresh_sqr; | ||
96 | |||
97 | /* Touchpad enabled state */ | ||
98 | bool active; | ||
108 | } fsm; | 99 | } fsm; |
109 | 100 | ||
110 | /* coordinates below this are the left hand buttons, | 101 | /* coordinates below this are the left hand buttons, |
@@ -210,9 +201,9 @@ static void ft_start_report_or_scroll(void) | |||
210 | static void ft_step_state(uint32_t t, int evt, int tx, int ty) | 201 | static void ft_step_state(uint32_t t, int evt, int tx, int ty) |
211 | { | 202 | { |
212 | /* Generate a release event automatically in case we missed it */ | 203 | /* Generate a release event automatically in case we missed it */ |
213 | if(evt == EVENT_NONE) { | 204 | if(evt == FT6x06_EVT_NONE) { |
214 | if(TICKS_SINCE(t, fsm.last_event_t) >= AUTORELEASE_TIME) { | 205 | if(TICKS_SINCE(t, fsm.last_event_t) >= AUTORELEASE_TIME) { |
215 | evt = EVENT_RELEASE; | 206 | evt = FT6x06_EVT_RELEASE; |
216 | tx = fsm.cur_x; | 207 | tx = fsm.cur_x; |
217 | ty = fsm.cur_y; | 208 | ty = fsm.cur_y; |
218 | } | 209 | } |
@@ -220,7 +211,7 @@ static void ft_step_state(uint32_t t, int evt, int tx, int ty) | |||
220 | 211 | ||
221 | switch(fsm.state) { | 212 | switch(fsm.state) { |
222 | case STATE_IDLE: { | 213 | case STATE_IDLE: { |
223 | if(evt == EVENT_PRESS || evt == EVENT_CONTACT) { | 214 | if(evt == FT6x06_EVT_PRESS || evt == FT6x06_EVT_CONTACT) { |
224 | /* Move to REPORT or PRESS state */ | 215 | /* Move to REPORT or PRESS state */ |
225 | if(ft_accum_touch(t, tx, ty)) | 216 | if(ft_accum_touch(t, tx, ty)) |
226 | ft_start_report_or_scroll(); | 217 | ft_start_report_or_scroll(); |
@@ -230,10 +221,10 @@ static void ft_step_state(uint32_t t, int evt, int tx, int ty) | |||
230 | } break; | 221 | } break; |
231 | 222 | ||
232 | case STATE_PRESS: { | 223 | case STATE_PRESS: { |
233 | if(evt == EVENT_RELEASE) { | 224 | if(evt == FT6x06_EVT_RELEASE) { |
234 | /* Ignore if the number of samples is too low */ | 225 | /* Ignore if the number of samples is too low */ |
235 | ft_go_idle(); | 226 | ft_go_idle(); |
236 | } else if(evt == EVENT_PRESS || evt == EVENT_CONTACT) { | 227 | } else if(evt == FT6x06_EVT_PRESS || evt == FT6x06_EVT_CONTACT) { |
237 | /* Accumulate the touch position in the filter */ | 228 | /* Accumulate the touch position in the filter */ |
238 | if(ft_accum_touch(t, tx, ty)) | 229 | if(ft_accum_touch(t, tx, ty)) |
239 | ft_start_report_or_scroll(); | 230 | ft_start_report_or_scroll(); |
@@ -241,14 +232,14 @@ static void ft_step_state(uint32_t t, int evt, int tx, int ty) | |||
241 | } break; | 232 | } break; |
242 | 233 | ||
243 | case STATE_REPORT: { | 234 | case STATE_REPORT: { |
244 | if(evt == EVENT_RELEASE) | 235 | if(evt == FT6x06_EVT_RELEASE) |
245 | ft_go_idle(); | 236 | ft_go_idle(); |
246 | else if(evt == EVENT_PRESS || evt == EVENT_CONTACT) | 237 | else if(evt == FT6x06_EVT_PRESS || evt == FT6x06_EVT_CONTACT) |
247 | ft_accum_touch(t, tx, ty); | 238 | ft_accum_touch(t, tx, ty); |
248 | } break; | 239 | } break; |
249 | 240 | ||
250 | case STATE_SCROLL_PRESS: { | 241 | case STATE_SCROLL_PRESS: { |
251 | if(evt == EVENT_RELEASE) { | 242 | if(evt == FT6x06_EVT_RELEASE) { |
252 | /* This _should_ synthesize a button press. | 243 | /* This _should_ synthesize a button press. |
253 | * | 244 | * |
254 | * - ft_start_report() will set the button bit based on the | 245 | * - ft_start_report() will set the button bit based on the |
@@ -257,10 +248,10 @@ static void ft_step_state(uint32_t t, int evt, int tx, int ty) | |||
257 | * | 248 | * |
258 | * - The next button_read_device() will see the button bit | 249 | * - The next button_read_device() will see the button bit |
259 | * and report it back to Rockbox, then step the FSM with | 250 | * and report it back to Rockbox, then step the FSM with |
260 | * EVENT_NONE. | 251 | * FT6x06_EVT_NONE. |
261 | * | 252 | * |
262 | * - The EVENT_NONE stepping will eventually autogenerate a | 253 | * - The FT6x06_EVT_NONE stepping will eventually autogenerate |
263 | * RELEASE event and restore the button state back to 0 | 254 | * a RELEASE event and restore the button state back to 0 |
264 | * | 255 | * |
265 | * - There's a small logic hole in the REPORT state which | 256 | * - There's a small logic hole in the REPORT state which |
266 | * could cause it to miss an immediately repeated PRESS | 257 | * could cause it to miss an immediately repeated PRESS |
@@ -271,7 +262,7 @@ static void ft_step_state(uint32_t t, int evt, int tx, int ty) | |||
271 | break; | 262 | break; |
272 | } | 263 | } |
273 | 264 | ||
274 | if(evt == EVENT_PRESS || evt == EVENT_CONTACT) | 265 | if(evt == FT6x06_EVT_PRESS || evt == FT6x06_EVT_CONTACT) |
275 | ft_accum_touch(t, tx, ty); | 266 | ft_accum_touch(t, tx, ty); |
276 | 267 | ||
277 | int dx = fsm.cur_x - fsm.orig_x; | 268 | int dx = fsm.cur_x - fsm.orig_x; |
@@ -289,21 +280,21 @@ static void ft_step_state(uint32_t t, int evt, int tx, int ty) | |||
289 | } break; | 280 | } break; |
290 | 281 | ||
291 | case STATE_SCROLLING: { | 282 | case STATE_SCROLLING: { |
292 | if(evt == EVENT_RELEASE) { | 283 | if(evt == FT6x06_EVT_RELEASE) { |
293 | ft_go_idle(); | 284 | ft_go_idle(); |
294 | break; | 285 | break; |
295 | } | 286 | } |
296 | 287 | ||
297 | if(evt == EVENT_PRESS || evt == EVENT_CONTACT) | 288 | if(evt == FT6x06_EVT_PRESS || evt == FT6x06_EVT_CONTACT) |
298 | ft_accum_touch(t, tx, ty); | 289 | ft_accum_touch(t, tx, ty); |
299 | 290 | ||
300 | int dx = fsm.cur_x - fsm.orig_x; | 291 | int dx = fsm.cur_x - fsm.orig_x; |
301 | int dy = fsm.cur_y - fsm.orig_y; | 292 | int dy = fsm.cur_y - fsm.orig_y; |
302 | int dp = (dx*dx) + (dy*dy); | 293 | int dp = (dx*dx) + (dy*dy); |
303 | if(dp >= ftd.scroll_thresh_sqr) { | 294 | if(dp >= fsm.scroll_thresh_sqr) { |
304 | /* avoid generating events if we're supposed to be inactive... | 295 | /* avoid generating events if we're supposed to be inactive... |
305 | * should not be necessary but better to be safe. */ | 296 | * should not be necessary but better to be safe. */ |
306 | if(ftd.active) { | 297 | if(fsm.active) { |
307 | if(dy < 0) { | 298 | if(dy < 0) { |
308 | queue_post(&button_queue, BUTTON_SCROLL_BACK, 0); | 299 | queue_post(&button_queue, BUTTON_SCROLL_BACK, 0); |
309 | } else { | 300 | } else { |
@@ -327,18 +318,8 @@ static void ft_step_state(uint32_t t, int evt, int tx, int ty) | |||
327 | } | 318 | } |
328 | } | 319 | } |
329 | 320 | ||
330 | static void ft_i2c_callback(int status, i2c_descriptor* desc) | 321 | static void ft_event_cb(int evt, int tx, int ty) |
331 | { | 322 | { |
332 | (void)desc; | ||
333 | if(status != I2C_STATUS_OK) | ||
334 | return; | ||
335 | |||
336 | /* The panel is oriented such that its X axis is vertical, | ||
337 | * so swap the axes for reporting */ | ||
338 | int evt = ftd.raw_data[1] >> 6; | ||
339 | int ty = ftd.raw_data[2] | ((ftd.raw_data[1] & 0xf) << 8); | ||
340 | int tx = ftd.raw_data[4] | ((ftd.raw_data[3] & 0xf) << 8); | ||
341 | |||
342 | /* TODO: convert the touch positions to linear positions. | 323 | /* TODO: convert the touch positions to linear positions. |
343 | * | 324 | * |
344 | * Points reported by the touch controller are distorted and non-linear, | 325 | * Points reported by the touch controller are distorted and non-linear, |
@@ -346,36 +327,11 @@ static void ft_i2c_callback(int status, i2c_descriptor* desc) | |||
346 | * the middle of the touchpad than on the edges, so scrolling feels slow | 327 | * the middle of the touchpad than on the edges, so scrolling feels slow |
347 | * in the middle and faster near the edge. | 328 | * in the middle and faster near the edge. |
348 | */ | 329 | */ |
349 | |||
350 | ft_step_state(__ost_read32(), evt, tx, ty); | 330 | ft_step_state(__ost_read32(), evt, tx, ty); |
351 | } | 331 | } |
352 | 332 | ||
353 | /* ft6x06 interrupt pin */ | ||
354 | void GPIOB12(void) | ||
355 | { | ||
356 | /* We don't care if this fails */ | ||
357 | i2c_async_queue(FT6x06_BUS, TIMEOUT_NOBLOCK, I2C_Q_ONCE, | ||
358 | ftd.i2c_cookie, &ftd.i2c_desc); | ||
359 | } | ||
360 | |||
361 | static void ft_init(void) | 333 | static void ft_init(void) |
362 | { | 334 | { |
363 | /* Initialize the driver state */ | ||
364 | ftd.i2c_cookie = i2c_async_reserve_cookies(FT6x06_BUS, 1); | ||
365 | ftd.i2c_desc.slave_addr = FT6x06_ADDR; | ||
366 | ftd.i2c_desc.bus_cond = I2C_START | I2C_STOP; | ||
367 | ftd.i2c_desc.tran_mode = I2C_READ; | ||
368 | ftd.i2c_desc.buffer[0] = &ftd.raw_data[5]; | ||
369 | ftd.i2c_desc.count[0] = 1; | ||
370 | ftd.i2c_desc.buffer[1] = &ftd.raw_data[0]; | ||
371 | ftd.i2c_desc.count[1] = 5; | ||
372 | ftd.i2c_desc.callback = ft_i2c_callback; | ||
373 | ftd.i2c_desc.arg = 0; | ||
374 | ftd.i2c_desc.next = NULL; | ||
375 | ftd.raw_data[5] = 0x02; | ||
376 | ftd.active = true; | ||
377 | touchpad_set_sensitivity(DEFAULT_TOUCHPAD_SENSITIVITY_SETTING); | ||
378 | |||
379 | /* Initialize the state machine */ | 335 | /* Initialize the state machine */ |
380 | fsm.buttons = 0; | 336 | fsm.buttons = 0; |
381 | fsm.state = STATE_IDLE; | 337 | fsm.state = STATE_IDLE; |
@@ -385,16 +341,24 @@ static void ft_init(void) | |||
385 | fsm.sum_x = fsm.sum_y = 0; | 341 | fsm.sum_x = fsm.sum_y = 0; |
386 | fsm.orig_x = fsm.orig_y = 0; | 342 | fsm.orig_x = fsm.orig_y = 0; |
387 | fsm.cur_x = fsm.cur_y = 0; | 343 | fsm.cur_x = fsm.cur_y = 0; |
344 | fsm.active = true; | ||
345 | touchpad_set_sensitivity(DEFAULT_TOUCHPAD_SENSITIVITY_SETTING); | ||
388 | 346 | ||
389 | /* Bring up I2C bus */ | 347 | /* Bring up I2C bus */ |
390 | i2c_x1000_set_freq(FT6x06_BUS, I2C_FREQ_400K); | 348 | i2c_x1000_set_freq(FT6x06_BUS, I2C_FREQ_400K); |
391 | 349 | ||
350 | /* Driver init */ | ||
351 | ft6x06_init(); | ||
352 | ft6x06_set_event_cb(ft_event_cb); | ||
353 | |||
392 | /* Reset chip */ | 354 | /* Reset chip */ |
393 | gpio_set_level(GPIO_FT6x06_RESET, 0); | 355 | gpio_set_level(GPIO_FT6x06_RESET, 0); |
394 | mdelay(5); | 356 | mdelay(5); |
395 | gpio_set_level(GPIO_FT6x06_RESET, 1); | 357 | gpio_set_level(GPIO_FT6x06_RESET, 1); |
396 | 358 | ||
397 | /* Configure the interrupt pin */ | 359 | /* Configure the interrupt pin */ |
360 | system_set_irq_handler(GPIO_TO_IRQ(GPIO_FT6x06_INTERRUPT), | ||
361 | ft6x06_irq_handler); | ||
398 | gpio_set_function(GPIO_FT6x06_INTERRUPT, GPIOF_IRQ_EDGE(0)); | 362 | gpio_set_function(GPIO_FT6x06_INTERRUPT, GPIOF_IRQ_EDGE(0)); |
399 | gpio_enable_irq(GPIO_FT6x06_INTERRUPT); | 363 | gpio_enable_irq(GPIO_FT6x06_INTERRUPT); |
400 | } | 364 | } |
@@ -403,13 +367,13 @@ void touchpad_set_sensitivity(int level) | |||
403 | { | 367 | { |
404 | int pixels = 40; | 368 | int pixels = 40; |
405 | pixels -= level; | 369 | pixels -= level; |
406 | ftd.scroll_thresh_sqr = pixels * pixels; | 370 | fsm.scroll_thresh_sqr = pixels * pixels; |
407 | } | 371 | } |
408 | 372 | ||
409 | void touchpad_enable_device(bool en) | 373 | void touchpad_enable_device(bool en) |
410 | { | 374 | { |
411 | i2c_reg_write1(FT6x06_BUS, FT6x06_ADDR, 0xa5, en ? 0 : 3); | 375 | ft6x06_enable(en); |
412 | ftd.active = en; | 376 | fsm.active = en; |
413 | } | 377 | } |
414 | 378 | ||
415 | /* Value of headphone detect register */ | 379 | /* Value of headphone detect register */ |
@@ -467,7 +431,7 @@ void button_init_device(void) | |||
467 | int button_read_device(void) | 431 | int button_read_device(void) |
468 | { | 432 | { |
469 | int r = fsm.buttons; | 433 | int r = fsm.buttons; |
470 | ft_step_state(__ost_read32(), EVENT_NONE, 0, 0); | 434 | ft_step_state(__ost_read32(), FT6x06_EVT_NONE, 0, 0); |
471 | 435 | ||
472 | /* Read GPIOs for physical buttons */ | 436 | /* Read GPIOs for physical buttons */ |
473 | uint32_t a = REG_GPIO_PIN(GPIO_A); | 437 | uint32_t a = REG_GPIO_PIN(GPIO_A); |