--- sys/arch/palm/conf/GENERIC | 5 + sys/arch/palm/conf/RAMDISK | 6 + sys/arch/palm/conf/files.palm | 4 + sys/arch/palm/dev/palm_tsc.c | 361 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 376 insertions(+), 0 deletions(-) create mode 100644 sys/arch/palm/dev/palm_tsc.c
diff --git a/sys/arch/palm/conf/GENERIC b/sys/arch/palm/conf/GENERIC index feff44d..c12bf82 100644 --- a/sys/arch/palm/conf/GENERIC +++ b/sys/arch/palm/conf/GENERIC @@ -33,6 +33,7 @@ option WSDISPLAY_DEFAULTSCREENS=2 # initial number of text consoles option WSDISPLAY_COMPAT_PCVT # emulate some ioctls; needed for X11 option USBVERBOSE +option APERTURE config bsd root on sd1a swap on sd1b @@ -220,6 +221,10 @@ owtemp* at onewire? # Temperature # APM emulation apm0 at pxaip? +# Touchscreen +palm_tsc0 at pxaip? addr 0x40500000 size 0x10000 +wsmouse* at palm_tsc? mux 0 + # Pseudo-Devices pseudo-device wsmux 2 # mouse & keyboard multiplexor pseudo-device hotplug 1 # devices hot plugging diff --git a/sys/arch/palm/conf/RAMDISK b/sys/arch/palm/conf/RAMDISK index c8c40c9..b22e09f 100644 --- a/sys/arch/palm/conf/RAMDISK +++ b/sys/arch/palm/conf/RAMDISK @@ -36,6 +36,8 @@ option WSDISPLAY_COMPAT_RAWKBD # provide raw scancodes; needed for X11 option WSDISPLAY_DEFAULTSCREENS=2 # initial number of text consoles option WSDISPLAY_COMPAT_PCVT # emulate some ioctls; needed for X11 +option APERTURE + config bsd root on rd0a swap on rd0b # The main bus device @@ -155,6 +157,10 @@ wsdisplay* at lcd? console ? # APM emulation apm0 at pxaip? +# Touchscreen +palm_tsc0 at pxaip? addr 0x40500000 size 0x10000 +wsmouse* at palm_tsc? mux 0 + # Pseudo-Devices pseudo-device wsmux 2 # mouse & keyboard multiplexor #pseudo-device crypto 1 diff --git a/sys/arch/palm/conf/files.palm b/sys/arch/palm/conf/files.palm index 6f960ca..94d8351 100644 --- a/sys/arch/palm/conf/files.palm +++ b/sys/arch/palm/conf/files.palm @@ -72,6 +72,10 @@ file arch/palm/dev/palm_udc.c pxaudc_palm attach pxa27x_kpc at pxaip with pxakpc_palm file arch/palm/dev/palm_kpc.c pxakpc_palm +device palm_tsc: wsmousedev +attach palm_tsc at pxaip +file arch/palm/dev/palm_tsc.c palm_tsc needs-flag + # Bluetooth include "dev/bluetooth/files.bluetooth" diff --git a/sys/arch/palm/dev/palm_tsc.c b/sys/arch/palm/dev/palm_tsc.c new file mode 100644 index 0000000..0a2ec04 --- /dev/null +++ b/sys/arch/palm/dev/palm_tsc.c @@ -0,0 +1,361 @@ +/* + * Copyright (c) 2009 Marek Vasut <ma...@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/types.h> +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/device.h> +#include <sys/malloc.h> +#include <sys/timeout.h> +#include <sys/kernel.h> + +#include <arm/xscale/pxa2x0reg.h> +#include <arm/xscale/pxa2x0_gpio.h> + +#include <dev/wscons/wsconsio.h> +#include <dev/wscons/wsmousevar.h> + +#include <dev/wscons/wsdisplayvar.h> +#include <arm/xscale/pxa2x0var.h> +#include <arm/xscale/pxa2x0_lcd.h> + +struct tsscale { + int minx, maxx; + int miny, maxy; + int swapxy; + int resx, resy; +} palm_tsc_scale = { + 0x128, 0xe8f, 0xa0, 0xf40, 0, 324, 484 +}; + +struct palm_tsc_softc { + struct device sc_dev; + bus_space_tag_t sc_iot; + bus_space_handle_t sc_ioh; + + + struct timeout sc_ts_poll; + void *sc_touch_ih; + struct device *sc_wsmousedev; + int sc_oldx; + int sc_oldy; + int sc_rawmode; + + struct tsscale sc_tsscale; +}; + +int palm_tsc_gsrw(struct palm_tsc_softc *, int); +int palm_tsc_read_4(struct palm_tsc_softc *, int); +void palm_tsc_write_4(struct palm_tsc_softc *, int, int); + +int palm_tsc_match(struct device *, void *, void *); +void palm_tsc_attach(struct device *, struct device *, void *); + +int palm_tsc_enable(void *); +void palm_tsc_disable(void *); +int palm_tsc_ioctl(void *, u_long, caddr_t, int, struct proc *); + +void palm_tsc_power(int, void *); +void palm_tsc_poll(void *); +int palm_tsc_irq(void *); + + +struct cfattach palm_tsc_ca = { + sizeof(struct palm_tsc_softc), palm_tsc_match, palm_tsc_attach +}; + +struct cfdriver palm_tsc_cd = { + NULL, "palm_tsc", DV_DULL +}; + +const struct wsmouse_accessops palm_tsc_accessops = { + palm_tsc_enable, + palm_tsc_ioctl, + palm_tsc_disable +}; + +int +palm_tsc_gsrw(struct palm_tsc_softc *sc, int mask) +{ + int timeout, val; + for (timeout = 5000; timeout > 0; timeout--) { + val = bus_space_read_4(sc->sc_iot, sc->sc_ioh, AC97_GSR); + if ((val & mask) == mask) + return 0; + } + return 1; +} +int +palm_tsc_read_4(struct palm_tsc_softc *sc, int reg) +{ + int ret; + bus_space_read_4(sc->sc_iot, sc->sc_ioh, reg); + if (!palm_tsc_gsrw(sc, GSR_SDONE)) + bus_space_write_4(sc->sc_iot, sc->sc_ioh, AC97_GSR, GSR_SDONE | GSR_CDONE); + + ret = bus_space_read_4(sc->sc_iot, sc->sc_ioh, reg); + if (!palm_tsc_gsrw(sc, GSR_SDONE)) + bus_space_write_4(sc->sc_iot, sc->sc_ioh, AC97_GSR, GSR_SDONE | GSR_CDONE); + + return ret; +} + +void +palm_tsc_write_4(struct palm_tsc_softc *sc, int reg, int val) +{ + bus_space_write_4(sc->sc_iot, sc->sc_ioh, reg, val); + if (!palm_tsc_gsrw(sc, GSR_CDONE)) + bus_space_write_4(sc->sc_iot, sc->sc_ioh, AC97_GSR, GSR_SDONE | GSR_CDONE); +} + +int +palm_tsc_match(struct device *parent, void *cf, void *aux) +{ + struct pxaip_attach_args *pxa = aux; + return (pxa->pxa_addr == 0x40500000); +} + +void +palm_tsc_attach(struct device *parent, struct device *self, void *aux) +{ + struct pxaip_attach_args *pxa = aux; + struct wsmousedev_attach_args a; + struct palm_tsc_softc *sc = (struct palm_tsc_softc *)self; + int s; + + s = spltty(); + timeout_set(&sc->sc_ts_poll, palm_tsc_poll, sc); + + /* Map registers */ + 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) { + splx(s); + printf(": can't map regs\n"); + return; + } + + pxa2x0_gpio_set_function(27, GPIO_IN); + sc->sc_touch_ih = pxa2x0_gpio_intr_establish(27, + IST_EDGE_BOTH, IPL_TTY, palm_tsc_irq, sc, "palm_tscd"); + if (sc->sc_touch_ih == NULL) { + splx(s); + printf(": can't establish touchscreen interrupt\n"); + return; + } + pxa2x0_gpio_intr_mask(sc->sc_touch_ih); + + /* Configure GPIOs */ + pxa2x0_gpio_set_function(28, GPIO_ALT_FN_1_IN); // BITCLK + pxa2x0_gpio_set_function(29, GPIO_ALT_FN_1_IN); // SDATA_IN_0 + pxa2x0_gpio_set_function(30, GPIO_ALT_FN_2_OUT); // SDATA_OUT + pxa2x0_gpio_set_function(31, GPIO_ALT_FN_2_OUT); // SYNC + pxa2x0_gpio_set_function(89, GPIO_ALT_FN_1_OUT); // SYSCLK + pxa2x0_gpio_set_function(95, GPIO_ALT_FN_1_OUT); // nRESET + + /* Enable clock */ + pxa2x0_clkman_config(CKEN_AC97, 1); + delay(100); + + /* Cold reset the codec */ + bus_space_write_4(sc->sc_iot, sc->sc_ioh, AC97_GCR, 0); + delay(100); + bus_space_write_4(sc->sc_iot, sc->sc_ioh, AC97_GCR, GCR_nCRST); + delay(100); + bus_space_write_4(sc->sc_iot, sc->sc_ioh, AC97_CAR, 0); + + /* Wait for codec ready */ + if (palm_tsc_gsrw(sc, GSR_PCRDY)) + return; + + /* init phy */ + palm_tsc_write_4(sc, (0x200 + (0x76<<1)), 0x0030); + palm_tsc_write_4(sc, (0x200 + (0x78<<1)), 0x2008); + + /* start TS */ + palm_tsc_write_4(sc, (0x200 + (0x78<<1)), 0xe008); + palm_tsc_read_4(sc, (0x200 + (0x7a<<1))); + + a.accessops = &palm_tsc_accessops; + a.accesscookie = sc; + + /* Copy the default scale values to each softc */ + bcopy(&palm_tsc_scale, &sc->sc_tsscale, sizeof(sc->sc_tsscale)); + + sc->sc_wsmousedev = config_found(self, &a, wsmousedevprint); + + pxa2x0_gpio_intr_unmask(sc->sc_touch_ih); + splx(s); +} + +int +palm_tsc_enable(void *v) +{ + struct palm_tsc_softc *sc = v; + timeout_del(&sc->sc_ts_poll); + return 0; +} + +void +palm_tsc_disable(void *v) +{ + struct palm_tsc_softc *sc = v; + timeout_del(&sc->sc_ts_poll); +} + +void +palm_tsc_power(int why, void *v) +{ + struct palm_tsc_softc *sc = v; + switch (why) { + case PWR_STANDBY: + case PWR_SUSPEND: + timeout_del(&sc->sc_ts_poll); + break; + case PWR_RESUME: + break; + } +} + +void +palm_tsc_poll(void *v) +{ + int s; + struct palm_tsc_softc *sc = v; + s = spltty(); + pxa2x0_gpio_intr_unmask(sc->sc_touch_ih); + splx(s); + palm_tsc_irq(v); +} + +#define TS_STABLE 8 +int +palm_tsc_irq(void *v) +{ + int s; + int x = 0, y = 0, t; + int i, timeout; + struct palm_tsc_softc *sc = v; + + s = spltty(); + + if (pxa2x0_gpio_get_bit(27)) { + timeout_add(&sc->sc_ts_poll, hz/20); + pxa2x0_gpio_intr_mask(sc->sc_touch_ih); + + palm_tsc_write_4(sc, (0x200 + (0x54<<1)), 0xdfff); + + i = 0; + timeout = 10; + while(--timeout && i < 3) { + palm_tsc_write_4(sc, (0x200 + (0x76<<1)), 0x9030); + while(palm_tsc_read_4(sc, (0x200 + (0x76<<1))) & 0x8000); + t = palm_tsc_read_4(sc, (0x200 + (0x7a<<1))); + if ((t & 0x9000) == 0x9000) { + x += t & 0xfff; + i++; + } + } + if (!timeout) + goto penrel; + x /= i; + + i = 0; + timeout = 10; + while(--timeout && i < 3) { + palm_tsc_write_4(sc, (0x200 + (0x76<<1)), 0xa030); + while(palm_tsc_read_4(sc, (0x200 + (0x76<<1))) & 0x8000); + t = palm_tsc_read_4(sc, (0x200 + (0x7a<<1))); + if ((t & 0xa000) == 0xa000) { + y += t & 0xfff; + i++; + } + } + if (!timeout) + goto penrel; + y /= i; + + splx(s); + if (!sc->sc_rawmode) { + x = ((x - sc->sc_tsscale.minx) * (sc->sc_tsscale.resx)) / (sc->sc_tsscale.maxx - sc->sc_tsscale.minx); + y = ((y - sc->sc_tsscale.miny) * (sc->sc_tsscale.resy)) / (sc->sc_tsscale.maxy - sc->sc_tsscale.miny); + } + x = sc->sc_tsscale.maxx - x; + y = sc->sc_tsscale.maxy - y; + + sc->sc_oldx = x; + sc->sc_oldy = y; + wsmouse_input(sc->sc_wsmousedev, 1, x, y, 0 /* z */, 0 /* w */, + WSMOUSE_INPUT_ABSOLUTE_X | WSMOUSE_INPUT_ABSOLUTE_Y | + WSMOUSE_INPUT_ABSOLUTE_Z); + return 1; + } +penrel: + splx(s); + wsmouse_input(sc->sc_wsmousedev, 0, sc->sc_oldx, sc->sc_oldy, + 0 /* z */, 0 /* w */, + WSMOUSE_INPUT_ABSOLUTE_X | WSMOUSE_INPUT_ABSOLUTE_Y | + WSMOUSE_INPUT_ABSOLUTE_Z); + + return 1; +} + +int +palm_tsc_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p) +{ + int error = 0; + struct palm_tsc_softc *sc = v; + struct wsmouse_calibcoords *wsmc = (struct wsmouse_calibcoords *)data; + switch (cmd) { + case WSMOUSEIO_SCALIBCOORDS: + if (!(wsmc->minx >= 0 && wsmc->maxx >= 0 && + wsmc->miny >= 0 && wsmc->maxy >= 0 && + wsmc->resx >= 0 && wsmc->resy >= 0 && + wsmc->minx < 32768 && wsmc->maxx < 32768 && + wsmc->miny < 32768 && wsmc->maxy < 32768 && + wsmc->resx < 32768 && wsmc->resy < 32768 && + wsmc->swapxy >= 0 && wsmc->swapxy <= 1 && + wsmc->samplelen >= 0 && wsmc->samplelen <= 1)) + return (EINVAL); + + sc->sc_tsscale.minx = wsmc->minx; + sc->sc_tsscale.maxx = wsmc->maxx; + sc->sc_tsscale.miny = wsmc->miny; + sc->sc_tsscale.maxy = wsmc->maxy; + sc->sc_tsscale.swapxy = wsmc->swapxy; + sc->sc_tsscale.resx = wsmc->resx; + sc->sc_tsscale.resy = wsmc->resy; + sc->sc_rawmode = wsmc->samplelen; + break; + case WSMOUSEIO_GCALIBCOORDS: + wsmc->minx = sc->sc_tsscale.minx; + wsmc->maxx = sc->sc_tsscale.maxx; + wsmc->miny = sc->sc_tsscale.miny; + wsmc->maxy = sc->sc_tsscale.maxy; + wsmc->swapxy = sc->sc_tsscale.swapxy; + wsmc->resx = sc->sc_tsscale.resx; + wsmc->resy = sc->sc_tsscale.resy; + wsmc->samplelen = sc->sc_rawmode; + break; + case WSMOUSEIO_GTYPE: + *(u_int *)data = WSMOUSE_TYPE_TPANEL; + break; + default: + error = ENOTTY; + break; + } + return (error); +} -- 1.7.0.5