1 /*- 2 * Copyright (c) 2005 Hans Petter Selasky 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 */ 26 27 #include <sys/cdefs.h> 28 #include "opt_acpi.h" 29 #include <sys/param.h> 30 #include <sys/kernel.h> 31 #include <sys/module.h> 32 #include <sys/bus.h> 33 34 #include <contrib/dev/acpica/include/acpi.h> 35 36 #include <dev/acpica/acpivar.h> 37 #include <dev/acpica/acpiio.h> 38 #include <dev/acpica/acpi_smbus.h> 39 40 /* Transactions have failed after 500 ms. */ 41 #define SMBUS_TIMEOUT 50 42 43 struct acpi_smbat_softc { 44 uint8_t sb_base_addr; 45 device_t ec_dev; 46 47 struct acpi_bix bix; 48 struct acpi_bst bst; 49 struct timespec bix_lastupdated; 50 struct timespec bst_lastupdated; 51 }; 52 53 static int acpi_smbat_probe(device_t dev); 54 static int acpi_smbat_attach(device_t dev); 55 static int acpi_smbat_shutdown(device_t dev); 56 static int acpi_smbat_info_expired(struct timespec *lastupdated); 57 static void acpi_smbat_info_updated(struct timespec *lastupdated); 58 static int acpi_smbat_get_bix(device_t dev, void *, size_t); 59 static int acpi_smbat_get_bst(device_t dev, struct acpi_bst *bst); 60 61 ACPI_SERIAL_DECL(smbat, "ACPI Smart Battery"); 62 63 static SYSCTL_NODE(_debug_acpi, OID_AUTO, batt, 64 CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, 65 "Battery debugging"); 66 67 /* On some laptops with smart batteries, enabling battery monitoring 68 * software causes keystrokes from atkbd to be lost. This has also been 69 * reported on Linux, and is apparently due to the keyboard and I2C line 70 * for the battery being routed through the same chip. Whether that's 71 * accurate or not, adding extra sleeps to the status checking code 72 * causes the problem to go away. 73 * 74 * If you experience that problem, try a value of 10ms and move up 75 * from there. 76 */ 77 static int batt_sleep_ms; 78 SYSCTL_INT(_debug_acpi_batt, OID_AUTO, batt_sleep_ms, CTLFLAG_RW, &batt_sleep_ms, 0, 79 "Sleep during battery status updates to prevent keystroke loss."); 80 81 static device_method_t acpi_smbat_methods[] = { 82 /* device interface */ 83 DEVMETHOD(device_probe, acpi_smbat_probe), 84 DEVMETHOD(device_attach, acpi_smbat_attach), 85 DEVMETHOD(device_shutdown, acpi_smbat_shutdown), 86 87 /* ACPI battery interface */ 88 DEVMETHOD(acpi_batt_get_status, acpi_smbat_get_bst), 89 DEVMETHOD(acpi_batt_get_info, acpi_smbat_get_bix), 90 91 DEVMETHOD_END 92 }; 93 94 static driver_t acpi_smbat_driver = { 95 "battery", 96 acpi_smbat_methods, 97 sizeof(struct acpi_smbat_softc), 98 }; 99 100 DRIVER_MODULE(acpi_smbat, acpi, acpi_smbat_driver, 0, 0); 101 MODULE_DEPEND(acpi_smbat, acpi, 1, 1, 1); 102 103 static int 104 acpi_smbat_probe(device_t dev) 105 { 106 static char *smbat_ids[] = {"ACPI0001", "ACPI0005", NULL}; 107 ACPI_STATUS status; 108 int rv; 109 110 if (acpi_disabled("smbat")) 111 return (ENXIO); 112 rv = ACPI_ID_PROBE(device_get_parent(dev), dev, smbat_ids, NULL); 113 if (rv > 0) 114 return (rv); 115 status = AcpiEvaluateObject(acpi_get_handle(dev), "_EC", NULL, NULL); 116 if (ACPI_FAILURE(status)) 117 return (ENXIO); 118 device_set_desc(dev, "ACPI Smart Battery"); 119 return (rv); 120 } 121 122 static int 123 acpi_smbat_attach(device_t dev) 124 { 125 struct acpi_smbat_softc *sc; 126 uint32_t base; 127 128 sc = device_get_softc(dev); 129 if (ACPI_FAILURE(acpi_GetInteger(acpi_get_handle(dev), "_EC", &base))) { 130 device_printf(dev, "cannot get EC base address\n"); 131 return (ENXIO); 132 } 133 sc->sb_base_addr = (base >> 8) & 0xff; 134 135 /* XXX Only works with one EC, but nearly all systems only have one. */ 136 sc->ec_dev = devclass_get_device(devclass_find("acpi_ec"), 0); 137 if (sc->ec_dev == NULL) { 138 device_printf(dev, "cannot find EC device\n"); 139 return (ENXIO); 140 } 141 142 timespecclear(&sc->bix_lastupdated); 143 timespecclear(&sc->bst_lastupdated); 144 145 if (acpi_battery_register(dev) != 0) { 146 device_printf(dev, "cannot register battery\n"); 147 return (ENXIO); 148 } 149 return (0); 150 } 151 152 static int 153 acpi_smbat_shutdown(device_t dev) 154 { 155 156 acpi_battery_remove(dev); 157 return (0); 158 } 159 160 static int 161 acpi_smbat_info_expired(struct timespec *lastupdated) 162 { 163 struct timespec curtime; 164 165 ACPI_SERIAL_ASSERT(smbat); 166 167 if (lastupdated == NULL) 168 return (TRUE); 169 if (!timespecisset(lastupdated)) 170 return (TRUE); 171 172 getnanotime(&curtime); 173 timespecsub(&curtime, lastupdated, &curtime); 174 return (curtime.tv_sec < 0 || 175 curtime.tv_sec > acpi_battery_get_info_expire()); 176 } 177 178 static void 179 acpi_smbat_info_updated(struct timespec *lastupdated) 180 { 181 182 ACPI_SERIAL_ASSERT(smbat); 183 184 if (lastupdated != NULL) 185 getnanotime(lastupdated); 186 } 187 188 static int 189 acpi_smbus_read_2(struct acpi_smbat_softc *sc, uint8_t addr, uint8_t cmd, 190 uint16_t *ptr) 191 { 192 int error, to; 193 UINT64 val; 194 195 ACPI_SERIAL_ASSERT(smbat); 196 197 if (batt_sleep_ms) 198 AcpiOsSleep(batt_sleep_ms); 199 200 val = addr; 201 error = ACPI_EC_WRITE(sc->ec_dev, sc->sb_base_addr + SMBUS_ADDR, 202 val, 1); 203 if (error) 204 goto out; 205 206 val = cmd; 207 error = ACPI_EC_WRITE(sc->ec_dev, sc->sb_base_addr + SMBUS_CMD, 208 val, 1); 209 if (error) 210 goto out; 211 212 val = 0x09; /* | 0x80 if PEC */ 213 error = ACPI_EC_WRITE(sc->ec_dev, sc->sb_base_addr + SMBUS_PRTCL, 214 val, 1); 215 if (error) 216 goto out; 217 218 if (batt_sleep_ms) 219 AcpiOsSleep(batt_sleep_ms); 220 221 for (to = SMBUS_TIMEOUT; to != 0; to--) { 222 error = ACPI_EC_READ(sc->ec_dev, sc->sb_base_addr + SMBUS_PRTCL, 223 &val, 1); 224 if (error) 225 goto out; 226 if (val == 0) 227 break; 228 AcpiOsSleep(10); 229 } 230 if (to == 0) { 231 error = ETIMEDOUT; 232 goto out; 233 } 234 235 error = ACPI_EC_READ(sc->ec_dev, sc->sb_base_addr + SMBUS_STS, &val, 1); 236 if (error) 237 goto out; 238 if (val & SMBUS_STS_MASK) { 239 printf("%s: AE_ERROR 0x%x\n", 240 __FUNCTION__, (int)(val & SMBUS_STS_MASK)); 241 error = EIO; 242 goto out; 243 } 244 245 error = ACPI_EC_READ(sc->ec_dev, sc->sb_base_addr + SMBUS_DATA, 246 &val, 2); 247 if (error) 248 goto out; 249 250 *ptr = val; 251 252 out: 253 return (error); 254 } 255 256 static int 257 acpi_smbus_read_multi_1(struct acpi_smbat_softc *sc, uint8_t addr, uint8_t cmd, 258 uint8_t *ptr, uint16_t len) 259 { 260 UINT64 val; 261 uint8_t to; 262 int error; 263 264 ACPI_SERIAL_ASSERT(smbat); 265 266 if (batt_sleep_ms) 267 AcpiOsSleep(batt_sleep_ms); 268 269 val = addr; 270 error = ACPI_EC_WRITE(sc->ec_dev, sc->sb_base_addr + SMBUS_ADDR, 271 val, 1); 272 if (error) 273 goto out; 274 275 val = cmd; 276 error = ACPI_EC_WRITE(sc->ec_dev, sc->sb_base_addr + SMBUS_CMD, 277 val, 1); 278 if (error) 279 goto out; 280 281 val = 0x0B /* | 0x80 if PEC */ ; 282 error = ACPI_EC_WRITE(sc->ec_dev, sc->sb_base_addr + SMBUS_PRTCL, 283 val, 1); 284 if (error) 285 goto out; 286 287 if (batt_sleep_ms) 288 AcpiOsSleep(batt_sleep_ms); 289 290 for (to = SMBUS_TIMEOUT; to != 0; to--) { 291 error = ACPI_EC_READ(sc->ec_dev, sc->sb_base_addr + SMBUS_PRTCL, 292 &val, 1); 293 if (error) 294 goto out; 295 if (val == 0) 296 break; 297 AcpiOsSleep(10); 298 } 299 if (to == 0) { 300 error = ETIMEDOUT; 301 goto out; 302 } 303 304 error = ACPI_EC_READ(sc->ec_dev, sc->sb_base_addr + SMBUS_STS, &val, 1); 305 if (error) 306 goto out; 307 if (val & SMBUS_STS_MASK) { 308 printf("%s: AE_ERROR 0x%x\n", 309 __FUNCTION__, (int)(val & SMBUS_STS_MASK)); 310 error = EIO; 311 goto out; 312 } 313 314 /* get length */ 315 error = ACPI_EC_READ(sc->ec_dev, sc->sb_base_addr + SMBUS_BCNT, 316 &val, 1); 317 if (error) 318 goto out; 319 val = (val & 0x1f) + 1; 320 321 bzero(ptr, len); 322 if (len > val) 323 len = val; 324 325 if (batt_sleep_ms) 326 AcpiOsSleep(batt_sleep_ms); 327 328 while (len--) { 329 error = ACPI_EC_READ(sc->ec_dev, sc->sb_base_addr + SMBUS_DATA 330 + len, &val, 1); 331 if (error) 332 goto out; 333 334 ptr[len] = val; 335 if (batt_sleep_ms) 336 AcpiOsSleep(batt_sleep_ms); 337 } 338 339 out: 340 return (error); 341 } 342 343 static int 344 acpi_smbat_get_bst(device_t dev, struct acpi_bst *bst) 345 { 346 struct acpi_smbat_softc *sc; 347 int error; 348 uint32_t factor; 349 int16_t val; 350 uint8_t addr; 351 352 ACPI_SERIAL_BEGIN(smbat); 353 354 addr = SMBATT_ADDRESS; 355 error = ENXIO; 356 sc = device_get_softc(dev); 357 358 if (!acpi_smbat_info_expired(&sc->bst_lastupdated)) { 359 error = 0; 360 goto out; 361 } 362 363 if (acpi_smbus_read_2(sc, addr, SMBATT_CMD_BATTERY_MODE, &val)) 364 goto out; 365 if (val & SMBATT_BM_CAPACITY_MODE) 366 factor = 10; 367 else 368 factor = 1; 369 370 /* get battery status */ 371 if (acpi_smbus_read_2(sc, addr, SMBATT_CMD_BATTERY_STATUS, &val)) 372 goto out; 373 374 sc->bst.state = 0; 375 if (val & SMBATT_BS_DISCHARGING) 376 sc->bst.state |= ACPI_BATT_STAT_DISCHARG; 377 378 if (val & SMBATT_BS_REMAINING_CAPACITY_ALARM) 379 sc->bst.state |= ACPI_BATT_STAT_CRITICAL; 380 381 /* 382 * If the rate is negative, it is discharging. Otherwise, 383 * it is charging. 384 */ 385 if (acpi_smbus_read_2(sc, addr, SMBATT_CMD_CURRENT, &val)) 386 goto out; 387 388 if (val > 0) { 389 sc->bst.rate = val * factor; 390 sc->bst.state &= ~SMBATT_BS_DISCHARGING; 391 sc->bst.state |= ACPI_BATT_STAT_CHARGING; 392 } else if (val < 0) 393 sc->bst.rate = (-val) * factor; 394 else 395 sc->bst.rate = 0; 396 397 if (acpi_smbus_read_2(sc, addr, SMBATT_CMD_REMAINING_CAPACITY, &val)) 398 goto out; 399 sc->bst.cap = val * factor; 400 401 if (acpi_smbus_read_2(sc, addr, SMBATT_CMD_VOLTAGE, &val)) 402 goto out; 403 sc->bst.volt = val; 404 405 acpi_smbat_info_updated(&sc->bst_lastupdated); 406 error = 0; 407 408 out: 409 if (error == 0) 410 memcpy(bst, &sc->bst, sizeof(sc->bst)); 411 ACPI_SERIAL_END(smbat); 412 return (error); 413 } 414 415 static int 416 acpi_smbat_get_bix(device_t dev, void *bix, size_t len) 417 { 418 struct acpi_smbat_softc *sc; 419 int error; 420 uint32_t factor; 421 uint16_t val; 422 uint8_t addr; 423 424 if (len != sizeof(struct acpi_bix) && 425 len != sizeof(struct acpi_bif)) 426 return (-1); 427 428 ACPI_SERIAL_BEGIN(smbat); 429 430 addr = SMBATT_ADDRESS; 431 error = ENXIO; 432 sc = device_get_softc(dev); 433 434 if (!acpi_smbat_info_expired(&sc->bix_lastupdated)) { 435 error = 0; 436 goto out; 437 } 438 439 sc->bix.rev = ACPI_BIX_REV_BIF; 440 441 if (acpi_smbus_read_2(sc, addr, SMBATT_CMD_BATTERY_MODE, &val)) 442 goto out; 443 if (val & SMBATT_BM_CAPACITY_MODE) { 444 factor = 10; 445 sc->bix.units = ACPI_BIX_UNITS_MW; 446 } else { 447 factor = 1; 448 sc->bix.units = ACPI_BIX_UNITS_MA; 449 } 450 451 if (acpi_smbus_read_2(sc, addr, SMBATT_CMD_DESIGN_CAPACITY, &val)) 452 goto out; 453 sc->bix.dcap = val * factor; 454 455 if (acpi_smbus_read_2(sc, addr, SMBATT_CMD_FULL_CHARGE_CAPACITY, &val)) 456 goto out; 457 sc->bix.lfcap = val * factor; 458 sc->bix.btech = 1; /* secondary (rechargeable) */ 459 460 if (acpi_smbus_read_2(sc, addr, SMBATT_CMD_DESIGN_VOLTAGE, &val)) 461 goto out; 462 sc->bix.dvol = val; 463 464 sc->bix.wcap = sc->bix.dcap / 10; 465 sc->bix.lcap = sc->bix.dcap / 10; 466 467 sc->bix.gra1 = factor; /* not supported */ 468 sc->bix.gra2 = factor; /* not supported */ 469 470 if (acpi_smbus_read_multi_1(sc, addr, SMBATT_CMD_DEVICE_NAME, 471 sc->bix.model, sizeof(sc->bix.model))) 472 goto out; 473 474 if (acpi_smbus_read_2(sc, addr, SMBATT_CMD_SERIAL_NUMBER, &val)) 475 goto out; 476 snprintf(sc->bix.serial, sizeof(sc->bix.serial), "0x%04x", val); 477 478 if (acpi_smbus_read_multi_1(sc, addr, SMBATT_CMD_DEVICE_CHEMISTRY, 479 sc->bix.type, sizeof(sc->bix.type))) 480 goto out; 481 482 if (acpi_smbus_read_multi_1(sc, addr, SMBATT_CMD_MANUFACTURER_DATA, 483 sc->bix.oeminfo, sizeof(sc->bix.oeminfo))) 484 goto out; 485 486 /* XXX check if device was replugged during read? */ 487 488 acpi_smbat_info_updated(&sc->bix_lastupdated); 489 error = 0; 490 491 out: 492 if (error == 0) 493 memcpy(bix, &sc->bix, len); 494 ACPI_SERIAL_END(smbat); 495 return (error); 496 } 497