diff options
author | Amaury Pouly <amaury.pouly@gmail.com> | 2012-05-19 13:42:49 +0200 |
---|---|---|
committer | Amaury Pouly <amaury.pouly@gmail.com> | 2012-05-19 16:10:52 +0200 |
commit | 85d5c19347c1665b765708cdb67f1d996c7f7fa4 (patch) | |
tree | 14cc20dbd694e408ece18c7d9788c2a74cef042e /firmware/target/arm/imx233/touchscreen-imx233.c | |
parent | 247e611f4945d048f280471d78b7b83a96b35454 (diff) | |
download | rockbox-85d5c19347c1665b765708cdb67f1d996c7f7fa4.tar.gz rockbox-85d5c19347c1665b765708cdb67f1d996c7f7fa4.tar.bz2 rockbox-85d5c19347c1665b765708cdb67f1d996c7f7fa4.zip |
imx233: add touchscreen driver
Change-Id: I406076d110e33cdae871222191d82262fabcf16a
Diffstat (limited to 'firmware/target/arm/imx233/touchscreen-imx233.c')
-rw-r--r-- | firmware/target/arm/imx233/touchscreen-imx233.c | 193 |
1 files changed, 193 insertions, 0 deletions
diff --git a/firmware/target/arm/imx233/touchscreen-imx233.c b/firmware/target/arm/imx233/touchscreen-imx233.c new file mode 100644 index 0000000000..f8cbf76896 --- /dev/null +++ b/firmware/target/arm/imx233/touchscreen-imx233.c @@ -0,0 +1,193 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2012 by Amaury Pouly + * + * Based on Rockbox iriver bootloader by Linus Nielsen Feltzing + * and the ipodlinux bootloader by Daniel Palffy and Bernard Leach + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ +#include "touchscreen-imx233.h" +#include "stdlib.h" + +/* Description: + * the driver basically has 2 modes: + * - wait mode: use the hardware touch detect mechanism to wait for an edge + * - measurement mode: use pull up/down and adc to measure X/Y + * In measurement mode, we start by measuring X then Y then we check if + * the hardware still detect a touch. When no touch is detected anymore, we + * go back to wait mode. + * For each axis, we handle stabilization by repeatedly measuring the position + * until it is stable. We consider a set of measures stable when + * no measure is further away from the average than DEBOUNCE_THRESHOLD and + * we have at least SAMPLES_THRESHOLD measures. This avoids using magic + * timing constants specific to the touchscreen stabilization time and + * it is much more robust. + * + * Inspired by linux touchscreen driver for the stmp37xx. + */ + +enum touch_state_t +{ + TOUCH_STATE_WAIT, /* wait for touch */ + TOUCH_STATE_MEASURE_X, /* measure x */ + TOUCH_STATE_MEASURE_Y, /* measure y */ + TOUCH_STATE_VERIFY, /* verify touch */ +}; + +#define DEBOUNCE_THRESHOLD 100 +#define SAMPLES_THRESHOLD 4 + +static enum touch_state_t touch_state; +static int touch_chan = -1; +static int touch_delay = -1; +static int touch_x, touch_y, nr_samples; +/* once a touch is confirmed, the parameters are copied to these value for + * instant readout by button code. */ +static bool old_touch_detect = false; +static int old_touch_x, old_touch_y; + +static void kick_measure(bool pull_x, bool pull_y, bool detect, int lradc_phys) +{ + /* setup measurement: x- pull down and x+ pull up */ + imx233_lradc_setup_touch(pull_x, pull_y, pull_x, pull_y, detect); + imx233_lradc_enable_touch_detect_irq(false); + imx233_lradc_enable_channel_irq(touch_chan, true); + /* measure channel, no accumulation */ + imx233_lradc_setup_channel(touch_chan, false, false, 0, lradc_phys); + /* use a delay */ + imx233_lradc_setup_delay(touch_delay, 1 << touch_chan, 0, 0, 8); + imx233_lradc_kick_delay(touch_delay); +} + +static void enter_state(enum touch_state_t state) +{ + touch_state = state; + switch(state) + { + case TOUCH_STATE_WAIT: + imx233_lradc_setup_touch(false, false, false, false, true); + imx233_lradc_enable_channel_irq(touch_chan, false); + imx233_lradc_enable_touch_detect_irq(true); + break; + case TOUCH_STATE_MEASURE_X: + kick_measure(true, false, false, HW_LRADC_CHANNEL_YPLUS); + break; + case TOUCH_STATE_MEASURE_Y: + kick_measure(false, true, false, HW_LRADC_CHANNEL_XPLUS); + break; + case TOUCH_STATE_VERIFY: + kick_measure(false, false, true, HW_LRADC_CHANNEL_YPLUS); + break; + } +} + +static void process(void) +{ + int val; + switch(touch_state) + { + case TOUCH_STATE_WAIT: + /* a touch has happened, check if it's still valid */ + if(imx233_lradc_read_touch_detect()) + enter_state(TOUCH_STATE_MEASURE_X); + else + { + old_touch_detect = false; + /* clear detect interrupt */ + imx233_lradc_clear_touch_detect_irq(); + } + break; + case TOUCH_STATE_MEASURE_X: + /* read value */ + val = imx233_lradc_read_channel(touch_chan); + /* if value is too far from average, restart */ + if(nr_samples > 0 && abs(val - touch_x) > DEBOUNCE_THRESHOLD) + nr_samples = 0; + touch_x = (touch_x * nr_samples + val) / (nr_samples + 1); + nr_samples++; + /* if we have enough samples, measure Y */ + if(nr_samples > SAMPLES_THRESHOLD) + enter_state(TOUCH_STATE_MEASURE_Y); + else + imx233_lradc_kick_delay(touch_delay); + break; + case TOUCH_STATE_MEASURE_Y: + /* read value */ + val = imx233_lradc_read_channel(touch_chan); + /* if value is too far from average, restart */ + if(nr_samples > 0 && abs(val - touch_y) > DEBOUNCE_THRESHOLD) + nr_samples = 0; + touch_y = (touch_y * nr_samples + val) / (nr_samples + 1); + nr_samples++; + /* if we have enough samples, verify touch */ + if(nr_samples > SAMPLES_THRESHOLD) + enter_state(TOUCH_STATE_VERIFY); + else + imx233_lradc_kick_delay(touch_delay); + break; + case TOUCH_STATE_VERIFY: + if(imx233_lradc_read_touch_detect()) + { + old_touch_detect = true; + old_touch_x = touch_x; + old_touch_y = touch_y; + enter_state(TOUCH_STATE_MEASURE_X); + } + else + { + old_touch_detect = false; + enter_state(TOUCH_STATE_WAIT); + } + break; + } +} + +void INT_TOUCH_DETECT(void) +{ + process(); +} + +static void touch_channel_irq(int chan) +{ + (void) chan; + process(); +} + +void imx233_touchscreen_init(void) +{ + touch_chan = imx233_lradc_acquire_channel(TIMEOUT_NOBLOCK); + touch_delay = imx233_lradc_acquire_delay(TIMEOUT_NOBLOCK); + if(touch_chan < 0 || touch_delay < 0) + panicf("Cannot acquire channel and delays for touchscreen measurement"); + imx233_touchscreen_enable(false); +} + +void imx233_touchscreen_enable(bool enable) +{ + enter_state(TOUCH_STATE_WAIT); + imx233_lradc_set_channel_irq_callback(touch_chan, &touch_channel_irq); + imx233_icoll_enable_interrupt(INT_SRC_LRADC_CHx(touch_chan), enable); + imx233_icoll_enable_interrupt(INT_SRC_TOUCH_DETECT, enable); +} + +bool imx233_touchscreen_get_touch(int *raw_x, int *raw_y) +{ + if(raw_x) *raw_x = old_touch_x; + if(raw_y) *raw_y = old_touch_y; + return old_touch_detect; +} |