|
1 /* |
|
2 * Intel PXA27X Keypad Controller emulation. |
|
3 * |
|
4 * Copyright (c) 2007 MontaVista Software, Inc |
|
5 * Written by Armin Kuster <akuster@kama-aina.net> |
|
6 * or <Akuster@mvista.com> |
|
7 * |
|
8 * This code is licensed under the GPLv2. |
|
9 */ |
|
10 |
|
11 #include "hw.h" |
|
12 #include "pxa.h" |
|
13 #include "console.h" |
|
14 #include "gui.h" |
|
15 |
|
16 /* |
|
17 * Keypad |
|
18 */ |
|
19 #define KPC 0x00 /* Keypad Interface Control register */ |
|
20 #define KPDK 0x08 /* Keypad Interface Direct Key register */ |
|
21 #define KPREC 0x10 /* Keypad Interface Rotary Encoder register */ |
|
22 #define KPMK 0x18 /* Keypad Interface Matrix Key register */ |
|
23 #define KPAS 0x20 /* Keypad Interface Automatic Scan register */ |
|
24 #define KPASMKP0 0x28 /* Keypad Interface Automatic Scan Multiple |
|
25 Key Presser register 0 */ |
|
26 #define KPASMKP1 0x30 /* Keypad Interface Automatic Scan Multiple |
|
27 Key Presser register 1 */ |
|
28 #define KPASMKP2 0x38 /* Keypad Interface Automatic Scan Multiple |
|
29 Key Presser register 2 */ |
|
30 #define KPASMKP3 0x40 /* Keypad Interface Automatic Scan Multiple |
|
31 Key Presser register 3 */ |
|
32 #define KPKDI 0x48 /* Keypad Interface Key Debounce Interval |
|
33 register */ |
|
34 |
|
35 /* Keypad defines */ |
|
36 #define KPC_AS (0x1 << 30) /* Automatic Scan bit */ |
|
37 #define KPC_ASACT (0x1 << 29) /* Automatic Scan on Activity */ |
|
38 #define KPC_MI (0x1 << 22) /* Matrix interrupt bit */ |
|
39 #define KPC_IMKP (0x1 << 21) /* Ignore Multiple Key Press */ |
|
40 #define KPC_MS7 (0x1 << 20) /* Matrix scan line 7 */ |
|
41 #define KPC_MS6 (0x1 << 19) /* Matrix scan line 6 */ |
|
42 #define KPC_MS5 (0x1 << 18) /* Matrix scan line 5 */ |
|
43 #define KPC_MS4 (0x1 << 17) /* Matrix scan line 4 */ |
|
44 #define KPC_MS3 (0x1 << 16) /* Matrix scan line 3 */ |
|
45 #define KPC_MS2 (0x1 << 15) /* Matrix scan line 2 */ |
|
46 #define KPC_MS1 (0x1 << 14) /* Matrix scan line 1 */ |
|
47 #define KPC_MS0 (0x1 << 13) /* Matrix scan line 0 */ |
|
48 #define KPC_ME (0x1 << 12) /* Matrix Keypad Enable */ |
|
49 #define KPC_MIE (0x1 << 11) /* Matrix Interrupt Enable */ |
|
50 #define KPC_DK_DEB_SEL (0x1 << 9) /* Direct Keypad Debounce Select */ |
|
51 #define KPC_DI (0x1 << 5) /* Direct key interrupt bit */ |
|
52 #define KPC_RE_ZERO_DEB (0x1 << 4) /* Rotary Encoder Zero Debounce */ |
|
53 #define KPC_REE1 (0x1 << 3) /* Rotary Encoder1 Enable */ |
|
54 #define KPC_REE0 (0x1 << 2) /* Rotary Encoder0 Enable */ |
|
55 #define KPC_DE (0x1 << 1) /* Direct Keypad Enable */ |
|
56 #define KPC_DIE (0x1 << 0) /* Direct Keypad interrupt Enable */ |
|
57 |
|
58 #define KPDK_DKP (0x1 << 31) |
|
59 #define KPDK_DK7 (0x1 << 7) |
|
60 #define KPDK_DK6 (0x1 << 6) |
|
61 #define KPDK_DK5 (0x1 << 5) |
|
62 #define KPDK_DK4 (0x1 << 4) |
|
63 #define KPDK_DK3 (0x1 << 3) |
|
64 #define KPDK_DK2 (0x1 << 2) |
|
65 #define KPDK_DK1 (0x1 << 1) |
|
66 #define KPDK_DK0 (0x1 << 0) |
|
67 |
|
68 #define KPREC_OF1 (0x1 << 31) |
|
69 #define KPREC_UF1 (0x1 << 30) |
|
70 #define KPREC_OF0 (0x1 << 15) |
|
71 #define KPREC_UF0 (0x1 << 14) |
|
72 |
|
73 #define KPMK_MKP (0x1 << 31) |
|
74 #define KPAS_SO (0x1 << 31) |
|
75 #define KPASMKPx_SO (0x1 << 31) |
|
76 |
|
77 |
|
78 #define KPASMKPx_MKC(row, col) (1 << (row + 16 * (col % 2))) |
|
79 |
|
80 #define PXAKBD_MAXROW 8 |
|
81 #define PXAKBD_MAXCOL 8 |
|
82 |
|
83 struct pxa2xx_keypad_s{ |
|
84 qemu_irq irq; |
|
85 struct keymap *map; |
|
86 |
|
87 uint32_t kpc; |
|
88 uint32_t kpdk; |
|
89 uint32_t kprec; |
|
90 uint32_t kpmk; |
|
91 uint32_t kpas; |
|
92 uint32_t kpasmkp0; |
|
93 uint32_t kpasmkp1; |
|
94 uint32_t kpasmkp2; |
|
95 uint32_t kpasmkp3; |
|
96 uint32_t kpkdi; |
|
97 }; |
|
98 |
|
99 static void pxa27x_keyboard_event (void *opaque, int keycode) |
|
100 { |
|
101 struct pxa2xx_keypad_s * const kp = opaque; |
|
102 int row, col,rel; |
|
103 |
|
104 if(!(kp->kpc & KPC_ME)) /* skip if not enabled */ |
|
105 return; |
|
106 |
|
107 if(kp->kpc & KPC_AS || kp->kpc & KPC_ASACT) { |
|
108 if(kp->kpc & KPC_AS) |
|
109 kp->kpc &= ~(KPC_AS); |
|
110 |
|
111 rel = (keycode & 0x80) ? 1 : 0; /* key release from qemu */ |
|
112 keycode &= ~(0x80); /* strip qemu key release bit */ |
|
113 row = kp->map[keycode].row; |
|
114 col = kp->map[keycode].column; |
|
115 if(row == -1 || col == -1) |
|
116 return; |
|
117 switch (col) { |
|
118 case 0: |
|
119 case 1: |
|
120 if(rel) |
|
121 kp->kpasmkp0 = ~(0xffffffff); |
|
122 else |
|
123 kp->kpasmkp0 |= KPASMKPx_MKC(row,col); |
|
124 break; |
|
125 case 2: |
|
126 case 3: |
|
127 if(rel) |
|
128 kp->kpasmkp1 = ~(0xffffffff); |
|
129 else |
|
130 kp->kpasmkp1 |= KPASMKPx_MKC(row,col); |
|
131 break; |
|
132 case 4: |
|
133 case 5: |
|
134 if(rel) |
|
135 kp->kpasmkp2 = ~(0xffffffff); |
|
136 else |
|
137 kp->kpasmkp2 |= KPASMKPx_MKC(row,col); |
|
138 break; |
|
139 case 6: |
|
140 case 7: |
|
141 if(rel) |
|
142 kp->kpasmkp3 = ~(0xffffffff); |
|
143 else |
|
144 kp->kpasmkp3 |= KPASMKPx_MKC(row,col); |
|
145 break; |
|
146 } /* switch */ |
|
147 goto out; |
|
148 } |
|
149 return; |
|
150 |
|
151 out: |
|
152 if(kp->kpc & KPC_MIE) { |
|
153 kp->kpc |= KPC_MI; |
|
154 qemu_irq_raise(kp->irq); |
|
155 } |
|
156 return; |
|
157 } |
|
158 |
|
159 static uint32_t pxa2xx_keypad_read(void *opaque, target_phys_addr_t offset) |
|
160 { |
|
161 struct pxa2xx_keypad_s *s = (struct pxa2xx_keypad_s *) opaque; |
|
162 uint32_t tmp; |
|
163 |
|
164 switch (offset) { |
|
165 case KPC: |
|
166 tmp = s->kpc; |
|
167 if(tmp & KPC_MI) |
|
168 s->kpc &= ~(KPC_MI); |
|
169 if(tmp & KPC_DI) |
|
170 s->kpc &= ~(KPC_DI); |
|
171 qemu_irq_lower(s->irq); |
|
172 return tmp; |
|
173 break; |
|
174 case KPDK: |
|
175 return s->kpdk; |
|
176 break; |
|
177 case KPREC: |
|
178 tmp = s->kprec; |
|
179 if(tmp & KPREC_OF1) |
|
180 s->kprec &= ~(KPREC_OF1); |
|
181 if(tmp & KPREC_UF1) |
|
182 s->kprec &= ~(KPREC_UF1); |
|
183 if(tmp & KPREC_OF0) |
|
184 s->kprec &= ~(KPREC_OF0); |
|
185 if(tmp & KPREC_UF0) |
|
186 s->kprec &= ~(KPREC_UF0); |
|
187 return tmp; |
|
188 break; |
|
189 case KPMK: |
|
190 tmp = s->kpmk; |
|
191 if(tmp & KPMK_MKP) |
|
192 s->kpmk &= ~(KPMK_MKP); |
|
193 return tmp; |
|
194 break; |
|
195 case KPAS: |
|
196 return s->kpas; |
|
197 break; |
|
198 case KPASMKP0: |
|
199 return s->kpasmkp0; |
|
200 break; |
|
201 case KPASMKP1: |
|
202 return s->kpasmkp1; |
|
203 break; |
|
204 case KPASMKP2: |
|
205 return s->kpasmkp2; |
|
206 break; |
|
207 case KPASMKP3: |
|
208 return s->kpasmkp3; |
|
209 break; |
|
210 case KPKDI: |
|
211 return s->kpkdi; |
|
212 break; |
|
213 default: |
|
214 cpu_abort(cpu_single_env, "%s: Bad offset " REG_FMT "\n", |
|
215 __FUNCTION__, offset); |
|
216 } |
|
217 |
|
218 return 0; |
|
219 } |
|
220 |
|
221 static void pxa2xx_keypad_write(void *opaque, |
|
222 target_phys_addr_t offset, uint32_t value) |
|
223 { |
|
224 struct pxa2xx_keypad_s *s = (struct pxa2xx_keypad_s *) opaque; |
|
225 |
|
226 switch (offset) { |
|
227 case KPC: |
|
228 s->kpc = value; |
|
229 break; |
|
230 case KPDK: |
|
231 s->kpdk = value; |
|
232 break; |
|
233 case KPREC: |
|
234 s->kprec = value; |
|
235 break; |
|
236 case KPMK: |
|
237 s->kpmk = value; |
|
238 break; |
|
239 case KPAS: |
|
240 s->kpas = value; |
|
241 break; |
|
242 case KPASMKP0: |
|
243 s->kpasmkp0 = value; |
|
244 break; |
|
245 case KPASMKP1: |
|
246 s->kpasmkp1 = value; |
|
247 break; |
|
248 case KPASMKP2: |
|
249 s->kpasmkp2 = value; |
|
250 break; |
|
251 case KPASMKP3: |
|
252 s->kpasmkp3 = value; |
|
253 break; |
|
254 case KPKDI: |
|
255 s->kpkdi = value; |
|
256 break; |
|
257 |
|
258 default: |
|
259 cpu_abort(cpu_single_env, "%s: Bad offset " REG_FMT "\n", |
|
260 __FUNCTION__, offset); |
|
261 } |
|
262 } |
|
263 |
|
264 static CPUReadMemoryFunc *pxa2xx_keypad_readfn[] = { |
|
265 pxa2xx_keypad_read, |
|
266 pxa2xx_keypad_read, |
|
267 pxa2xx_keypad_read |
|
268 }; |
|
269 |
|
270 static CPUWriteMemoryFunc *pxa2xx_keypad_writefn[] = { |
|
271 pxa2xx_keypad_write, |
|
272 pxa2xx_keypad_write, |
|
273 pxa2xx_keypad_write |
|
274 }; |
|
275 |
|
276 static void pxa2xx_keypad_save(QEMUFile *f, void *opaque) |
|
277 { |
|
278 struct pxa2xx_keypad_s *s = (struct pxa2xx_keypad_s *) opaque; |
|
279 |
|
280 qemu_put_be32s(f, &s->kpc); |
|
281 qemu_put_be32s(f, &s->kpdk); |
|
282 qemu_put_be32s(f, &s->kprec); |
|
283 qemu_put_be32s(f, &s->kpmk); |
|
284 qemu_put_be32s(f, &s->kpas); |
|
285 qemu_put_be32s(f, &s->kpasmkp0); |
|
286 qemu_put_be32s(f, &s->kpasmkp1); |
|
287 qemu_put_be32s(f, &s->kpasmkp2); |
|
288 qemu_put_be32s(f, &s->kpasmkp3); |
|
289 qemu_put_be32s(f, &s->kpkdi); |
|
290 |
|
291 } |
|
292 |
|
293 static int pxa2xx_keypad_load(QEMUFile *f, void *opaque, int version_id) |
|
294 { |
|
295 struct pxa2xx_keypad_s *s = (struct pxa2xx_keypad_s *) opaque; |
|
296 |
|
297 qemu_get_be32s(f, &s->kpc); |
|
298 qemu_get_be32s(f, &s->kpdk); |
|
299 qemu_get_be32s(f, &s->kprec); |
|
300 qemu_get_be32s(f, &s->kpmk); |
|
301 qemu_get_be32s(f, &s->kpas); |
|
302 qemu_get_be32s(f, &s->kpasmkp0); |
|
303 qemu_get_be32s(f, &s->kpasmkp1); |
|
304 qemu_get_be32s(f, &s->kpasmkp2); |
|
305 qemu_get_be32s(f, &s->kpasmkp3); |
|
306 qemu_get_be32s(f, &s->kpkdi); |
|
307 |
|
308 return 0; |
|
309 } |
|
310 |
|
311 struct pxa2xx_keypad_s *pxa27x_keypad_init(target_phys_addr_t base, |
|
312 qemu_irq irq) |
|
313 { |
|
314 int iomemtype; |
|
315 struct pxa2xx_keypad_s *s; |
|
316 |
|
317 s = (struct pxa2xx_keypad_s *) qemu_mallocz(sizeof(struct pxa2xx_keypad_s)); |
|
318 s->irq = irq; |
|
319 |
|
320 iomemtype = cpu_register_io_memory(0, pxa2xx_keypad_readfn, |
|
321 pxa2xx_keypad_writefn, s); |
|
322 cpu_register_physical_memory(base, 0x00100000, iomemtype); |
|
323 |
|
324 register_savevm("pxa2xx_keypad", 0, 0, |
|
325 pxa2xx_keypad_save, pxa2xx_keypad_load, s); |
|
326 |
|
327 return s; |
|
328 } |
|
329 |
|
330 void pxa27x_register_keypad(struct pxa2xx_keypad_s *kp, struct keymap *map, |
|
331 int size) |
|
332 { |
|
333 if(!map || size < 0x80) { |
|
334 fprintf(stderr, "%s - No PXA keypad map defined\n", __FUNCTION__); |
|
335 exit(-1); |
|
336 } |
|
337 |
|
338 kp->map = map; |
|
339 gui_register_dev_key_callback(pxa27x_keyboard_event, kp); |
|
340 } |