11.10Sthorpej/* $NetBSD: sunxi_ts.c,v 1.10 2021/08/07 16:18:45 thorpej Exp $ */
21.1Sjmcneill
31.1Sjmcneill/*-
41.1Sjmcneill * Copyright (c) 2017 Jared McNeill <jmcneill@invisible.ca>
51.1Sjmcneill * All rights reserved.
61.1Sjmcneill *
71.1Sjmcneill * Redistribution and use in source and binary forms, with or without
81.1Sjmcneill * modification, are permitted provided that the following conditions
91.1Sjmcneill * are met:
101.1Sjmcneill * 1. Redistributions of source code must retain the above copyright
111.1Sjmcneill *    notice, this list of conditions and the following disclaimer.
121.1Sjmcneill * 2. Redistributions in binary form must reproduce the above copyright
131.1Sjmcneill *    notice, this list of conditions and the following disclaimer in the
141.1Sjmcneill *    documentation and/or other materials provided with the distribution.
151.1Sjmcneill *
161.1Sjmcneill * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
171.1Sjmcneill * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
181.1Sjmcneill * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
191.1Sjmcneill * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
201.1Sjmcneill * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
211.1Sjmcneill * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
221.1Sjmcneill * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
231.1Sjmcneill * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
241.1Sjmcneill * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
251.1Sjmcneill * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
261.1Sjmcneill * POSSIBILITY OF SUCH DAMAGE.
271.1Sjmcneill */
281.1Sjmcneill
291.1Sjmcneill#include <sys/cdefs.h>
301.1Sjmcneill
311.10Sthorpej__KERNEL_RCSID(0, "$NetBSD: sunxi_ts.c,v 1.10 2021/08/07 16:18:45 thorpej Exp $");
321.1Sjmcneill
331.1Sjmcneill#include <sys/param.h>
341.1Sjmcneill#include <sys/bus.h>
351.1Sjmcneill#include <sys/device.h>
361.1Sjmcneill#include <sys/intr.h>
371.1Sjmcneill#include <sys/systm.h>
381.1Sjmcneill#include <sys/time.h>
391.1Sjmcneill
401.1Sjmcneill#include <dev/fdt/fdtvar.h>
411.1Sjmcneill
421.2Sjmcneill#include <dev/sysmon/sysmonvar.h>
431.2Sjmcneill
441.1Sjmcneill#include <dev/wscons/wsconsio.h>
451.1Sjmcneill#include <dev/wscons/wsmousevar.h>
461.1Sjmcneill#include <dev/wscons/tpcalibvar.h>
471.1Sjmcneill
481.1Sjmcneill#define	TS_TP_SENSITIVITY_ADJUST_DEFAULT	15
491.1Sjmcneill#define	TS_FILTER_TYPE_DEFAULT			1
501.1Sjmcneill
511.1Sjmcneill#define	TP_CTRL0		0x00
521.1Sjmcneill#define	 TP_CTRL0_ADC_FIRST_DLY		__BITS(31,24)
531.1Sjmcneill#define	 TP_CTRL0_ADC_FIRST_DLY_MODE	__BIT(23)
541.1Sjmcneill#define	 TP_CTRL0_ADC_CLK_SELECT	__BIT(22)
551.1Sjmcneill#define	 TP_CTRL0_ADC_CLK_DIVIDER	__BITS(21,20)
561.1Sjmcneill#define	 TP_CTRL0_FS_DIV		__BITS(19,16)
571.1Sjmcneill#define	 TP_CTRL0_T_ACQ			__BITS(15,0)
581.1Sjmcneill#define	TP_CTRL1		0x04
591.1Sjmcneill#define	 TP_CTRL1_STYLUS_UP_DEBOUNCE	__BITS(19,12)
601.1Sjmcneill#define	 TP_CTRL1_STYLUS_UP_DEBOUNCE_EN	__BIT(9)
611.1Sjmcneill#define	 TP_CTRL1_TOUCH_PAN_CALI_EN	__BIT(6)
621.1Sjmcneill#define	 TP_CTRL1_TP_DUAL_EN		__BIT(5)
631.1Sjmcneill#define	 TP_CTRL1_TP_MODE_EN		__BIT(4)
641.1Sjmcneill#define	 TP_CTRL1_TP_ADC_SELECT		__BIT(3)
651.1Sjmcneill#define	 TP_CTRL1_ADC_CHAN_SELECT	__BITS(2,0)
661.1Sjmcneill#define	TP_CTRL2		0x08
671.1Sjmcneill#define	 TP_CTRL2_SENSITIVE_ADJUST	__BITS(31,28)
681.1Sjmcneill#define	 TP_CTRL2_MODE_SELECT		__BITS(27,26)
691.1Sjmcneill#define	 TP_CTRL2_PRE_MEA_EN		__BIT(24)
701.1Sjmcneill#define	 TP_CTRL2_PRE_MEA_THRE_CNT	__BITS(23,0)
711.1Sjmcneill#define	TP_CTRL3		0x0c
721.1Sjmcneill#define	 TP_CTRL3_FILTER_EN		__BIT(2)
731.1Sjmcneill#define	 TP_CTRL3_FILTER_TYPE		__BITS(1,0)
741.1Sjmcneill#define	TP_INT			0x10
751.2Sjmcneill#define	 TP_INT_TEMP_IRQ_EN	__BIT(18)
761.1Sjmcneill#define	 TP_INT_OVERRUN_IRQ_EN	__BIT(17)
771.1Sjmcneill#define	 TP_INT_DATA_IRQ_EN	__BIT(16)
781.1Sjmcneill#define	 TP_INT_DATA_XY_CHANGE	__BIT(13)
791.1Sjmcneill#define	 TP_INT_FIFO_TRIG_LEVEL	__BITS(12,8)
801.1Sjmcneill#define	 TP_INT_DATA_DRQ_EN	__BIT(7)
811.1Sjmcneill#define	 TP_INT_FIFO_FLUSH	__BIT(4)
821.1Sjmcneill#define	 TP_INT_UP_IRQ_EN	__BIT(1)
831.1Sjmcneill#define	 TP_INT_DOWN_IRQ_EN	__BIT(0)
841.1Sjmcneill#define	TP_FIFOCS		0x14
851.2Sjmcneill#define	 TP_FIFOCS_TEMP_IRQ_PENDING __BIT(18)
861.1Sjmcneill#define	 TP_FIFOCS_OVERRUN_PENDING __BIT(17)
871.1Sjmcneill#define	 TP_FIFOCS_DATA_PENDING	__BIT(16)
881.1Sjmcneill#define	 TP_FIFOCS_RXA_CNT	__BITS(12,8)
891.1Sjmcneill#define	 TP_FIFOCS_IDLE_FLG	__BIT(2)
901.1Sjmcneill#define	 TP_FIFOCS_UP_PENDING	__BIT(1)
911.1Sjmcneill#define	 TP_FIFOCS_DOWN_PENDING	__BIT(0)
921.2Sjmcneill#define	TP_TPR			0x18
931.2Sjmcneill#define	 TP_TPR_TEMP_EN		__BIT(16)
941.2Sjmcneill#define	 TP_TPR_TEMP_PER	__BITS(15,0)
951.1Sjmcneill#define	TP_CDAT			0x1c
961.1Sjmcneill#define	 TP_CDAT_MASK		__BITS(11,0)
971.2Sjmcneill#define	TEMP_DATA		0x20
981.2Sjmcneill#define	 TEMP_DATA_MASK		__BITS(11,0)
991.1Sjmcneill#define	TP_DATA			0x24
1001.1Sjmcneill#define	 TP_DATA_MASK		__BITS(11,0)
1011.1Sjmcneill#define	TP_IO_CONFIG		0x28
1021.1Sjmcneill#define	TP_PORT_DATA		0x2c
1031.1Sjmcneill#define	 TP_PORT_DATA_MASK	__BITS(3,0)
1041.1Sjmcneill
1051.2Sjmcneill#define	TEMP_C_TO_K		273150000
1061.2Sjmcneill
1071.1Sjmcneillstatic int sunxi_ts_match(device_t, cfdata_t, void *);
1081.1Sjmcneillstatic void sunxi_ts_attach(device_t, device_t, void *);
1091.1Sjmcneill
1101.2Sjmcneillstruct sunxi_ts_config {
1111.2Sjmcneill	int64_t	temp_offset;
1121.2Sjmcneill	int64_t	temp_step;
1131.2Sjmcneill	uint32_t tp_mode_en_mask;
1141.2Sjmcneill};
1151.2Sjmcneill
1161.2Sjmcneillstatic const struct sunxi_ts_config sun4i_a10_ts_config = {
1171.2Sjmcneill	.temp_offset = 257000000,
1181.2Sjmcneill	.temp_step = 133000,
1191.2Sjmcneill	.tp_mode_en_mask = TP_CTRL1_TP_MODE_EN,
1201.2Sjmcneill};
1211.2Sjmcneill
1221.2Sjmcneillstatic const struct sunxi_ts_config sun5i_a13_ts_config = {
1231.2Sjmcneill	.temp_offset = 144700000,
1241.2Sjmcneill	.temp_step = 100000,
1251.2Sjmcneill	.tp_mode_en_mask = TP_CTRL1_TP_MODE_EN,
1261.2Sjmcneill};
1271.2Sjmcneill
1281.2Sjmcneillstatic const struct sunxi_ts_config sun6i_a31_ts_config = {
1291.2Sjmcneill	.temp_offset = 271000000,
1301.2Sjmcneill	.temp_step = 167000,
1311.2Sjmcneill	.tp_mode_en_mask = TP_CTRL1_TP_DUAL_EN,
1321.2Sjmcneill};
1331.2Sjmcneill
1341.5Sthorpejstatic const struct device_compatible_entry compat_data[] = {
1351.5Sthorpej	{ .compat = "allwinner,sun4i-a10-ts",	.data = &sun4i_a10_ts_config },
1361.5Sthorpej	{ .compat = "allwinner,sun5i-a13-ts",	.data = &sun5i_a13_ts_config },
1371.5Sthorpej	{ .compat = "allwinner,sun6i-a31-ts",	.data = &sun6i_a31_ts_config },
1381.7Sthorpej	DEVICE_COMPAT_EOL
1391.1Sjmcneill};
1401.1Sjmcneill
1411.1Sjmcneillstatic struct wsmouse_calibcoords sunxi_ts_default_calib = {
1421.1Sjmcneill	.minx = 0,
1431.1Sjmcneill	.miny = 0,
1441.1Sjmcneill	.maxx = __SHIFTOUT_MASK(TP_DATA_MASK),
1451.1Sjmcneill	.maxy = __SHIFTOUT_MASK(TP_DATA_MASK),
1461.1Sjmcneill	.samplelen = WSMOUSE_CALIBCOORDS_RESET,
1471.1Sjmcneill};
1481.1Sjmcneill
1491.1Sjmcneillstruct sunxi_ts_softc {
1501.1Sjmcneill	device_t		sc_dev;
1511.1Sjmcneill	int			sc_phandle;
1521.1Sjmcneill	bus_space_tag_t		sc_bst;
1531.1Sjmcneill	bus_space_handle_t	sc_bsh;
1541.1Sjmcneill
1551.2Sjmcneill	const struct sunxi_ts_config *sc_conf;
1561.2Sjmcneill
1571.1Sjmcneill	bool			sc_ts_attached;
1581.1Sjmcneill	bool			sc_ts_inverted_x;
1591.1Sjmcneill	bool			sc_ts_inverted_y;
1601.1Sjmcneill
1611.1Sjmcneill	struct tpcalib_softc	sc_tpcalib;
1621.1Sjmcneill	device_t		sc_wsmousedev;
1631.1Sjmcneill	bool			sc_ignoredata;
1641.1Sjmcneill
1651.1Sjmcneill	u_int			sc_tp_x;
1661.1Sjmcneill	u_int			sc_tp_y;
1671.1Sjmcneill	u_int			sc_tp_btns;
1681.2Sjmcneill
1691.2Sjmcneill	struct sysmon_envsys	*sc_sme;
1701.2Sjmcneill	envsys_data_t		sc_temp_data;
1711.1Sjmcneill};
1721.1Sjmcneill
1731.1SjmcneillCFATTACH_DECL_NEW(sunxi_ts, sizeof(struct sunxi_ts_softc),
1741.1Sjmcneill	sunxi_ts_match, sunxi_ts_attach, NULL, NULL);
1751.1Sjmcneill
1761.1Sjmcneill#define	TS_READ(sc, reg)		\
1771.1Sjmcneill	bus_space_read_4((sc)->sc_bst, (sc)->sc_bsh, (reg))
1781.1Sjmcneill#define	TS_WRITE(sc, reg, val)		\
1791.1Sjmcneill	bus_space_write_4((sc)->sc_bst, (sc)->sc_bsh, (reg), (val))
1801.1Sjmcneill
1811.1Sjmcneillstatic int
1821.1Sjmcneillsunxi_ts_enable(void *v)
1831.1Sjmcneill{
1841.1Sjmcneill	struct sunxi_ts_softc * const sc = v;
1851.2Sjmcneill	uint32_t val;
1861.1Sjmcneill
1871.1Sjmcneill	/* reset state */
1881.1Sjmcneill	sc->sc_ignoredata = true;
1891.1Sjmcneill	sc->sc_tp_x = 0;
1901.1Sjmcneill	sc->sc_tp_y = 0;
1911.1Sjmcneill	sc->sc_tp_btns = 0;
1921.1Sjmcneill
1931.1Sjmcneill	/* Enable touchpanel IRQs */
1941.2Sjmcneill	val = TS_READ(sc, TP_INT);
1951.2Sjmcneill	val |= TP_INT_DATA_IRQ_EN | TP_INT_FIFO_FLUSH | TP_INT_UP_IRQ_EN;
1961.2Sjmcneill	val &= ~TP_INT_FIFO_TRIG_LEVEL;
1971.2Sjmcneill	val |= __SHIFTIN(1, TP_INT_FIFO_TRIG_LEVEL);
1981.2Sjmcneill	TS_WRITE(sc, TP_INT, val);
1991.1Sjmcneill
2001.1Sjmcneill	return 0;
2011.1Sjmcneill}
2021.1Sjmcneill
2031.1Sjmcneillstatic void
2041.1Sjmcneillsunxi_ts_disable(void *v)
2051.1Sjmcneill{
2061.1Sjmcneill	struct sunxi_ts_softc * const sc = v;
2071.2Sjmcneill	uint32_t val;
2081.1Sjmcneill
2091.1Sjmcneill	/* Disable touchpanel IRQs */
2101.2Sjmcneill	val = TS_READ(sc, TP_INT);
2111.2Sjmcneill	val &= ~(TP_INT_DATA_IRQ_EN | TP_INT_FIFO_FLUSH | TP_INT_UP_IRQ_EN);
2121.2Sjmcneill	TS_WRITE(sc, TP_INT, val);
2131.1Sjmcneill}
2141.1Sjmcneill
2151.1Sjmcneillstatic int
2161.1Sjmcneillsunxi_ts_ioctl(void *v, u_long cmd, void *data, int flag, lwp_t *l)
2171.1Sjmcneill{
2181.1Sjmcneill	struct sunxi_ts_softc * const sc = v;
2191.1Sjmcneill	struct wsmouse_id *id;
2201.1Sjmcneill
2211.1Sjmcneill	switch (cmd) {
2221.1Sjmcneill	case WSMOUSEIO_GTYPE:
2231.1Sjmcneill		*(int *)data = WSMOUSE_TYPE_TPANEL;
2241.1Sjmcneill		return 0;
2251.1Sjmcneill
2261.1Sjmcneill	case WSMOUSEIO_GETID:
2271.1Sjmcneill		id = data;
2281.1Sjmcneill		if (id->type != WSMOUSE_ID_TYPE_UIDSTR)
2291.1Sjmcneill			return EINVAL;
2301.1Sjmcneill		snprintf(id->data, WSMOUSE_ID_MAXLEN,
2311.1Sjmcneill		    "Allwinner TS SN000000");
2321.1Sjmcneill		id->length = strlen(id->data);
2331.1Sjmcneill		return 0;
2341.1Sjmcneill
2351.1Sjmcneill	case WSMOUSEIO_SCALIBCOORDS:
2361.1Sjmcneill	case WSMOUSEIO_GCALIBCOORDS:
2371.1Sjmcneill		return tpcalib_ioctl(&sc->sc_tpcalib, cmd, data, flag, l);
2381.1Sjmcneill	}
2391.1Sjmcneill
2401.1Sjmcneill	return EPASSTHROUGH;
2411.1Sjmcneill}
2421.1Sjmcneill
2431.1Sjmcneillstatic const struct wsmouse_accessops sunxi_ts_accessops = {
2441.1Sjmcneill	.enable = sunxi_ts_enable,
2451.1Sjmcneill	.disable = sunxi_ts_disable,
2461.1Sjmcneill	.ioctl = sunxi_ts_ioctl,
2471.1Sjmcneill};
2481.1Sjmcneill
2491.1Sjmcneillstatic int
2501.1Sjmcneillsunxi_ts_intr(void *priv)
2511.1Sjmcneill{
2521.1Sjmcneill	struct sunxi_ts_softc * const sc = priv;
2531.1Sjmcneill	uint32_t fifocs, x, y;
2541.1Sjmcneill	int s;
2551.1Sjmcneill
2561.1Sjmcneill	fifocs = TS_READ(sc, TP_FIFOCS);
2571.1Sjmcneill
2581.2Sjmcneill	if (fifocs & TP_FIFOCS_TEMP_IRQ_PENDING) {
2591.2Sjmcneill		sc->sc_temp_data.value_cur = (TS_READ(sc, TEMP_DATA) *
2601.2Sjmcneill		    sc->sc_conf->temp_step - sc->sc_conf->temp_offset) +
2611.2Sjmcneill		    TEMP_C_TO_K;
2621.2Sjmcneill		sc->sc_temp_data.state = ENVSYS_SVALID;
2631.2Sjmcneill	}
2641.2Sjmcneill
2651.1Sjmcneill	if (fifocs & TP_FIFOCS_DATA_PENDING) {
2661.1Sjmcneill		x = TS_READ(sc, TP_DATA);
2671.1Sjmcneill		y = TS_READ(sc, TP_DATA);
2681.1Sjmcneill		if (sc->sc_ignoredata) {
2691.1Sjmcneill			/* Discard the first report */
2701.1Sjmcneill			sc->sc_ignoredata = false;
2711.3Sthorpej		} else if (sc->sc_wsmousedev != NULL) {
2721.1Sjmcneill			if (sc->sc_ts_inverted_x)
2731.1Sjmcneill				x = __SHIFTOUT_MASK(TP_DATA_MASK) - x;
2741.1Sjmcneill			if (sc->sc_ts_inverted_y)
2751.1Sjmcneill				y = __SHIFTOUT_MASK(TP_DATA_MASK) - y;
2761.1Sjmcneill			tpcalib_trans(&sc->sc_tpcalib, x, y,
2771.1Sjmcneill			    &sc->sc_tp_x, &sc->sc_tp_y);
2781.1Sjmcneill			sc->sc_tp_btns |= 1;
2791.1Sjmcneill
2801.1Sjmcneill			s = spltty();
2811.1Sjmcneill			wsmouse_input(sc->sc_wsmousedev,
2821.1Sjmcneill			    sc->sc_tp_btns, sc->sc_tp_x, sc->sc_tp_y, 0, 0,
2831.1Sjmcneill			    WSMOUSE_INPUT_ABSOLUTE_X | WSMOUSE_INPUT_ABSOLUTE_Y);
2841.1Sjmcneill			splx(s);
2851.1Sjmcneill		}
2861.1Sjmcneill	}
2871.1Sjmcneill
2881.1Sjmcneill	if (fifocs & TP_FIFOCS_UP_PENDING) {
2891.1Sjmcneill		sc->sc_ignoredata = true;
2901.1Sjmcneill		sc->sc_tp_btns &= ~1;
2911.1Sjmcneill		s = spltty();
2921.1Sjmcneill		wsmouse_input(sc->sc_wsmousedev,
2931.1Sjmcneill		    sc->sc_tp_btns, sc->sc_tp_x, sc->sc_tp_y, 0, 0,
2941.1Sjmcneill		    WSMOUSE_INPUT_ABSOLUTE_X | WSMOUSE_INPUT_ABSOLUTE_Y);
2951.1Sjmcneill		splx(s);
2961.1Sjmcneill	}
2971.1Sjmcneill
2981.1Sjmcneill	TS_WRITE(sc, TP_FIFOCS, fifocs);
2991.1Sjmcneill
3001.1Sjmcneill	return 1;
3011.1Sjmcneill}
3021.1Sjmcneill
3031.1Sjmcneillstatic void
3041.1Sjmcneillsunxi_ts_init(struct sunxi_ts_softc *sc)
3051.1Sjmcneill{
3061.1Sjmcneill	u_int tp_sensitivity_adjust = TS_TP_SENSITIVITY_ADJUST_DEFAULT;
3071.1Sjmcneill	u_int filter_type = TS_FILTER_TYPE_DEFAULT;
3081.1Sjmcneill
3091.1Sjmcneill	of_getprop_uint32(sc->sc_phandle, "allwinner,tp-sensitive-adjust",
3101.1Sjmcneill	    &tp_sensitivity_adjust);
3111.1Sjmcneill	of_getprop_uint32(sc->sc_phandle, "allwinner,filter-type",
3121.1Sjmcneill	    &filter_type);
3131.1Sjmcneill
3141.1Sjmcneill	TS_WRITE(sc, TP_CTRL0,
3151.1Sjmcneill	    __SHIFTIN(0, TP_CTRL0_ADC_CLK_SELECT) |
3161.1Sjmcneill	    __SHIFTIN(2, TP_CTRL0_ADC_CLK_DIVIDER) |
3171.1Sjmcneill	    __SHIFTIN(7, TP_CTRL0_FS_DIV) |
3181.1Sjmcneill	    __SHIFTIN(63, TP_CTRL0_T_ACQ));
3191.1Sjmcneill	TS_WRITE(sc, TP_CTRL2,
3201.1Sjmcneill	    __SHIFTIN(0, TP_CTRL2_MODE_SELECT) |
3211.1Sjmcneill	    __SHIFTIN(tp_sensitivity_adjust, TP_CTRL2_SENSITIVE_ADJUST));
3221.1Sjmcneill	TS_WRITE(sc, TP_CTRL3,
3231.1Sjmcneill	    TP_CTRL3_FILTER_EN |
3241.1Sjmcneill	    __SHIFTIN(filter_type, TP_CTRL3_FILTER_TYPE));
3251.1Sjmcneill	TS_WRITE(sc, TP_CTRL1,
3261.2Sjmcneill	    sc->sc_conf->tp_mode_en_mask |
3271.1Sjmcneill	    TP_CTRL1_STYLUS_UP_DEBOUNCE_EN |
3281.1Sjmcneill	    __SHIFTIN(5, TP_CTRL1_STYLUS_UP_DEBOUNCE));
3291.2Sjmcneill
3301.2Sjmcneill	/* Enable temperature sensor */
3311.2Sjmcneill	TS_WRITE(sc, TP_TPR,
3321.2Sjmcneill	    TP_TPR_TEMP_EN | __SHIFTIN(1953, TP_TPR_TEMP_PER));
3331.2Sjmcneill
3341.2Sjmcneill	/* Enable temperature sensor IRQ */
3351.2Sjmcneill	TS_WRITE(sc, TP_INT, TP_INT_TEMP_IRQ_EN);
3361.2Sjmcneill
3371.2Sjmcneill	/* Clear pending IRQs */
3381.2Sjmcneill	TS_WRITE(sc, TP_FIFOCS, TS_READ(sc, TP_FIFOCS));
3391.1Sjmcneill}
3401.1Sjmcneill
3411.1Sjmcneillstatic int
3421.1Sjmcneillsunxi_ts_match(device_t parent, cfdata_t cf, void *aux)
3431.1Sjmcneill{
3441.1Sjmcneill	struct fdt_attach_args * const faa = aux;
3451.1Sjmcneill
3461.8Sthorpej	return of_compatible_match(faa->faa_phandle, compat_data);
3471.1Sjmcneill}
3481.1Sjmcneill
3491.1Sjmcneillstatic void
3501.1Sjmcneillsunxi_ts_attach(device_t parent, device_t self, void *aux)
3511.1Sjmcneill{
3521.1Sjmcneill	struct sunxi_ts_softc * const sc = device_private(self);
3531.1Sjmcneill	struct fdt_attach_args * const faa = aux;
3541.1Sjmcneill	const int phandle = faa->faa_phandle;
3551.1Sjmcneill	struct wsmousedev_attach_args a;
3561.1Sjmcneill	char intrstr[128];
3571.1Sjmcneill	bus_addr_t addr;
3581.1Sjmcneill	bus_size_t size;
3591.1Sjmcneill	void *ih;
3601.1Sjmcneill
3611.1Sjmcneill	if (fdtbus_get_reg(phandle, 0, &addr, &size) != 0) {
3621.1Sjmcneill		aprint_error(": couldn't get registers\n");
3631.1Sjmcneill		return;
3641.1Sjmcneill	}
3651.1Sjmcneill
3661.1Sjmcneill	if (!fdtbus_intr_str(phandle, 0, intrstr, sizeof(intrstr))) {
3671.1Sjmcneill		aprint_error(": failed to decode interrupt\n");
3681.1Sjmcneill		return;
3691.1Sjmcneill	}
3701.1Sjmcneill
3711.1Sjmcneill	sc->sc_dev = self;
3721.1Sjmcneill	sc->sc_phandle = phandle;
3731.1Sjmcneill	sc->sc_bst = faa->faa_bst;
3741.1Sjmcneill	if (bus_space_map(sc->sc_bst, addr, size, 0, &sc->sc_bsh) != 0) {
3751.1Sjmcneill		aprint_error(": couldn't map registers\n");
3761.1Sjmcneill		return;
3771.1Sjmcneill	}
3781.8Sthorpej	sc->sc_conf = of_compatible_lookup(phandle, compat_data)->data;
3791.2Sjmcneill
3801.1Sjmcneill	sc->sc_ts_attached = of_getprop_bool(phandle, "allwinner,ts-attached");
3811.1Sjmcneill	sc->sc_ts_inverted_x = of_getprop_bool(phandle,
3821.1Sjmcneill	    "touchscreen-inverted-x");
3831.1Sjmcneill	sc->sc_ts_inverted_y = of_getprop_bool(phandle,
3841.1Sjmcneill	    "touchscreen-inverted-y");
3851.1Sjmcneill
3861.1Sjmcneill	aprint_naive("\n");
3871.1Sjmcneill	aprint_normal(": Touch Screen Controller\n");
3881.1Sjmcneill
3891.1Sjmcneill	sunxi_ts_init(sc);
3901.1Sjmcneill
3911.4Sjmcneill	ih = fdtbus_intr_establish_xname(phandle, 0, IPL_VM, 0, sunxi_ts_intr,
3921.4Sjmcneill	    sc, device_xname(self));
3931.1Sjmcneill	if (ih == NULL) {
3941.1Sjmcneill		aprint_error_dev(self, "couldn't establish interrupt on %s\n",
3951.1Sjmcneill		    intrstr);
3961.1Sjmcneill		return;
3971.1Sjmcneill	}
3981.1Sjmcneill	aprint_normal_dev(self, "interrupting on %s\n", intrstr);
3991.1Sjmcneill
4001.2Sjmcneill	sc->sc_sme = sysmon_envsys_create();
4011.2Sjmcneill	sc->sc_sme->sme_name = device_xname(self);
4021.2Sjmcneill	sc->sc_sme->sme_cookie = sc;
4031.2Sjmcneill	sc->sc_sme->sme_flags = SME_DISABLE_REFRESH;
4041.2Sjmcneill
4051.2Sjmcneill	sc->sc_temp_data.units = ENVSYS_STEMP;
4061.2Sjmcneill	sc->sc_temp_data.state = ENVSYS_SINVALID;
4071.2Sjmcneill	snprintf(sc->sc_temp_data.desc, sizeof(sc->sc_temp_data.desc),
4081.2Sjmcneill	    "temperature");
4091.2Sjmcneill	sysmon_envsys_sensor_attach(sc->sc_sme, &sc->sc_temp_data);
4101.2Sjmcneill
4111.2Sjmcneill	sysmon_envsys_register(sc->sc_sme);
4121.2Sjmcneill
4131.1Sjmcneill	if (sc->sc_ts_attached) {
4141.1Sjmcneill		tpcalib_init(&sc->sc_tpcalib);
4151.1Sjmcneill		tpcalib_ioctl(&sc->sc_tpcalib, WSMOUSEIO_SCALIBCOORDS,
4161.1Sjmcneill		    &sunxi_ts_default_calib, 0, 0);
4171.1Sjmcneill
4181.1Sjmcneill		memset(&a, 0, sizeof(a));
4191.1Sjmcneill		a.accessops = &sunxi_ts_accessops;
4201.1Sjmcneill		a.accesscookie = sc;
4211.9Sthorpej		sc->sc_wsmousedev =
4221.10Sthorpej		    config_found(self, &a, wsmousedevprint, CFARGS_NONE);
4231.1Sjmcneill	}
4241.1Sjmcneill}
425