1 /*- 2 * Copyright (c) 2016 Emmanuel Vadot <manu@freebsd.org> 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 14 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 16 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 17 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 18 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 19 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 20 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 21 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 22 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 23 * SUCH DAMAGE. 24 */ 25 26 /* 27 * Allwinner Touch Sreen driver 28 * Touch screen part is not done, only the thermal sensor part is. 29 */ 30 31 #include <sys/cdefs.h> 32 __FBSDID("$FreeBSD$"); 33 34 #include <sys/param.h> 35 #include <sys/systm.h> 36 #include <sys/bus.h> 37 #include <sys/kernel.h> 38 #include <sys/module.h> 39 #include <sys/rman.h> 40 #include <sys/sysctl.h> 41 #include <machine/bus.h> 42 43 #include <dev/ofw/openfirm.h> 44 #include <dev/ofw/ofw_bus.h> 45 #include <dev/ofw/ofw_bus_subr.h> 46 47 #define READ(_sc, _r) bus_read_4((_sc)->res[0], (_r)) 48 #define WRITE(_sc, _r, _v) bus_write_4((_sc)->res[0], (_r), (_v)) 49 50 /* Control register 0 */ 51 #define TP_CTRL0 0x00 52 #define TP_CTRL0_TACQ(x) ((x & 0xFF) << 0) 53 #define TP_CTRL0_FS_DIV(x) ((x & 0xF) << 16) 54 #define TP_CTRL0_CLK_DIV(x) ((x & 0x3) << 20) 55 #define TP_CTRL0_CLK_SELECT(x) ((x & 0x1) << 22) 56 57 /* Control register 1 */ 58 #define TP_CTRL1 0x04 59 #define TP_CTRL1_MODE_EN (1 << 4) 60 61 /* Control register 2 */ 62 #define TP_CTRL2 0x08 63 64 /* Control register 3 */ 65 #define TP_CTRL3 0x0C 66 67 /* Int/FIFO control register */ 68 #define TP_FIFOC 0x10 69 #define TP_FIFOC_TEMP_IRQ_ENABLE (1 << 18) 70 71 /* Int/FIFO status register */ 72 #define TP_FIFOS 0x14 73 #define TP_FIFOS_TEMP_IRQ_PENDING (1 << 18) 74 75 /* Temperature Period Register */ 76 #define TP_TPR 0x18 77 #define TP_TPR_TEMP_EN (1 << 16) 78 #define TP_TPR_TEMP_PERIOD(x) (x << 0) 79 80 /* Common data register */ 81 #define TP_CDAT 0x1C 82 83 /* Temperature data register */ 84 #define TEMP_DATA 0x20 85 86 /* TP Data register*/ 87 #define TP_DATA 0x24 88 89 /* TP IO config register */ 90 #define TP_IO_CONFIG 0x28 91 92 /* TP IO port data register */ 93 #define TP_IO_DATA 0x2C 94 95 struct aw_ts_softc { 96 device_t dev; 97 struct resource * res[2]; 98 void * intrhand; 99 int temp_data; 100 int temp_offset; 101 int temp_step; 102 }; 103 104 static struct resource_spec aw_ts_spec[] = { 105 { SYS_RES_MEMORY, 0, RF_ACTIVE }, 106 { SYS_RES_IRQ, 0, RF_ACTIVE | RF_SHAREABLE }, 107 { -1, 0 } 108 }; 109 110 #define A10_TS 1 111 #define A13_TS 2 112 113 #define AW_TS_TEMP_SYSCTL 1 114 115 static struct ofw_compat_data compat_data[] = { 116 {"allwinner,sun4i-a10-ts", A10_TS}, 117 {"allwinner,sun5i-a13-ts", A13_TS}, 118 {NULL, 0} 119 }; 120 121 static void 122 aw_ts_intr(void *arg) 123 { 124 struct aw_ts_softc *sc; 125 int val; 126 127 sc= (struct aw_ts_softc *)arg; 128 129 val = READ(sc, TP_FIFOS); 130 if (val & TP_FIFOS_TEMP_IRQ_PENDING) { 131 /* Convert the value to millicelsius then millikelvin */ 132 sc->temp_data = (READ(sc, TEMP_DATA) * sc->temp_step - sc->temp_offset) 133 + 273150; 134 } 135 136 WRITE(sc, TP_FIFOS, val); 137 } 138 139 static int 140 aw_ts_probe(device_t dev) 141 { 142 143 if (!ofw_bus_status_okay(dev)) 144 return (ENXIO); 145 146 if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0) 147 return (ENXIO); 148 149 device_set_desc(dev, "Allwinner Touch Screen controller"); 150 return (BUS_PROBE_DEFAULT); 151 } 152 153 static int 154 aw_ts_attach(device_t dev) 155 { 156 struct aw_ts_softc *sc; 157 158 sc = device_get_softc(dev); 159 sc->dev = dev; 160 161 if (bus_alloc_resources(dev, aw_ts_spec, sc->res) != 0) { 162 device_printf(dev, "could not allocate memory resource\n"); 163 return (ENXIO); 164 } 165 166 if (bus_setup_intr(dev, sc->res[1], 167 INTR_TYPE_MISC | INTR_MPSAFE, NULL, aw_ts_intr, sc, 168 &sc->intrhand)) { 169 bus_release_resources(dev, aw_ts_spec, sc->res); 170 device_printf(dev, "cannot setup interrupt handler\n"); 171 return (ENXIO); 172 } 173 174 /* 175 * Thoses magic values were taken from linux which take them from 176 * the allwinner SDK or found them by deduction 177 */ 178 switch (ofw_bus_search_compatible(dev, compat_data)->ocd_data) { 179 case A10_TS: 180 sc->temp_offset = 257000; 181 sc->temp_step = 133; 182 break; 183 case A13_TS: 184 sc->temp_offset = 144700; 185 sc->temp_step = 100; 186 break; 187 } 188 189 /* Enable clock and set divisers */ 190 WRITE(sc, TP_CTRL0, TP_CTRL0_CLK_SELECT(0) | 191 TP_CTRL0_CLK_DIV(2) | 192 TP_CTRL0_FS_DIV(7) | 193 TP_CTRL0_TACQ(63)); 194 195 /* Enable TS module */ 196 WRITE(sc, TP_CTRL1, TP_CTRL1_MODE_EN); 197 198 /* Enable Temperature, period is ~2s */ 199 WRITE(sc, TP_TPR, TP_TPR_TEMP_EN | TP_TPR_TEMP_PERIOD(1953)); 200 201 /* Enable temp irq */ 202 WRITE(sc, TP_FIFOC, TP_FIFOC_TEMP_IRQ_ENABLE); 203 204 /* Add sysctl */ 205 SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 206 SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 207 OID_AUTO, "temperature", 208 CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_NEEDGIANT, 209 &sc->temp_data, 0, sysctl_handle_int, 210 "IK3", "CPU Temperature"); 211 212 return (0); 213 } 214 215 static device_method_t aw_ts_methods[] = { 216 DEVMETHOD(device_probe, aw_ts_probe), 217 DEVMETHOD(device_attach, aw_ts_attach), 218 219 DEVMETHOD_END 220 }; 221 222 static driver_t aw_ts_driver = { 223 "aw_ts", 224 aw_ts_methods, 225 sizeof(struct aw_ts_softc), 226 }; 227 228 DRIVER_MODULE(aw_ts, simplebus, aw_ts_driver, 0, 0); 229