1 /* $OpenBSD: tipmic.c,v 1.5 2020/01/09 14:35:19 mpi 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 { 0x00, TIPMIC_SYSTEMP_HI, TIPMIC_SYSTEMP_LO }, 276 { 0x18, TIPMIC_SYSTEMP_HI, TIPMIC_SYSTEMP_LO } 277 }; 278 279 int 280 tipmic_thermal_opreg_handler(void *cookie, int iodir, uint64_t address, 281 int size, uint64_t *value) 282 { 283 struct tipmic_softc *sc = cookie; 284 int32_t temp; 285 uint16_t raw; 286 uint8_t hi, lo; 287 uint8_t reg; 288 int i, s; 289 290 /* Only allow 32-bit read access. */ 291 if (size != 4 || iodir != ACPI_IOREAD) 292 return -1; 293 294 for (i = 0; i < nitems(tipmic_thermal_regmap); i++) { 295 if (address == tipmic_thermal_regmap[i].address) 296 break; 297 } 298 if (i == nitems(tipmic_thermal_regmap)) { 299 printf("%s: addr 0x%02llx\n", __func__, address); 300 return -1; 301 } 302 303 /* Turn ADC on and select the appropriate channel. */ 304 reg = tipmic_read_1(sc, TIPMIC_ADC_CTRL, 0); 305 reg |= TIPMIC_ADC_CTRL_EN; 306 tipmic_write_1(sc, TIPMIC_ADC_CTRL, reg, 0); 307 switch (tipmic_thermal_regmap[i].hi) { 308 case TIPMIC_SYSTEMP_HI: 309 reg |= TIPMIC_ADC_CTRL_CH_SYSTEMP; 310 break; 311 default: 312 panic("%s: unsupported channel", sc->sc_dev.dv_xname); 313 } 314 tipmic_write_1(sc, TIPMIC_ADC_CTRL, reg, 0); 315 316 /* Need to wait 50us before starting the conversion. */ 317 delay(50); 318 319 /* Start conversion. */ 320 sc->sc_stat_adc = 0; 321 reg |= TIPMIC_ADC_CTRL_START; 322 tipmic_write_1(sc, TIPMIC_ADC_CTRL, reg, 0); 323 324 /* 325 * Block interrupts to prevent I2C access from the interrupt 326 * handler during the completion of the write that unmasks the 327 * ADC interrupt. 328 */ 329 s = splbio(); 330 reg = tipmic_read_1(sc, TIPMIC_INTR_MASK, I2C_F_POLL); 331 reg &= ~TIPMIC_INTR_MASK_ADC; 332 tipmic_write_1(sc, TIPMIC_INTR_MASK, reg, I2C_F_POLL); 333 splx(s); 334 335 while (sc->sc_stat_adc == 0) { 336 if (tsleep_nsec(&sc->sc_stat_adc, PRIBIO, "tipmic", 337 SEC_TO_NSEC(1))) { 338 printf("%s: ADC timeout\n", sc->sc_dev.dv_xname); 339 break; 340 } 341 } 342 343 /* Mask ADC interrupt again. */ 344 s = splbio(); 345 reg = tipmic_read_1(sc, TIPMIC_INTR_MASK, I2C_F_POLL); 346 reg |= TIPMIC_INTR_MASK_ADC; 347 tipmic_write_1(sc, TIPMIC_INTR_MASK, reg, I2C_F_POLL); 348 splx(s); 349 350 hi = tipmic_thermal_regmap[i].hi; 351 lo = tipmic_thermal_regmap[i].lo; 352 raw = (tipmic_read_1(sc, hi, 0) & 0x03) << 8; 353 raw |= tipmic_read_1(sc, lo, 0); 354 355 /* Turn ADC off. */ 356 reg = tipmic_read_1(sc, TIPMIC_ADC_CTRL, 0); 357 reg &= ~(TIPMIC_ADC_CTRL_EN | TIPMIC_ADC_CTRL_CH_MASK); 358 tipmic_write_1(sc, TIPMIC_ADC_CTRL, reg, 0); 359 360 temp = tipmic_raw_to_temp(sc, raw); 361 if (temp < 0) 362 return -1; 363 364 *value = temp; 365 return 0; 366 } 367 368 struct tipmic_regmap tipmic_power_regmap[] = { 369 { 0x00, TIPMIC_LDO1_CTRL }, 370 { 0x04, TIPMIC_LDO2_CTRL }, 371 { 0x08, TIPMIC_LDO3_CTRL }, 372 { 0x0c, TIPMIC_LDO5_CTRL }, 373 { 0x10, TIPMIC_LDO6_CTRL }, 374 { 0x14, TIPMIC_LDO7_CTRL }, 375 { 0x18, TIPMIC_LDO8_CTRL }, 376 { 0x1c, TIPMIC_LDO9_CTRL }, 377 { 0x20, TIPMIC_LDO10_CTRL }, 378 { 0x24, TIPMIC_LDO11_CTRL }, 379 { 0x28, TIPMIC_LDO12_CTRL }, 380 { 0x2c, TIPMIC_LDO13_CTRL }, 381 { 0x30, TIPMIC_LDO14_CTRL } 382 }; 383 384 int 385 tipmic_power_opreg_handler(void *cookie, int iodir, uint64_t address, 386 int size, uint64_t *value) 387 { 388 struct tipmic_softc *sc = cookie; 389 uint8_t reg, val; 390 int i; 391 392 /* Only allow 32-bit access. */ 393 if (size != 4) 394 return -1; 395 396 for (i = 0; i < nitems(tipmic_power_regmap); i++) { 397 if (address == tipmic_power_regmap[i].address) 398 break; 399 } 400 if (i == nitems(tipmic_power_regmap)) { 401 printf("%s: addr 0x%02llx\n", __func__, address); 402 return -1; 403 } 404 405 reg = tipmic_power_regmap[i].hi; 406 val = tipmic_read_1(sc, reg, 0); 407 if (iodir == ACPI_IOREAD) { 408 *value = val & 0x1; 409 } else { 410 if (*value) 411 val |= 0x1; 412 else 413 val &= ~0x1; 414 tipmic_write_1(sc, reg, val, 0); 415 } 416 417 return 0; 418 } 419 420 /* 421 * Allegdly the GPIOs are virtual and only there to deal with a 422 * limitation of Microsoft Windows. 423 */ 424 425 int 426 tipmic_read_pin(void *cookie, int pin) 427 { 428 return 0; 429 } 430 431 void 432 tipmic_write_pin(void *cookie, int pin, int value) 433 { 434 } 435