[WIP] Voice IND
[osmocom-bb.git] / src / target / firmware / calypso / keypad.c
1 /* Driver for the keypad attached to the TI Calypso */
2
3 /* (C) 2010 by roh <roh@hyte.de>
4  *
5  * All Rights Reserved
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License along
18  * with this program; if not, write to the Free Software Foundation, Inc.,
19  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20  *
21  */
22
23 #include <stdint.h>
24 #include <stdio.h>
25
26 #include <defines.h>
27 #include <debug.h>
28 #include <delay.h>
29 #include <memory.h>
30 #include <keypad.h>
31
32 #include <calypso/irq.h>
33 #include <abb/twl3025.h>
34
35
36 #define KBR_LATCH_REG   0xfffe480a
37 #define KBC_REG         0xfffe480c
38 #define KBD_GPIO_INT    0xfffe4816
39 #define KBD_GPIO_MASKIT 0xfffe4818
40
41 static key_handler_t key_handler = NULL;
42
43 void emit_key(uint8_t key, uint8_t state)
44 {
45         printf("key=%u %s\n", key, state == PRESSED ? "pressed" : "released");
46
47         if (state == RELEASED)
48                 if (key == KEY_POWER)
49                         twl3025_power_off();
50
51         if(key_handler) {
52                 key_handler(key, state);
53         }
54 }
55
56 volatile uint32_t lastbuttons = 0;
57
58 #define BTN_TO_KEY(name) \
59         ((diff & BTN_##name) == BTN_##name)     \
60         {                                       \
61                 key = KEY_##name;               \
62                 diff = diff & ~BTN_##name;      \
63                 state = (buttons & BTN_##name) ? PRESSED : RELEASED;    \
64         }
65
66 void dispatch_buttons(uint32_t buttons)
67 {
68         uint8_t state;
69
70         if (buttons == lastbuttons)
71                 return;
72
73         uint32_t diff = buttons ^ lastbuttons;
74         uint8_t key=KEY_INV;
75
76         while (diff != 0)
77         {
78                 if BTN_TO_KEY(POWER)
79                 else if BTN_TO_KEY(0)
80                 else if BTN_TO_KEY(1)
81                 else if BTN_TO_KEY(2)
82                 else if BTN_TO_KEY(3)
83                 else if BTN_TO_KEY(4)
84                 else if BTN_TO_KEY(5)
85                 else if BTN_TO_KEY(6)
86                 else if BTN_TO_KEY(7)
87                 else if BTN_TO_KEY(8)
88                 else if BTN_TO_KEY(9)
89                 else if BTN_TO_KEY(STAR)
90                 else if BTN_TO_KEY(HASH)
91                 else if BTN_TO_KEY(MENU)
92                 else if BTN_TO_KEY(LEFT_SB)
93                 else if BTN_TO_KEY(RIGHT_SB)
94                 else if BTN_TO_KEY(UP)
95                 else if BTN_TO_KEY(DOWN)
96                 else if BTN_TO_KEY(LEFT)
97                 else if BTN_TO_KEY(RIGHT)
98                 else if BTN_TO_KEY(OK)
99                 else
100                 {
101                         printf("\nunknown keycode: 0x%08x\n", diff);
102                         break;
103                 }
104                 emit_key(key, state);
105         }
106         lastbuttons = buttons;
107 }
108
109 static uint8_t  polling = 0;
110 static uint8_t  with_interrupts = 0;
111
112 static void keypad_irq(__unused enum irq_nr nr)
113 {
114         /* enable polling */
115         polling = 1;
116         irq_disable(IRQ_KEYPAD_GPIO);
117 }
118
119 void keypad_init(uint8_t interrupts)
120 {
121         lastbuttons = 0;
122         polling = 0;
123         writew(0, KBD_GPIO_MASKIT);
124         writew(0, KBC_REG);
125
126         if(interrupts) {
127                 with_interrupts = 1;
128                 irq_register_handler(IRQ_KEYPAD_GPIO, &keypad_irq);
129                 irq_config(IRQ_KEYPAD_GPIO, 0, 0, 0);
130                 irq_enable(IRQ_KEYPAD_GPIO);
131         }
132 }
133
134 void keypad_set_handler(key_handler_t handler)
135 {
136         key_handler = handler;
137 }
138
139 void keypad_poll()
140 {
141         static uint16_t reg;
142         static uint16_t col;
143         static uint32_t buttons = 0, debounce1 = 0, debounce2 = 0;
144
145         if (with_interrupts && !polling)
146                 return;
147
148         /* start polling */
149         if (polling == 1) {
150                 writew(0x1f & ~0x1, KBC_REG); /* first col */
151                 col = 0;
152                 polling = 2;
153                 return;
154         }
155
156         /* enable keypad irq after the signal settles */
157         if (polling == 3) {
158                 if(with_interrupts) {
159                         irq_enable(IRQ_KEYPAD_GPIO);
160                         polling = 0;
161                 } else {
162                         polling = 1;
163                 }
164                 return;
165         }
166
167         reg = readw(KBR_LATCH_REG);
168         buttons = (buttons & ~(0x1f << (col * 5)))
169                 | ((~reg & 0x1f) << (col * 5 ));
170         /* if key is released, stay in column for faster debounce */
171         if ((debounce1 | debounce2) & ~buttons) {
172                 debounce2 = debounce1;
173                 debounce1 = buttons;
174                 return;
175         }
176
177         col++;
178         if (col > 4) {
179                 col = 0;
180                 /* if power button, ignore other states */
181                 if (buttons & BTN_POWER)
182                         buttons = lastbuttons | BTN_POWER;
183                 else if (lastbuttons & BTN_POWER)
184                         buttons = lastbuttons & ~BTN_POWER;
185                 dispatch_buttons(buttons);
186                 if (buttons == 0) {
187                         writew(0x0, KBC_REG);
188                         polling = 3;
189                         return;
190                 }
191         }
192         if (col == 4)
193                 writew(0xff, KBC_REG);
194         else
195                 writew(0x1f & ~(0x1 << col ), KBC_REG);
196
197 }
198