1*c7fb772bSthorpej /* $NetBSD: sunxi_ts.c,v 1.10 2021/08/07 16:18:45 thorpej Exp $ */
2301a1392Sjmcneill
3301a1392Sjmcneill /*-
4301a1392Sjmcneill * Copyright (c) 2017 Jared McNeill <jmcneill@invisible.ca>
5301a1392Sjmcneill * All rights reserved.
6301a1392Sjmcneill *
7301a1392Sjmcneill * Redistribution and use in source and binary forms, with or without
8301a1392Sjmcneill * modification, are permitted provided that the following conditions
9301a1392Sjmcneill * are met:
10301a1392Sjmcneill * 1. Redistributions of source code must retain the above copyright
11301a1392Sjmcneill * notice, this list of conditions and the following disclaimer.
12301a1392Sjmcneill * 2. Redistributions in binary form must reproduce the above copyright
13301a1392Sjmcneill * notice, this list of conditions and the following disclaimer in the
14301a1392Sjmcneill * documentation and/or other materials provided with the distribution.
15301a1392Sjmcneill *
16301a1392Sjmcneill * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
17301a1392Sjmcneill * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18301a1392Sjmcneill * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19301a1392Sjmcneill * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
20301a1392Sjmcneill * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21301a1392Sjmcneill * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22301a1392Sjmcneill * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23301a1392Sjmcneill * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24301a1392Sjmcneill * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25301a1392Sjmcneill * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26301a1392Sjmcneill * POSSIBILITY OF SUCH DAMAGE.
27301a1392Sjmcneill */
28301a1392Sjmcneill
29301a1392Sjmcneill #include <sys/cdefs.h>
30301a1392Sjmcneill
31*c7fb772bSthorpej __KERNEL_RCSID(0, "$NetBSD: sunxi_ts.c,v 1.10 2021/08/07 16:18:45 thorpej Exp $");
32301a1392Sjmcneill
33301a1392Sjmcneill #include <sys/param.h>
34301a1392Sjmcneill #include <sys/bus.h>
35301a1392Sjmcneill #include <sys/device.h>
36301a1392Sjmcneill #include <sys/intr.h>
37301a1392Sjmcneill #include <sys/systm.h>
38301a1392Sjmcneill #include <sys/time.h>
39301a1392Sjmcneill
40301a1392Sjmcneill #include <dev/fdt/fdtvar.h>
41301a1392Sjmcneill
42f3ec8c48Sjmcneill #include <dev/sysmon/sysmonvar.h>
43f3ec8c48Sjmcneill
44301a1392Sjmcneill #include <dev/wscons/wsconsio.h>
45301a1392Sjmcneill #include <dev/wscons/wsmousevar.h>
46301a1392Sjmcneill #include <dev/wscons/tpcalibvar.h>
47301a1392Sjmcneill
48301a1392Sjmcneill #define TS_TP_SENSITIVITY_ADJUST_DEFAULT 15
49301a1392Sjmcneill #define TS_FILTER_TYPE_DEFAULT 1
50301a1392Sjmcneill
51301a1392Sjmcneill #define TP_CTRL0 0x00
52301a1392Sjmcneill #define TP_CTRL0_ADC_FIRST_DLY __BITS(31,24)
53301a1392Sjmcneill #define TP_CTRL0_ADC_FIRST_DLY_MODE __BIT(23)
54301a1392Sjmcneill #define TP_CTRL0_ADC_CLK_SELECT __BIT(22)
55301a1392Sjmcneill #define TP_CTRL0_ADC_CLK_DIVIDER __BITS(21,20)
56301a1392Sjmcneill #define TP_CTRL0_FS_DIV __BITS(19,16)
57301a1392Sjmcneill #define TP_CTRL0_T_ACQ __BITS(15,0)
58301a1392Sjmcneill #define TP_CTRL1 0x04
59301a1392Sjmcneill #define TP_CTRL1_STYLUS_UP_DEBOUNCE __BITS(19,12)
60301a1392Sjmcneill #define TP_CTRL1_STYLUS_UP_DEBOUNCE_EN __BIT(9)
61301a1392Sjmcneill #define TP_CTRL1_TOUCH_PAN_CALI_EN __BIT(6)
62301a1392Sjmcneill #define TP_CTRL1_TP_DUAL_EN __BIT(5)
63301a1392Sjmcneill #define TP_CTRL1_TP_MODE_EN __BIT(4)
64301a1392Sjmcneill #define TP_CTRL1_TP_ADC_SELECT __BIT(3)
65301a1392Sjmcneill #define TP_CTRL1_ADC_CHAN_SELECT __BITS(2,0)
66301a1392Sjmcneill #define TP_CTRL2 0x08
67301a1392Sjmcneill #define TP_CTRL2_SENSITIVE_ADJUST __BITS(31,28)
68301a1392Sjmcneill #define TP_CTRL2_MODE_SELECT __BITS(27,26)
69301a1392Sjmcneill #define TP_CTRL2_PRE_MEA_EN __BIT(24)
70301a1392Sjmcneill #define TP_CTRL2_PRE_MEA_THRE_CNT __BITS(23,0)
71301a1392Sjmcneill #define TP_CTRL3 0x0c
72301a1392Sjmcneill #define TP_CTRL3_FILTER_EN __BIT(2)
73301a1392Sjmcneill #define TP_CTRL3_FILTER_TYPE __BITS(1,0)
74301a1392Sjmcneill #define TP_INT 0x10
75f3ec8c48Sjmcneill #define TP_INT_TEMP_IRQ_EN __BIT(18)
76301a1392Sjmcneill #define TP_INT_OVERRUN_IRQ_EN __BIT(17)
77301a1392Sjmcneill #define TP_INT_DATA_IRQ_EN __BIT(16)
78301a1392Sjmcneill #define TP_INT_DATA_XY_CHANGE __BIT(13)
79301a1392Sjmcneill #define TP_INT_FIFO_TRIG_LEVEL __BITS(12,8)
80301a1392Sjmcneill #define TP_INT_DATA_DRQ_EN __BIT(7)
81301a1392Sjmcneill #define TP_INT_FIFO_FLUSH __BIT(4)
82301a1392Sjmcneill #define TP_INT_UP_IRQ_EN __BIT(1)
83301a1392Sjmcneill #define TP_INT_DOWN_IRQ_EN __BIT(0)
84301a1392Sjmcneill #define TP_FIFOCS 0x14
85f3ec8c48Sjmcneill #define TP_FIFOCS_TEMP_IRQ_PENDING __BIT(18)
86301a1392Sjmcneill #define TP_FIFOCS_OVERRUN_PENDING __BIT(17)
87301a1392Sjmcneill #define TP_FIFOCS_DATA_PENDING __BIT(16)
88301a1392Sjmcneill #define TP_FIFOCS_RXA_CNT __BITS(12,8)
89301a1392Sjmcneill #define TP_FIFOCS_IDLE_FLG __BIT(2)
90301a1392Sjmcneill #define TP_FIFOCS_UP_PENDING __BIT(1)
91301a1392Sjmcneill #define TP_FIFOCS_DOWN_PENDING __BIT(0)
92f3ec8c48Sjmcneill #define TP_TPR 0x18
93f3ec8c48Sjmcneill #define TP_TPR_TEMP_EN __BIT(16)
94f3ec8c48Sjmcneill #define TP_TPR_TEMP_PER __BITS(15,0)
95301a1392Sjmcneill #define TP_CDAT 0x1c
96301a1392Sjmcneill #define TP_CDAT_MASK __BITS(11,0)
97f3ec8c48Sjmcneill #define TEMP_DATA 0x20
98f3ec8c48Sjmcneill #define TEMP_DATA_MASK __BITS(11,0)
99301a1392Sjmcneill #define TP_DATA 0x24
100301a1392Sjmcneill #define TP_DATA_MASK __BITS(11,0)
101301a1392Sjmcneill #define TP_IO_CONFIG 0x28
102301a1392Sjmcneill #define TP_PORT_DATA 0x2c
103301a1392Sjmcneill #define TP_PORT_DATA_MASK __BITS(3,0)
104301a1392Sjmcneill
105f3ec8c48Sjmcneill #define TEMP_C_TO_K 273150000
106f3ec8c48Sjmcneill
107301a1392Sjmcneill static int sunxi_ts_match(device_t, cfdata_t, void *);
108301a1392Sjmcneill static void sunxi_ts_attach(device_t, device_t, void *);
109301a1392Sjmcneill
110f3ec8c48Sjmcneill struct sunxi_ts_config {
111f3ec8c48Sjmcneill int64_t temp_offset;
112f3ec8c48Sjmcneill int64_t temp_step;
113f3ec8c48Sjmcneill uint32_t tp_mode_en_mask;
114f3ec8c48Sjmcneill };
115f3ec8c48Sjmcneill
116f3ec8c48Sjmcneill static const struct sunxi_ts_config sun4i_a10_ts_config = {
117f3ec8c48Sjmcneill .temp_offset = 257000000,
118f3ec8c48Sjmcneill .temp_step = 133000,
119f3ec8c48Sjmcneill .tp_mode_en_mask = TP_CTRL1_TP_MODE_EN,
120f3ec8c48Sjmcneill };
121f3ec8c48Sjmcneill
122f3ec8c48Sjmcneill static const struct sunxi_ts_config sun5i_a13_ts_config = {
123f3ec8c48Sjmcneill .temp_offset = 144700000,
124f3ec8c48Sjmcneill .temp_step = 100000,
125f3ec8c48Sjmcneill .tp_mode_en_mask = TP_CTRL1_TP_MODE_EN,
126f3ec8c48Sjmcneill };
127f3ec8c48Sjmcneill
128f3ec8c48Sjmcneill static const struct sunxi_ts_config sun6i_a31_ts_config = {
129f3ec8c48Sjmcneill .temp_offset = 271000000,
130f3ec8c48Sjmcneill .temp_step = 167000,
131f3ec8c48Sjmcneill .tp_mode_en_mask = TP_CTRL1_TP_DUAL_EN,
132f3ec8c48Sjmcneill };
133f3ec8c48Sjmcneill
134646c0f59Sthorpej static const struct device_compatible_entry compat_data[] = {
135646c0f59Sthorpej { .compat = "allwinner,sun4i-a10-ts", .data = &sun4i_a10_ts_config },
136646c0f59Sthorpej { .compat = "allwinner,sun5i-a13-ts", .data = &sun5i_a13_ts_config },
137646c0f59Sthorpej { .compat = "allwinner,sun6i-a31-ts", .data = &sun6i_a31_ts_config },
138ec189949Sthorpej DEVICE_COMPAT_EOL
139301a1392Sjmcneill };
140301a1392Sjmcneill
141301a1392Sjmcneill static struct wsmouse_calibcoords sunxi_ts_default_calib = {
142301a1392Sjmcneill .minx = 0,
143301a1392Sjmcneill .miny = 0,
144301a1392Sjmcneill .maxx = __SHIFTOUT_MASK(TP_DATA_MASK),
145301a1392Sjmcneill .maxy = __SHIFTOUT_MASK(TP_DATA_MASK),
146301a1392Sjmcneill .samplelen = WSMOUSE_CALIBCOORDS_RESET,
147301a1392Sjmcneill };
148301a1392Sjmcneill
149301a1392Sjmcneill struct sunxi_ts_softc {
150301a1392Sjmcneill device_t sc_dev;
151301a1392Sjmcneill int sc_phandle;
152301a1392Sjmcneill bus_space_tag_t sc_bst;
153301a1392Sjmcneill bus_space_handle_t sc_bsh;
154301a1392Sjmcneill
155f3ec8c48Sjmcneill const struct sunxi_ts_config *sc_conf;
156f3ec8c48Sjmcneill
157301a1392Sjmcneill bool sc_ts_attached;
158301a1392Sjmcneill bool sc_ts_inverted_x;
159301a1392Sjmcneill bool sc_ts_inverted_y;
160301a1392Sjmcneill
161301a1392Sjmcneill struct tpcalib_softc sc_tpcalib;
162301a1392Sjmcneill device_t sc_wsmousedev;
163301a1392Sjmcneill bool sc_ignoredata;
164301a1392Sjmcneill
165301a1392Sjmcneill u_int sc_tp_x;
166301a1392Sjmcneill u_int sc_tp_y;
167301a1392Sjmcneill u_int sc_tp_btns;
168f3ec8c48Sjmcneill
169f3ec8c48Sjmcneill struct sysmon_envsys *sc_sme;
170f3ec8c48Sjmcneill envsys_data_t sc_temp_data;
171301a1392Sjmcneill };
172301a1392Sjmcneill
173301a1392Sjmcneill CFATTACH_DECL_NEW(sunxi_ts, sizeof(struct sunxi_ts_softc),
174301a1392Sjmcneill sunxi_ts_match, sunxi_ts_attach, NULL, NULL);
175301a1392Sjmcneill
176301a1392Sjmcneill #define TS_READ(sc, reg) \
177301a1392Sjmcneill bus_space_read_4((sc)->sc_bst, (sc)->sc_bsh, (reg))
178301a1392Sjmcneill #define TS_WRITE(sc, reg, val) \
179301a1392Sjmcneill bus_space_write_4((sc)->sc_bst, (sc)->sc_bsh, (reg), (val))
180301a1392Sjmcneill
181301a1392Sjmcneill static int
sunxi_ts_enable(void * v)182301a1392Sjmcneill sunxi_ts_enable(void *v)
183301a1392Sjmcneill {
184301a1392Sjmcneill struct sunxi_ts_softc * const sc = v;
185f3ec8c48Sjmcneill uint32_t val;
186301a1392Sjmcneill
187301a1392Sjmcneill /* reset state */
188301a1392Sjmcneill sc->sc_ignoredata = true;
189301a1392Sjmcneill sc->sc_tp_x = 0;
190301a1392Sjmcneill sc->sc_tp_y = 0;
191301a1392Sjmcneill sc->sc_tp_btns = 0;
192301a1392Sjmcneill
193301a1392Sjmcneill /* Enable touchpanel IRQs */
194f3ec8c48Sjmcneill val = TS_READ(sc, TP_INT);
195f3ec8c48Sjmcneill val |= TP_INT_DATA_IRQ_EN | TP_INT_FIFO_FLUSH | TP_INT_UP_IRQ_EN;
196f3ec8c48Sjmcneill val &= ~TP_INT_FIFO_TRIG_LEVEL;
197f3ec8c48Sjmcneill val |= __SHIFTIN(1, TP_INT_FIFO_TRIG_LEVEL);
198f3ec8c48Sjmcneill TS_WRITE(sc, TP_INT, val);
199301a1392Sjmcneill
200301a1392Sjmcneill return 0;
201301a1392Sjmcneill }
202301a1392Sjmcneill
203301a1392Sjmcneill static void
sunxi_ts_disable(void * v)204301a1392Sjmcneill sunxi_ts_disable(void *v)
205301a1392Sjmcneill {
206301a1392Sjmcneill struct sunxi_ts_softc * const sc = v;
207f3ec8c48Sjmcneill uint32_t val;
208301a1392Sjmcneill
209301a1392Sjmcneill /* Disable touchpanel IRQs */
210f3ec8c48Sjmcneill val = TS_READ(sc, TP_INT);
211f3ec8c48Sjmcneill val &= ~(TP_INT_DATA_IRQ_EN | TP_INT_FIFO_FLUSH | TP_INT_UP_IRQ_EN);
212f3ec8c48Sjmcneill TS_WRITE(sc, TP_INT, val);
213301a1392Sjmcneill }
214301a1392Sjmcneill
215301a1392Sjmcneill static int
sunxi_ts_ioctl(void * v,u_long cmd,void * data,int flag,lwp_t * l)216301a1392Sjmcneill sunxi_ts_ioctl(void *v, u_long cmd, void *data, int flag, lwp_t *l)
217301a1392Sjmcneill {
218301a1392Sjmcneill struct sunxi_ts_softc * const sc = v;
219301a1392Sjmcneill struct wsmouse_id *id;
220301a1392Sjmcneill
221301a1392Sjmcneill switch (cmd) {
222301a1392Sjmcneill case WSMOUSEIO_GTYPE:
223301a1392Sjmcneill *(int *)data = WSMOUSE_TYPE_TPANEL;
224301a1392Sjmcneill return 0;
225301a1392Sjmcneill
226301a1392Sjmcneill case WSMOUSEIO_GETID:
227301a1392Sjmcneill id = data;
228301a1392Sjmcneill if (id->type != WSMOUSE_ID_TYPE_UIDSTR)
229301a1392Sjmcneill return EINVAL;
230301a1392Sjmcneill snprintf(id->data, WSMOUSE_ID_MAXLEN,
231301a1392Sjmcneill "Allwinner TS SN000000");
232301a1392Sjmcneill id->length = strlen(id->data);
233301a1392Sjmcneill return 0;
234301a1392Sjmcneill
235301a1392Sjmcneill case WSMOUSEIO_SCALIBCOORDS:
236301a1392Sjmcneill case WSMOUSEIO_GCALIBCOORDS:
237301a1392Sjmcneill return tpcalib_ioctl(&sc->sc_tpcalib, cmd, data, flag, l);
238301a1392Sjmcneill }
239301a1392Sjmcneill
240301a1392Sjmcneill return EPASSTHROUGH;
241301a1392Sjmcneill }
242301a1392Sjmcneill
243301a1392Sjmcneill static const struct wsmouse_accessops sunxi_ts_accessops = {
244301a1392Sjmcneill .enable = sunxi_ts_enable,
245301a1392Sjmcneill .disable = sunxi_ts_disable,
246301a1392Sjmcneill .ioctl = sunxi_ts_ioctl,
247301a1392Sjmcneill };
248301a1392Sjmcneill
249301a1392Sjmcneill static int
sunxi_ts_intr(void * priv)250301a1392Sjmcneill sunxi_ts_intr(void *priv)
251301a1392Sjmcneill {
252301a1392Sjmcneill struct sunxi_ts_softc * const sc = priv;
253301a1392Sjmcneill uint32_t fifocs, x, y;
254301a1392Sjmcneill int s;
255301a1392Sjmcneill
256301a1392Sjmcneill fifocs = TS_READ(sc, TP_FIFOCS);
257301a1392Sjmcneill
258f3ec8c48Sjmcneill if (fifocs & TP_FIFOCS_TEMP_IRQ_PENDING) {
259f3ec8c48Sjmcneill sc->sc_temp_data.value_cur = (TS_READ(sc, TEMP_DATA) *
260f3ec8c48Sjmcneill sc->sc_conf->temp_step - sc->sc_conf->temp_offset) +
261f3ec8c48Sjmcneill TEMP_C_TO_K;
262f3ec8c48Sjmcneill sc->sc_temp_data.state = ENVSYS_SVALID;
263f3ec8c48Sjmcneill }
264f3ec8c48Sjmcneill
265301a1392Sjmcneill if (fifocs & TP_FIFOCS_DATA_PENDING) {
266301a1392Sjmcneill x = TS_READ(sc, TP_DATA);
267301a1392Sjmcneill y = TS_READ(sc, TP_DATA);
268301a1392Sjmcneill if (sc->sc_ignoredata) {
269301a1392Sjmcneill /* Discard the first report */
270301a1392Sjmcneill sc->sc_ignoredata = false;
271efb285d5Sthorpej } else if (sc->sc_wsmousedev != NULL) {
272301a1392Sjmcneill if (sc->sc_ts_inverted_x)
273301a1392Sjmcneill x = __SHIFTOUT_MASK(TP_DATA_MASK) - x;
274301a1392Sjmcneill if (sc->sc_ts_inverted_y)
275301a1392Sjmcneill y = __SHIFTOUT_MASK(TP_DATA_MASK) - y;
276301a1392Sjmcneill tpcalib_trans(&sc->sc_tpcalib, x, y,
277301a1392Sjmcneill &sc->sc_tp_x, &sc->sc_tp_y);
278301a1392Sjmcneill sc->sc_tp_btns |= 1;
279301a1392Sjmcneill
280301a1392Sjmcneill s = spltty();
281301a1392Sjmcneill wsmouse_input(sc->sc_wsmousedev,
282301a1392Sjmcneill sc->sc_tp_btns, sc->sc_tp_x, sc->sc_tp_y, 0, 0,
283301a1392Sjmcneill WSMOUSE_INPUT_ABSOLUTE_X | WSMOUSE_INPUT_ABSOLUTE_Y);
284301a1392Sjmcneill splx(s);
285301a1392Sjmcneill }
286301a1392Sjmcneill }
287301a1392Sjmcneill
288301a1392Sjmcneill if (fifocs & TP_FIFOCS_UP_PENDING) {
289301a1392Sjmcneill sc->sc_ignoredata = true;
290301a1392Sjmcneill sc->sc_tp_btns &= ~1;
291301a1392Sjmcneill s = spltty();
292301a1392Sjmcneill wsmouse_input(sc->sc_wsmousedev,
293301a1392Sjmcneill sc->sc_tp_btns, sc->sc_tp_x, sc->sc_tp_y, 0, 0,
294301a1392Sjmcneill WSMOUSE_INPUT_ABSOLUTE_X | WSMOUSE_INPUT_ABSOLUTE_Y);
295301a1392Sjmcneill splx(s);
296301a1392Sjmcneill }
297301a1392Sjmcneill
298301a1392Sjmcneill TS_WRITE(sc, TP_FIFOCS, fifocs);
299301a1392Sjmcneill
300301a1392Sjmcneill return 1;
301301a1392Sjmcneill }
302301a1392Sjmcneill
303301a1392Sjmcneill static void
sunxi_ts_init(struct sunxi_ts_softc * sc)304301a1392Sjmcneill sunxi_ts_init(struct sunxi_ts_softc *sc)
305301a1392Sjmcneill {
306301a1392Sjmcneill u_int tp_sensitivity_adjust = TS_TP_SENSITIVITY_ADJUST_DEFAULT;
307301a1392Sjmcneill u_int filter_type = TS_FILTER_TYPE_DEFAULT;
308301a1392Sjmcneill
309301a1392Sjmcneill of_getprop_uint32(sc->sc_phandle, "allwinner,tp-sensitive-adjust",
310301a1392Sjmcneill &tp_sensitivity_adjust);
311301a1392Sjmcneill of_getprop_uint32(sc->sc_phandle, "allwinner,filter-type",
312301a1392Sjmcneill &filter_type);
313301a1392Sjmcneill
314301a1392Sjmcneill TS_WRITE(sc, TP_CTRL0,
315301a1392Sjmcneill __SHIFTIN(0, TP_CTRL0_ADC_CLK_SELECT) |
316301a1392Sjmcneill __SHIFTIN(2, TP_CTRL0_ADC_CLK_DIVIDER) |
317301a1392Sjmcneill __SHIFTIN(7, TP_CTRL0_FS_DIV) |
318301a1392Sjmcneill __SHIFTIN(63, TP_CTRL0_T_ACQ));
319301a1392Sjmcneill TS_WRITE(sc, TP_CTRL2,
320301a1392Sjmcneill __SHIFTIN(0, TP_CTRL2_MODE_SELECT) |
321301a1392Sjmcneill __SHIFTIN(tp_sensitivity_adjust, TP_CTRL2_SENSITIVE_ADJUST));
322301a1392Sjmcneill TS_WRITE(sc, TP_CTRL3,
323301a1392Sjmcneill TP_CTRL3_FILTER_EN |
324301a1392Sjmcneill __SHIFTIN(filter_type, TP_CTRL3_FILTER_TYPE));
325301a1392Sjmcneill TS_WRITE(sc, TP_CTRL1,
326f3ec8c48Sjmcneill sc->sc_conf->tp_mode_en_mask |
327301a1392Sjmcneill TP_CTRL1_STYLUS_UP_DEBOUNCE_EN |
328301a1392Sjmcneill __SHIFTIN(5, TP_CTRL1_STYLUS_UP_DEBOUNCE));
329f3ec8c48Sjmcneill
330f3ec8c48Sjmcneill /* Enable temperature sensor */
331f3ec8c48Sjmcneill TS_WRITE(sc, TP_TPR,
332f3ec8c48Sjmcneill TP_TPR_TEMP_EN | __SHIFTIN(1953, TP_TPR_TEMP_PER));
333f3ec8c48Sjmcneill
334f3ec8c48Sjmcneill /* Enable temperature sensor IRQ */
335f3ec8c48Sjmcneill TS_WRITE(sc, TP_INT, TP_INT_TEMP_IRQ_EN);
336f3ec8c48Sjmcneill
337f3ec8c48Sjmcneill /* Clear pending IRQs */
338f3ec8c48Sjmcneill TS_WRITE(sc, TP_FIFOCS, TS_READ(sc, TP_FIFOCS));
339301a1392Sjmcneill }
340301a1392Sjmcneill
341301a1392Sjmcneill static int
sunxi_ts_match(device_t parent,cfdata_t cf,void * aux)342301a1392Sjmcneill sunxi_ts_match(device_t parent, cfdata_t cf, void *aux)
343301a1392Sjmcneill {
344301a1392Sjmcneill struct fdt_attach_args * const faa = aux;
345301a1392Sjmcneill
3466e54367aSthorpej return of_compatible_match(faa->faa_phandle, compat_data);
347301a1392Sjmcneill }
348301a1392Sjmcneill
349301a1392Sjmcneill static void
sunxi_ts_attach(device_t parent,device_t self,void * aux)350301a1392Sjmcneill sunxi_ts_attach(device_t parent, device_t self, void *aux)
351301a1392Sjmcneill {
352301a1392Sjmcneill struct sunxi_ts_softc * const sc = device_private(self);
353301a1392Sjmcneill struct fdt_attach_args * const faa = aux;
354301a1392Sjmcneill const int phandle = faa->faa_phandle;
355301a1392Sjmcneill struct wsmousedev_attach_args a;
356301a1392Sjmcneill char intrstr[128];
357301a1392Sjmcneill bus_addr_t addr;
358301a1392Sjmcneill bus_size_t size;
359301a1392Sjmcneill void *ih;
360301a1392Sjmcneill
361301a1392Sjmcneill if (fdtbus_get_reg(phandle, 0, &addr, &size) != 0) {
362301a1392Sjmcneill aprint_error(": couldn't get registers\n");
363301a1392Sjmcneill return;
364301a1392Sjmcneill }
365301a1392Sjmcneill
366301a1392Sjmcneill if (!fdtbus_intr_str(phandle, 0, intrstr, sizeof(intrstr))) {
367301a1392Sjmcneill aprint_error(": failed to decode interrupt\n");
368301a1392Sjmcneill return;
369301a1392Sjmcneill }
370301a1392Sjmcneill
371301a1392Sjmcneill sc->sc_dev = self;
372301a1392Sjmcneill sc->sc_phandle = phandle;
373301a1392Sjmcneill sc->sc_bst = faa->faa_bst;
374301a1392Sjmcneill if (bus_space_map(sc->sc_bst, addr, size, 0, &sc->sc_bsh) != 0) {
375301a1392Sjmcneill aprint_error(": couldn't map registers\n");
376301a1392Sjmcneill return;
377301a1392Sjmcneill }
3786e54367aSthorpej sc->sc_conf = of_compatible_lookup(phandle, compat_data)->data;
379f3ec8c48Sjmcneill
380301a1392Sjmcneill sc->sc_ts_attached = of_getprop_bool(phandle, "allwinner,ts-attached");
381301a1392Sjmcneill sc->sc_ts_inverted_x = of_getprop_bool(phandle,
382301a1392Sjmcneill "touchscreen-inverted-x");
383301a1392Sjmcneill sc->sc_ts_inverted_y = of_getprop_bool(phandle,
384301a1392Sjmcneill "touchscreen-inverted-y");
385301a1392Sjmcneill
386301a1392Sjmcneill aprint_naive("\n");
387301a1392Sjmcneill aprint_normal(": Touch Screen Controller\n");
388301a1392Sjmcneill
389301a1392Sjmcneill sunxi_ts_init(sc);
390301a1392Sjmcneill
391076a1169Sjmcneill ih = fdtbus_intr_establish_xname(phandle, 0, IPL_VM, 0, sunxi_ts_intr,
392076a1169Sjmcneill sc, device_xname(self));
393301a1392Sjmcneill if (ih == NULL) {
394301a1392Sjmcneill aprint_error_dev(self, "couldn't establish interrupt on %s\n",
395301a1392Sjmcneill intrstr);
396301a1392Sjmcneill return;
397301a1392Sjmcneill }
398301a1392Sjmcneill aprint_normal_dev(self, "interrupting on %s\n", intrstr);
399301a1392Sjmcneill
400f3ec8c48Sjmcneill sc->sc_sme = sysmon_envsys_create();
401f3ec8c48Sjmcneill sc->sc_sme->sme_name = device_xname(self);
402f3ec8c48Sjmcneill sc->sc_sme->sme_cookie = sc;
403f3ec8c48Sjmcneill sc->sc_sme->sme_flags = SME_DISABLE_REFRESH;
404f3ec8c48Sjmcneill
405f3ec8c48Sjmcneill sc->sc_temp_data.units = ENVSYS_STEMP;
406f3ec8c48Sjmcneill sc->sc_temp_data.state = ENVSYS_SINVALID;
407f3ec8c48Sjmcneill snprintf(sc->sc_temp_data.desc, sizeof(sc->sc_temp_data.desc),
408f3ec8c48Sjmcneill "temperature");
409f3ec8c48Sjmcneill sysmon_envsys_sensor_attach(sc->sc_sme, &sc->sc_temp_data);
410f3ec8c48Sjmcneill
411f3ec8c48Sjmcneill sysmon_envsys_register(sc->sc_sme);
412f3ec8c48Sjmcneill
413301a1392Sjmcneill if (sc->sc_ts_attached) {
414301a1392Sjmcneill tpcalib_init(&sc->sc_tpcalib);
415301a1392Sjmcneill tpcalib_ioctl(&sc->sc_tpcalib, WSMOUSEIO_SCALIBCOORDS,
416301a1392Sjmcneill &sunxi_ts_default_calib, 0, 0);
417301a1392Sjmcneill
418301a1392Sjmcneill memset(&a, 0, sizeof(a));
419301a1392Sjmcneill a.accessops = &sunxi_ts_accessops;
420301a1392Sjmcneill a.accesscookie = sc;
4212685996bSthorpej sc->sc_wsmousedev =
422*c7fb772bSthorpej config_found(self, &a, wsmousedevprint, CFARGS_NONE);
423301a1392Sjmcneill }
424301a1392Sjmcneill }
425