summaryrefslogtreecommitdiffstats
path: root/firmware/target/arm/imx233/button-imx233.h
blob: 9e244e01ac12e06a27127a990777539aa453aba3 (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
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
/***************************************************************************
 *             __________               __   ___.
 *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
 *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
 *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
 *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
 *                     \/            \/     \/    \/            \/
 * $Id$
 *
 * Copyright (C) 2014 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.
 *
 ****************************************************************************/
#ifndef __button_imx233__
#define __button_imx233__

#include "button.h"
#include "button-target.h"
#include "lradc-imx233.h"
#include "pinctrl-imx233.h"
#include "power-imx233.h"

/* special values for .btn field */
#define IMX233_BUTTON_END   -1 /* end of the list */
#define IMX233_BUTTON_HOLD  -2 /* HOLD button */
#define IMX233_BUTTON_JACK  -3 /* JACK detect */
#define IMX233_BUTTON_VDDIO -4 /* VDDIO value */

/* values for .periph field */
#define IMX233_BUTTON_GPIO      0 /* GPIO pin */
#define IMX233_BUTTON_LRADC     1 /* LRADC channel */
#define IMX233_BUTTON_PSWITCH   2 /* PSWITCH */

/* values for the .flags field */
#define IMX233_BUTTON_INVERTED  (1 << 0) /* invert button detection */
#define IMX233_BUTTON_PULLUP    (1 << 1) /* pin needs a pullup (GPIO) */

/* values for the .op field */
#define IMX233_BUTTON_EQ    0 /* channel is equal to value up to error margin */
#define IMX233_BUTTON_GT    1 /* channel is greater than value */
#define IMX233_BUTTON_LT    2 /* channel is less than value */

/** target-defined
 * NOTE for proper operation:
 * - the table must end which a dummy entry of type IMX233_BUTTON_END
 * - default is active: high for GPIO, around value for LRADC, exact value for PSWITCH
 * - inverted flags reverses the above behaviour
 * - if lradc channel is relative, the .relative field specify a entry in the
 *   button table to which it is relative. This entry must have <0 .btn value
 *   and be of type LRADC. For example, if a channel is VDDIO relative, set
 *   .relative to IMX233_BUTTON_VDDIO and create an entry which .btn set to
 *   IMX233_BUTTON_VDDIO, channel set to VDDIO source and value set to the ideal values
 *   for which no correction is necessary. Note that the IMX233_BUTTON_VDDIO value is 
 *   defined for convenience */
struct imx233_button_map_t
{
    int btn; /* target button or magic value (END, HOLD, JACK) */
    int periph; /* GPIO, LRADC, or PSWITCH, ... */
    union
    {
        struct
        {
            int bank;
            int pin;
        }gpio;
        struct
        {
            int src; /* source channel */
            int value; /* comparison value */
            int op; /* comparison operation */
            int margin; /* error margin for equal operation (0 means default) */
            int relative; /* button to which it is relative or -1 if none */
        }lradc;
        struct
        {
            int level; /* value of the PSWITCH field: low, mid, high */
        }pswitch;
    }u;
    int flags; /* flags */
    const char *name; /* name of the button */
    /** private fields */
    bool last_val; /* last interpreted value */
    int rounds; /* how many rounds it survived (debouncing) */
    int threshold; /* round threshold for acceptance */
};

/* macros for the common cases (see below for explanation) */

#define IMX233_BUTTON_PATH_GPIO(bank_, pin_) .periph = IMX233_BUTTON_GPIO, \
    .u = {.gpio = {.bank = bank_, .pin = pin_}}
#define IMX233_BUTTON_PATH_LRADC_EX(src_, op_, val_, rel_, margin_) .periph = IMX233_BUTTON_LRADC, \
    .u = {.lradc = {.src = src_, .value = val_, .relative = rel_, .margin = margin_, \
    .op = IMX233_BUTTON_##op_}}
#define IMX233_BUTTON_PATH_LRADC_REL(src_, val_, rel_) \
    IMX233_BUTTON_PATH_LRADC_EX(src_, EQ, val_, rel_, 0)
#define IMX233_BUTTON_PATH_LRADC(src_, val_) \
    IMX233_BUTTON_PATH_LRADC_REL(src_, val_, -1)
#define IMX233_BUTTON_PATH_PSWITCH(lvl_) .periph = IMX233_BUTTON_PSWITCH, \
    .u = {.pswitch = {.level = lvl_}}
#define IMX233_BUTTON_PATH_END() .periph = -1
/* special macro for VDDIO, for convenience */
#define IMX233_BUTTON_PATH_VDDIO(val_) IMX233_BUTTON_PATH_LRADC(LRADC_SRC_VDDIO, val_)

#define IMX233_BUTTON_NAMEFLAGS1(_,name_) .name = name_
#define IMX233_BUTTON_NAMEFLAGS2(_,name_,f1)  .name = name_, .flags = IMX233_BUTTON_##f1
#define IMX233_BUTTON_NAMEFLAGS3(_,name_,f1,f2)   .name = name_, \
    .flags = IMX233_BUTTON_##f1 | IMX233_BUTTON_##f2
#define IMX233_BUTTON_NAMEFLAGS4(_,name_,f1,f2,f3)    .name = name_, \
    .flags = IMX233_BUTTON_##f1 | IMX233_BUTTON_##f2 | IMX233_BUTTON_##f3

#define IMX233_BUTTON__(btn_, path_, ...) \
    {.btn = btn_, IMX233_BUTTON_PATH_##path_, \
     __VAR_EXPAND(IMX233_BUTTON_NAMEFLAGS, dummy, __VA_ARGS__)}
#define IMX233_BUTTON_(btn_, path_, ...) \
    IMX233_BUTTON__(IMX233_BUTTON_##btn_, path_, __VA_ARGS__)
#define IMX233_BUTTON(btn_, path_, ...) \
    IMX233_BUTTON__(BUTTON_##btn_, path_, __VA_ARGS__)

#define IMX233_BUTTON_END_() \
    {.btn = IMX233_BUTTON_END}

/**
 * This header provides macro to ease definition of buttons. There three types of
 * buttons:
 * - normal buttons: BUTTON_X -> defined using IMX233_BUTTON(X, ...)
 * - special buttons IMX233_BUTTON_X -> defined using IMX233_BUTTON_(X, ...)
 * - others: X -> defined using IMX233_BUTTON__(X, ...)
 * A definition contains three mandatory parts and a fourth optional:
 * IMX233_BUTTON(btn, path_spec, name [, flags])
 * The path_spec can be of the form:
 * - GPIO(bank, pin)
 * - LRADC(src, value)
 * - LRADC_REL(src, value, rel_idx)
 * - LRADC_EX(src, op, val, rel_idx, margin) where op must one of EQ, GT, LT
 *     and margin is the error margin for EQ (use 0 for default value). Operation
 *     EQ means the src value must match val within error margin. Operation GT
 *     (resp. LT) means src value must greater (resp. lower) than val.
 * - PSWITCH(level)
 * - END()
 * The optional flags are specified as a list, without the IMX233_BUTTON_ prefix.
 * Examples:
 * - BUTTON_POWER named "power", mapped to PSWITCH mid level, no flags:
 *   IMX233_BUTTON(POWER, PSWICTH(1), "power")
 * - IMX233_BUTTON_JACK named "jack", mapped to GPIO B2P17 inverted and pullup:
 *   IMX233_BUTTON_(JACK, GPIO(2, 17), "jack", INVERTED, PULLUP)
 * - BIZARRE named "bizarre", mapped to LRADC channel 0, expected value 42:
 *   IMX233_BUTTON__(BIZARRE, LRADC(0, 42), "bizarre")
 * - BUTTON_PLAY named "play", mapped to LRADc channel 2, expected value 300 related
 *   to button entry IDX
 *   IMX233_BUTTON(PLAY, LRADC_REL(2, 300, IDX), "play")
 * - VDDIO entry, expected value 4000 (for relative entries):
 *   IMX233_BUTTON_(VDDIO, VDDIO(4000), "vddio")
 * - last entry:
 *   IMX233_BUTTON_(END, END(), "")
 * 
 * The driver also provides default implementations for headphones_inserted()
 * and button_hold() which can be overriden since they have weak linkage.
 *
 * The button-target.h header can also define IMX233_BUTTON_LRADC_MARGIN
 * to control the error margin allowed for button using LRADC. The default
 * margin is 30. Obviously, the margin should be less than M/2 where M is the
 * minimum LRADC value between two buttons. The margin can be overriden one a
 * per button basis using LRADC_EX.
 */

extern struct imx233_button_map_t imx233_button_map[];

/* initialise button driver */
void imx233_button_init(void);
/* others gives the bitmask of other buttons: the function will OR the result
 * with them except if hold is detected in which case 0 is always returned */
int imx233_button_read(int others);
#ifdef HAS_BUTTON_HOLD
bool imx233_button_read_hold(void);
bool button_hold(void);
#endif
#ifdef HAVE_HEADPHONE_DETECTION
bool imx233_button_read_jack(void);
bool headphones_inserted(void);
#endif
/* return interpreted button value, after processing.
 * Argument is an index into the imx233_button_map table */
bool imx233_button_read_btn(int idx);
/* return raw value for a button, before any processing: GPIO state, LRADC
 * channel value, PSWITCH value. Return -1 if there is no match.
 * Argument is an index into the imx233_button_map table */
int imx233_button_read_raw(int idx);

#endif /* __button_imx233__ */