diff options
author | Marek Vasut <marex@cvs.openbsd.org> | 2009-09-09 12:14:40 +0000 |
---|---|---|
committer | Marek Vasut <marex@cvs.openbsd.org> | 2009-09-09 12:14:40 +0000 |
commit | cb686eb47fc128abf85877b7d85d88f23f43b5f4 (patch) | |
tree | ad3cf41e3e161ee4efd773c40f3982bc97e6d3c8 /sys/arch/arm | |
parent | 8936a54ac6c24f8d4b7c3e15f83f90beb2481da7 (diff) |
Add simple PXA27x matrix keypad controller driver
Diffstat (limited to 'sys/arch/arm')
-rw-r--r-- | sys/arch/arm/xscale/files.pxa2x0 | 6 | ||||
-rw-r--r-- | sys/arch/arm/xscale/pxa27x_kpc.c | 224 | ||||
-rw-r--r-- | sys/arch/arm/xscale/pxa27x_kpc.h | 47 | ||||
-rw-r--r-- | sys/arch/arm/xscale/pxa2x0reg.h | 22 |
4 files changed, 297 insertions, 2 deletions
diff --git a/sys/arch/arm/xscale/files.pxa2x0 b/sys/arch/arm/xscale/files.pxa2x0 index 1439e545514..7cb2b2c4501 100644 --- a/sys/arch/arm/xscale/files.pxa2x0 +++ b/sys/arch/arm/xscale/files.pxa2x0 @@ -1,4 +1,4 @@ -# $OpenBSD: files.pxa2x0,v 1.21 2007/05/15 05:26:44 miod Exp $ +# $OpenBSD: files.pxa2x0,v 1.22 2009/09/09 12:14:39 marex Exp $ # $NetBSD: files.pxa2x0,v 1.6 2004/05/01 19:09:14 thorpej Exp $ # # Configuration info for Intel PXA2[51]0 CPU support @@ -84,3 +84,7 @@ device fdc # MMC/SD/SDIO controller device pxammc: sdmmcbus file arch/arm/xscale/pxa2x0_mmc.c pxammc + +# PXA27x keypad +device pxa27x_kpc: wskbddev +file arch/arm/xscale/pxa27x_kpc.c pxa27x_kpc diff --git a/sys/arch/arm/xscale/pxa27x_kpc.c b/sys/arch/arm/xscale/pxa27x_kpc.c new file mode 100644 index 00000000000..0d746c25385 --- /dev/null +++ b/sys/arch/arm/xscale/pxa27x_kpc.c @@ -0,0 +1,224 @@ +/* + * Copyright (c) 2009 Marek Vasut <marex@openbsd.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <sys/param.h> +#include <sys/device.h> +#include <sys/kernel.h> +#include <sys/limits.h> +#include <sys/timeout.h> +#include <sys/systm.h> + +#include <arch/arm/xscale/pxa2x0_gpio.h> +#include <arch/arm/xscale/pxa2x0reg.h> +#include <arch/arm/xscale/pxa2x0var.h> +#include <arch/arm/xscale/pxa27x_kpc.h> + +int pxa27x_kpc_enable(void *, int); +void pxa27x_kpc_setleds(void *, int); +int pxa27x_kpc_ioctl(void *, u_long, caddr_t, int, struct proc *); + +inline void pxa27x_kpc_submit(struct pxa27x_kpc_softc *, int); +int pxa27x_kpc_intr(void *); + +struct cfdriver pxa27x_kpc_cd = { + NULL, "pxa27x_kpc", DV_DULL, +}; + +struct wskbd_accessops pxa27x_kpc_accessops = { + pxa27x_kpc_enable, + pxa27x_kpc_setleds, + pxa27x_kpc_ioctl, +}; + +struct wscons_keydesc pxa27x_kpc_keydesctab[] = { + {KB_US, 0, 0, 0}, + {0, 0, 0, 0}, +}; + +struct wskbd_mapdata pxa27x_kpc_mapdata = { + pxa27x_kpc_keydesctab, KB_US, +}; + +void pxa27x_kpc_cngetc(void *, u_int *, int *); +void pxa27x_kpc_cnpollc(void *, int); +void pxa27x_kpc_cnbell(void *, u_int, u_int, u_int); + +struct wskbd_consops pxa27x_kpc_consops = { + pxa27x_kpc_cngetc, + pxa27x_kpc_cnpollc, + pxa27x_kpc_cnbell, +}; + +int +pxa27x_kpc_match(void *aux) +{ + struct pxaip_attach_args *pxa = aux; + if (pxa->pxa_addr != PXA2X0_KPC_BASE) + return 0; /* Wrong device */ + + if ((cputype & ~CPU_ID_XSCALE_COREREV_MASK) != CPU_ID_PXA27X) + return 0; /* Wrong CPU */ + + pxa->pxa_size = PXA2X0_KPC_SIZE; + return 1; +} + +void +pxa27x_kpc_attach(struct pxa27x_kpc_softc *sc, void *aux) +{ + struct pxaip_attach_args *pxa = aux; + struct wskbddev_attach_args a; + + sc->sc_iot = pxa->pxa_sa.sa_iot; + if (bus_space_map(sc->sc_iot, pxa->pxa_addr, pxa->pxa_size, 0, + &sc->sc_ioh) != 0) { + printf(": can't map regs\n"); + goto err; + } + + pxa2x0_clkman_config(CKEN_KEY, 1); + + sc->sc_ih = pxa2x0_intr_establish(PXA2X0_INT_KPC, IPL_TTY, + pxa27x_kpc_intr, sc, sc->sc_dev.dv_xname); + if (!sc->sc_ih) { + printf(": can't establish interrupt\n"); + goto err2; + } + + bus_space_write_4(sc->sc_iot, sc->sc_ioh, KPC_KPC, KPC_MIE | KPC_ME | + KPC_MS(0xff) | KPC_IMKP | KPC_MI | KPC_MKCN(sc->sc_cols) | + KPC_MKRN(sc->sc_rows) | KPC_ASACT); + bus_space_write_4(sc->sc_iot, sc->sc_ioh, KPC_KPKDI, 0x30); + + pxa27x_kpc_keydesctab[0].map_size = sc->sc_ksize; + pxa27x_kpc_keydesctab[0].map = sc->sc_kcodes; + + a.console = 1; + a.keymap = &pxa27x_kpc_mapdata; + a.accessops = &pxa27x_kpc_accessops; + a.accesscookie = sc; + + printf("\n"); + + wskbd_cnattach(&pxa27x_kpc_consops, sc, &pxa27x_kpc_mapdata); + + sc->sc_wskbddev = config_found((struct device *)sc, &a, wskbddevprint); + + return; + +err2: + bus_space_unmap(sc->sc_iot, sc->sc_ioh, PXA2X0_KPC_SIZE); +err: + return; +} + +inline void +pxa27x_kpc_submit(struct pxa27x_kpc_softc *sc, int event) +{ +#ifdef WSDISPLAY_COMPAT_RAWKBD + u_char key; + if (sc->sc_rawkbd) { + key = sc->sc_key; + if (event == WSCONS_EVENT_KEY_DOWN) + key |= 0x80; + wskbd_rawinput(sc->sc_wskbddev, &key, 1); + } else +#endif + wskbd_input(sc->sc_wskbddev, event, sc->sc_key); +} + +int +pxa27x_kpc_intr(void *arg) +{ + u_int32_t val; + int row = -1, col = -1; + int i = 0; + struct pxa27x_kpc_softc *sc = arg; + + val = bus_space_read_4(sc->sc_iot, sc->sc_ioh, KPC_KPC); + if (!(val & KPC_MI)) /* interrupt didn't happen .. what ?! */ + return 0; + + val = bus_space_read_4(sc->sc_iot, sc->sc_ioh, KPC_KPAS); + if (val & KPAS_SO) /* bogus interrupt */ + return 0; + + if (val & KPAS_MUKP) { /* keypress */ + col = val & KPAS_CP; + row = (val & KPAS_RP) >> 4; + for (i = 0; i < sc->sc_ksize; i++) + if (sc->sc_kmap[i].row == row && + sc->sc_kmap[i].col == col) { + sc->sc_key = sc->sc_kmap[i].key; + pxa27x_kpc_submit(sc, WSCONS_EVENT_KEY_DOWN); + break; + } + } else /* no keypress aka keyrelease */ + pxa27x_kpc_submit(sc, WSCONS_EVENT_KEY_UP); + + return 1; +} + +int +pxa27x_kpc_enable(void *v, int power) +{ + return 0; +} + +void +pxa27x_kpc_setleds(void *v, int power) +{ +} + +int +pxa27x_kpc_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p) +{ +#ifdef WSDISPLAY_COMPAT_RAWKBD + struct pxa27x_kpc_softc *sc = v; +#endif + + switch (cmd) { + case WSKBDIO_GTYPE: + *(int *)data = WSKBD_TYPE_KPC; + return 0; + case WSKBDIO_SETLEDS: + return 0; + case WSKBDIO_GETLEDS: + *(int *)data = 0; + return 0; +#ifdef WSDISPLAY_COMPAT_RAWKBD + case WSKBDIO_SETMODE: + sc->sc_rawkbd = *(int *)data == WSKBD_RAW; + return 0; +#endif + } + return -1; +} + +void +pxa27x_kpc_cnbell(void *v, u_int pitch, u_int period, u_int volume) +{ +} + +void +pxa27x_kpc_cngetc(void *v, u_int *type, int *data) +{ +} + +void +pxa27x_kpc_cnpollc(void *v, int on) +{ +} diff --git a/sys/arch/arm/xscale/pxa27x_kpc.h b/sys/arch/arm/xscale/pxa27x_kpc.h new file mode 100644 index 00000000000..d3a63db8b00 --- /dev/null +++ b/sys/arch/arm/xscale/pxa27x_kpc.h @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2009 Marek Vasut <marex@openbsd.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <dev/wscons/wsconsio.h> +#include <dev/wscons/wskbdraw.h> +#include <dev/wscons/wskbdvar.h> +#include <dev/wscons/wsksymdef.h> +#include <dev/wscons/wsksymvar.h> + +struct pxa27x_kpc_keymap { + int row; + int col; + keysym_t key; +}; + +struct pxa27x_kpc_softc { + struct device sc_dev; + struct device *sc_wskbddev; + void *sc_ih; + bus_space_tag_t sc_iot; + bus_space_handle_t sc_ioh; + int sc_key; + int sc_rawkbd; + + int sc_rows; + int sc_cols; + const struct pxa27x_kpc_keymap *sc_kmap; + const keysym_t *sc_kcodes; + const keysym_t *sc_xt_kcodes; + int sc_ksize; +}; + +int pxa27x_kpc_match(void *); +void pxa27x_kpc_attach(struct pxa27x_kpc_softc *, void *); diff --git a/sys/arch/arm/xscale/pxa2x0reg.h b/sys/arch/arm/xscale/pxa2x0reg.h index 421f3e727e7..9595049f156 100644 --- a/sys/arch/arm/xscale/pxa2x0reg.h +++ b/sys/arch/arm/xscale/pxa2x0reg.h @@ -1,4 +1,4 @@ -/* $OpenBSD: pxa2x0reg.h,v 1.30 2007/05/25 21:27:15 krw Exp $ */ +/* $OpenBSD: pxa2x0reg.h,v 1.31 2009/09/09 12:14:39 marex Exp $ */ /* $NetBSD: pxa2x0reg.h,v 1.4 2003/06/11 20:43:01 scw Exp $ */ /* @@ -124,6 +124,8 @@ #define PXA2X0_MEMCTL_SIZE 0x84 #define PXA2X0_USBHC_BASE 0x4c000000 /* USB Host Controller */ #define PXA2X0_USBHC_SIZE 0x70 +#define PXA2X0_KPC_BASE 0x41500000 /* Keypad Controller */ +#define PXA2X0_KPC_SIZE 0x50 /* width of interrupt controller */ #define ICU_LEN 32 /* but some are not used */ @@ -136,6 +138,7 @@ */ #define PXA2X0_INT_USBH2 2 /* USB host (all other events) */ #define PXA2X0_INT_USBH1 3 /* USB host (OHCI) */ +#define PXA2X0_INT_KPC 4 #define PXA2X0_INT_OST 7 /* OS timers */ #define PXA2X0_INT_GPIO0 8 #define PXA2X0_INT_GPIO1 9 @@ -872,4 +875,21 @@ struct pxa2x0_dma_desc { #define SSSR_RNE (1<<3) #define SSP_SSDR 0x10 +/* KPC */ +#define KPC_KPC 0x00 +#define KPC_MIE (1<<11) +#define KPC_ME (1<<12) +#define KPC_MS(n) ((n & 0xff) << 13) +#define KPC_IMKP (1<<21) +#define KPC_MI (1<<22) +#define KPC_MKCN(n) ((n & 0x7) << 23) +#define KPC_MKRN(n) ((n & 0x7) << 26) +#define KPC_ASACT (1<<29) +#define KPC_KPAS 0x20 +#define KPAS_CP (0xf<<0) +#define KPAS_RP (0xf<<4) +#define KPAS_MUKP (0x1f<<26) +#define KPAS_SO (1<<31) +#define KPC_KPKDI 0x48 + #endif /* _ARM_XSCALE_PXA2X0REG_H_ */ |