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