summaryrefslogtreecommitdiffstats
path: root/firmware/target/arm/imx233/button-lradc-imx233.c
blob: 5e3b7165a6096abbb2d56d2919edc5b140f0ad48 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
/***************************************************************************
 *             __________               __   ___.
 *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
 *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
 *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
 *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
 *                     \/            \/     \/    \/            \/
 * $Id$
 *
 * Copyright (C) 2013 by Amaury Pouly
 *
 * 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 "button-lradc-imx233.h"
#include "stdlib.h"
#include "lradc-imx233.h"
#include "pinctrl-imx233.h"

#ifndef IMX233_BUTTON_LRADC_CHANNEL
# error You must define IMX233_BUTTON_LRADC_CHANNEL to use button-lradc
#endif

#if defined(HAS_BUTTON_HOLD) && !defined(IMX233_BUTTON_LRADC_HOLD_DET)
# error You must defined IMX233_BUTTON_LRADC_HOLD_DET if you use hold
#endif

#if defined(IMX233_BUTTON_LRADC_HOLD_DET) && \
    IMX233_BUTTON_LRADC_HOLD_DET == BLH_GPIO && \
    (!defined(BLH_GPIO_BANK) || !defined(BLH_GPIO_PIN))
# error You must define BLH_GPIO_BANK and BLH_GPIO_PIN when detecting hold using GPIO
#endif

/* physical channel */
#define CHAN    IMX233_BUTTON_LRADC_CHANNEL
/* number of irq per second */
#ifdef IMX233_BUTTON_LRADC_RATE
# define RATE    IMX233_BUTTON_LRADC_RATE
#else
# define RATE    HZ
#endif
/* number of samples per irq */
#ifdef IMX233_BUTTON_LRADC_SAMPLES
# define SAMPLES    IMX233_BUTTON_LRADC_SAMPLES
#else
# define SAMPLES    10
#endif
/* delay's delay */
#define DELAY   (LRADC_DELAY_FREQ / RATE / SAMPLES)

static int button_delay;
static int button_chan;
static int button_val[2];
static int button_idx;
static int button_mask;
static int table_size;
static int raw_val;

static int button_find(int val)
{
    // shortcuts
    struct imx233_button_lradc_mapping_t *table = imx233_button_lradc_mapping;
    /* FIXME use a dichotomy */
    int i = 0;
    while(i < table_size && val >= table[i].adc_val)
        i++;
    // extreme cases
    int btn = 0;
    // if i=n then choose i-1 and otherwise choose best between i-1 and i
    if(i == 0)
        btn = table[0].btn;
    else if(i == table_size)
        btn = table[i - 1].btn;
    // choose best between i-1 and i (note that table[i-1]<=val<table[i]) */
    else if(val - table[i - 1].adc_val < table[i].adc_val - val)
        btn = table[i - 1].btn;
    else
        btn = table[i].btn;
    return btn;
}

static void button_lradc_irq(int chan)
{
    (void) chan;
    /* read value, kick channel */
    raw_val = imx233_lradc_read_channel(button_chan) / SAMPLES;
    imx233_lradc_clear_channel(button_chan);
    imx233_lradc_setup_channel(button_chan, true, true, SAMPLES - 1, LRADC_SRC(CHAN));
    imx233_lradc_setup_delay(button_delay, 1 << button_chan, 0, SAMPLES - 1, DELAY);
    imx233_lradc_kick_delay(button_delay);
    /* compute mask, compare to previous one */
    button_val[button_idx] = button_find(raw_val);
    button_idx = 1 - button_idx;
    if(button_val[0] == button_val[1])
        button_mask = button_val[0];
}

void imx233_button_lradc_init(void)
{
    table_size = 0;
    while(imx233_button_lradc_mapping[table_size].btn != IMX233_BUTTON_LRADC_END)
        table_size++;

    button_chan = imx233_lradc_acquire_channel(LRADC_SRC(CHAN), TIMEOUT_NOBLOCK);
    if(button_chan < 0)
        panicf("Cannot get channel for button-lradc");
    button_delay = imx233_lradc_acquire_delay(TIMEOUT_NOBLOCK);
    if(button_delay < 0)
        panicf("Cannot get delay for button-lradc");
    imx233_lradc_setup_channel(button_chan, true, true, SAMPLES - 1, LRADC_SRC(CHAN));
    imx233_lradc_setup_delay(button_delay, 1 << button_chan, 0, SAMPLES - 1, DELAY);
    imx233_lradc_enable_channel_irq(button_chan, true);
    imx233_lradc_set_channel_irq_callback(button_chan, button_lradc_irq);
    imx233_lradc_kick_delay(button_delay);
#if defined(HAS_BUTTON_HOLD) && IMX233_BUTTON_LRADC_HOLD_DET == BLH_GPIO
    imx233_pinctrl_acquire(BLH_GPIO_BANK, BLH_GPIO_PIN, "button_lradc_hold");
    imx233_pinctrl_set_function(BLH_GPIO_BANK, BLH_GPIO_PIN, PINCTRL_FUNCTION_GPIO);
    imx233_pinctrl_enable_gpio(BLH_GPIO_BANK, BLH_GPIO_PIN, false);
# ifdef BLH_GPIO_PULLUP
    imx233_pinctrl_enable_pullup(BLH_GPIO_BANK, BLH_GPIO_PIN, true);
# endif
#endif
}

#if defined(HAS_BUTTON_HOLD) && IMX233_BUTTON_LRADC_HOLD_DET == BLH_ADC
bool imx233_button_lradc_hold(void)
{
    return button_mask == IMX233_BUTTON_LRADC_HOLD;
}
#endif


#if defined(HAS_BUTTON_HOLD) && IMX233_BUTTON_LRADC_HOLD_DET == BLH_GPIO
bool imx233_button_lradc_hold(void)
{
    bool res = imx233_pinctrl_get_gpio(BLH_GPIO_BANK, BLH_GPIO_PIN);
#ifdef BLH_GPIO_INVERTED
    res = !res;
#endif
    return res;
}
#endif

int imx233_button_lradc_read(int others)
{
#ifdef HAS_BUTTON_HOLD
    return imx233_button_lradc_hold() ? 0 : button_mask | others;
#else
    return button_mask | others;
#endif
}

int imx233_button_lradc_read_raw(void)
{
    return raw_val;
}