1 /* $NetBSD: mcp980x.c,v 1.1 2013/05/06 22:04:12 rkujawa Exp $ */ 2 3 /*- 4 * Copyright (c) 2013 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Radoslaw Kujawa. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 /* 33 * Microchip MCP9800/1/2/3 2-Wire High-Accuracy Temperature Sensor driver. 34 * TODO: everything besides simple temperature read with default configuration. 35 * 36 * Note: MCP9805 is different and is supported by the sdtemp(4) driver. 37 */ 38 39 #include <sys/cdefs.h> 40 __KERNEL_RCSID(0, "$NetBSD: mcp980x.c,v 1.1 2013/05/06 22:04:12 rkujawa Exp $"); 41 42 #include <sys/param.h> 43 #include <sys/systm.h> 44 #include <sys/device.h> 45 #include <sys/kernel.h> 46 #include <sys/mutex.h> 47 #include <sys/endian.h> 48 49 #include <sys/bus.h> 50 #include <dev/i2c/i2cvar.h> 51 52 #include <dev/sysmon/sysmonvar.h> 53 54 #include <dev/i2c/mcp980xreg.h> 55 56 struct mcp980x_softc { 57 device_t sc_dev; 58 59 i2c_tag_t sc_tag; 60 i2c_addr_t sc_addr; 61 62 /* envsys(4) stuff */ 63 struct sysmon_envsys *sc_sme; 64 envsys_data_t sc_sensor; 65 kmutex_t sc_lock; 66 }; 67 68 69 static int mcp980x_match(device_t, cfdata_t, void *); 70 static void mcp980x_attach(device_t, device_t, void *); 71 72 /*static uint8_t mcp980x_reg_read_1(struct mcp980x_softc *sc, uint8_t);*/ 73 static uint16_t mcp980x_reg_read_2(struct mcp980x_softc *sc, uint8_t reg); 74 75 static uint32_t mcp980x_temperature(struct mcp980x_softc *sc); 76 77 static void mcp980x_envsys_register(struct mcp980x_softc *); 78 static void mcp980x_envsys_refresh(struct sysmon_envsys *, envsys_data_t *); 79 80 CFATTACH_DECL_NEW(mcp980x, sizeof (struct mcp980x_softc), 81 mcp980x_match, mcp980x_attach, NULL, NULL); 82 83 static int 84 mcp980x_match(device_t parent, cfdata_t cf, void *aux) 85 { 86 /* 87 * No sane way to probe? Perhaps at least try to match constant part 88 * of the I2Caddress. 89 */ 90 91 return 1; 92 } 93 94 static void 95 mcp980x_attach(device_t parent, device_t self, void *aux) 96 { 97 struct mcp980x_softc *sc = device_private(self); 98 struct i2c_attach_args *ia = aux; 99 100 sc->sc_dev = self; 101 sc->sc_addr = ia->ia_addr; 102 sc->sc_tag = ia->ia_tag; 103 104 aprint_normal(": Microchip MCP980x Temperature Sensor\n"); 105 106 mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE); 107 108 mcp980x_envsys_register(sc); 109 } 110 111 static uint16_t 112 mcp980x_reg_read_2(struct mcp980x_softc *sc, uint8_t reg) 113 { 114 uint8_t wbuf[2]; 115 uint16_t rv; 116 117 if (iic_acquire_bus(sc->sc_tag, I2C_F_POLL) != 0) { 118 aprint_error_dev(sc->sc_dev, "cannot acquire bus for read\n"); 119 return 0; 120 } 121 122 wbuf[0] = reg; 123 124 if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, sc->sc_addr, wbuf, 125 1, &rv, 2, I2C_F_POLL)) { 126 aprint_error_dev(sc->sc_dev, "cannot execute operation\n"); 127 iic_release_bus(sc->sc_tag, I2C_F_POLL); 128 return 0; 129 } 130 iic_release_bus(sc->sc_tag, I2C_F_POLL); 131 132 return be16toh(rv); 133 } 134 135 /* Will need that later for reading config register. */ 136 /* 137 static uint8_t 138 mcp980x_reg_read_1(struct mcp980x_softc *sc, uint8_t reg) 139 { 140 uint8_t rv, wbuf[2]; 141 142 if (iic_acquire_bus(sc->sc_tag, I2C_F_POLL) != 0) { 143 aprint_error_dev(sc->sc_dev, "cannot acquire bus for read\n"); 144 return 0; 145 } 146 147 wbuf[0] = reg; 148 149 if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, sc->sc_addr, wbuf, 150 1, &rv, 1, I2C_F_POLL)) { 151 aprint_error_dev(sc->sc_dev, "cannot execute operation\n"); 152 iic_release_bus(sc->sc_tag, I2C_F_POLL); 153 return 0; 154 } 155 iic_release_bus(sc->sc_tag, I2C_F_POLL); 156 157 return rv; 158 }*/ 159 160 /* Get temperature in microKelvins. */ 161 static uint32_t 162 mcp980x_temperature(struct mcp980x_softc *sc) 163 { 164 uint16_t raw; 165 uint32_t rv, uk, basedegc; 166 167 raw = mcp980x_reg_read_2(sc, MCP980X_AMBIENT_TEMP); 168 169 basedegc = (raw & MCP980X_AMBIENT_TEMP_DEGREES) >> 170 MCP980X_AMBIENT_TEMP_DEGREES_SHIFT; 171 172 uk = 1000000 * basedegc; 173 174 if (raw & MCP980X_AMBIENT_TEMP_05DEGREE) 175 uk += 500000; 176 if (raw & MCP980X_AMBIENT_TEMP_025DEGREE) 177 uk += 250000; 178 if (raw & MCP980X_AMBIENT_TEMP_0125DEGREE) 179 uk += 125000; 180 if (raw & MCP980X_AMBIENT_TEMP_00625DEGREE) 181 uk += 62500; 182 183 if (raw & MCP980X_AMBIENT_TEMP_SIGN) 184 rv = 273150000U - uk; 185 else 186 rv = 273150000U + uk; 187 188 return rv; 189 } 190 191 static void 192 mcp980x_envsys_register(struct mcp980x_softc *sc) 193 { 194 sc->sc_sme = sysmon_envsys_create(); 195 196 strlcpy(sc->sc_sensor.desc, "Ambient temp", 197 sizeof(sc->sc_sensor.desc)); 198 sc->sc_sensor.units = ENVSYS_STEMP; 199 sc->sc_sensor.state = ENVSYS_SINVALID; 200 201 if (sysmon_envsys_sensor_attach(sc->sc_sme, &sc->sc_sensor)) { 202 aprint_error_dev(sc->sc_dev, 203 "error attaching sensor\n"); 204 return; 205 } 206 207 sc->sc_sme->sme_name = device_xname(sc->sc_dev); 208 sc->sc_sme->sme_cookie = sc; 209 sc->sc_sme->sme_refresh = mcp980x_envsys_refresh; 210 211 if (sysmon_envsys_register(sc->sc_sme)) { 212 aprint_error_dev(sc->sc_dev, "unable to register in sysmon\n"); 213 sysmon_envsys_destroy(sc->sc_sme); 214 } 215 } 216 217 static void 218 mcp980x_envsys_refresh(struct sysmon_envsys *sme, envsys_data_t *edata) 219 { 220 struct mcp980x_softc *sc = sme->sme_cookie; 221 222 mutex_enter(&sc->sc_lock); 223 224 edata->value_cur = mcp980x_temperature(sc); 225 edata->state = ENVSYS_SVALID; 226 227 mutex_exit(&sc->sc_lock); 228 } 229