1 /* $OpenBSD: adm1030.c,v 1.10 2022/04/06 18:59:28 naddy Exp $ */ 2 3 /* 4 * Copyright (c) 2005 Theo de Raadt 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include <sys/param.h> 20 #include <sys/systm.h> 21 #include <sys/device.h> 22 #include <sys/sensors.h> 23 24 #include <dev/i2c/i2cvar.h> 25 26 /* adm 1030 registers */ 27 #define ADM1030_INT_TEMP 0x0a 28 #define ADM1030_EXT_TEMP 0x0b 29 #define ADM1030_FAN 0x08 30 #define ADM1030_FANC 0x20 31 #define ADM1024_FANC_VAL(x) (x >> 6) 32 33 /* Sensors */ 34 #define ADMTMP_INT 0 35 #define ADMTMP_EXT 1 36 #define ADMTMP_FAN 2 37 #define ADMTMP_NUM_SENSORS 3 38 39 struct admtmp_softc { 40 struct device sc_dev; 41 i2c_tag_t sc_tag; 42 i2c_addr_t sc_addr; 43 int sc_fanmul; 44 45 struct ksensor sc_sensor[ADMTMP_NUM_SENSORS]; 46 struct ksensordev sc_sensordev; 47 }; 48 49 int admtmp_match(struct device *, void *, void *); 50 void admtmp_attach(struct device *, struct device *, void *); 51 void admtmp_refresh(void *); 52 53 const struct cfattach admtmp_ca = { 54 sizeof(struct admtmp_softc), admtmp_match, admtmp_attach 55 }; 56 57 struct cfdriver admtmp_cd = { 58 NULL, "admtmp", DV_DULL 59 }; 60 61 int 62 admtmp_match(struct device *parent, void *match, void *aux) 63 { 64 struct i2c_attach_args *ia = aux; 65 66 if (strcmp(ia->ia_name, "adm1030") == 0) 67 return (1); 68 return (0); 69 } 70 71 void 72 admtmp_attach(struct device *parent, struct device *self, void *aux) 73 { 74 struct admtmp_softc *sc = (struct admtmp_softc *)self; 75 struct i2c_attach_args *ia = aux; 76 u_int8_t cmd, data; 77 int i; 78 79 sc->sc_tag = ia->ia_tag; 80 sc->sc_addr = ia->ia_addr; 81 82 cmd = ADM1030_FANC; 83 if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, 84 sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0)) { 85 printf(": unable to read fan setting\n"); 86 return; 87 } 88 89 sc->sc_fanmul = 11250/8 * (1 << ADM1024_FANC_VAL(data)) * 60; 90 91 /* Initialize sensor data. */ 92 strlcpy(sc->sc_sensordev.xname, sc->sc_dev.dv_xname, 93 sizeof(sc->sc_sensordev.xname)); 94 95 sc->sc_sensor[ADMTMP_INT].type = SENSOR_TEMP; 96 strlcpy(sc->sc_sensor[ADMTMP_INT].desc, "Internal", 97 sizeof(sc->sc_sensor[ADMTMP_INT].desc)); 98 99 sc->sc_sensor[ADMTMP_EXT].type = SENSOR_TEMP; 100 strlcpy(sc->sc_sensor[ADMTMP_EXT].desc, "External", 101 sizeof(sc->sc_sensor[ADMTMP_EXT].desc)); 102 103 sc->sc_sensor[ADMTMP_FAN].type = SENSOR_FANRPM; 104 105 if (sensor_task_register(sc, admtmp_refresh, 5) == NULL) { 106 printf(": unable to register update task\n"); 107 return; 108 } 109 110 for (i = 0; i < ADMTMP_NUM_SENSORS; i++) 111 sensor_attach(&sc->sc_sensordev, &sc->sc_sensor[i]); 112 sensordev_install(&sc->sc_sensordev); 113 114 printf("\n"); 115 } 116 117 void 118 admtmp_refresh(void *arg) 119 { 120 struct admtmp_softc *sc = arg; 121 u_int8_t cmd, data; 122 123 iic_acquire_bus(sc->sc_tag, 0); 124 125 cmd = ADM1030_INT_TEMP; 126 if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, 127 sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0) == 0) 128 sc->sc_sensor[ADMTMP_INT].value = 273150000 + 1000000 * data; 129 130 cmd = ADM1030_EXT_TEMP; 131 if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, 132 sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0) == 0) 133 sc->sc_sensor[ADMTMP_EXT].value = 273150000 + 1000000 * data; 134 135 cmd = ADM1030_FAN; 136 if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, 137 sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0) == 0) { 138 if (data == 0) 139 sc->sc_sensor[ADMTMP_FAN].flags |= SENSOR_FINVALID; 140 else { 141 sc->sc_sensor[ADMTMP_FAN].value = 142 sc->sc_fanmul / (2 * (int)data); 143 sc->sc_sensor[ADMTMP_FAN].flags &= ~SENSOR_FINVALID; 144 } 145 } 146 147 iic_release_bus(sc->sc_tag, 0); 148 } 149