Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(272)

Side by Side Diff: drivers/input/tegra-kbc.c

Issue 3548006: Tegra2: input: Add tegra keyboard support. (Closed) Base URL: http://git.chromium.org/git/u-boot.git
Patch Set: Removing static variable's zero init Created 10 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« board/tegra2/seaboard/seaboard.c ('K') | « drivers/input/Makefile ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 /*
2 * (C) Copyright 2010
3 * NVIDIA Corporation <www.nvidia.com>
4 *
5 * See file CREDITS for list of people who contributed to this
6 * project.
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License as
10 * published by the Free Software Foundation; either version 2 of
11 * the License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
21 * MA 02111-1307 USA
22 */
23
24 #include <common.h>
25 #include <malloc.h>
26 #include <stdio_dev.h>
27
28 #define DEVNAME "tegra-kbc"
29
30 #define KBC_MAX_GPIO 24
31 #define KBC_MAX_KPENT 8
32 #define KBC_MAX_ROW 16
33 #define KBC_MAX_COL 8
34
35 #define KBC_MAX_KEY (KBC_MAX_ROW*KBC_MAX_COL)
36
37 #define TEGRA_KBC_BASE 0x7000E200
38
39 #define KBC_CONTROL_0 0
40 #define KBC_INT_0 4
41 #define KBC_ROW_CFG0_0 8
42 #define KBC_COL_CFG0_0 0x18
43 #define KBC_RPT_DLY_0 0x2c
44 #define KBC_KP_ENT0_0 0x30
45 #define KBC_KP_ENT1_0 0x34
46 #define KBC_ROW0_MASK_0 0x38
47
48 #define KBC_RPT_DLY 20
49 #define KBC_RPT_RATE 4
50
51 #define readl(addr) (*(volatile unsigned int *)(addr))
52 #define writel(b, addr) ((*(volatile unsigned int *) (addr)) = (b))
53 #define kbc_readl(addr) readl(TEGRA_KBC_BASE + addr)
54 #define kbc_writel(b, addr) writel(b, TEGRA_KBC_BASE + addr)
55
56 /* Define function and shift keys to untypable ASCII values */
57 #define KEY_FN 222
58 #define KEY_SHIFT 223
59
60 #ifdef CONFIG_SYS_CONSOLE_OVERWRITE_ROUTINE
61 extern int overwrite_console(void);
62 #define OVERWRITE_CONSOLE overwrite_console()
63 #else
64 #define OVERWRITE_CONSOLE 0
65 #endif /* CONFIG_SYS_CONSOLE_OVERWRITE_ROUTINE */
66
67 extern void config_kbc_pinmux(void);
68 extern void config_kbc_clock(void);
69
70 enum bool {false = 0, true = 1};
71
72 struct tegra_kbc {
73 void *mmio;
74 unsigned int repoll_time;
75 unsigned int debounce_cnt;
76 unsigned int rpt_cnt;
77 int *plain_keycode;
78 int *fn_keycode;
79 int *shift_keycode;
80 };
81
82 struct tegra_kbc *kbc;
83
84 static int plain_kbd_keycode[] = {
85 0, 0, 'w', 's', 'a', 'z', 0, KEY_FN,
86 0, 0, 0, 0, 0, 0, 0, 0,
87 0, 0, 0, 0, 0, 0, 0, 0,
88 '5', '4', 'r', 'e', 'f', 'd', 'x', 0,
89 '7', '6', 't', 'h', 'g', 'v', 'c', ' ',
90 '9', '8', 'u', 'y', 'j', 'n', 'b', '\\',
91 '-', '0', 'o', 'i', 'l', 'k', ',', 'm',
92 0, '=', ']', '\r', 0, 0, 0, 0,
93 0, 0, 0, 0, KEY_SHIFT, KEY_SHIFT, 0, 0,
94 0, 0, 0, 0, 0, 0, 0, 0,
95 0, 0, 0, 0, 0, 0, 0, 0,
96 '[', 'p', '\'', ';', '/', '.', 0, 0,
97 0, 0, 0x08, '3', '2', 0, 0, 0,
98 0, 0x7F, 0, 0, 0, 0, 0, 0,
99 0, 0, 0, 'q', 0, 0, '1', 0,
100 0x1B, '`', 0, 0x9, 0, 0, 0, 0
101 };
102
103 static int shift_kbd_keycode[] = {
104 0, 0, 'W', 'S', 'A', 'Z', 0, 0,
105 0, 0, 0, 0, 0, 0, 0, 0,
106 0, 0, 0, 0, 0, 0, 0, 0,
107 '%', '$', 'R', 'E', 'F', 'D', 'X', 0,
108 '&', '^', 'T', 'H', 'G', 'V', 'C', ' ',
109 '(', '*', 'U', 'Y', 'J', 'N', 'B', '|',
110 '_', ')', 'O', 'I', 'L', 'K', ',', 'M',
111 0, '+', '}', '\r', 0, 0, 0, 0,
112 0, 0, 0, 0, 0, 0, 0, 0,
113 0, 0, 0, 0, 0, 0, 0, 0,
114 0, 0, 0, 0, 0, 0, 0, 0,
115 '{', 'P', '"', ':', '?', '>', 0, 0,
116 0, 0, 0x08, '#', '@', 0, 0, 0,
117 0, 0x7F, 0, 0, 0, 0, 0, 0,
118 0, 0, 0, 'Q', 0, 0, '!', 0,
119 0x1B, '~', 0, 0x9, 0, 0, 0, 0
120 };
121
122 static int fn_kbd_keycode[] = {
123 0, 0, 0, 0, 0, 0, 0, 0,
124 0, 0, 0, 0, 0, 0, 0, 0,
125 0, 0, 0, 0, 0, 0, 0, 0,
126 0, 0, 0, 0, 0, 0, 0, 0,
127 '7', 0, 0, 0, 0, 0, 0, 0,
128 '9', '8', '4', 0, '1', 0, 0, 0,
129 0, '/', '6', '5', '3', '2', 0, '0',
130 0, 0, 0, 0, 0, 0, 0, 0,
131 0, 0, 0, 0, 0, 0, 0, 0,
132 0, 0, 0, 0, 0, 0, 0, 0,
133 0, 0, 0, 0, 0, 0, 0, 0,
134 0, '\'', 0, '-', '+', '.', 0, 0,
135 0, 0, 0, 0, 0, 0, 0, 0,
136 0, 0, 0, 0, 0, 0, 0, 0,
137 0, 0, 0, 0, 0, 0, 0, 0,
138 0, 0, 0, 0, '?', 0, 0, 0
139 };
140
141 void msleep(int a)
142 {
143 int i;
144
145 for (i = 0; i < a; i++)
146 udelay(1000);
147 }
148
149 static int tegra_kbc_keycode(struct tegra_kbc *kbc, int r, int c, int spl_key)
150 {
151 if (spl_key == KEY_FN)
152 return kbc->fn_keycode[(r * KBC_MAX_COL) + c];
153 else if (spl_key == KEY_SHIFT)
154 return kbc->shift_keycode[(r * KBC_MAX_COL) + c];
155 else
156 return kbc->plain_keycode[(r * KBC_MAX_COL) + c];
157 }
158
159 static int tegra_kbc_find_keys(int *fifo)
160 {
161 int rows_val[KBC_MAX_KPENT], cols_val[KBC_MAX_KPENT];
162 u32 kp_ent_val[(KBC_MAX_KPENT + 3) / 4];
163 u32 *kp_ents = kp_ent_val;
164 u32 kp_ent = 0;
165 int i, j, valid = 0;
166 int spl = 0;
167
168 for (i = 0; i < ARRAY_SIZE(kp_ent_val); i++)
169 kp_ent_val[i] = kbc_readl(KBC_KP_ENT0_0 + (i*4));
170
171 valid = 0;
172 for (i = 0; i < KBC_MAX_KPENT; i++) {
173 if (!(i&3))
174 kp_ent = *kp_ents++;
175
176 if (kp_ent & 0x80) {
177 cols_val[valid] = kp_ent & 0x7;
178 rows_val[valid++] = (kp_ent >> 3) & 0xf;
179 }
180 kp_ent >>= 8;
181 }
182
183 for (i = 0; i < valid; i++) {
184 int k = tegra_kbc_keycode(kbc, rows_val[i], cols_val[i], 0);
185 if ((k == KEY_FN) || (k == KEY_SHIFT)) {
186 spl = k;
187 break;
188 }
189 }
190
191 j = 0;
192 for (i = 0; i < valid; i++) {
193 int k = tegra_kbc_keycode(kbc, rows_val[i], cols_val[i], spl);
194 if (k != -1)
195 fifo[j++] = k;
196 }
197
198 return j;
199 }
200
201 static unsigned char tegra_kbc_get_char(void)
202 {
203 u32 val, ctl;
204 int fifo[KBC_MAX_KPENT], i, cnt;
205 char c = 0;
206
207 for (i = 0; i < KBC_MAX_KPENT; i++)
208 fifo[i] = 0;
209
210 /* until all keys are released, defer further processing to
211 * the polling loop in tegra_kbc_key_repeat */
212 ctl = kbc_readl(KBC_CONTROL_0);
213 ctl &= ~(1<<3);
214 kbc_writel(ctl, KBC_CONTROL_0);
215
216 /* quickly bail out & reenable interrupts if the interrupt source
217 * wasn't fifo count threshold */
218 val = kbc_readl(KBC_INT_0);
219 kbc_writel(val, KBC_INT_0);
220
221 if (!(val & (1<<2))) {
222 ctl |= 1<<3;
223 kbc_writel(ctl, KBC_CONTROL_0);
224 return 0;
225 }
226
227 val = (val >> 4) & 0xf;
228 if (val) {
229 cnt = tegra_kbc_find_keys(fifo);
230
231 /*
232 * Get to the firxt non-zero key value in the key fifo.
233 * The FN and Shift keys will appear as zero values.
234 * The U-boot upper layers can accept only one key.
235 */
236 for (i = 0; i < cnt; i++) {
237 if (fifo[i]) {
238 c = fifo[i];
239 break;
240 }
241 }
242 }
243
244 msleep((val == 1) ? kbc->repoll_time : 1);
245
246 ctl |= (1<<3);
247 kbc_writel(ctl, KBC_CONTROL_0);
248
249 return c;
250 }
251
252 static int kbd_fetch_char(int loop)
253 {
254 unsigned char c;
255 static unsigned char prev_c;
256 static unsigned int rpt_dly = KBC_RPT_DLY;
257
258 do {
259 c = tegra_kbc_get_char();
260 if (!c) {
261 prev_c = 0;
262 continue;
263 }
264
265 /* This logic takes care of the repeat rate */
266 if ((c != prev_c) || !(rpt_dly--))
267 break;
268 } while (loop);
269
270 if (c == prev_c) {
271 /* kbc_testc should return 0 to indicate repeat charachters */
272 if (!loop)
273 c = 0;
274 else
275 rpt_dly = KBC_RPT_RATE;
276 } else {
277 rpt_dly = KBC_RPT_DLY;
278 prev_c = c;
279 }
280
281 return c;
282 }
283
284 static int kbd_testc(void)
285 {
286 unsigned char c = kbd_fetch_char(false);
287
288 return (c != 0);
289 }
290
291 static int kbd_getc(void)
292 {
293 unsigned char c = kbd_fetch_char(true);
294
295 return c;
296 }
297
298 static void config_kbc(void)
299 {
300 int i;
301
302 for (i = 0; i < KBC_MAX_GPIO; i++) {
303 u32 row_cfg, col_cfg;
304 u32 r_shift = 5 * (i%6);
305 u32 c_shift = 4 * (i%8);
306 u32 r_mask = 0x1f << r_shift;
307 u32 c_mask = 0xf << c_shift;
308 u32 r_offs = (i / 6) * 4 + KBC_ROW_CFG0_0;
309 u32 c_offs = (i / 8) * 4 + KBC_COL_CFG0_0;
310
311 row_cfg = kbc_readl(r_offs);
312 col_cfg = kbc_readl(c_offs);
313
314 row_cfg &= ~r_mask;
315 col_cfg &= ~c_mask;
316
317 if (i < KBC_MAX_ROW)
318 row_cfg |= ((i << 1) | 1) << r_shift;
319 else
320 col_cfg |= (((i - KBC_MAX_ROW) << 1) | 1) << c_shift;
321
322 kbc_writel(row_cfg, r_offs);
323 kbc_writel(col_cfg, c_offs);
324 }
325 }
326
327 static int tegra_kbc_open(void)
328 {
329 u32 val = 0;
330
331 config_kbc();
332
333 kbc_writel(kbc->rpt_cnt, KBC_RPT_DLY_0);
334
335 val = kbc->debounce_cnt << 4;
336 val |= 1<<14; /* fifo interrupt threshold = 1 entry */
337 val |= 1<<3; /* interrupt on FIFO threshold reached */
338 val |= 1; /* enable */
339 kbc_writel(val, KBC_CONTROL_0);
340
341 /*
342 * atomically clear out any remaining entries in the key FIFO
343 * and enable keyboard interrupts.
344 */
345 while (1) {
346 val = kbc_readl(KBC_INT_0);
347 val >>= 4;
348 if (val) {
349 val = kbc_readl(KBC_KP_ENT0_0);
350 val = kbc_readl(KBC_KP_ENT1_0);
351 } else {
352 break;
353 }
354 }
355 kbc_writel(0x7, KBC_INT_0);
356
357 return 0;
358 }
359
360 int tegra_kbc_init(void)
361 {
362 int error;
363 struct stdio_dev kbddev;
364 char *stdinname;
365
366 config_kbc_pinmux();
367 config_kbc_clock();
368
369 kbc = malloc(sizeof(*kbc));
370 if (!kbc)
371 return -1;
372
373 kbc->debounce_cnt = 2;
374 kbc->rpt_cnt = 5 * 32;
375 kbc->debounce_cnt = min(kbc->debounce_cnt, 0x3fful);
376 kbc->repoll_time = 5 + (16 + kbc->debounce_cnt) * 0x10 + kbc->rpt_cnt;
377 kbc->repoll_time = (kbc->repoll_time + 31) / 32;
378
379 kbc->plain_keycode = plain_kbd_keycode;
380 kbc->fn_keycode = fn_kbd_keycode;
381 kbc->shift_keycode = shift_kbd_keycode;
382
383 stdinname = getenv("stdin");
384 memset(&kbddev, 0, sizeof(kbddev));
385 strcpy(kbddev.name, DEVNAME);
386 kbddev.flags = DEV_FLAGS_INPUT | DEV_FLAGS_SYSTEM;
387 kbddev.putc = NULL;
388 kbddev.puts = NULL;
389 kbddev.getc = kbd_getc;
390 kbddev.tstc = kbd_testc;
391 kbddev.start = tegra_kbc_open;
392
393 error = stdio_register(&kbddev);
394 if (!error) {
395 /* check if this is the standard input device*/
396 if (strcmp(stdinname, DEVNAME) == 0) {
397 /* reassign the console */
398 if (OVERWRITE_CONSOLE)
399 return 1;
400
401 error = console_assign(stdin, DEVNAME);
402 if (!error)
403 return 0;
404 else
405 return error;
406 }
407 return 1;
408 }
409
410 return error;
411 }
412
OLDNEW
« board/tegra2/seaboard/seaboard.c ('K') | « drivers/input/Makefile ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698