1 /*/* $NetBSD: tadpmu.c,v 1.6 2023/12/20 05:33:58 thorpej Exp $ */ 2 3 /*- 4 * Copyright (c) 2018 Michael Lorenz <macallan@netbsd.org> 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 17 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 18 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 * POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 /* a driver for the PMU found in Tadpole Viper and SPARCle laptops */ 30 31 #include "opt_tadpmu.h" 32 #ifdef HAVE_TADPMU 33 #include <sys/param.h> 34 #include <sys/systm.h> 35 #include <sys/kernel.h> 36 #include <sys/device.h> 37 #include <sys/proc.h> 38 #include <sys/bus.h> 39 #include <sys/intr.h> 40 #include <sys/kthread.h> 41 #include <sys/mutex.h> 42 43 #include <dev/sysmon/sysmonvar.h> 44 #include <dev/sysmon/sysmon_taskq.h> 45 46 #include <sparc64/dev/tadpmureg.h> 47 #include <sparc64/dev/tadpmuvar.h> 48 49 #ifdef TADPMU_DEBUG 50 #define DPRINTF printf 51 #else 52 #define DPRINTF while (0) printf 53 #endif 54 55 static bus_space_tag_t tadpmu_iot; 56 static bus_space_handle_t tadpmu_hcmd; 57 static bus_space_handle_t tadpmu_hdata; 58 static struct sysmon_envsys *tadpmu_sens_sme; 59 static struct sysmon_envsys *tadpmu_acad_sme; 60 static struct sysmon_envsys *tadpmu_batt_sme; 61 static envsys_data_t tadpmu_sensors[8]; 62 static uint8_t idata = 0xff; 63 static uint8_t ivalid = 0; 64 static uint8_t ev_data = 0; 65 static wchan_t tadpmu, tadpmuev; 66 static struct sysmon_pswitch tadpmu_pbutton, tadpmu_lidswitch, tadpmu_dcpower; 67 static kmutex_t tadpmu_lock, data_lock; 68 static lwp_t *tadpmu_thread; 69 static int tadpmu_dying = 0; 70 71 static inline void 72 tadpmu_cmd(uint8_t d) 73 { 74 bus_space_write_1(tadpmu_iot, tadpmu_hcmd, 0, d); 75 } 76 77 static inline void 78 tadpmu_wdata(uint8_t d) 79 { 80 bus_space_write_1(tadpmu_iot, tadpmu_hdata, 0, d); 81 } 82 83 static inline uint8_t 84 tadpmu_status(void) 85 { 86 return bus_space_read_1(tadpmu_iot, tadpmu_hcmd, 0); 87 } 88 89 static inline uint8_t 90 tadpmu_data(void) 91 { 92 return bus_space_read_1(tadpmu_iot, tadpmu_hdata, 0); 93 } 94 95 static void 96 tadpmu_flush(void) 97 { 98 volatile uint8_t junk, d; 99 int bail = 0; 100 101 d = tadpmu_status(); 102 while (d & STATUS_HAVE_DATA) { 103 junk = tadpmu_data(); 104 __USE(junk); 105 delay(10); 106 bail++; 107 if (bail > 100) { 108 printf("%s: timeout waiting for data out to clear %2x\n", 109 __func__, d); 110 break; 111 } 112 d = tadpmu_status(); 113 } 114 bail = 0; 115 d = tadpmu_status(); 116 while (d & STATUS_SEND_DATA) { 117 bus_space_write_1(tadpmu_iot, tadpmu_hdata, 0, 0); 118 delay(10); 119 bail++; 120 if (bail > 100) { 121 printf("%s: timeout waiting for data in to clear %02x\n", 122 __func__, d); 123 break; 124 } 125 d = tadpmu_status(); 126 } 127 } 128 129 static void 130 tadpmu_send_cmd(uint8_t cmd) 131 { 132 int bail = 0; 133 uint8_t d; 134 135 ivalid = 0; 136 tadpmu_cmd(cmd); 137 138 d = tadpmu_status(); 139 while ((d & STATUS_CMD_IN_PROGRESS) == 0) { 140 delay(10); 141 bail++; 142 if (bail > 100) { 143 printf("%s: timeout waiting for command to start\n", 144 __func__); 145 break; 146 } 147 d = tadpmu_status(); 148 } 149 } 150 151 static uint8_t 152 tadpmu_recv(void) 153 { 154 int bail = 0; 155 uint8_t d; 156 157 if (cold) { 158 d = tadpmu_status(); 159 while ((d & STATUS_HAVE_DATA) == 0) { 160 delay(10); 161 bail++; 162 if (bail > 1000) { 163 printf("%s: timeout waiting for data %02x\n", 164 __func__, d); 165 break; 166 } 167 d = tadpmu_status(); 168 } 169 return bus_space_read_1(tadpmu_iot, tadpmu_hdata, 0); 170 } else { 171 while (ivalid == 0) 172 tsleep(tadpmu, 0, "pmucmd", 1); 173 return idata; 174 } 175 } 176 177 static void 178 tadpmu_send(uint8_t v) 179 { 180 int bail = 0; 181 uint8_t d; 182 183 d = tadpmu_status(); 184 while ((d & STATUS_SEND_DATA) == 0) { 185 delay(10); 186 bail++; 187 if (bail > 1000) { 188 printf("%s: timeout waiting for PMU ready %02x\n", __func__, d); 189 break; 190 } 191 d = tadpmu_status(); 192 } 193 194 tadpmu_wdata(v); 195 196 while ((d & STATUS_SEND_DATA) != 0) { 197 delay(10); 198 bail++; 199 if (bail > 1000) { 200 printf("%s: timeout waiting for accept data %02x\n", __func__, d); 201 break; 202 } 203 d = tadpmu_status(); 204 } 205 } 206 207 static uint32_t 208 tadpmu_battery_capacity(uint8_t gstat) 209 { 210 uint8_t res; 211 212 if (gstat == GENSTAT_STATE_BATTERY_FULL) { 213 return ENVSYS_BATTERY_CAPACITY_NORMAL; 214 } 215 216 mutex_enter(&tadpmu_lock); 217 tadpmu_flush(); 218 tadpmu_send_cmd(CMD_READ_VBATT); 219 res = tadpmu_recv(); 220 mutex_exit(&tadpmu_lock); 221 222 if (gstat & GENSTAT_STATE_BATTERY_DISCHARGE) { 223 if (res < TADPMU_BATT_DIS_CAP_CRIT) 224 return ENVSYS_BATTERY_CAPACITY_CRITICAL; 225 if (res < TADPMU_BATT_DIS_CAP_WARN) 226 return ENVSYS_BATTERY_CAPACITY_WARNING; 227 if (res < TADPMU_BATT_DIS_CAP_LOW) 228 return ENVSYS_BATTERY_CAPACITY_LOW; 229 else 230 return ENVSYS_BATTERY_CAPACITY_NORMAL; 231 } else if (gstat == GENSTAT_STATE_BATTERY_CHARGE) { 232 if (res < TADPMU_BATT_CHG_CAP_CRIT) 233 return ENVSYS_BATTERY_CAPACITY_CRITICAL; 234 else if (res < TADPMU_BATT_CHG_CAP_WARN) 235 return ENVSYS_BATTERY_CAPACITY_WARNING; 236 else if (res < TADPMU_BATT_CHG_CAP_LOW) 237 return ENVSYS_BATTERY_CAPACITY_LOW; 238 else 239 return ENVSYS_BATTERY_CAPACITY_NORMAL; 240 } else { 241 DPRINTF("%s unknown battery state %02x\n", 242 __func__, gstat); 243 return ENVSYS_BATTERY_CAPACITY_NORMAL; 244 } 245 } 246 247 /* The data to read is calculated from the command and the units */ 248 static void 249 tadpmu_sensors_refresh(struct sysmon_envsys *sme, envsys_data_t *edata) 250 { 251 int res; 252 253 if (edata->private > 0) { 254 mutex_enter(&tadpmu_lock); 255 tadpmu_flush(); 256 tadpmu_send_cmd(edata->private); 257 res = tadpmu_recv(); 258 mutex_exit(&tadpmu_lock); 259 if (edata->units == ENVSYS_STEMP) { 260 edata->value_cur = res * 1000000 + 273150000; 261 } else if (edata->units == ENVSYS_SVOLTS_DC) { 262 edata->value_cur = res * 100000; 263 } else if (edata->units == ENVSYS_BATTERY_CHARGE) { 264 if (res & GENSTAT_BATTERY_CHARGING) 265 edata->value_cur = ENVSYS_INDICATOR_TRUE; 266 else 267 edata->value_cur = ENVSYS_INDICATOR_FALSE; 268 } else if (edata->units == ENVSYS_BATTERY_CAPACITY) { 269 edata->value_cur = tadpmu_battery_capacity(res); 270 } else { 271 if (edata->units == ENVSYS_INDICATOR && 272 edata->private == CMD_READ_GENSTAT) { 273 if (res & GENSTAT_DC_PRESENT) 274 edata->value_cur = 275 ENVSYS_INDICATOR_TRUE; 276 else 277 edata->value_cur = 278 ENVSYS_INDICATOR_FALSE; 279 } else { 280 edata->value_cur = res; 281 } 282 } 283 edata->state = ENVSYS_SVALID; 284 } else { 285 edata->state = ENVSYS_SINVALID; 286 } 287 } 288 289 static void 290 tadpmu_events(void *cookie) 291 { 292 uint8_t events, gs, vb; 293 294 while (!tadpmu_dying) { 295 mutex_enter(&tadpmu_lock); 296 tadpmu_flush(); 297 tadpmu_send_cmd(CMD_READ_GENSTAT); 298 gs = tadpmu_recv(); 299 tadpmu_send_cmd(CMD_READ_VBATT); 300 vb = tadpmu_recv(); 301 mutex_exit(&tadpmu_lock); 302 303 mutex_enter(&data_lock); 304 events = ev_data; 305 mutex_exit(&data_lock); 306 DPRINTF("%s event %02x, status %02x/%02x\n", __func__, 307 events, gs, vb); 308 309 if (events & TADPMU_EV_PWRBUTT) { 310 mutex_enter(&data_lock); 311 ev_data &= ~TADPMU_EV_PWRBUTT; 312 mutex_exit(&data_lock); 313 sysmon_pswitch_event(&tadpmu_pbutton, 314 PSWITCH_EVENT_PRESSED); 315 } 316 317 if (events & TADPMU_EV_LID) { 318 mutex_enter(&data_lock); 319 ev_data &= ~TADPMU_EV_LID; 320 mutex_exit(&data_lock); 321 sysmon_pswitch_event(&tadpmu_lidswitch, 322 gs & GENSTAT_LID_CLOSED ? 323 PSWITCH_EVENT_PRESSED : PSWITCH_EVENT_RELEASED); 324 } 325 326 if (events & TADPMU_EV_DCPOWER) { 327 mutex_enter(&data_lock); 328 ev_data &= ~TADPMU_EV_DCPOWER; 329 mutex_exit(&data_lock); 330 sysmon_pswitch_event(&tadpmu_dcpower, 331 gs & GENSTAT_DC_PRESENT ? 332 PSWITCH_EVENT_PRESSED : PSWITCH_EVENT_RELEASED); 333 } 334 335 if (events & TADPMU_EV_BATTCHANGE) { 336 mutex_enter(&data_lock); 337 ev_data &= ~TADPMU_EV_BATTCHANGE; 338 mutex_exit(&data_lock); 339 if (gs == GENSTAT_STATE_BATTERY_DISCHARGE) { 340 if (vb < TADPMU_BATT_DIS_CAP_CRIT) 341 printf("Battery critical!\n"); 342 else if (vb < TADPMU_BATT_DIS_CAP_WARN) 343 printf("Battery warning!\n"); 344 } 345 } 346 347 if (events & TADPMU_EV_BATTCHARGED) { 348 mutex_enter(&data_lock); 349 ev_data &= ~TADPMU_EV_BATTCHARGED; 350 mutex_exit(&data_lock); 351 printf("Battery charged\n"); 352 } 353 354 tsleep(tadpmuev, 0, "tadpmuev", hz); 355 } 356 kthread_exit(0); 357 } 358 359 int 360 tadpmu_intr(void *cookie) 361 { 362 uint8_t s = tadpmu_status(), d; 363 if (s & STATUS_INTR) { 364 /* interrupt message */ 365 d = tadpmu_data(); 366 DPRINTF("%s status change %02x\n", __func__, d); 367 368 switch (d) { 369 case TADPMU_INTR_POWERBUTTON: 370 mutex_enter(&data_lock); 371 ev_data |= TADPMU_EV_PWRBUTT;; 372 mutex_exit(&data_lock); 373 break; 374 case TADPMU_INTR_LID: 375 mutex_enter(&data_lock); 376 ev_data |= TADPMU_EV_LID; 377 mutex_exit(&data_lock); 378 break; 379 case TADPMU_INTR_DCPOWER: 380 mutex_enter(&data_lock); 381 ev_data |= TADPMU_EV_DCPOWER; 382 mutex_exit(&data_lock); 383 break; 384 case TADPMU_INTR_BATTERY_STATE: 385 mutex_enter(&data_lock); 386 ev_data |= TADPMU_EV_BATTCHANGE; 387 mutex_exit(&data_lock); 388 break; 389 case TADPMU_INTR_BATTERY_CHARGED: 390 mutex_enter(&data_lock); 391 ev_data |= TADPMU_EV_BATTCHARGED; 392 mutex_exit(&data_lock); 393 break; 394 } 395 /* Report events */ 396 if (ev_data) 397 wakeup(tadpmuev); 398 } 399 s = tadpmu_status(); 400 if (s & STATUS_HAVE_DATA) { 401 idata = tadpmu_data(); 402 ivalid = 1; 403 wakeup(tadpmu); 404 DPRINTF("%s data %02x\n", __func__, idata); 405 } 406 407 return 1; 408 } 409 410 int 411 tadpmu_init(bus_space_tag_t t, bus_space_handle_t hcmd, bus_space_handle_t hdata) 412 { 413 uint8_t ver; 414 415 tadpmu_iot = t; 416 tadpmu_hcmd = hcmd; 417 tadpmu_hdata = hdata; 418 419 tadpmu_flush(); 420 delay(1000); 421 422 tadpmu_send_cmd(CMD_READ_VERSION); 423 ver = tadpmu_recv(); 424 printf("Tadpole PMU Version 1.%d\n", ver); 425 426 tadpmu_send_cmd(CMD_SET_OPMODE); 427 tadpmu_send(OPMODE_UNIX); 428 429 #ifdef TADPMU_DEBUG 430 tadpmu_send_cmd(CMD_READ_SYSTEMP); 431 ver = tadpmu_recv(); 432 printf("Temperature 0x%02x\n", ver); 433 434 tadpmu_send_cmd(CMD_READ_VBATT); 435 ver = tadpmu_recv(); 436 printf("Battery voltage 0x%02x\n", ver); 437 438 tadpmu_send_cmd(CMD_READ_GENSTAT); 439 ver = tadpmu_recv(); 440 printf("status 0x%02x\n", ver); 441 #endif 442 443 mutex_init(&tadpmu_lock, MUTEX_DEFAULT, IPL_NONE); 444 mutex_init(&data_lock, MUTEX_DEFAULT, IPL_HIGH); 445 446 tadpmu_sens_sme = sysmon_envsys_create(); 447 tadpmu_sens_sme->sme_name = "tadpmu"; 448 tadpmu_sens_sme->sme_cookie = NULL; 449 tadpmu_sens_sme->sme_refresh = tadpmu_sensors_refresh; 450 451 tadpmu_acad_sme = sysmon_envsys_create(); 452 tadpmu_acad_sme->sme_name = "ac adapter"; 453 tadpmu_acad_sme->sme_cookie = NULL; 454 tadpmu_acad_sme->sme_refresh = tadpmu_sensors_refresh; 455 tadpmu_acad_sme->sme_class = SME_CLASS_ACADAPTER; 456 457 tadpmu_batt_sme = sysmon_envsys_create(); 458 tadpmu_batt_sme->sme_name = "battery"; 459 tadpmu_batt_sme->sme_cookie = NULL; 460 tadpmu_batt_sme->sme_refresh = tadpmu_sensors_refresh; 461 tadpmu_batt_sme->sme_class = SME_CLASS_BATTERY; 462 463 tadpmu_sensors[0].state = ENVSYS_SINVALID; 464 tadpmu_sensors[0].units = ENVSYS_STEMP; 465 tadpmu_sensors[0].private = CMD_READ_SYSTEMP; 466 strcpy(tadpmu_sensors[0].desc, "systemp"); 467 sysmon_envsys_sensor_attach(tadpmu_sens_sme, &tadpmu_sensors[0]); 468 469 tadpmu_sensors[1].state = ENVSYS_SINVALID; 470 tadpmu_sensors[1].units = ENVSYS_INDICATOR; 471 tadpmu_sensors[1].private = CMD_READ_FAN_EN; 472 strcpy(tadpmu_sensors[1].desc, "fan on"); 473 sysmon_envsys_sensor_attach(tadpmu_sens_sme, &tadpmu_sensors[1]); 474 475 tadpmu_sensors[2].state = ENVSYS_SINVALID; 476 tadpmu_sensors[2].units = ENVSYS_INDICATOR; 477 tadpmu_sensors[2].private = CMD_READ_GENSTAT; 478 strcpy(tadpmu_sensors[2].desc, "DC power"); 479 sysmon_envsys_sensor_attach(tadpmu_acad_sme, &tadpmu_sensors[2]); 480 481 tadpmu_sensors[3].state = ENVSYS_SINVALID; 482 tadpmu_sensors[3].units = ENVSYS_SVOLTS_DC; 483 tadpmu_sensors[3].private = CMD_READ_VBATT; 484 strcpy(tadpmu_sensors[3].desc, "Vbatt"); 485 sysmon_envsys_sensor_attach(tadpmu_batt_sme, &tadpmu_sensors[3]); 486 487 tadpmu_sensors[4].state = ENVSYS_SINVALID; 488 tadpmu_sensors[4].units = ENVSYS_BATTERY_CAPACITY; 489 tadpmu_sensors[4].private = CMD_READ_GENSTAT; 490 /* We must provide an initial value for battery capacity */ 491 tadpmu_sensors[4].value_cur = ENVSYS_BATTERY_CAPACITY_NORMAL; 492 strcpy(tadpmu_sensors[4].desc, "capacity"); 493 sysmon_envsys_sensor_attach(tadpmu_batt_sme, &tadpmu_sensors[4]); 494 495 tadpmu_sensors[5].state = ENVSYS_SINVALID; 496 tadpmu_sensors[5].units = ENVSYS_BATTERY_CHARGE; 497 tadpmu_sensors[5].private = CMD_READ_GENSTAT; 498 strcpy(tadpmu_sensors[5].desc, "charging"); 499 sysmon_envsys_sensor_attach(tadpmu_batt_sme, &tadpmu_sensors[5]); 500 501 #ifdef TADPMU_DEBUG 502 tadpmu_sensors[6].state = ENVSYS_SINVALID; 503 tadpmu_sensors[6].units = ENVSYS_INTEGER; 504 tadpmu_sensors[6].private = CMD_READ_GENSTAT; 505 strcpy(tadpmu_sensors[6].desc, "genstat"); 506 sysmon_envsys_sensor_attach(tadpmu_sens_sme, &tadpmu_sensors[6]); 507 #endif 508 509 sysmon_envsys_register(tadpmu_sens_sme); 510 sysmon_envsys_register(tadpmu_acad_sme); 511 sysmon_envsys_register(tadpmu_batt_sme); 512 513 sysmon_task_queue_init(); 514 memset(&tadpmu_pbutton, 0, sizeof(struct sysmon_pswitch)); 515 tadpmu_pbutton.smpsw_name = "power"; 516 tadpmu_pbutton.smpsw_type = PSWITCH_TYPE_POWER; 517 if (sysmon_pswitch_register(&tadpmu_pbutton) != 0) 518 aprint_error( 519 "unable to register power button with sysmon\n"); 520 521 memset(&tadpmu_lidswitch, 0, sizeof(struct sysmon_pswitch)); 522 tadpmu_lidswitch.smpsw_name = "lid"; 523 tadpmu_lidswitch.smpsw_type = PSWITCH_TYPE_LID; 524 if (sysmon_pswitch_register(&tadpmu_lidswitch) != 0) 525 aprint_error( 526 "unable to register lid switch with sysmon\n"); 527 528 memset(&tadpmu_dcpower, 0, sizeof(struct sysmon_pswitch)); 529 tadpmu_dcpower.smpsw_name = "AC adapter"; 530 tadpmu_dcpower.smpsw_type = PSWITCH_TYPE_ACADAPTER; 531 if (sysmon_pswitch_register(&tadpmu_dcpower) != 0) 532 aprint_error( 533 "unable to register AC adapter with sysmon\n"); 534 535 kthread_create(PRI_NONE, 0, curcpu(), tadpmu_events, NULL, 536 &tadpmu_thread, "tadpmu_events"); 537 538 return 0; 539 } 540 #endif /* HAVE_TADPMU */ 541