From 0341244bae5a0e5b5bc90abdde7cd02e6c44b8e9 Mon Sep 17 00:00:00 2001 From: kettenis Date: Sun, 14 Aug 2016 19:08:44 +0000 Subject: [PATCH] Add imxtemp(4), a temperature sensor for the i.MX6 SoC. Based on code written by patrick@. ok deraadt@ --- sys/arch/armv7/conf/GENERIC | 3 +- sys/arch/armv7/imx/files.imx | 6 +- sys/arch/armv7/imx/imxocotp.c | 11 +- sys/arch/armv7/imx/imxocotpvar.h | 3 +- sys/arch/armv7/imx/imxtemp.c | 210 +++++++++++++++++++++++++++++++ 5 files changed, 229 insertions(+), 4 deletions(-) create mode 100644 sys/arch/armv7/imx/imxtemp.c diff --git a/sys/arch/armv7/conf/GENERIC b/sys/arch/armv7/conf/GENERIC index 147766516fc..982bb53b3af 100644 --- a/sys/arch/armv7/conf/GENERIC +++ b/sys/arch/armv7/conf/GENERIC @@ -1,4 +1,4 @@ -# $OpenBSD: GENERIC,v 1.46 2016/08/13 22:07:01 kettenis Exp $ +# $OpenBSD: GENERIC,v 1.47 2016/08/14 19:08:44 kettenis Exp $ # # For further information on compiling OpenBSD kernels, see the config(8) # man page. @@ -45,6 +45,7 @@ imxiomuxc* at imx? # iomux controller imxgpc* at fdt? # power controller imxdog* at fdt? # watchdog timer imxocotp* at imx? # on-chip otp controller +imxtemp* at fdt? # temperature monitor imxgpio* at fdt? # user-visible GPIO pins? fec* at fdt? # Ethernet imxuart* at fdt? # onboard uarts diff --git a/sys/arch/armv7/imx/files.imx b/sys/arch/armv7/imx/files.imx index 83fd4d4a82b..981efac9a0c 100644 --- a/sys/arch/armv7/imx/files.imx +++ b/sys/arch/armv7/imx/files.imx @@ -1,4 +1,4 @@ -# $OpenBSD: files.imx,v 1.16 2016/08/04 14:31:50 kettenis Exp $ +# $OpenBSD: files.imx,v 1.17 2016/08/14 19:08:44 kettenis Exp $ define imx {} device imx: imx @@ -55,3 +55,7 @@ file arch/armv7/imx/imxesdhc.c imxesdhc device imxahci: scsi, atascsi attach imxahci at fdt file arch/armv7/imx/imxahci.c imxahci + +device imxtemp +attach imxtemp at fdt +file arch/armv7/imx/imxtemp.c imxtemp \ No newline at end of file diff --git a/sys/arch/armv7/imx/imxocotp.c b/sys/arch/armv7/imx/imxocotp.c index f9d78811c68..e4cd7973223 100644 --- a/sys/arch/armv7/imx/imxocotp.c +++ b/sys/arch/armv7/imx/imxocotp.c @@ -1,4 +1,4 @@ -/* $OpenBSD: imxocotp.c,v 1.2 2013/11/06 19:03:07 syl Exp $ */ +/* $OpenBSD: imxocotp.c,v 1.3 2016/08/14 19:08:44 kettenis Exp $ */ /* * Copyright (c) 2012-2013 Patrick Wildt * @@ -30,6 +30,9 @@ #include /* registers */ +#define OCOTP_ANA0 0x4d0 +#define OCOTP_ANA1 0x4e0 +#define OCOTP_ANA2 0x4f0 #define OCOTP_MAC0 0x620 #define OCOTP_MAC1 0x630 @@ -80,3 +83,9 @@ imxocotp_get_ethernet_address(u_int8_t* mac) mac[1] = value & 0xff; mac[0] = (value >> 8) & 0xff; } + +uint32_t +imxocotp_get_temperature_calibration(void) +{ + return bus_space_read_4(imxocotp_sc->sc_iot, imxocotp_sc->sc_ioh, OCOTP_ANA1); +} diff --git a/sys/arch/armv7/imx/imxocotpvar.h b/sys/arch/armv7/imx/imxocotpvar.h index b546638de5c..e64a8188dfd 100644 --- a/sys/arch/armv7/imx/imxocotpvar.h +++ b/sys/arch/armv7/imx/imxocotpvar.h @@ -1,4 +1,4 @@ -/* $OpenBSD: imxocotpvar.h,v 1.1 2013/09/06 20:45:54 patrick Exp $ */ +/* $OpenBSD: imxocotpvar.h,v 1.2 2016/08/14 19:08:44 kettenis Exp $ */ /* * Copyright (c) 2012-2013 Patrick Wildt * @@ -16,3 +16,4 @@ */ void imxocotp_get_ethernet_address(u_int8_t* mac); +uint32_t imxocotp_get_temperature_calibration(void); diff --git a/sys/arch/armv7/imx/imxtemp.c b/sys/arch/armv7/imx/imxtemp.c new file mode 100644 index 00000000000..2f17c037089 --- /dev/null +++ b/sys/arch/armv7/imx/imxtemp.c @@ -0,0 +1,210 @@ +/* + * Copyright (c) 2014 Patrick Wildt + * Copyright (c) 2016 Mark Kettenis + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include +#include + +/* registers */ +#define TEMPMON_TEMPSENSE0 0x180 +#define TEMPMON_TEMPSENSE0_SET 0x184 +#define TEMPMON_TEMPSENSE0_CLR 0x188 +#define TEMPMON_TEMPSENSE0_TOG 0x18c +#define TEMPMON_TEMPSENSE1 0x190 +#define TEMPMON_TEMPSENSE1_SET 0x194 +#define TEMPMON_TEMPSENSE1_CLR 0x198 +#define TEMPMON_TEMPSENSE1_TOG 0x19c + +/* bits and bytes */ +#define TEMPMON_TEMPSENSE0_POWER_DOWN (1 << 0) +#define TEMPMON_TEMPSENSE0_MEASURE_TEMP (1 << 1) +#define TEMPMON_TEMPSENSE0_FINISHED (1 << 2) +#define TEMPMON_TEMPSENSE0_TEMP_CNT_MASK 0xfff +#define TEMPMON_TEMPSENSE0_TEMP_CNT_SHIFT 8 +#define TEMPMON_TEMPSENSE0_ALARM_VALUE_MASK 0xfff +#define TEMPMON_TEMPSENSE0_ALARM_VALUE_SHIFT 20 + +/* calibration */ +#define OCOTP_ANA1_HOT_TEMP_MASK 0xff +#define OCOTP_ANA1_HOT_TEMP_SHIFT 0 +#define OCOTP_ANA1_HOT_COUNT_MASK 0xfff +#define OCOTP_ANA1_HOT_COUNT_SHIFT 8 +#define OCOTP_ANA1_ROOM_COUNT_MASK 0xfff +#define OCOTP_ANA1_ROOM_COUNT_SHIFT 20 + +#define HREAD4(sc, reg) \ + (bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg))) +#define HWRITE4(sc, reg, val) \ + bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, (reg), (val)) +#define HSET4(sc, reg, bits) \ + HWRITE4((sc), (reg), HREAD4((sc), (reg)) | (bits)) +#define HCLR4(sc, reg, bits) \ + HWRITE4((sc), (reg), HREAD4((sc), (reg)) & ~(bits)) + +struct imxtemp_softc { + struct device sc_dev; + bus_space_tag_t sc_iot; + bus_space_handle_t sc_ioh; + + uint32_t sc_hot_count; + uint32_t sc_hot_temp; + uint32_t sc_room_count; + + struct ksensor sc_sensor; + struct ksensordev sc_sensordev; + struct timeout sc_sensorto; +}; + +int imxtemp_match(struct device *, void *, void *); +void imxtemp_attach(struct device *, struct device *, void *); + +struct cfattach imxtemp_ca = { + sizeof(struct imxtemp_softc), imxtemp_match, imxtemp_attach +}; + +struct cfdriver imxtemp_cd = { + NULL, "imxtemp", DV_DULL +}; + +int32_t imxtemp_calc_temp(struct imxtemp_softc *, uint32_t); +void imxtemp_refresh_sensors(void *); +void imxtemp_pickup_sensors(void *); + +int +imxtemp_match(struct device *parent, void *match, void *aux) +{ + struct fdt_attach_args *faa = aux; + + if (OF_is_compatible(faa->fa_node, "fsl,imx6q-anatop")) + return 10; /* Must beat simplebus(4). */ + + return 0; +} + +void +imxtemp_attach(struct device *parent, struct device *self, void *aux) +{ + struct imxtemp_softc *sc = (struct imxtemp_softc *)self; + struct fdt_attach_args *faa = aux; + uint32_t calibration; + + if (faa->fa_nreg < 1) + return; + + sc->sc_iot = faa->fa_iot; + if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr, + faa->fa_reg[0].size, 0, &sc->sc_ioh)) + panic("%s: bus_space_map failed!", __func__); + + printf("\n"); + + calibration = imxocotp_get_temperature_calibration(); + sc->sc_hot_count = (calibration >> OCOTP_ANA1_HOT_COUNT_SHIFT) & + OCOTP_ANA1_HOT_COUNT_MASK; + sc->sc_hot_temp = (calibration >> OCOTP_ANA1_HOT_TEMP_SHIFT) & + OCOTP_ANA1_HOT_TEMP_MASK; + sc->sc_room_count = (calibration >> OCOTP_ANA1_ROOM_COUNT_SHIFT) & + OCOTP_ANA1_ROOM_COUNT_MASK; + + strlcpy(sc->sc_sensordev.xname, sc->sc_dev.dv_xname, + sizeof(sc->sc_sensordev.xname)); + strlcpy(sc->sc_sensor.desc, "core", + sizeof(sc->sc_sensor.desc)); + sc->sc_sensor.type = SENSOR_TEMP; + sc->sc_sensor.flags = SENSOR_FINVALID; + sensor_attach(&sc->sc_sensordev, &sc->sc_sensor); + sensordev_install(&sc->sc_sensordev); + timeout_set(&sc->sc_sensorto, imxtemp_pickup_sensors, sc); + sensor_task_register(sc, imxtemp_refresh_sensors, 5); +} + +int32_t +imxtemp_calc_temp(struct imxtemp_softc *sc, uint32_t temp_cnt) +{ + int32_t value; + + /* + * Calculate the calibrated tempterature based on the equation + * provided in the i.MX6 reference manual: + * + * Tmeas = HOT_TEMP - (Nmeas - HOT_COUNT) * ((HOT_TEMP - 25.0) / + * (ROOM_COUNT - HOT_COUNT)) + * + * Note that we calculate the temperature in uC to avoid loss + * of precision. + */ + value = ((sc->sc_hot_temp - 25) * 1000000) / + (sc->sc_room_count - sc->sc_hot_count); + value *= (temp_cnt - sc->sc_hot_count); + return ((sc->sc_hot_temp * 1000000) - value); +} + +void +imxtemp_refresh_sensors(void *arg) +{ + struct imxtemp_softc *sc = (struct imxtemp_softc *)arg; + + timeout_del(&sc->sc_sensorto); + + /* Power on temperature sensor. */ + HCLR4(sc, TEMPMON_TEMPSENSE0, TEMPMON_TEMPSENSE0_POWER_DOWN); + HSET4(sc, TEMPMON_TEMPSENSE0, TEMPMON_TEMPSENSE0_MEASURE_TEMP); + + /* It may require up to ~17us to complete a measurement. */ + timeout_add_usec(&sc->sc_sensorto, 25); +} + +void +imxtemp_pickup_sensors(void *arg) +{ + struct imxtemp_softc *sc = (struct imxtemp_softc *)arg; + uint32_t value; + uint32_t temp_cnt; + + value = HREAD4(sc, TEMPMON_TEMPSENSE0); + + /* Power down temperature sensor. */ + HCLR4(sc, TEMPMON_TEMPSENSE0, TEMPMON_TEMPSENSE0_MEASURE_TEMP); + HSET4(sc, TEMPMON_TEMPSENSE0, TEMPMON_TEMPSENSE0_POWER_DOWN); + + if ((value & TEMPMON_TEMPSENSE0_FINISHED) == 0) { + sc->sc_sensor.flags |= SENSOR_FINVALID; + return; + } + + temp_cnt = (value >> TEMPMON_TEMPSENSE0_TEMP_CNT_SHIFT) & + TEMPMON_TEMPSENSE0_TEMP_CNT_MASK; + sc->sc_sensor.value = imxtemp_calc_temp(sc, temp_cnt) + 273150000; + sc->sc_sensor.flags &= ~SENSOR_FINVALID; +} -- 2.20.1