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