summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorUwe Stuehler <uwe@cvs.openbsd.org>2005-04-08 22:12:15 +0000
committerUwe Stuehler <uwe@cvs.openbsd.org>2005-04-08 22:12:15 +0000
commit354cdc86241db3659af6c32dfd698c5cd65c2881 (patch)
tree02d65f125be8f4598b5f37491a64332515b80277
parentc3d422f42c322c54826a1524fbbd977b8bc2d80a (diff)
Synchronize ADS7846 communication and LCD refresh so as to avoid jitter
in the touch screen data, and enable the existing IRQ handling code (even though polling is still mandatory).
-rw-r--r--sys/arch/zaurus/dev/zts.c533
1 files changed, 380 insertions, 153 deletions
diff --git a/sys/arch/zaurus/dev/zts.c b/sys/arch/zaurus/dev/zts.c
index ddbede15ba2..258519ca547 100644
--- a/sys/arch/zaurus/dev/zts.c
+++ b/sys/arch/zaurus/dev/zts.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: zts.c,v 1.6 2005/03/15 00:35:11 drahn Exp $ */
+/* $OpenBSD: zts.c,v 1.7 2005/04/08 22:12:14 uwe Exp $ */
/*
* Copyright (c) 2005 Dale Rahn <drahn@openbsd.org>
*
@@ -26,25 +26,43 @@
#include <arm/xscale/pxa2x0reg.h>
#include <arm/xscale/pxa2x0_gpio.h>
+#include <zaurus/dev/zaurus_sspvar.h>
+
#include <dev/wscons/wsconsio.h>
#include <dev/wscons/wsmousevar.h>
-u_int32_t pxa2x0_ssp_read_val(u_int32_t);
-
-int zts_match(struct device *, void *, void *);
-void zts_attach(struct device *, struct device *, void *);
-int zts_irq(void *v);
-void zts_poll(void *v);
-
-int zts_enable(void *);
-void zts_disable(void *);
-int zts_ioctl(void *, u_long, caddr_t, int, struct proc *);
+/*
+ * ADS784x touch screen controller
+ */
+#define ADSCTRL_PD0_SH 0 /* PD0 bit */
+#define ADSCTRL_PD1_SH 1 /* PD1 bit */
+#define ADSCTRL_DFR_SH 2 /* SER/DFR bit */
+#define ADSCTRL_MOD_SH 3 /* Mode bit */
+#define ADSCTRL_ADR_SH 4 /* Address setting */
+#define ADSCTRL_STS_SH 7 /* Start bit */
+
+#define GPIO_TP_INT_C3K 11
+#define GPIO_HSYNC_C3K 22
+
+#define POLL_TIMEOUT_RATE0 ((hz * 150)/1000)
+#define POLL_TIMEOUT_RATE1 (hz / 100) /* XXX every tick */
+
+#define CCNT_HS_400_VGA_C3K 6250 /* 15.024us */
+
+int zts_match(struct device *, void *, void *);
+void zts_attach(struct device *, struct device *, void *);
+int zts_enable(void *);
+void zts_disable(void *);
+void zts_power(int, void *);
+void zts_poll(void *);
+int zts_irq(void *);
+int zts_ioctl(void *, u_long, caddr_t, int, struct proc *);
struct zts_softc {
struct device sc_dev;
-
struct timeout sc_ts_poll;
-
+ void *sc_gh;
+ void *sc_powerhook;
int sc_enabled;
int sc_buttons; /* button emulation ? */
struct device *sc_wsmousedev;
@@ -52,14 +70,6 @@ struct zts_softc {
int sc_oldy;
};
-#define ADSCTRL_PD0_SH 0 // PD0 bit
-#define ADSCTRL_PD1_SH 1 // PD1 bit
-#define ADSCTRL_DFR_SH 2 // SER/DFR bit
-#define ADSCTRL_MOD_SH 3 // Mode bit
-#define ADSCTRL_ADR_SH 4 // Address setting
-#define ADSCTRL_STS_SH 7 // Start bit
-
-
struct cfattach zts_ca = {
sizeof(struct zts_softc), zts_match, zts_attach
};
@@ -74,163 +84,411 @@ zts_match(struct device *parent, void *cf, void *aux)
return 1;
}
-#define IRQ_GPIO_TP_INT_C3K 11
-#define POLL_TIMEOUT_RATE ((hz * 150)/1000)
-/*
-#define POLL_TIMEOUT_RATE ((hz * 500)/1000)
-*/
-
const struct wsmouse_accessops zts_accessops = {
zts_enable,
zts_ioctl,
zts_disable
};
-
void
zts_attach(struct device *parent, struct device *self, void *aux)
{
struct zts_softc *sc = (struct zts_softc *)self;
struct wsmousedev_attach_args a;
+ timeout_set(&sc->sc_ts_poll, zts_poll, sc);
+
+ /* Initialize ADS7846 Difference Reference mode */
+ (void)zssp_ic_send(ZSSP_IC_ADS7846,
+ (1<<ADSCTRL_ADR_SH) | (1<<ADSCTRL_STS_SH));
+ delay(5000);
+ (void)zssp_ic_send(ZSSP_IC_ADS7846,
+ (3<<ADSCTRL_ADR_SH) | (1<<ADSCTRL_STS_SH));
+ delay(5000);
+ (void)zssp_ic_send(ZSSP_IC_ADS7846,
+ (4<<ADSCTRL_ADR_SH) | (1<<ADSCTRL_STS_SH));
+ delay(5000);
+ (void)zssp_ic_send(ZSSP_IC_ADS7846,
+ (5<<ADSCTRL_ADR_SH) | (1<<ADSCTRL_STS_SH));
+ delay(5000);
- timeout_set(&(sc->sc_ts_poll), zts_poll, sc);
+ a.accessops = &zts_accessops;
+ a.accesscookie = sc;
+
+ sc->sc_wsmousedev = config_found(self, &a, wsmousedevprint);
+}
- sc->sc_enabled = 0;
+int
+zts_enable(void *v)
+{
+ struct zts_softc *sc = v;
+
+ if (sc->sc_enabled)
+ return EBUSY;
+
+ timeout_del(&sc->sc_ts_poll);
+
+ sc->sc_powerhook = powerhook_establish(zts_power, sc);
+ if (sc->sc_powerhook == NULL) {
+ printf("%s: enable failed\n", sc->sc_dev.dv_xname);
+ return ENOMEM;
+ }
+
+ pxa2x0_gpio_set_function(GPIO_TP_INT_C3K, GPIO_IN);
+
+ /* XXX */
+ if (sc->sc_gh == NULL)
+ sc->sc_gh = pxa2x0_gpio_intr_establish(GPIO_TP_INT_C3K,
+ IST_EDGE_FALLING, IPL_TTY, zts_irq, sc,
+ sc->sc_dev.dv_xname);
+ else
+ pxa2x0_gpio_intr_unmask(sc->sc_gh);
+
+ /* enable interrupts */
+ sc->sc_enabled = 1;
sc->sc_buttons = 0;
-/*
- pxa2x0_gpio_set_function(IRQ_GPIO_TP_INT_C3K, GPIO_IN);
+ return 0;
+}
- pxa2x0_gpio_intr_establish(IRQ_GPIO_TP_INT_C3K, IST_EDGE_RISING,
- IPL_TTY, zts_irq, sc, sc->sc_dev.dv_xname);
-*/
+void
+zts_disable(void *v)
+{
+ struct zts_softc *sc = v;
- printf ("\n");
+ timeout_del(&sc->sc_ts_poll);
- a.accessops = &zts_accessops;
- a.accesscookie = sc;
-
- sc->sc_wsmousedev = config_found(self, &a, wsmousedevprint);
+ if (sc->sc_powerhook != NULL) {
+ powerhook_disestablish(sc->sc_powerhook);
+ sc->sc_powerhook = NULL;
+ }
+
+ if (sc->sc_gh != NULL) {
+#if 0
+ pxa2x0_gpio_intr_disestablish(sc->sc_gh);
+ sc->sc_gh = NULL;
+#endif
+ }
+ /* disable interrupts */
+ sc->sc_enabled = 0;
}
void
-zts_poll(void *v)
+zts_power(int why, void *v)
{
struct zts_softc *sc = v;
- timeout_add(&sc->sc_ts_poll, POLL_TIMEOUT_RATE);
+ switch (why) {
+ case PWR_STANDBY:
+ case PWR_SUSPEND:
+ sc->sc_enabled = 0;
+#if 0
+ pxa2x0_gpio_intr_disestablish(sc->sc_gh);
+#endif
+ timeout_del(&sc->sc_ts_poll);
+
+ pxa2x0_gpio_intr_mask(sc->sc_gh);
- zts_irq(v);
+ /* Turn off reference voltage but leave ADC on. */
+ (void)zssp_ic_send(ZSSP_IC_ADS7846, (1 << ADSCTRL_PD1_SH) |
+ (1 << ADSCTRL_ADR_SH) | (1 << ADSCTRL_STS_SH));
+
+ pxa2x0_gpio_set_function(GPIO_TP_INT_C3K,
+ GPIO_OUT | GPIO_SET);
+ break;
+
+ case PWR_RESUME:
+ pxa2x0_gpio_set_function(GPIO_TP_INT_C3K, GPIO_IN);
+ pxa2x0_gpio_intr_mask(sc->sc_gh);
+
+ /* Enable automatic low power mode. */
+ (void)zssp_ic_send(ZSSP_IC_ADS7846,
+ (4 << ADSCTRL_ADR_SH) | (1 << ADSCTRL_STS_SH));
+
+#if 0
+ sc->sc_gh = pxa2x0_gpio_intr_establish(GPIO_TP_INT_C3K,
+ IST_EDGE_FALLING, IPL_TTY, zts_irq, sc,
+ sc->sc_dev.dv_xname);
+#else
+ pxa2x0_gpio_intr_unmask(sc->sc_gh);
+#endif
+ sc->sc_enabled = 1;
+ break;
+ }
}
-#define TS_STABLE 8
+struct zts_pos {
+ int x;
+ int y;
+ int z; /* touch pressure */
+};
+
#define NSAMPLES 3
+struct zts_pos zts_samples[NSAMPLES];
+int ztsavgloaded = 0;
+
+int zts_readpos(struct zts_pos *);
+void zts_avgpos(struct zts_pos *);
+
+#define HSYNC() \
+ do { \
+ while (pxa2x0_gpio_get_bit(GPIO_HSYNC_C3K) == 0); \
+ while (pxa2x0_gpio_get_bit(GPIO_HSYNC_C3K) != 0); \
+ } while (0)
+
+int pxa2x0_ccnt_enable(int);
+u_int32_t pxa2x0_read_ccnt(void);
+u_int32_t zts_sync_ads784x(int, int, u_int32_t);
+void zts_sync_send(u_int32_t);
+
int
-zts_irq(void *v)
+pxa2x0_ccnt_enable(int on)
{
- struct zts_softc *sc = v;
- u_int32_t cmd;
- u_int32_t t0, tn[NSAMPLES], xv, x[NSAMPLES], yv, y[NSAMPLES];
- int i, diff[NSAMPLES];
- int down = 1;
- int mindiff, mindiffv;
- extern int zkbd_modstate;
+ u_int32_t rv;
+
+ on = on ? 0x1 : 0x0;
+ __asm __volatile("mrc p14, 0, %0, c0, c1, 0" : "=r" (rv));
+ __asm __volatile("mcr p14, 0, %0, c0, c1, 0" : : "r" (on));
+ return ((int)(rv & 0x1));
+}
+
+u_int32_t
+pxa2x0_read_ccnt(void)
+{
+ u_int32_t rv;
+
+ __asm __volatile("mrc p14, 0, %0, c1, c1, 0" : "=r" (rv));
+ return (rv);
+}
+
+/*
+ * Communicate synchronously with the ADS784x touch screen controller.
+ */
+u_int32_t
+zts_sync_ads784x(int dorecv/* XXX */, int dosend/* XXX */, u_int32_t cmd)
+{
+ int ccen;
+ u_int32_t rv;
+
+ /* XXX poll hsync only if LCD is enabled */
+
+ /* start clock counter */
+ ccen = pxa2x0_ccnt_enable(1);
+
+ HSYNC();
+
+ if (dorecv)
+ /* read SSDR and disable ADS784x */
+ rv = zssp_ic_stop(ZSSP_IC_ADS7846);
+ else
+ rv = 0;
+
+ if (dosend)
+ zts_sync_send(cmd);
+
+ /* stop clock counter */
+ pxa2x0_ccnt_enable(ccen);
+
+ return (rv);
+}
+
+void
+zts_sync_send(u_int32_t cmd)
+{
+ u_int32_t tck;
+ u_int32_t a, b;
+
+ /* XXX */
+ tck = CCNT_HS_400_VGA_C3K - 151;
+
+ /* send dummy command; discard SSDR */
+ (void)zssp_ic_send(ZSSP_IC_ADS7846, cmd);
+
+ /* wait for refresh */
+ HSYNC();
+
+ /* wait after refresh */
+ a = pxa2x0_read_ccnt();
+ b = pxa2x0_read_ccnt();
+ while ((b - a) < tck)
+ b = pxa2x0_read_ccnt();
+
+ /* send the actual command; keep ADS784x enabled */
+ zssp_ic_start(ZSSP_IC_ADS7846, cmd);
+}
+
+int
+zts_readpos(struct zts_pos *pos)
+{
+ int cmd;
+ int t0, t1;
+ int down;
+
+ /* XXX */
+ pxa2x0_gpio_set_function(GPIO_HSYNC_C3K, GPIO_IN);
/* check that pen is down */
cmd = (1 << ADSCTRL_PD0_SH) | (1 << ADSCTRL_PD1_SH) |
(3 << ADSCTRL_ADR_SH) | (1 << ADSCTRL_STS_SH);
- t0 = pxa2x0_ssp_read_val(cmd);
- down &= !(t0 < 10);
+ t0 = zssp_ic_send(ZSSP_IC_ADS7846, cmd);
+ down = !(t0 < 10);
+ if (down == 0)
+ goto out;
+
+ /* Y */
+ cmd = (1 << ADSCTRL_PD0_SH) | (1 << ADSCTRL_PD1_SH) |
+ (1 << ADSCTRL_ADR_SH) | (1 << ADSCTRL_STS_SH);
+
+ (void)zts_sync_ads784x(0, 1, cmd);
+
+ /* Y */
+ cmd = (1 << ADSCTRL_PD0_SH) | (1 << ADSCTRL_PD1_SH) |
+ (1 << ADSCTRL_ADR_SH) | (1 << ADSCTRL_STS_SH);
+
+ (void)zts_sync_ads784x(1, 1, cmd);
- for (i = 0; i < NSAMPLES; i++) {
+ /* X */
+ cmd = (1 << ADSCTRL_PD0_SH) | (1 << ADSCTRL_PD1_SH) |
+ (5 << ADSCTRL_ADR_SH) | (1 << ADSCTRL_STS_SH);
+
+ pos->y = zts_sync_ads784x(1, 1, cmd);
+
+ /* T0 */
+ cmd = (1 << ADSCTRL_PD0_SH) | (1 << ADSCTRL_PD1_SH) |
+ (3 << ADSCTRL_ADR_SH) | (1 << ADSCTRL_STS_SH);
- /* X */
- cmd = (1 << ADSCTRL_PD0_SH) | (1 << ADSCTRL_PD1_SH) |
- (5 << ADSCTRL_ADR_SH) | (1 << ADSCTRL_STS_SH);
+ pos->x = zts_sync_ads784x(1, 1, cmd);
- x[i] = pxa2x0_ssp_read_val(cmd);
+ /* T1 */
+ cmd = (1 << ADSCTRL_PD0_SH) | (1 << ADSCTRL_PD1_SH) |
+ (4 << ADSCTRL_ADR_SH) | (1 << ADSCTRL_STS_SH);
- /* Y */
- cmd = (1 << ADSCTRL_PD0_SH) | (1 << ADSCTRL_PD1_SH) |
- (1 << ADSCTRL_ADR_SH) | (1 << ADSCTRL_STS_SH);
+ t0 = zts_sync_ads784x(1, 1, cmd);
+ t1 = zts_sync_ads784x(1, 0, cmd);
- y[i] = pxa2x0_ssp_read_val(cmd);
+ /* check that pen is still down */
+ /* XXX pressure sensitivity varies with X or what? */
+ if (t0 == 0 || (pos->x * (t1 - t0) / t0) >= 15000)
+ down = 0;
+ pos->z = down;
- /* check that pen is still down */
- cmd = (1 << ADSCTRL_PD0_SH) | (1 << ADSCTRL_PD1_SH) |
- (3 << ADSCTRL_ADR_SH) | (1 << ADSCTRL_STS_SH);
+out:
+ /* Enable automatic low power mode. */
+ cmd = (4 << ADSCTRL_ADR_SH) | (1 << ADSCTRL_STS_SH);
+ (void)zssp_ic_send(ZSSP_IC_ADS7846, cmd);
+
+ return (down);
+}
- tn[i] = pxa2x0_ssp_read_val(cmd);
- down &= !(tn[i] < 10);
+#define NAVGSAMPLES (NSAMPLES < 3 ? NSAMPLES : 3)
+void
+zts_avgpos(struct zts_pos *pos)
+{
+ struct zts_pos *tpp = zts_samples;
+ int diff[NAVGSAMPLES];
+ int mindiff, mindiffv;
+ int n;
+ int i;
+ static int tail;
+
+ if (ztsavgloaded < NAVGSAMPLES) {
+ tpp[(tail + ztsavgloaded) % NSAMPLES] = *pos;
+ ztsavgloaded++;
+ return;
}
+ tpp[tail] = *pos;
+ tail = (tail+1) % NSAMPLES;
+
/* X */
- for (i = 0 ; i < NSAMPLES; i++) {
+ i = tail;
+ for (n = 0 ; n < NAVGSAMPLES; n++) {
int alt;
- alt = i+1;
- if (alt == NSAMPLES)
- alt = 0;
-
- diff[i] = x[i]-x[alt];
- if (diff[i] < 0)
- diff[i] = -diff[i]; /* ABS */
+ alt = (i+1) % NSAMPLES;
+ diff[n] = tpp[i].x - tpp[alt].x;
+ if (diff[n] < 0)
+ diff[n] = - diff[n]; /* ABS */
+ i = alt;
}
mindiffv = diff[0];
mindiff = 0;
- if (diff[1] < mindiffv) {
- mindiffv = diff[1];
- mindiff = 1;
- }
- if (diff[2] < mindiffv) {
- mindiff = 2;
- }
- switch (mindiff) {
- case 0:
- xv = (x[0] + x[1]) / 2;
- break;
- case 1:
- xv = (x[1] + x[2]) / 2;
- break;
- case 2:
- xv = (x[2] + x[0]) / 2;
- break;
+ for (n = 1; n < NAVGSAMPLES; n++) {
+ if (diff[n] < mindiffv) {
+ mindiffv = diff[n];
+ mindiff = n;
+ }
}
+ pos->x = (tpp[(tail + mindiff) % NSAMPLES].x +
+ tpp[(tail + mindiff + 1) % NSAMPLES].x) / 2;
/* Y */
- for (i = 0 ; i < NSAMPLES; i++) {
+ i = tail;
+ for (n = 0 ; n < NAVGSAMPLES; n++) {
int alt;
- alt = i+1;
- if (alt == NSAMPLES)
- alt = 0;
-
- diff[i] = y[i]-y[alt];
- if (diff[i] < 0)
- diff[i] = -diff[i]; /* ABS */
+ alt = (i+1) % NSAMPLES;
+ diff[n] = tpp[i].y - tpp[alt].y;
+ if (diff[n] < 0)
+ diff[n] = - diff[n]; /* ABS */
+ i = alt;
}
mindiffv = diff[0];
mindiff = 0;
- if (diff[1] < mindiffv) {
- mindiffv = diff[1];
- mindiff = 1;
+ for (n = 1; n < NAVGSAMPLES; n++) {
+ if (diff[n] < mindiffv) {
+ mindiffv = diff[n];
+ mindiff = n;
+ }
}
- if (diff[2] < mindiffv) {
- mindiff = 2;
+ pos->y = (tpp[(tail + mindiff) % NSAMPLES].y +
+ tpp[(tail + mindiff + 1) % NSAMPLES].y) / 2;
+}
+
+void
+zts_poll(void *v)
+{
+ int s;
+
+ s = spltty();
+ (void)zts_irq(v);
+ splx(s);
+}
+
+#define TS_STABLE 8
+int
+zts_irq(void *v)
+{
+ struct zts_softc *sc = v;
+ struct zts_pos tp;
+ int s;
+ int pindown;
+ int down;
+ extern int zkbd_modstate;
+
+ if (!sc->sc_enabled)
+ return 0;
+
+ s = splhigh();
+ pindown = pxa2x0_gpio_get_bit(GPIO_TP_INT_C3K) ? 0 : 1;
+ if (pindown) {
+ pxa2x0_gpio_intr_mask(sc->sc_gh);
+ timeout_add(&sc->sc_ts_poll, POLL_TIMEOUT_RATE1);
}
- switch (mindiff) {
- case 0:
- yv = (y[0] + y[1]) / 2;
- break;
- case 1:
- yv = (y[1] + y[2]) / 2;
- break;
- case 2:
- yv = (y[2] + y[0]) / 2;
- break;
+
+ down = zts_readpos(&tp);
+
+ if (!pindown) {
+ pxa2x0_gpio_intr_unmask(sc->sc_gh);
+ timeout_add(&sc->sc_ts_poll, POLL_TIMEOUT_RATE0);
+ ztsavgloaded = 0;
}
+ pxa2x0_gpio_clear_intr(GPIO_TP_INT_C3K);
+ splx(s);
+ if (down)
+ zts_avgpos(&tp);
+
if (zkbd_modstate != 0 && down) {
if(zkbd_modstate & (1 << 1)) {
/* Fn */
@@ -243,54 +501,23 @@ zts_irq(void *v)
}
if (!down) {
/* x/y values are not reliable when pen is up */
- xv = sc->sc_oldx;
- yv = sc->sc_oldy;
+ tp.x = sc->sc_oldx;
+ tp.y = sc->sc_oldy;
}
+
if (down || sc->sc_buttons != down) {
- wsmouse_input(sc->sc_wsmousedev, down, xv, yv, 0 /* z */,
+ wsmouse_input(sc->sc_wsmousedev, down, tp.x, tp.y, 0 /* z */,
WSMOUSE_INPUT_ABSOLUTE_X | WSMOUSE_INPUT_ABSOLUTE_Y |
WSMOUSE_INPUT_ABSOLUTE_Z);
sc->sc_buttons = down;
- sc->sc_oldx = xv;
- sc->sc_oldy = yv;
+ sc->sc_oldx = tp.x;
+ sc->sc_oldy = tp.y;
}
- /*
- pxa2x0_gpio_clear_intr(IRQ_GPIO_TP_INT_C3K);
- */
-
return 1;
}
int
-zts_enable(void *v)
-{
- struct zts_softc *sc = v;
-
- if (sc->sc_enabled)
- return EBUSY;
-
- sc->sc_enabled = 1;
- sc->sc_buttons = 0;
-
- /* enable interrupt, or polling */
- timeout_add(&sc->sc_ts_poll, POLL_TIMEOUT_RATE);
-
- return 0;
-}
-
-void
-zts_disable(void *v)
-{
- struct zts_softc *sc = v;
-
- timeout_del(&sc->sc_ts_poll);
-
- /* disable interrupts/polling */
- sc->sc_enabled = 0;
-}
-
-int
zts_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p)
{