1/* $OpenBSD: tipmic.c,v 1.8 2023/03/04 01:23:40 dlg 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 67struct acpi_lpat { 68 int32_t temp; 69 int32_t raw; 70}; 71 72struct 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 88int tipmic_match(struct device *, void *, void *); 89void tipmic_attach(struct device *, struct device *, void *); 90 91const struct cfattach tipmic_ca = { 92 sizeof(struct tipmic_softc), tipmic_match, tipmic_attach 93}; 94 95struct cfdriver tipmic_cd = { 96 NULL, "tipmic", DV_DULL 97}; 98 99uint8_t tipmic_read_1(struct tipmic_softc *, uint8_t, int); 100void tipmic_write_1(struct tipmic_softc *, uint8_t, uint8_t, int); 101int tipmic_intr(void *); 102void tipmic_get_lpat(struct tipmic_softc *); 103int32_t tipmic_raw_to_temp(struct tipmic_softc *, int32_t); 104int tipmic_thermal_opreg_handler(void *, int, uint64_t, int, uint64_t *); 105int tipmic_power_opreg_handler(void *, int, uint64_t, int, uint64_t *); 106int tipmic_read_pin(void *, int); 107void tipmic_write_pin(void *, int, int); 108 109int 110tipmic_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 117void 118tipmic_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 163uint8_t 164tipmic_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 183void 184tipmic_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 199int 200tipmic_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 217void 218tipmic_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 239out: 240 aml_freevalue(&res); 241} 242 243int32_t 244tipmic_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 269struct tipmic_regmap { 270 uint8_t address; 271 uint8_t hi, lo; 272}; 273 274struct tipmic_regmap tipmic_thermal_regmap[] = { 275 { 0x00, TIPMIC_SYSTEMP_HI, TIPMIC_SYSTEMP_LO }, 276 { 0x18, TIPMIC_SYSTEMP_HI, TIPMIC_SYSTEMP_LO } 277}; 278 279static int 280tipmic_wait_adc(struct tipmic_softc *sc) 281{ 282 int i; 283 284 if (!cold) { 285 return (tsleep_nsec(&sc->sc_stat_adc, PRIBIO, "tipmic", 286 SEC_TO_NSEC(1))); 287 } 288 289 for (i = 0; i < 1000; i++) { 290 delay(1000); 291 if (tipmic_intr(sc) == 1) 292 return (0); 293 } 294 295 return (EWOULDBLOCK); 296} 297 298int 299tipmic_thermal_opreg_handler(void *cookie, int iodir, uint64_t address, 300 int size, uint64_t *value) 301{ 302 struct tipmic_softc *sc = cookie; 303 int32_t temp; 304 uint16_t raw; 305 uint8_t hi, lo; 306 uint8_t reg; 307 int i, s; 308 309 /* Only allow 32-bit read access. */ 310 if (size != 4 || iodir != ACPI_IOREAD) 311 return -1; 312 313 for (i = 0; i < nitems(tipmic_thermal_regmap); i++) { 314 if (address == tipmic_thermal_regmap[i].address) 315 break; 316 } 317 if (i == nitems(tipmic_thermal_regmap)) { 318 printf("%s: addr 0x%02llx\n", __func__, address); 319 return -1; 320 } 321 322 /* Turn ADC on and select the appropriate channel. */ 323 reg = tipmic_read_1(sc, TIPMIC_ADC_CTRL, 0); 324 reg |= TIPMIC_ADC_CTRL_EN; 325 tipmic_write_1(sc, TIPMIC_ADC_CTRL, reg, 0); 326 switch (tipmic_thermal_regmap[i].hi) { 327 case TIPMIC_SYSTEMP_HI: 328 reg |= TIPMIC_ADC_CTRL_CH_SYSTEMP; 329 break; 330 default: 331 panic("%s: unsupported channel", sc->sc_dev.dv_xname); 332 } 333 tipmic_write_1(sc, TIPMIC_ADC_CTRL, reg, 0); 334 335 /* Need to wait 50us before starting the conversion. */ 336 delay(50); 337 338 /* Start conversion. */ 339 sc->sc_stat_adc = 0; 340 reg |= TIPMIC_ADC_CTRL_START; 341 tipmic_write_1(sc, TIPMIC_ADC_CTRL, reg, 0); 342 343 /* 344 * Block interrupts to prevent I2C access from the interrupt 345 * handler during the completion of the write that unmasks the 346 * ADC interrupt. 347 */ 348 s = splbio(); 349 reg = tipmic_read_1(sc, TIPMIC_INTR_MASK, I2C_F_POLL); 350 reg &= ~TIPMIC_INTR_MASK_ADC; 351 tipmic_write_1(sc, TIPMIC_INTR_MASK, reg, I2C_F_POLL); 352 splx(s); 353 354 while (sc->sc_stat_adc == 0) { 355 if (tipmic_wait_adc(sc)) { 356 printf("%s: ADC timeout\n", sc->sc_dev.dv_xname); 357 break; 358 } 359 } 360 361 /* Mask ADC interrupt again. */ 362 s = splbio(); 363 reg = tipmic_read_1(sc, TIPMIC_INTR_MASK, I2C_F_POLL); 364 reg |= TIPMIC_INTR_MASK_ADC; 365 tipmic_write_1(sc, TIPMIC_INTR_MASK, reg, I2C_F_POLL); 366 splx(s); 367 368 hi = tipmic_thermal_regmap[i].hi; 369 lo = tipmic_thermal_regmap[i].lo; 370 raw = (tipmic_read_1(sc, hi, 0) & 0x03) << 8; 371 raw |= tipmic_read_1(sc, lo, 0); 372 373 /* Turn ADC off. */ 374 reg = tipmic_read_1(sc, TIPMIC_ADC_CTRL, 0); 375 reg &= ~(TIPMIC_ADC_CTRL_EN | TIPMIC_ADC_CTRL_CH_MASK); 376 tipmic_write_1(sc, TIPMIC_ADC_CTRL, reg, 0); 377 378 temp = tipmic_raw_to_temp(sc, raw); 379 if (temp < 0) 380 return -1; 381 382 *value = temp; 383 return 0; 384} 385 386struct tipmic_regmap tipmic_power_regmap[] = { 387 { 0x00, TIPMIC_LDO1_CTRL }, 388 { 0x04, TIPMIC_LDO2_CTRL }, 389 { 0x08, TIPMIC_LDO3_CTRL }, 390 { 0x0c, TIPMIC_LDO5_CTRL }, 391 { 0x10, TIPMIC_LDO6_CTRL }, 392 { 0x14, TIPMIC_LDO7_CTRL }, 393 { 0x18, TIPMIC_LDO8_CTRL }, 394 { 0x1c, TIPMIC_LDO9_CTRL }, 395 { 0x20, TIPMIC_LDO10_CTRL }, 396 { 0x24, TIPMIC_LDO11_CTRL }, 397 { 0x28, TIPMIC_LDO12_CTRL }, 398 { 0x2c, TIPMIC_LDO13_CTRL }, 399 { 0x30, TIPMIC_LDO14_CTRL } 400}; 401 402int 403tipmic_power_opreg_handler(void *cookie, int iodir, uint64_t address, 404 int size, uint64_t *value) 405{ 406 struct tipmic_softc *sc = cookie; 407 uint8_t reg, val; 408 int i; 409 410 /* Only allow 32-bit access. */ 411 if (size != 4) 412 return -1; 413 414 for (i = 0; i < nitems(tipmic_power_regmap); i++) { 415 if (address == tipmic_power_regmap[i].address) 416 break; 417 } 418 if (i == nitems(tipmic_power_regmap)) { 419 printf("%s: addr 0x%02llx\n", __func__, address); 420 return -1; 421 } 422 423 reg = tipmic_power_regmap[i].hi; 424 val = tipmic_read_1(sc, reg, 0); 425 if (iodir == ACPI_IOREAD) { 426 *value = val & 0x1; 427 } else { 428 if (*value) 429 val |= 0x1; 430 else 431 val &= ~0x1; 432 tipmic_write_1(sc, reg, val, 0); 433 } 434 435 return 0; 436} 437 438/* 439 * Allegedly the GPIOs are virtual and only there to deal with a 440 * limitation of Microsoft Windows. 441 */ 442 443int 444tipmic_read_pin(void *cookie, int pin) 445{ 446 return 0; 447} 448 449void 450tipmic_write_pin(void *cookie, int pin, int value) 451{ 452} 453