Commit 31b87f2eeb928657d8f5f9202d5f62ea55d7dd9c
1 parent
76ea08f9
Initial PXA27x keypad support, by Armin Kuster.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3818 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
4 changed files
with
360 additions
and
1 deletions
Makefile.target
| ... | ... | @@ -498,7 +498,7 @@ VL_OBJS+= armv7m.o armv7m_nvic.o stellaris.o pl022.o stellaris_enet.o |
| 498 | 498 | VL_OBJS+= pl061.o |
| 499 | 499 | VL_OBJS+= arm-semi.o |
| 500 | 500 | VL_OBJS+= pxa2xx.o pxa2xx_pic.o pxa2xx_gpio.o pxa2xx_timer.o pxa2xx_dma.o |
| 501 | -VL_OBJS+= pxa2xx_lcd.o pxa2xx_mmci.o pxa2xx_pcmcia.o | |
| 501 | +VL_OBJS+= pxa2xx_lcd.o pxa2xx_mmci.o pxa2xx_pcmcia.o pxa2xx_keypad.o | |
| 502 | 502 | VL_OBJS+= pflash_cfi01.o gumstix.o |
| 503 | 503 | VL_OBJS+= spitz.o ide.o serial.o nand.o ecc.o |
| 504 | 504 | VL_OBJS+= omap.o omap_lcdc.o omap1_clk.o omap_mmc.o omap_i2c.o | ... | ... |
hw/pxa.h
| ... | ... | @@ -13,6 +13,7 @@ |
| 13 | 13 | # define PXA2XX_PIC_SSP3 0 |
| 14 | 14 | # define PXA2XX_PIC_USBH2 2 |
| 15 | 15 | # define PXA2XX_PIC_USBH1 3 |
| 16 | +# define PXA2XX_PIC_KEYPAD 4 | |
| 16 | 17 | # define PXA2XX_PIC_PWRI2C 6 |
| 17 | 18 | # define PXA25X_PIC_HWUART 7 |
| 18 | 19 | # define PXA27X_PIC_OST_4_11 7 |
| ... | ... | @@ -106,6 +107,17 @@ int pxa2xx_pcmcia_attach(void *opaque, struct pcmcia_card_s *card); |
| 106 | 107 | int pxa2xx_pcmcia_dettach(void *opaque); |
| 107 | 108 | void pxa2xx_pcmcia_set_irq_cb(void *opaque, qemu_irq irq, qemu_irq cd_irq); |
| 108 | 109 | |
| 110 | +/* pxa2xx_keypad.c */ | |
| 111 | +struct keymap { | |
| 112 | + int column; | |
| 113 | + int row; | |
| 114 | +}; | |
| 115 | +struct pxa2xx_keypad_s; | |
| 116 | +struct pxa2xx_keypad_s *pxa27x_keypad_init(target_phys_addr_t base, | |
| 117 | + qemu_irq irq); | |
| 118 | +void pxa27x_register_keypad(struct pxa2xx_keypad_s *kp, struct keymap *map, | |
| 119 | + int size); | |
| 120 | + | |
| 109 | 121 | /* pxa2xx.c */ |
| 110 | 122 | struct pxa2xx_ssp_s; |
| 111 | 123 | void pxa2xx_ssp_attach(struct pxa2xx_ssp_s *port, |
| ... | ... | @@ -133,6 +145,7 @@ struct pxa2xx_state_s { |
| 133 | 145 | struct pxa2xx_pcmcia_s *pcmcia[2]; |
| 134 | 146 | struct pxa2xx_i2s_s *i2s; |
| 135 | 147 | struct pxa2xx_fir_s *fir; |
| 148 | + struct pxa2xx_keypad_s *kp; | |
| 136 | 149 | |
| 137 | 150 | /* Power management */ |
| 138 | 151 | target_phys_addr_t pm_base; | ... | ... |
hw/pxa2xx.c
| ... | ... | @@ -2153,6 +2153,8 @@ struct pxa2xx_state_s *pxa270_init(unsigned int sdram_size, |
| 2153 | 2153 | |
| 2154 | 2154 | s->i2s = pxa2xx_i2s_init(0x40400000, s->pic[PXA2XX_PIC_I2S], s->dma); |
| 2155 | 2155 | |
| 2156 | + s->kp = pxa27x_keypad_init(0x41500000, s->pic[PXA2XX_PIC_KEYPAD]); | |
| 2157 | + | |
| 2156 | 2158 | /* GPIO1 resets the processor */ |
| 2157 | 2159 | /* The handler can be overridden by board-specific code */ |
| 2158 | 2160 | pxa2xx_gpio_out_set(s->gpio, 1, s->reset); | ... | ... |
hw/pxa2xx_keypad.c
0 → 100644
| 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 | + | |
| 15 | +/* | |
| 16 | + * Keypad | |
| 17 | + */ | |
| 18 | +#define KPC 0x00 /* Keypad Interface Control register */ | |
| 19 | +#define KPDK 0x08 /* Keypad Interface Direct Key register */ | |
| 20 | +#define KPREC 0x10 /* Keypad Interface Rotary Encoder register */ | |
| 21 | +#define KPMK 0x18 /* Keypad Interface Matrix Key register */ | |
| 22 | +#define KPAS 0x20 /* Keypad Interface Automatic Scan register */ | |
| 23 | +#define KPASMKP0 0x28 /* Keypad Interface Automatic Scan Multiple | |
| 24 | + Key Presser register 0 */ | |
| 25 | +#define KPASMKP1 0x30 /* Keypad Interface Automatic Scan Multiple | |
| 26 | + Key Presser register 1 */ | |
| 27 | +#define KPASMKP2 0x38 /* Keypad Interface Automatic Scan Multiple | |
| 28 | + Key Presser register 2 */ | |
| 29 | +#define KPASMKP3 0x40 /* Keypad Interface Automatic Scan Multiple | |
| 30 | + Key Presser register 3 */ | |
| 31 | +#define KPKDI 0x48 /* Keypad Interface Key Debounce Interval | |
| 32 | + register */ | |
| 33 | + | |
| 34 | +/* Keypad defines */ | |
| 35 | +#define KPC_AS (0x1 << 30) /* Automatic Scan bit */ | |
| 36 | +#define KPC_ASACT (0x1 << 29) /* Automatic Scan on Activity */ | |
| 37 | +#define KPC_MI (0x1 << 22) /* Matrix interrupt bit */ | |
| 38 | +#define KPC_IMKP (0x1 << 21) /* Ignore Multiple Key Press */ | |
| 39 | +#define KPC_MS7 (0x1 << 20) /* Matrix scan line 7 */ | |
| 40 | +#define KPC_MS6 (0x1 << 19) /* Matrix scan line 6 */ | |
| 41 | +#define KPC_MS5 (0x1 << 18) /* Matrix scan line 5 */ | |
| 42 | +#define KPC_MS4 (0x1 << 17) /* Matrix scan line 4 */ | |
| 43 | +#define KPC_MS3 (0x1 << 16) /* Matrix scan line 3 */ | |
| 44 | +#define KPC_MS2 (0x1 << 15) /* Matrix scan line 2 */ | |
| 45 | +#define KPC_MS1 (0x1 << 14) /* Matrix scan line 1 */ | |
| 46 | +#define KPC_MS0 (0x1 << 13) /* Matrix scan line 0 */ | |
| 47 | +#define KPC_ME (0x1 << 12) /* Matrix Keypad Enable */ | |
| 48 | +#define KPC_MIE (0x1 << 11) /* Matrix Interrupt Enable */ | |
| 49 | +#define KPC_DK_DEB_SEL (0x1 << 9) /* Direct Keypad Debounce Select */ | |
| 50 | +#define KPC_DI (0x1 << 5) /* Direct key interrupt bit */ | |
| 51 | +#define KPC_RE_ZERO_DEB (0x1 << 4) /* Rotary Encoder Zero Debounce */ | |
| 52 | +#define KPC_REE1 (0x1 << 3) /* Rotary Encoder1 Enable */ | |
| 53 | +#define KPC_REE0 (0x1 << 2) /* Rotary Encoder0 Enable */ | |
| 54 | +#define KPC_DE (0x1 << 1) /* Direct Keypad Enable */ | |
| 55 | +#define KPC_DIE (0x1 << 0) /* Direct Keypad interrupt Enable */ | |
| 56 | + | |
| 57 | +#define KPDK_DKP (0x1 << 31) | |
| 58 | +#define KPDK_DK7 (0x1 << 7) | |
| 59 | +#define KPDK_DK6 (0x1 << 6) | |
| 60 | +#define KPDK_DK5 (0x1 << 5) | |
| 61 | +#define KPDK_DK4 (0x1 << 4) | |
| 62 | +#define KPDK_DK3 (0x1 << 3) | |
| 63 | +#define KPDK_DK2 (0x1 << 2) | |
| 64 | +#define KPDK_DK1 (0x1 << 1) | |
| 65 | +#define KPDK_DK0 (0x1 << 0) | |
| 66 | + | |
| 67 | +#define KPREC_OF1 (0x1 << 31) | |
| 68 | +#define KPREC_UF1 (0x1 << 30) | |
| 69 | +#define KPREC_OF0 (0x1 << 15) | |
| 70 | +#define KPREC_UF0 (0x1 << 14) | |
| 71 | + | |
| 72 | +#define KPMK_MKP (0x1 << 31) | |
| 73 | +#define KPAS_SO (0x1 << 31) | |
| 74 | +#define KPASMKPx_SO (0x1 << 31) | |
| 75 | + | |
| 76 | + | |
| 77 | +#define KPASMKPx_MKC(row, col) (1 << (row + 16 * (col % 2))) | |
| 78 | + | |
| 79 | +#define PXAKBD_MAXROW 8 | |
| 80 | +#define PXAKBD_MAXCOL 8 | |
| 81 | + | |
| 82 | +struct pxa2xx_keypad_s{ | |
| 83 | + target_phys_addr_t base; | |
| 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 (struct pxa2xx_keypad_s *kp, int keycode) | |
| 100 | +{ | |
| 101 | + int row, col,rel; | |
| 102 | + | |
| 103 | + if(!(kp->kpc & KPC_ME)) /* skip if not enabled */ | |
| 104 | + return; | |
| 105 | + | |
| 106 | + if(kp->kpc & KPC_AS || kp->kpc & KPC_ASACT) { | |
| 107 | + if(kp->kpc & KPC_AS) | |
| 108 | + kp->kpc &= ~(KPC_AS); | |
| 109 | + | |
| 110 | + rel = (keycode & 0x80) ? 1 : 0; /* key release from qemu */ | |
| 111 | + keycode &= ~(0x80); /* strip qemu key release bit */ | |
| 112 | + row = kp->map[keycode].row; | |
| 113 | + col = kp->map[keycode].column; | |
| 114 | + if(row == -1 || col == -1) | |
| 115 | + return; | |
| 116 | + switch (col) { | |
| 117 | + case 0: | |
| 118 | + case 1: | |
| 119 | + if(rel) | |
| 120 | + kp->kpasmkp0 = ~(0xffffffff); | |
| 121 | + else | |
| 122 | + kp->kpasmkp0 |= KPASMKPx_MKC(row,col); | |
| 123 | + break; | |
| 124 | + case 2: | |
| 125 | + case 3: | |
| 126 | + if(rel) | |
| 127 | + kp->kpasmkp1 = ~(0xffffffff); | |
| 128 | + else | |
| 129 | + kp->kpasmkp1 |= KPASMKPx_MKC(row,col); | |
| 130 | + break; | |
| 131 | + case 4: | |
| 132 | + case 5: | |
| 133 | + if(rel) | |
| 134 | + kp->kpasmkp2 = ~(0xffffffff); | |
| 135 | + else | |
| 136 | + kp->kpasmkp2 |= KPASMKPx_MKC(row,col); | |
| 137 | + break; | |
| 138 | + case 6: | |
| 139 | + case 7: | |
| 140 | + if(rel) | |
| 141 | + kp->kpasmkp3 = ~(0xffffffff); | |
| 142 | + else | |
| 143 | + kp->kpasmkp3 |= KPASMKPx_MKC(row,col); | |
| 144 | + break; | |
| 145 | + } /* switch */ | |
| 146 | + goto out; | |
| 147 | + } | |
| 148 | + return; | |
| 149 | + | |
| 150 | +out: | |
| 151 | + if(kp->kpc & KPC_MIE) { | |
| 152 | + kp->kpc |= KPC_MI; | |
| 153 | + qemu_irq_raise(kp->irq); | |
| 154 | + } | |
| 155 | + return; | |
| 156 | +} | |
| 157 | + | |
| 158 | +static uint32_t pxa2xx_keypad_read(void *opaque, target_phys_addr_t offset) | |
| 159 | +{ | |
| 160 | + struct pxa2xx_keypad_s *s = (struct pxa2xx_keypad_s *) opaque; | |
| 161 | + uint32_t tmp; | |
| 162 | + offset -= s->base; | |
| 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 | + offset -= s->base; | |
| 226 | + | |
| 227 | + switch (offset) { | |
| 228 | + case KPC: | |
| 229 | + s->kpc = value; | |
| 230 | + break; | |
| 231 | + case KPDK: | |
| 232 | + s->kpdk = value; | |
| 233 | + break; | |
| 234 | + case KPREC: | |
| 235 | + s->kprec = value; | |
| 236 | + break; | |
| 237 | + case KPMK: | |
| 238 | + s->kpmk = value; | |
| 239 | + break; | |
| 240 | + case KPAS: | |
| 241 | + s->kpas = value; | |
| 242 | + break; | |
| 243 | + case KPASMKP0: | |
| 244 | + s->kpasmkp0 = value; | |
| 245 | + break; | |
| 246 | + case KPASMKP1: | |
| 247 | + s->kpasmkp1 = value; | |
| 248 | + break; | |
| 249 | + case KPASMKP2: | |
| 250 | + s->kpasmkp2 = value; | |
| 251 | + break; | |
| 252 | + case KPASMKP3: | |
| 253 | + s->kpasmkp3 = value; | |
| 254 | + break; | |
| 255 | + case KPKDI: | |
| 256 | + s->kpkdi = value; | |
| 257 | + break; | |
| 258 | + | |
| 259 | + default: | |
| 260 | + cpu_abort(cpu_single_env, "%s: Bad offset " REG_FMT "\n", | |
| 261 | + __FUNCTION__, offset); | |
| 262 | + } | |
| 263 | +} | |
| 264 | + | |
| 265 | +static CPUReadMemoryFunc *pxa2xx_keypad_readfn[] = { | |
| 266 | + pxa2xx_keypad_read, | |
| 267 | + pxa2xx_keypad_read, | |
| 268 | + pxa2xx_keypad_read | |
| 269 | +}; | |
| 270 | + | |
| 271 | +static CPUWriteMemoryFunc *pxa2xx_keypad_writefn[] = { | |
| 272 | + pxa2xx_keypad_write, | |
| 273 | + pxa2xx_keypad_write, | |
| 274 | + pxa2xx_keypad_write | |
| 275 | +}; | |
| 276 | + | |
| 277 | +static void pxa2xx_keypad_save(QEMUFile *f, void *opaque) | |
| 278 | +{ | |
| 279 | + struct pxa2xx_keypad_s *s = (struct pxa2xx_keypad_s *) opaque; | |
| 280 | + | |
| 281 | + qemu_put_be32s(f, &s->kpc); | |
| 282 | + qemu_put_be32s(f, &s->kpdk); | |
| 283 | + qemu_put_be32s(f, &s->kprec); | |
| 284 | + qemu_put_be32s(f, &s->kpmk); | |
| 285 | + qemu_put_be32s(f, &s->kpas); | |
| 286 | + qemu_put_be32s(f, &s->kpasmkp0); | |
| 287 | + qemu_put_be32s(f, &s->kpasmkp1); | |
| 288 | + qemu_put_be32s(f, &s->kpasmkp2); | |
| 289 | + qemu_put_be32s(f, &s->kpasmkp3); | |
| 290 | + qemu_put_be32s(f, &s->kpkdi); | |
| 291 | + | |
| 292 | +} | |
| 293 | + | |
| 294 | +static int pxa2xx_keypad_load(QEMUFile *f, void *opaque, int version_id) | |
| 295 | +{ | |
| 296 | + struct pxa2xx_keypad_s *s = (struct pxa2xx_keypad_s *) opaque; | |
| 297 | + | |
| 298 | + qemu_get_be32s(f, &s->kpc); | |
| 299 | + qemu_get_be32s(f, &s->kpdk); | |
| 300 | + qemu_get_be32s(f, &s->kprec); | |
| 301 | + qemu_get_be32s(f, &s->kpmk); | |
| 302 | + qemu_get_be32s(f, &s->kpas); | |
| 303 | + qemu_get_be32s(f, &s->kpasmkp0); | |
| 304 | + qemu_get_be32s(f, &s->kpasmkp1); | |
| 305 | + qemu_get_be32s(f, &s->kpasmkp2); | |
| 306 | + qemu_get_be32s(f, &s->kpasmkp3); | |
| 307 | + qemu_get_be32s(f, &s->kpkdi); | |
| 308 | + | |
| 309 | + return 0; | |
| 310 | +} | |
| 311 | + | |
| 312 | +struct pxa2xx_keypad_s *pxa27x_keypad_init(target_phys_addr_t base, | |
| 313 | + qemu_irq irq) | |
| 314 | +{ | |
| 315 | + int iomemtype; | |
| 316 | + struct pxa2xx_keypad_s *s; | |
| 317 | + | |
| 318 | + s = (struct pxa2xx_keypad_s *) qemu_mallocz(sizeof(struct pxa2xx_keypad_s)); | |
| 319 | + s->base = base; | |
| 320 | + s->irq = irq; | |
| 321 | + | |
| 322 | + iomemtype = cpu_register_io_memory(0, pxa2xx_keypad_readfn, | |
| 323 | + pxa2xx_keypad_writefn, s); | |
| 324 | + cpu_register_physical_memory(base, 0x00100000, iomemtype);////check size | |
| 325 | + | |
| 326 | + register_savevm("pxa2xx_keypad", 0, 0, | |
| 327 | + pxa2xx_keypad_save, pxa2xx_keypad_load, s); | |
| 328 | + | |
| 329 | + return s; | |
| 330 | +} | |
| 331 | + | |
| 332 | +void pxa27x_register_keypad(struct pxa2xx_keypad_s *kp, struct keymap *map, | |
| 333 | + int size) | |
| 334 | +{ | |
| 335 | + kp->map = (struct keymap *) qemu_mallocz(sizeof(struct keymap) * size); | |
| 336 | + | |
| 337 | + if(!map || size < 80) { | |
| 338 | + fprintf(stderr, "%s - No PXA keypad map defined\n", __FUNCTION__); | |
| 339 | + exit(-1); | |
| 340 | + } | |
| 341 | + | |
| 342 | + kp->map = map; | |
| 343 | + qemu_add_kbd_event_handler((QEMUPutKBDEvent *) pxa27x_keyboard_event, kp); | |
| 344 | +} | ... | ... |