1 /* $OpenBSD: tda.c,v 1.9 2021/10/24 17:05:04 mpi Exp $ */ 2 3 /* 4 * Copyright (c) 2008 Robert Nagy <robert@openbsd.org> 5 * Copyright (c) 2008 Mark Kettenis <kettenis@openbsd.org> 6 * 7 * Permission to use, copy, modify, and distribute this software for any 8 * purpose with or without fee is hereby granted, provided that the above 9 * copyright notice and this permission notice appear in all copies. 10 * 11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18 */ 19 20 #include <sys/param.h> 21 #include <sys/systm.h> 22 #include <sys/kernel.h> 23 #include <sys/device.h> 24 #include <sys/sensors.h> 25 26 #include <machine/autoconf.h> 27 #include <machine/openfirm.h> 28 29 #include <dev/i2c/i2cvar.h> 30 31 /* fan control registers */ 32 #define TDA_SYSFAN_REG 0xf0 33 #define TDA_CPUFAN_REG 0xf2 34 #define TDA_PSFAN_REG 0xf4 35 36 #define TDA_FANSPEED_MIN 0x0c 37 #define TDA_FANSPEED_MAX 0x3f 38 39 #define TDA_PSFAN_ON 0x1f 40 #define TDA_PSFAN_OFF 0x00 41 42 /* Internal and External temperature sensor numbers */ 43 #define SENSOR_TEMP_EXT 0 44 #define SENSOR_TEMP_INT 1 45 46 #define CPU_TEMP_MAX (67 * 1000000 + 273150000) 47 #define CPU_TEMP_MIN (57 * 1000000 + 273150000) 48 #define SYS_TEMP_MAX (35 * 1000000 + 273150000) 49 #define SYS_TEMP_MIN (25 * 1000000 + 273150000) 50 51 struct tda_softc { 52 struct device sc_dev; 53 i2c_tag_t sc_tag; 54 i2c_addr_t sc_addr; 55 56 u_int16_t sc_cfan_speed; /* current CPU fan speed */ 57 u_int16_t sc_sfan_speed; /* current SYS fan speed */ 58 59 int sc_nsensors; 60 }; 61 #define DEVNAME(_s) ((_s)->sc_dev.dv_xname) 62 63 int tda_match(struct device *, void *, void *); 64 void tda_attach(struct device *, struct device *, void *); 65 66 void tda_setspeed(struct tda_softc *); 67 void tda_adjust(void *); 68 69 const struct cfattach tda_ca = { 70 sizeof(struct tda_softc), tda_match, tda_attach 71 }; 72 73 struct cfdriver tda_cd = { 74 NULL, "tda", DV_DULL 75 }; 76 77 void *tda_cookie; 78 79 int 80 tda_match(struct device *parent, void *match, void *aux) 81 { 82 struct i2c_attach_args *ia = aux; 83 char name[32]; 84 85 if (strcmp(ia->ia_name, "tda8444") != 0) 86 return (0); 87 88 /* Only attach on the Sun Blade 1000/2000. */ 89 if (OF_getprop(findroot(), "name", name, sizeof(name)) <= 0) 90 return (0); 91 if (strcmp(name, "SUNW,Sun-Blade-1000") != 0) 92 return (0); 93 94 return (1); 95 } 96 97 void 98 tda_attach(struct device *parent, struct device *self, void *aux) 99 { 100 struct tda_softc *sc = (struct tda_softc *)self; 101 struct i2c_attach_args *ia = aux; 102 struct ksensordev *ksens; 103 int i; 104 105 sc->sc_tag = ia->ia_tag; 106 sc->sc_addr = ia->ia_addr; 107 108 printf("\n"); 109 110 /* 111 * Set the fans to maximum speed and save the power levels; 112 * the controller is write-only. 113 */ 114 sc->sc_cfan_speed = sc->sc_sfan_speed = TDA_FANSPEED_MAX; 115 tda_setspeed(sc); 116 117 /* Get the number of sensor devices. */ 118 for (i = 0; ; i++) { 119 if (sensordev_get(i, &ksens) == ENOENT) 120 break; 121 } 122 sc->sc_nsensors = i; 123 124 if (!sc->sc_nsensors) { 125 printf("%s: no temperature sensors found\n", DEVNAME(sc)); 126 return; 127 } 128 129 if (sensor_task_register(sc, tda_adjust, 10) == NULL) { 130 printf("%s: unable to register update task\n", DEVNAME(sc)); 131 return; 132 } 133 134 tda_cookie = sc; 135 } 136 137 void 138 tda_setspeed(struct tda_softc *sc) 139 { 140 u_int8_t cmd[2]; 141 142 if (sc->sc_cfan_speed < TDA_FANSPEED_MIN) 143 sc->sc_cfan_speed = TDA_FANSPEED_MIN; 144 if (sc->sc_sfan_speed < TDA_FANSPEED_MIN) 145 sc->sc_sfan_speed = TDA_FANSPEED_MIN; 146 if (sc->sc_cfan_speed > TDA_FANSPEED_MAX) 147 sc->sc_cfan_speed = TDA_FANSPEED_MAX; 148 if (sc->sc_sfan_speed > TDA_FANSPEED_MAX) 149 sc->sc_sfan_speed = TDA_FANSPEED_MAX; 150 151 iic_acquire_bus(sc->sc_tag, 0); 152 153 cmd[0] = TDA_CPUFAN_REG; 154 cmd[1] = sc->sc_cfan_speed; 155 if (iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP, 156 sc->sc_addr, &cmd, sizeof(cmd), NULL, 0, 0)) { 157 printf("%s: cannot write cpu-fan register\n", 158 DEVNAME(sc)); 159 iic_release_bus(sc->sc_tag, 0); 160 return; 161 } 162 163 cmd[0] = TDA_SYSFAN_REG; 164 cmd[1] = sc->sc_sfan_speed; 165 if (iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP, 166 sc->sc_addr, &cmd, sizeof(cmd), NULL, 0, 0)) { 167 printf("%s: cannot write system-fan register\n", 168 DEVNAME(sc)); 169 iic_release_bus(sc->sc_tag, 0); 170 return; 171 } 172 173 iic_release_bus(sc->sc_tag, 0); 174 175 #if 0 176 printf("%s: changed fan speed to cpu=%d system=%d\n", 177 DEVNAME(sc), sc->sc_cfan_speed, sc->sc_sfan_speed); 178 #endif 179 180 } 181 182 void 183 tda_adjust(void *v) 184 { 185 struct tda_softc *sc = v; 186 struct ksensor *ks; 187 u_int64_t ctemp, stemp; 188 int i, err; 189 190 /* Default to running the fans at maximum speed. */ 191 sc->sc_cfan_speed = sc->sc_sfan_speed = TDA_FANSPEED_MAX; 192 193 ctemp = stemp = 0; 194 for (i = 0; i < sc->sc_nsensors; i++) { 195 err = sensor_find(i, SENSOR_TEMP, SENSOR_TEMP_EXT, &ks); 196 if (err) { 197 printf("%s: failed to get external sensor\n", 198 DEVNAME(sc)); 199 goto out; 200 } 201 ctemp = MAX(ctemp, ks->value); 202 203 err = sensor_find(i, SENSOR_TEMP, SENSOR_TEMP_INT, &ks); 204 if (err) { 205 printf("%s: failed to get internal sensors\n", 206 DEVNAME(sc)); 207 goto out; 208 } 209 stemp = MAX(stemp, ks->value); 210 } 211 212 if (ctemp < CPU_TEMP_MIN) 213 sc->sc_cfan_speed = TDA_FANSPEED_MIN; 214 else if (ctemp < CPU_TEMP_MAX) 215 sc->sc_cfan_speed = TDA_FANSPEED_MIN + 216 (ctemp - CPU_TEMP_MIN) * 217 (TDA_FANSPEED_MAX - TDA_FANSPEED_MIN) / 218 (CPU_TEMP_MAX - CPU_TEMP_MIN); 219 220 if (stemp < SYS_TEMP_MIN) 221 sc->sc_sfan_speed = TDA_FANSPEED_MIN; 222 else if (stemp < SYS_TEMP_MAX) 223 sc->sc_sfan_speed = TDA_FANSPEED_MIN + 224 (stemp - SYS_TEMP_MIN) * 225 (TDA_FANSPEED_MAX - TDA_FANSPEED_MIN) / 226 (SYS_TEMP_MAX - SYS_TEMP_MIN); 227 228 out: 229 tda_setspeed(sc); 230 } 231 232 /* This code gets called when we are about to drop to ddb, 233 * in order to operate the fans at full speed during the 234 * timeouts are not working. 235 */ 236 void 237 tda_full_blast(void) 238 { 239 struct tda_softc *sc = tda_cookie; 240 u_int8_t cmd[2]; 241 242 if (sc == NULL) 243 return; 244 245 sc->sc_cfan_speed = sc->sc_sfan_speed = TDA_FANSPEED_MAX; 246 247 iic_acquire_bus(sc->sc_tag, I2C_F_POLL); 248 249 cmd[0] = TDA_CPUFAN_REG; 250 cmd[1] = sc->sc_cfan_speed; 251 if (iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP, 252 sc->sc_addr, &cmd, sizeof(cmd), NULL, 0, 0)) { 253 printf("%s: cannot write cpu-fan register\n", 254 DEVNAME(sc)); 255 iic_release_bus(sc->sc_tag, I2C_F_POLL); 256 return; 257 } 258 259 cmd[0] = TDA_SYSFAN_REG; 260 cmd[1] = sc->sc_sfan_speed; 261 if (iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP, 262 sc->sc_addr, &cmd, sizeof(cmd), NULL, 0, 0)) { 263 printf("%s: cannot write system-fan register\n", 264 DEVNAME(sc)); 265 iic_release_bus(sc->sc_tag, I2C_F_POLL); 266 return; 267 } 268 269 iic_release_bus(sc->sc_tag, I2C_F_POLL); 270 } 271