1 /* $NetBSD: titemp.c,v 1.2 2015/12/13 17:15:06 jmcneill Exp $ */ 2 3 /*- 4 * Copyright (c) 2015 Jared D. McNeill <jmcneill@invisible.ca> 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 17 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 18 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 * POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 #include <sys/cdefs.h> 30 __KERNEL_RCSID(0, "$NetBSD: titemp.c,v 1.2 2015/12/13 17:15:06 jmcneill Exp $"); 31 32 #include <sys/param.h> 33 #include <sys/systm.h> 34 #include <sys/device.h> 35 #include <sys/conf.h> 36 #include <sys/bus.h> 37 #include <sys/kmem.h> 38 39 #include <dev/i2c/i2cvar.h> 40 41 #include <dev/sysmon/sysmonvar.h> 42 43 #define TITEMP_LTEMP_HI_REG 0x00 44 #define TITEMP_RTEMP_HI_REG 0x01 45 #define TITEMP_STATUS_REG 0x02 46 #define TITEMP_CONFIG_REG 0x03 47 #define TITEMP_CONVRATE_REG 0x04 48 #define TITEMP_LTEMP_HLIMIT_HI_REG 0x05 49 #define TITEMP_LTEMP_LLIMIT_HI_REG 0x06 50 #define TITEMP_RTEMP_HLIMIT_HI_REG 0x07 51 #define TITEMP_RTEMP_LLIMIT_HI_REG 0x08 52 #define TITEMP_RTEMP_LO_REG 0x10 53 #define TITEMP_RTEMP_OFF_HI_REG 0x11 54 #define TITEMP_RTEMP_OFF_LO_REG 0x12 55 #define TITEMP_RTEMP_HLIMIT_LO_REG 0x13 56 #define TITEMP_RTEMP_LLIMIT_LO_REG 0x14 57 #define TITEMP_LTEMP_LO_REG 0x15 58 #define TITEMP_RTEMP_THERM_LIMIT_REG 0x19 59 #define TITEMP_LTEMP_THERM_LIMIT_REG 0x20 60 #define TITEMP_THERM_HYST_REG 0x21 61 #define TITEMP_CONAL_REG 0x22 62 #define TITEMP_NC_REG 0x23 63 #define TITEMP_DF_REG 0x24 64 #define TITEMP_MFID_REG 0xfe 65 66 #define TITEMP_MFID_TMP451 0x55 67 68 struct titemp_softc { 69 device_t sc_dev; 70 i2c_tag_t sc_i2c; 71 i2c_addr_t sc_addr; 72 73 struct sysmon_envsys *sc_sme; 74 envsys_data_t sc_sensor_ltemp; 75 envsys_data_t sc_sensor_rtemp; 76 }; 77 78 static int titemp_match(device_t, cfdata_t, void *); 79 static void titemp_attach(device_t, device_t, void *); 80 81 static void titemp_sensors_refresh(struct sysmon_envsys *, envsys_data_t *); 82 static int titemp_read(struct titemp_softc *, uint8_t, uint8_t *); 83 84 CFATTACH_DECL_NEW(titemp, sizeof(struct titemp_softc), 85 titemp_match, titemp_attach, NULL, NULL); 86 87 static const char * titemp_compats[] = { 88 "ti,tmp451", 89 NULL 90 }; 91 92 static int 93 titemp_match(device_t parent, cfdata_t match, void *aux) 94 { 95 struct i2c_attach_args *ia = aux; 96 uint8_t mfid; 97 int error; 98 99 if (ia->ia_name == NULL) { 100 if (iic_acquire_bus(ia->ia_tag, I2C_F_POLL) != 0) 101 return 0; 102 error = iic_smbus_read_byte(ia->ia_tag, ia->ia_addr, 103 TITEMP_MFID_REG, &mfid, I2C_F_POLL); 104 iic_release_bus(ia->ia_tag, I2C_F_POLL); 105 106 if (error || mfid != TITEMP_MFID_TMP451) 107 return 0; 108 109 return 1; 110 } else { 111 return iic_compat_match(ia, titemp_compats); 112 } 113 } 114 115 static void 116 titemp_attach(device_t parent, device_t self, void *aux) 117 { 118 struct titemp_softc *sc = device_private(self); 119 struct i2c_attach_args *ia = aux; 120 121 sc->sc_dev = self; 122 sc->sc_i2c = ia->ia_tag; 123 sc->sc_addr = ia->ia_addr; 124 125 aprint_naive("\n"); 126 aprint_normal(": TMP451\n"); 127 128 sc->sc_sme = sysmon_envsys_create(); 129 sc->sc_sme->sme_name = device_xname(self); 130 sc->sc_sme->sme_cookie = sc; 131 sc->sc_sme->sme_refresh = titemp_sensors_refresh; 132 133 sc->sc_sensor_ltemp.units = ENVSYS_STEMP; 134 sc->sc_sensor_ltemp.state = ENVSYS_SINVALID; 135 snprintf(sc->sc_sensor_ltemp.desc, sizeof(sc->sc_sensor_ltemp.desc), 136 "local temperature"); 137 sysmon_envsys_sensor_attach(sc->sc_sme, &sc->sc_sensor_ltemp); 138 139 sc->sc_sensor_rtemp.units = ENVSYS_STEMP; 140 sc->sc_sensor_rtemp.state = ENVSYS_SINVALID; 141 snprintf(sc->sc_sensor_rtemp.desc, sizeof(sc->sc_sensor_rtemp.desc), 142 "remote temperature"); 143 sysmon_envsys_sensor_attach(sc->sc_sme, &sc->sc_sensor_rtemp); 144 145 sysmon_envsys_register(sc->sc_sme); 146 } 147 148 static void 149 titemp_sensors_refresh(struct sysmon_envsys *sme, envsys_data_t *edata) 150 { 151 struct titemp_softc *sc = sme->sme_cookie; 152 uint8_t reg_hi, reg_lo, temp[2]; 153 int error; 154 155 if (edata == &sc->sc_sensor_ltemp) { 156 reg_hi = TITEMP_LTEMP_HI_REG; 157 reg_lo = TITEMP_LTEMP_LO_REG; 158 } else if (edata == &sc->sc_sensor_rtemp) { 159 reg_hi = TITEMP_RTEMP_HI_REG; 160 reg_lo = TITEMP_RTEMP_LO_REG; 161 } else { 162 edata->state = ENVSYS_SINVALID; 163 return; 164 } 165 166 iic_acquire_bus(sc->sc_i2c, 0); 167 if ((error = titemp_read(sc, reg_hi, &temp[0])) != 0) 168 goto done; 169 if ((error = titemp_read(sc, reg_lo, &temp[1])) != 0) 170 goto done; 171 done: 172 iic_release_bus(sc->sc_i2c, 0); 173 174 if (error) { 175 edata->state = ENVSYS_SINVALID; 176 } else { 177 edata->value_cur = 178 ((uint64_t)temp[0] * 1000000) + 179 ((uint64_t)temp[1] * 62500) + 180 + 273150000; 181 edata->state = ENVSYS_SVALID; 182 } 183 } 184 185 static int 186 titemp_read(struct titemp_softc *sc, uint8_t reg, uint8_t *val) 187 { 188 return iic_smbus_read_byte(sc->sc_i2c, sc->sc_addr, reg, val, 0); 189 } 190