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