summaryrefslogtreecommitdiff
path: root/sys/arch/zaurus/dev
diff options
context:
space:
mode:
Diffstat (limited to 'sys/arch/zaurus/dev')
-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)
{