1 /* $OpenBSD: sxits.c,v 1.1 2018/01/06 13:04:47 kettenis Exp $ */ 2 /* 3 * Copyright (c) 2018 Mark Kettenis <kettenis@openbsd.org> 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18 #include <sys/param.h> 19 #include <sys/systm.h> 20 #include <sys/device.h> 21 #include <sys/sensors.h> 22 23 #include <machine/intr.h> 24 #include <machine/bus.h> 25 #include <machine/fdt.h> 26 27 #include <dev/ofw/openfirm.h> 28 #include <dev/ofw/fdt.h> 29 30 /* Registers */ 31 #define TP_CTRL0 0x00 32 #define TP_CTRL0_ADC_CLK_DIVIDER(x) (((x) & 0x3) << 20) 33 #define TP_CTRL0_FS_DIV(x) (((x) & 0xf) << 16) 34 #define TP_CTRL0_TACQ(x) ((x) & 0xffff) 35 #define TP_CTRL1 0x04 36 #define TP_CTRL1_TP_MODE_EN (1 << 4) 37 #define TP_CTRL3 0x0c 38 #define TP_CTRL3_FILTER_EN (1 << 2) 39 #define TP_CTRL3_FILTER_TYPE(x) ((x) & 0x3) 40 #define TP_TPR 0x18 41 #define TP_TPR_TEMP_EN (1 << 16) 42 #define TP_TPR_TEMP_PER(x) ((x) & 0xffff) 43 #define TEMP_DATA 0x20 44 45 #define HREAD4(sc, reg) \ 46 (bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg))) 47 #define HWRITE4(sc, reg, val) \ 48 bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, (reg), (val)) 49 50 struct sxits_softc { 51 struct device sc_dev; 52 bus_space_tag_t sc_iot; 53 bus_space_handle_t sc_ioh; 54 55 uint16_t sc_offset; 56 uint16_t sc_scale; 57 58 struct ksensor sc_sensor; 59 struct ksensordev sc_sensordev; 60 }; 61 62 int sxits_match(struct device *, void *, void *); 63 void sxits_attach(struct device *, struct device *, void *); 64 65 struct cfattach sxits_ca = { 66 sizeof (struct sxits_softc), sxits_match, sxits_attach 67 }; 68 69 struct cfdriver sxits_cd = { 70 NULL, "sxits", DV_DULL 71 }; 72 73 void sxits_refresh_sensors(void *); 74 75 int 76 sxits_match(struct device *parent, void *match, void *aux) 77 { 78 struct fdt_attach_args *faa = aux; 79 80 return (OF_is_compatible(faa->fa_node, "allwinner,sun4i-a10-ts") || 81 OF_is_compatible(faa->fa_node, "allwinner,sun5i-a13-ts")); 82 } 83 84 void 85 sxits_attach(struct device *parent, struct device *self, void *aux) 86 { 87 struct sxits_softc *sc = (struct sxits_softc *)self; 88 struct fdt_attach_args *faa = aux; 89 90 if (faa->fa_nreg < 1) { 91 printf(": no registers\n"); 92 return; 93 } 94 95 sc->sc_iot = faa->fa_iot; 96 if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr, 97 faa->fa_reg[0].size, 0, &sc->sc_ioh)) { 98 printf(": can't map registers\n"); 99 return; 100 } 101 102 printf("\n"); 103 104 if (OF_is_compatible(faa->fa_node, "allwinner,sun4i-a10-ts")) { 105 sc->sc_offset = 1932; 106 sc->sc_scale = 133; 107 } else { 108 sc->sc_offset = 1447; 109 sc->sc_scale = 100; 110 } 111 112 /* Start data acquisition. */ 113 HWRITE4(sc, TP_CTRL0, TP_CTRL0_ADC_CLK_DIVIDER(2) | 114 TP_CTRL0_FS_DIV(7) | TP_CTRL0_TACQ(63)); 115 HWRITE4(sc, TP_CTRL1, TP_CTRL1_TP_MODE_EN); 116 HWRITE4(sc, TP_CTRL3, TP_CTRL3_FILTER_EN | TP_CTRL3_FILTER_TYPE(1)); 117 HWRITE4(sc, TP_TPR, TP_TPR_TEMP_EN | TP_TPR_TEMP_PER(800)); 118 119 /* Register sensors. */ 120 strlcpy(sc->sc_sensordev.xname, sc->sc_dev.dv_xname, 121 sizeof(sc->sc_sensordev.xname)); 122 sc->sc_sensor.type = SENSOR_TEMP; 123 sc->sc_sensor.flags = SENSOR_FINVALID; 124 sensor_attach(&sc->sc_sensordev, &sc->sc_sensor); 125 sensordev_install(&sc->sc_sensordev); 126 sensor_task_register(sc, sxits_refresh_sensors, 5); 127 } 128 129 void 130 sxits_refresh_sensors(void *arg) 131 { 132 struct sxits_softc *sc = arg; 133 uint32_t data, temp; 134 135 data = HREAD4(sc, TEMP_DATA); 136 if (data == 0) { 137 sc->sc_sensor.flags |= SENSOR_FINVALID; 138 return; 139 } 140 141 temp = (data - sc->sc_offset) * sc->sc_scale; 142 sc->sc_sensor.value = temp * 1000 + 273150000; 143 sc->sc_sensor.flags &= ~SENSOR_FINVALID; 144 } 145