1 /* $OpenBSD: tipmic.c,v 1.3 2018/05/23 23:08:21 kettenis Exp $ */ 2 /* 3 * Copyright (c) 2018 Mark Kettenis <kettenis@openbsd.org> 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18 #include <sys/param.h> 19 #include <sys/systm.h> 20 #include <sys/device.h> 21 #include <sys/kernel.h> 22 #include <sys/malloc.h> 23 24 #include <dev/acpi/acpireg.h> 25 #include <dev/acpi/acpivar.h> 26 #include <dev/acpi/acpidev.h> 27 #include <dev/acpi/amltypes.h> 28 #include <dev/acpi/dsdt.h> 29 30 #include <dev/i2c/i2cvar.h> 31 32 #define TIPMIC_INTR_STAT 0x01 33 #define TIPMIC_INTR_STAT_ADC (1 << 2) 34 #define TIPMIC_INTR_MASK 0x02 35 #define TIPMIC_INTR_MASK_ADC (1 << 2) 36 #define TIPMIC_INTR_MASK_ALL 0xff 37 #define TIPMIC_LDO1_CTRL 0x41 38 #define TIPMIC_LDO2_CTRL 0x42 39 #define TIPMIC_LDO3_CTRL 0x43 40 #define TIPMIC_LDO5_CTRL 0x45 41 #define TIPMIC_LDO6_CTRL 0x46 42 #define TIPMIC_LDO7_CTRL 0x47 43 #define TIPMIC_LDO8_CTRL 0x48 44 #define TIPMIC_LDO9_CTRL 0x49 45 #define TIPMIC_LDO10_CTRL 0x4a 46 #define TIPMIC_LDO11_CTRL 0x4b 47 #define TIPMIC_LDO12_CTRL 0x4c 48 #define TIPMIC_LDO13_CTRL 0x4d 49 #define TIPMIC_LDO14_CTRL 0x4e 50 #define TIPMIC_ADC_CTRL 0x50 51 #define TIPMIC_ADC_CTRL_START (1 << 0) 52 #define TIPMIC_ADC_CTRL_CH_MASK (3 << 1) 53 #define TIPMIC_ADC_CTRL_CH_PMICTEMP (1 << 1) 54 #define TIPMIC_ADC_CTRL_CH_BATTEMP (2 << 1) 55 #define TIPMIC_ADC_CTRL_CH_SYSTEMP (3 << 1) 56 #define TIPMIC_ADC_CTRL_EN (1 << 5) 57 #define TIPMIC_PMICTEMP_HI 0x56 58 #define TIPMIC_PMICTEMP_LO 0x57 59 #define TIPMIC_BATTEMP_HI 0x58 60 #define TIPMIC_BATTEMP_LO 0x59 61 #define TIPMIC_SYSTEMP_HI 0x5a 62 #define TIPMIC_SYSTEMP_LO 0x5b 63 64 #define TIPMIC_REGIONSPACE_THERMAL 0x8c 65 #define TIPMIC_REGIONSPACE_POWER 0x8d 66 67 struct acpi_lpat { 68 int32_t temp; 69 int32_t raw; 70 }; 71 72 struct tipmic_softc { 73 struct device sc_dev; 74 struct acpi_softc *sc_acpi; 75 struct aml_node *sc_node; 76 i2c_tag_t sc_tag; 77 i2c_addr_t sc_addr; 78 79 void *sc_ih; 80 volatile int sc_stat_adc; 81 82 struct acpi_lpat *sc_lpat; 83 size_t sc_lpat_len; 84 85 struct acpi_gpio sc_gpio; 86 }; 87 88 int tipmic_match(struct device *, void *, void *); 89 void tipmic_attach(struct device *, struct device *, void *); 90 91 struct cfattach tipmic_ca = { 92 sizeof(struct tipmic_softc), tipmic_match, tipmic_attach 93 }; 94 95 struct cfdriver tipmic_cd = { 96 NULL, "tipmic", DV_DULL 97 }; 98 99 uint8_t tipmic_read_1(struct tipmic_softc *, uint8_t, int); 100 void tipmic_write_1(struct tipmic_softc *, uint8_t, uint8_t, int); 101 int tipmic_intr(void *); 102 void tipmic_get_lpat(struct tipmic_softc *); 103 int32_t tipmic_raw_to_temp(struct tipmic_softc *, int32_t); 104 int tipmic_thermal_opreg_handler(void *, int, uint64_t, int, uint64_t *); 105 int tipmic_power_opreg_handler(void *, int, uint64_t, int, uint64_t *); 106 int tipmic_read_pin(void *, int); 107 void tipmic_write_pin(void *, int, int); 108 109 int 110 tipmic_match(struct device *parent, void *match, void *aux) 111 { 112 struct i2c_attach_args *ia = aux; 113 114 return (strcmp(ia->ia_name, "INT33F5") == 0); 115 } 116 117 void 118 tipmic_attach(struct device *parent, struct device *self, void *aux) 119 { 120 struct tipmic_softc *sc = (struct tipmic_softc *)self; 121 struct i2c_attach_args *ia = aux; 122 123 sc->sc_tag = ia->ia_tag; 124 sc->sc_addr = ia->ia_addr; 125 sc->sc_acpi = acpi_softc; 126 sc->sc_node = ia->ia_cookie; 127 128 if (ia->ia_intr == NULL) { 129 printf(": no interrupt\n"); 130 return; 131 } 132 133 /* Mask all interrupts before we install our interrupt handler. */ 134 tipmic_write_1(sc, TIPMIC_INTR_MASK, TIPMIC_INTR_MASK_ALL, I2C_F_POLL); 135 136 printf(" %s", iic_intr_string(sc->sc_tag, ia->ia_intr)); 137 sc->sc_ih = iic_intr_establish(sc->sc_tag, ia->ia_intr, 138 IPL_BIO, tipmic_intr, sc, sc->sc_dev.dv_xname); 139 if (sc->sc_ih == NULL) { 140 printf(": can't establish interrupt\n"); 141 return; 142 } 143 144 printf("\n"); 145 146 tipmic_get_lpat(sc); 147 if (sc->sc_lpat == NULL) 148 return; 149 150 sc->sc_gpio.cookie = sc; 151 sc->sc_gpio.read_pin = tipmic_read_pin; 152 sc->sc_gpio.write_pin = tipmic_write_pin; 153 sc->sc_node->gpio = &sc->sc_gpio; 154 acpi_register_gpio(sc->sc_acpi, sc->sc_node); 155 156 /* Register OEM defined address space. */ 157 aml_register_regionspace(sc->sc_node, TIPMIC_REGIONSPACE_THERMAL, 158 sc, tipmic_thermal_opreg_handler); 159 aml_register_regionspace(sc->sc_node, TIPMIC_REGIONSPACE_POWER, 160 sc, tipmic_power_opreg_handler); 161 } 162 163 uint8_t 164 tipmic_read_1(struct tipmic_softc *sc, uint8_t reg, int flags) 165 { 166 uint8_t val; 167 int error; 168 169 iic_acquire_bus(sc->sc_tag, flags); 170 error = iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, sc->sc_addr, 171 ®, sizeof(reg), &val, sizeof(val), flags); 172 iic_release_bus(sc->sc_tag, flags); 173 174 if (error) { 175 printf("%s: can't read register 0x%02x\n", 176 sc->sc_dev.dv_xname, reg); 177 val = 0xff; 178 } 179 180 return val; 181 } 182 183 void 184 tipmic_write_1(struct tipmic_softc *sc, uint8_t reg, uint8_t val, int flags) 185 { 186 int error; 187 188 iic_acquire_bus(sc->sc_tag, flags); 189 error = iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP, sc->sc_addr, 190 ®, sizeof(reg), &val, sizeof(val), flags); 191 iic_release_bus(sc->sc_tag, flags); 192 193 if (error) { 194 printf("%s: can't write register 0x%02x\n", 195 sc->sc_dev.dv_xname, reg); 196 } 197 } 198 199 int 200 tipmic_intr(void *arg) 201 { 202 struct tipmic_softc *sc = arg; 203 int handled = 0; 204 uint8_t stat; 205 206 stat = tipmic_read_1(sc, TIPMIC_INTR_STAT, I2C_F_POLL); 207 tipmic_write_1(sc, TIPMIC_INTR_STAT, stat, I2C_F_POLL); 208 if (stat & TIPMIC_INTR_STAT_ADC) { 209 sc->sc_stat_adc = 1; 210 wakeup(&sc->sc_stat_adc); 211 handled = 1; 212 } 213 214 return handled; 215 } 216 217 void 218 tipmic_get_lpat(struct tipmic_softc *sc) 219 { 220 struct aml_value res; 221 int i; 222 223 if (aml_evalname(sc->sc_acpi, sc->sc_node, "LPAT", 0, NULL, &res)) 224 return; 225 if (res.type != AML_OBJTYPE_PACKAGE) 226 goto out; 227 if (res.length < 4 || (res.length % 2) != 0) 228 goto out; 229 230 sc->sc_lpat_len = res.length / 2; 231 sc->sc_lpat = mallocarray(sc->sc_lpat_len, sizeof(struct acpi_lpat), 232 M_DEVBUF, M_WAITOK); 233 234 for (i = 0; i < sc->sc_lpat_len; i++) { 235 sc->sc_lpat[i].temp = aml_val2int(res.v_package[2 * i]); 236 sc->sc_lpat[i].raw = aml_val2int(res.v_package[2 * i + 1]); 237 } 238 239 out: 240 aml_freevalue(&res); 241 } 242 243 int32_t 244 tipmic_raw_to_temp(struct tipmic_softc *sc, int32_t raw) 245 { 246 struct acpi_lpat *lpat = sc->sc_lpat; 247 int32_t raw0, delta_raw; 248 int32_t temp0, delta_temp; 249 int i; 250 251 for (i = 1; i < sc->sc_lpat_len; i++) { 252 /* Coefficient can be positive or negative. */ 253 if (raw >= lpat[i - 1].raw && raw <= lpat[i].raw) 254 break; 255 if (raw <= lpat[i - 1].raw && raw >= lpat[i].raw) 256 break; 257 } 258 if (i == sc->sc_lpat_len) 259 return -1; 260 261 raw0 = lpat[i - 1].raw; 262 temp0 = lpat[i - 1].temp; 263 delta_raw = lpat[i].raw - raw0; 264 delta_temp = lpat[i].temp - temp0; 265 266 return temp0 + (raw - raw0) * delta_temp / delta_raw; 267 } 268 269 struct tipmic_regmap { 270 uint8_t address; 271 uint8_t hi, lo; 272 }; 273 274 struct tipmic_regmap tipmic_thermal_regmap[] = { 275 { 0x18, TIPMIC_SYSTEMP_HI, TIPMIC_SYSTEMP_LO } 276 }; 277 278 int 279 tipmic_thermal_opreg_handler(void *cookie, int iodir, uint64_t address, 280 int size, uint64_t *value) 281 { 282 struct tipmic_softc *sc = cookie; 283 int32_t temp; 284 uint16_t raw; 285 uint8_t hi, lo; 286 uint8_t reg; 287 int i, s; 288 289 /* Only allow 32-bit read access. */ 290 if (size != 4 || iodir != ACPI_IOREAD) 291 return -1; 292 293 for (i = 0; i < nitems(tipmic_thermal_regmap); i++) { 294 if (address == tipmic_thermal_regmap[i].address) 295 break; 296 } 297 if (i == nitems(tipmic_thermal_regmap)) { 298 printf("%s: addr 0x%02llx\n", __func__, address); 299 return -1; 300 } 301 302 /* Turn ADC on and select the appropriate channel. */ 303 reg = tipmic_read_1(sc, TIPMIC_ADC_CTRL, 0); 304 reg |= TIPMIC_ADC_CTRL_EN; 305 tipmic_write_1(sc, TIPMIC_ADC_CTRL, reg, 0); 306 switch (tipmic_thermal_regmap[i].hi) { 307 case TIPMIC_SYSTEMP_HI: 308 reg |= TIPMIC_ADC_CTRL_CH_SYSTEMP; 309 break; 310 default: 311 panic("%s: unsupported channel", sc->sc_dev.dv_xname); 312 } 313 tipmic_write_1(sc, TIPMIC_ADC_CTRL, reg, 0); 314 315 /* Need to wait 50us before starting the conversion. */ 316 delay(50); 317 318 /* Start conversion. */ 319 sc->sc_stat_adc = 0; 320 reg |= TIPMIC_ADC_CTRL_START; 321 tipmic_write_1(sc, TIPMIC_ADC_CTRL, reg, 0); 322 323 /* 324 * Block interrupts to prevent I2C access from the interrupt 325 * handler during the completion of the write that unmasks the 326 * ADC interrupt. 327 */ 328 s = splbio(); 329 reg = tipmic_read_1(sc, TIPMIC_INTR_MASK, I2C_F_POLL); 330 reg &= ~TIPMIC_INTR_MASK_ADC; 331 tipmic_write_1(sc, TIPMIC_INTR_MASK, reg, I2C_F_POLL); 332 splx(s); 333 334 while (sc->sc_stat_adc == 0) { 335 if (tsleep(&sc->sc_stat_adc, PRIBIO, "tipmic", hz)) { 336 printf("%s: ADC timeout\n", sc->sc_dev.dv_xname); 337 break; 338 } 339 } 340 341 /* Mask ADC interrupt again. */ 342 s = splbio(); 343 reg = tipmic_read_1(sc, TIPMIC_INTR_MASK, I2C_F_POLL); 344 reg |= TIPMIC_INTR_MASK_ADC; 345 tipmic_write_1(sc, TIPMIC_INTR_MASK, reg, I2C_F_POLL); 346 splx(s); 347 348 hi = tipmic_thermal_regmap[i].hi; 349 lo = tipmic_thermal_regmap[i].lo; 350 raw = (tipmic_read_1(sc, hi, 0) & 0x03) << 8; 351 raw |= tipmic_read_1(sc, lo, 0); 352 353 /* Turn ADC off. */ 354 reg = tipmic_read_1(sc, TIPMIC_ADC_CTRL, 0); 355 reg &= ~(TIPMIC_ADC_CTRL_EN | TIPMIC_ADC_CTRL_CH_MASK); 356 tipmic_write_1(sc, TIPMIC_ADC_CTRL, reg, 0); 357 358 temp = tipmic_raw_to_temp(sc, raw); 359 if (temp < 0) 360 return -1; 361 362 *value = temp; 363 return 0; 364 } 365 366 struct tipmic_regmap tipmic_power_regmap[] = { 367 { 0x00, TIPMIC_LDO1_CTRL }, 368 { 0x04, TIPMIC_LDO2_CTRL }, 369 { 0x08, TIPMIC_LDO3_CTRL }, 370 { 0x0c, TIPMIC_LDO5_CTRL }, 371 { 0x10, TIPMIC_LDO6_CTRL }, 372 { 0x14, TIPMIC_LDO7_CTRL }, 373 { 0x18, TIPMIC_LDO8_CTRL }, 374 { 0x1c, TIPMIC_LDO9_CTRL }, 375 { 0x20, TIPMIC_LDO10_CTRL }, 376 { 0x24, TIPMIC_LDO11_CTRL }, 377 { 0x28, TIPMIC_LDO12_CTRL }, 378 { 0x2c, TIPMIC_LDO13_CTRL }, 379 { 0x30, TIPMIC_LDO14_CTRL } 380 }; 381 382 int 383 tipmic_power_opreg_handler(void *cookie, int iodir, uint64_t address, 384 int size, uint64_t *value) 385 { 386 struct tipmic_softc *sc = cookie; 387 uint8_t reg, val; 388 int i; 389 390 /* Only allow 32-bit access. */ 391 if (size != 4) 392 return -1; 393 394 for (i = 0; i < nitems(tipmic_power_regmap); i++) { 395 if (address == tipmic_power_regmap[i].address) 396 break; 397 } 398 if (i == nitems(tipmic_power_regmap)) { 399 printf("%s: addr 0x%02llx\n", __func__, address); 400 return -1; 401 } 402 403 reg = tipmic_power_regmap[i].hi; 404 val = tipmic_read_1(sc, reg, 0); 405 if (iodir == ACPI_IOREAD) { 406 *value = val & 0x1; 407 } else { 408 if (*value) 409 val |= 0x1; 410 else 411 val &= ~0x1; 412 tipmic_write_1(sc, reg, val, 0); 413 } 414 415 return 0; 416 } 417 418 /* 419 * Allegdly the GPIOs are virtual and only there to deal with a 420 * limitation of Microsoft Windows. 421 */ 422 423 int 424 tipmic_read_pin(void *cookie, int pin) 425 { 426 return 0; 427 } 428 429 void 430 tipmic_write_pin(void *cookie, int pin, int value) 431 { 432 } 433