Module Name:    src
Committed By:   jmcneill
Date:           Sun Aug 27 02:19:46 UTC 2017

Modified Files:
        src/sys/arch/arm/sunxi: files.sunxi
Added Files:
        src/sys/arch/arm/sunxi: sunxi_ts.c

Log Message:
Add sun5i touchscreen driver.


To generate a diff of this commit:
cvs rdiff -u -r1.18 -r1.19 src/sys/arch/arm/sunxi/files.sunxi
cvs rdiff -u -r0 -r1.1 src/sys/arch/arm/sunxi/sunxi_ts.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/arch/arm/sunxi/files.sunxi
diff -u src/sys/arch/arm/sunxi/files.sunxi:1.18 src/sys/arch/arm/sunxi/files.sunxi:1.19
--- src/sys/arch/arm/sunxi/files.sunxi:1.18	Sat Aug 26 22:24:50 2017
+++ src/sys/arch/arm/sunxi/files.sunxi	Sun Aug 27 02:19:46 2017
@@ -1,4 +1,4 @@
-#	$NetBSD: files.sunxi,v 1.18 2017/08/26 22:24:50 jmcneill Exp $
+#	$NetBSD: files.sunxi,v 1.19 2017/08/27 02:19:46 jmcneill Exp $
 #
 # Configuration info for Allwinner sunxi family SoCs
 #
@@ -143,6 +143,11 @@ file	arch/arm/sunxi/sun8i_h3_codec.c		h3
 attach	genfb at fdt with sunxi_debe
 file	arch/arm/sunxi/sunxi_debe.c		sunxi_debe
 
+# Touch Screen controller
+device	sunxits: wsmousedev, tpcalib
+attach	sunxits at fdt with sunxi_ts
+file	arch/arm/sunxi/sunxi_ts.c		sunxi_ts
+
 # SOC parameters
 defflag	opt_soc.h			SOC_SUNXI
 defflag	opt_soc.h			SOC_SUN5I: SOC_SUNXI

Added files:

Index: src/sys/arch/arm/sunxi/sunxi_ts.c
diff -u /dev/null src/sys/arch/arm/sunxi/sunxi_ts.c:1.1
--- /dev/null	Sun Aug 27 02:19:46 2017
+++ src/sys/arch/arm/sunxi/sunxi_ts.c	Sun Aug 27 02:19:46 2017
@@ -0,0 +1,343 @@
+/* $NetBSD: sunxi_ts.c,v 1.1 2017/08/27 02:19:46 jmcneill Exp $ */
+
+/*-
+ * Copyright (c) 2017 Jared McNeill <jmcne...@invisible.ca>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+
+__KERNEL_RCSID(0, "$NetBSD: sunxi_ts.c,v 1.1 2017/08/27 02:19:46 jmcneill Exp $");
+
+#include <sys/param.h>
+#include <sys/bus.h>
+#include <sys/device.h>
+#include <sys/intr.h>
+#include <sys/systm.h>
+#include <sys/time.h>
+
+#include <dev/fdt/fdtvar.h>
+
+#include <dev/wscons/wsconsio.h>
+#include <dev/wscons/wsmousevar.h>
+#include <dev/wscons/tpcalibvar.h>
+
+#define	TS_TP_SENSITIVITY_ADJUST_DEFAULT	15
+#define	TS_FILTER_TYPE_DEFAULT			1
+
+#define	TP_CTRL0		0x00
+#define	 TP_CTRL0_ADC_FIRST_DLY		__BITS(31,24)
+#define	 TP_CTRL0_ADC_FIRST_DLY_MODE	__BIT(23)
+#define	 TP_CTRL0_ADC_CLK_SELECT	__BIT(22)
+#define	 TP_CTRL0_ADC_CLK_DIVIDER	__BITS(21,20)
+#define	 TP_CTRL0_FS_DIV		__BITS(19,16)
+#define	 TP_CTRL0_T_ACQ			__BITS(15,0)
+#define	TP_CTRL1		0x04
+#define	 TP_CTRL1_STYLUS_UP_DEBOUNCE	__BITS(19,12)
+#define	 TP_CTRL1_STYLUS_UP_DEBOUNCE_EN	__BIT(9)
+#define	 TP_CTRL1_TOUCH_PAN_CALI_EN	__BIT(6)
+#define	 TP_CTRL1_TP_DUAL_EN		__BIT(5)
+#define	 TP_CTRL1_TP_MODE_EN		__BIT(4)
+#define	 TP_CTRL1_TP_ADC_SELECT		__BIT(3)
+#define	 TP_CTRL1_ADC_CHAN_SELECT	__BITS(2,0)
+#define	TP_CTRL2		0x08
+#define	 TP_CTRL2_SENSITIVE_ADJUST	__BITS(31,28)
+#define	 TP_CTRL2_MODE_SELECT		__BITS(27,26)
+#define	 TP_CTRL2_PRE_MEA_EN		__BIT(24)
+#define	 TP_CTRL2_PRE_MEA_THRE_CNT	__BITS(23,0)
+#define	TP_CTRL3		0x0c
+#define	 TP_CTRL3_FILTER_EN		__BIT(2)
+#define	 TP_CTRL3_FILTER_TYPE		__BITS(1,0)
+#define	TP_INT			0x10
+#define	 TP_INT_OVERRUN_IRQ_EN	__BIT(17)
+#define	 TP_INT_DATA_IRQ_EN	__BIT(16)
+#define	 TP_INT_DATA_XY_CHANGE	__BIT(13)
+#define	 TP_INT_FIFO_TRIG_LEVEL	__BITS(12,8)
+#define	 TP_INT_DATA_DRQ_EN	__BIT(7)
+#define	 TP_INT_FIFO_FLUSH	__BIT(4)
+#define	 TP_INT_UP_IRQ_EN	__BIT(1)
+#define	 TP_INT_DOWN_IRQ_EN	__BIT(0)
+#define	TP_FIFOCS		0x14
+#define	 TP_FIFOCS_OVERRUN_PENDING __BIT(17)
+#define	 TP_FIFOCS_DATA_PENDING	__BIT(16)
+#define	 TP_FIFOCS_RXA_CNT	__BITS(12,8)
+#define	 TP_FIFOCS_IDLE_FLG	__BIT(2)
+#define	 TP_FIFOCS_UP_PENDING	__BIT(1)
+#define	 TP_FIFOCS_DOWN_PENDING	__BIT(0)
+#define	TP_CDAT			0x1c
+#define	 TP_CDAT_MASK		__BITS(11,0)
+#define	TP_DATA			0x24
+#define	 TP_DATA_MASK		__BITS(11,0)
+#define	TP_IO_CONFIG		0x28
+#define	TP_PORT_DATA		0x2c
+#define	 TP_PORT_DATA_MASK	__BITS(3,0)
+
+static int sunxi_ts_match(device_t, cfdata_t, void *);
+static void sunxi_ts_attach(device_t, device_t, void *);
+
+static const char * const compatible[] = {
+	"allwinner,sun5i-a13-ts",
+	NULL
+};
+
+static struct wsmouse_calibcoords sunxi_ts_default_calib = {
+	.minx = 0,
+	.miny = 0,
+	.maxx = __SHIFTOUT_MASK(TP_DATA_MASK),
+	.maxy = __SHIFTOUT_MASK(TP_DATA_MASK),
+	.samplelen = WSMOUSE_CALIBCOORDS_RESET,
+};
+
+struct sunxi_ts_softc {
+	device_t		sc_dev;
+	int			sc_phandle;
+	bus_space_tag_t		sc_bst;
+	bus_space_handle_t	sc_bsh;
+
+	bool			sc_ts_attached;
+	bool			sc_ts_inverted_x;
+	bool			sc_ts_inverted_y;
+
+	struct tpcalib_softc	sc_tpcalib;
+	device_t		sc_wsmousedev;
+	bool			sc_ignoredata;
+
+	u_int			sc_tp_x;
+	u_int			sc_tp_y;
+	u_int			sc_tp_btns;
+};
+
+CFATTACH_DECL_NEW(sunxi_ts, sizeof(struct sunxi_ts_softc),
+	sunxi_ts_match, sunxi_ts_attach, NULL, NULL);
+
+#define	TS_READ(sc, reg)		\
+	bus_space_read_4((sc)->sc_bst, (sc)->sc_bsh, (reg))
+#define	TS_WRITE(sc, reg, val)		\
+	bus_space_write_4((sc)->sc_bst, (sc)->sc_bsh, (reg), (val))
+
+static int
+sunxi_ts_enable(void *v)
+{
+	struct sunxi_ts_softc * const sc = v;
+
+	/* reset state */
+	sc->sc_ignoredata = true;
+	sc->sc_tp_x = 0;
+	sc->sc_tp_y = 0;
+	sc->sc_tp_btns = 0;
+
+	/* Enable touchpanel IRQs */
+	TS_WRITE(sc, TP_INT,
+	    TP_INT_DATA_IRQ_EN | TP_INT_FIFO_FLUSH | TP_INT_UP_IRQ_EN |
+	    __SHIFTIN(1, TP_INT_FIFO_TRIG_LEVEL));
+
+	return 0;
+}
+
+static void
+sunxi_ts_disable(void *v)
+{
+	struct sunxi_ts_softc * const sc = v;
+
+	/* Disable touchpanel IRQs */
+	TS_WRITE(sc, TP_INT, 0);
+}
+
+static int
+sunxi_ts_ioctl(void *v, u_long cmd, void *data, int flag, lwp_t *l)
+{
+	struct sunxi_ts_softc * const sc = v;
+	struct wsmouse_id *id;
+
+	switch (cmd) {
+	case WSMOUSEIO_GTYPE:
+		*(int *)data = WSMOUSE_TYPE_TPANEL;
+		return 0;
+
+	case WSMOUSEIO_GETID:
+		id = data;
+		if (id->type != WSMOUSE_ID_TYPE_UIDSTR)
+			return EINVAL;
+		snprintf(id->data, WSMOUSE_ID_MAXLEN,
+		    "Allwinner TS SN000000");
+		id->length = strlen(id->data);
+		return 0;
+
+	case WSMOUSEIO_SCALIBCOORDS:
+	case WSMOUSEIO_GCALIBCOORDS:
+		return tpcalib_ioctl(&sc->sc_tpcalib, cmd, data, flag, l);
+	}
+
+	return EPASSTHROUGH;
+}
+
+static const struct wsmouse_accessops sunxi_ts_accessops = {
+	.enable = sunxi_ts_enable,
+	.disable = sunxi_ts_disable,
+	.ioctl = sunxi_ts_ioctl,
+};
+
+static int
+sunxi_ts_intr(void *priv)
+{
+	struct sunxi_ts_softc * const sc = priv;
+	uint32_t fifocs, x, y;
+	int s;
+
+	fifocs = TS_READ(sc, TP_FIFOCS);
+
+	if (fifocs & TP_FIFOCS_DATA_PENDING) {
+		x = TS_READ(sc, TP_DATA);
+		y = TS_READ(sc, TP_DATA);
+		if (sc->sc_ignoredata) {
+			/* Discard the first report */
+			sc->sc_ignoredata = false;
+		} else {
+			if (sc->sc_ts_inverted_x)
+				x = __SHIFTOUT_MASK(TP_DATA_MASK) - x;
+			if (sc->sc_ts_inverted_y)
+				y = __SHIFTOUT_MASK(TP_DATA_MASK) - y;
+			tpcalib_trans(&sc->sc_tpcalib, x, y,
+			    &sc->sc_tp_x, &sc->sc_tp_y);
+			sc->sc_tp_btns |= 1;
+
+			s = spltty();
+			wsmouse_input(sc->sc_wsmousedev,
+			    sc->sc_tp_btns, sc->sc_tp_x, sc->sc_tp_y, 0, 0,
+			    WSMOUSE_INPUT_ABSOLUTE_X | WSMOUSE_INPUT_ABSOLUTE_Y);
+			splx(s);
+		}
+	}
+
+	if (fifocs & TP_FIFOCS_UP_PENDING) {
+		sc->sc_ignoredata = true;
+		sc->sc_tp_btns &= ~1;
+		s = spltty();
+		wsmouse_input(sc->sc_wsmousedev,
+		    sc->sc_tp_btns, sc->sc_tp_x, sc->sc_tp_y, 0, 0,
+		    WSMOUSE_INPUT_ABSOLUTE_X | WSMOUSE_INPUT_ABSOLUTE_Y);
+		splx(s);
+	}
+
+	TS_WRITE(sc, TP_FIFOCS, fifocs);
+
+	return 1;
+}
+
+static void
+sunxi_ts_init(struct sunxi_ts_softc *sc)
+{
+	u_int tp_sensitivity_adjust = TS_TP_SENSITIVITY_ADJUST_DEFAULT;
+	u_int filter_type = TS_FILTER_TYPE_DEFAULT;
+
+	of_getprop_uint32(sc->sc_phandle, "allwinner,tp-sensitive-adjust",
+	    &tp_sensitivity_adjust);
+	of_getprop_uint32(sc->sc_phandle, "allwinner,filter-type",
+	    &filter_type);
+
+	TS_WRITE(sc, TP_CTRL0,
+	    __SHIFTIN(0, TP_CTRL0_ADC_CLK_SELECT) |
+	    __SHIFTIN(2, TP_CTRL0_ADC_CLK_DIVIDER) |
+	    __SHIFTIN(7, TP_CTRL0_FS_DIV) |
+	    __SHIFTIN(63, TP_CTRL0_T_ACQ));
+	TS_WRITE(sc, TP_CTRL2,
+	    __SHIFTIN(0, TP_CTRL2_MODE_SELECT) |
+	    __SHIFTIN(tp_sensitivity_adjust, TP_CTRL2_SENSITIVE_ADJUST));
+	TS_WRITE(sc, TP_CTRL3,
+	    TP_CTRL3_FILTER_EN |
+	    __SHIFTIN(filter_type, TP_CTRL3_FILTER_TYPE));
+	TS_WRITE(sc, TP_CTRL1,
+	    TP_CTRL1_TP_MODE_EN |
+	    TP_CTRL1_STYLUS_UP_DEBOUNCE_EN |
+	    __SHIFTIN(5, TP_CTRL1_STYLUS_UP_DEBOUNCE));
+}
+
+static int
+sunxi_ts_match(device_t parent, cfdata_t cf, void *aux)
+{
+	struct fdt_attach_args * const faa = aux;
+
+	return of_match_compatible(faa->faa_phandle, compatible);
+}
+
+static void
+sunxi_ts_attach(device_t parent, device_t self, void *aux)
+{
+	struct sunxi_ts_softc * const sc = device_private(self);
+	struct fdt_attach_args * const faa = aux;
+	const int phandle = faa->faa_phandle;
+	struct wsmousedev_attach_args a;
+	char intrstr[128];
+	bus_addr_t addr;
+	bus_size_t size;
+	void *ih;
+
+	if (fdtbus_get_reg(phandle, 0, &addr, &size) != 0) {
+		aprint_error(": couldn't get registers\n");
+		return;
+	}
+
+	if (!fdtbus_intr_str(phandle, 0, intrstr, sizeof(intrstr))) {
+		aprint_error(": failed to decode interrupt\n");
+		return;
+	}
+
+	sc->sc_dev = self;
+	sc->sc_phandle = phandle;
+	sc->sc_bst = faa->faa_bst;
+	if (bus_space_map(sc->sc_bst, addr, size, 0, &sc->sc_bsh) != 0) {
+		aprint_error(": couldn't map registers\n");
+		return;
+	}
+	sc->sc_ts_attached = of_getprop_bool(phandle, "allwinner,ts-attached");
+	sc->sc_ts_inverted_x = of_getprop_bool(phandle,
+	    "touchscreen-inverted-x");
+	sc->sc_ts_inverted_y = of_getprop_bool(phandle,
+	    "touchscreen-inverted-y");
+
+	aprint_naive("\n");
+	aprint_normal(": Touch Screen Controller\n");
+
+	sunxi_ts_init(sc);
+
+	ih = fdtbus_intr_establish(phandle, 0, IPL_VM, 0, sunxi_ts_intr, sc);
+	if (ih == NULL) {
+		aprint_error_dev(self, "couldn't establish interrupt on %s\n",
+		    intrstr);
+		return;
+	}
+	aprint_normal_dev(self, "interrupting on %s\n", intrstr);
+
+	if (sc->sc_ts_attached) {
+		tpcalib_init(&sc->sc_tpcalib);
+		tpcalib_ioctl(&sc->sc_tpcalib, WSMOUSEIO_SCALIBCOORDS,
+		    &sunxi_ts_default_calib, 0, 0);
+
+		memset(&a, 0, sizeof(a));
+		a.accessops = &sunxi_ts_accessops;
+		a.accesscookie = sc;
+		sc->sc_wsmousedev = config_found_ia(self, "wsmousedev",
+		    &a, wsmousedevprint);
+	}
+}

Reply via email to