1 1.1 bouyer /* $OpenBSD: kb3310.c,v 1.16 2010/10/14 21:23:04 pirofti Exp $ */ 2 1.1 bouyer /* 3 1.1 bouyer * Copyright (c) 2010 Otto Moerbeek <otto (at) drijf.net> 4 1.1 bouyer * 5 1.1 bouyer * Permission to use, copy, modify, and distribute this software for any 6 1.1 bouyer * purpose with or without fee is hereby granted, provided that the above 7 1.1 bouyer * copyright notice and this permission notice appear in all copies. 8 1.1 bouyer * 9 1.1 bouyer * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 1.1 bouyer * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 1.1 bouyer * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 1.1 bouyer * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 1.1 bouyer * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 1.1 bouyer * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 1.1 bouyer * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 1.1 bouyer */ 17 1.1 bouyer 18 1.1 bouyer #include <sys/param.h> 19 1.1 bouyer #include <sys/kernel.h> 20 1.1 bouyer #include <sys/systm.h> 21 1.1 bouyer #include <sys/device.h> 22 1.1 bouyer #include <sys/sensors.h> 23 1.1 bouyer #include <sys/timeout.h> 24 1.1 bouyer 25 1.1 bouyer #include <mips64/archtype.h> 26 1.1 bouyer #include <machine/apmvar.h> 27 1.1 bouyer #include <evbmips/loongson/autoconf.h> 28 1.1 bouyer #include <machine/bus.h> 29 1.1 bouyer #include <dev/isa/isavar.h> 30 1.1 bouyer 31 1.1 bouyer #include <dev/pci/glxreg.h> 32 1.1 bouyer 33 1.1 bouyer #include <loongson/dev/bonitoreg.h> 34 1.1 bouyer #include <loongson/dev/kb3310var.h> 35 1.1 bouyer 36 1.1 bouyer #include "apm.h" 37 1.1 bouyer #include "pckbd.h" 38 1.1 bouyer #include "hidkbd.h" 39 1.1 bouyer 40 1.1 bouyer #if NPCKBD > 0 || NHIDKBD > 0 41 1.1 bouyer #include <dev/ic/pckbcvar.h> 42 1.1 bouyer #include <dev/pckbc/pckbdvar.h> 43 1.1 bouyer #include <dev/usb/hidkbdvar.h> 44 1.1 bouyer #endif 45 1.1 bouyer 46 1.1 bouyer struct cfdriver ykbec_cd = { 47 1.1 bouyer NULL, "ykbec", DV_DULL, 48 1.1 bouyer }; 49 1.1 bouyer 50 1.1 bouyer #ifdef KB3310_DEBUG 51 1.1 bouyer #define DPRINTF(x) printf x 52 1.1 bouyer #else 53 1.1 bouyer #define DPRINTF(x) 54 1.1 bouyer #endif 55 1.1 bouyer 56 1.1 bouyer #define IO_YKBEC 0x381 57 1.1 bouyer #define IO_YKBECSIZE 0x3 58 1.1 bouyer 59 1.1 bouyer static const struct { 60 1.1 bouyer const char *desc; 61 1.1 bouyer int type; 62 1.1 bouyer } ykbec_table[] = { 63 1.1 bouyer #define YKBEC_FAN 0 64 1.1 bouyer { NULL, SENSOR_FANRPM }, 65 1.1 bouyer #define YKBEC_ITEMP 1 66 1.1 bouyer { "Internal temperature", SENSOR_TEMP }, 67 1.1 bouyer #define YKBEC_FCAP 2 68 1.1 bouyer { "Battery full charge capacity", SENSOR_AMPHOUR }, 69 1.1 bouyer #define YKBEC_BCURRENT 3 70 1.1 bouyer { "Battery current", SENSOR_AMPS }, 71 1.1 bouyer #define YKBEC_BVOLT 4 72 1.1 bouyer { "Battery voltage", SENSOR_VOLTS_DC }, 73 1.1 bouyer #define YKBEC_BTEMP 5 74 1.1 bouyer { "Battery temperature", SENSOR_TEMP }, 75 1.1 bouyer #define YKBEC_CAP 6 76 1.1 bouyer { "Battery capacity", SENSOR_PERCENT }, 77 1.1 bouyer #define YKBEC_CHARGING 7 78 1.1 bouyer { "Battery charging", SENSOR_INDICATOR }, 79 1.1 bouyer #define YKBEC_AC 8 80 1.1 bouyer { "AC-Power", SENSOR_INDICATOR } 81 1.1 bouyer #define YKBEC_NSENSORS 9 82 1.1 bouyer }; 83 1.1 bouyer 84 1.1 bouyer struct ykbec_softc { 85 1.1 bouyer bus_space_tag_t sc_iot; 86 1.1 bouyer bus_space_handle_t sc_ioh; 87 1.1 bouyer struct ksensor sc_sensor[YKBEC_NSENSORS]; 88 1.1 bouyer struct ksensordev sc_sensordev; 89 1.1 bouyer #if NPCKBD > 0 || NHIDKBD > 0 90 1.1 bouyer struct timeout sc_bell_tmo; 91 1.1 bouyer #endif 92 1.1 bouyer }; 93 1.1 bouyer 94 1.1 bouyer static struct ykbec_softc *ykbec_sc; 95 1.1 bouyer static int ykbec_chip_config; 96 1.1 bouyer 97 1.1 bouyer extern void loongson_set_isa_imr(uint); 98 1.1 bouyer 99 1.2 chs int ykbec_match(device_t, cfdata_t, void *); 100 1.2 chs void ykbec_attach(device_t, device_t, void *); 101 1.1 bouyer 102 1.3 riastrad CFATTACH_DECL_NEW(ykbec, sizeof(struct ykbec_softc), 103 1.3 riastrad ykbec_match, ykbec_attach, NULL, NULL); 104 1.1 bouyer 105 1.1 bouyer int ykbec_apminfo(struct apm_power_info *); 106 1.1 bouyer void ykbec_bell(void *, u_int, u_int, u_int, int); 107 1.1 bouyer void ykbec_bell_stop(void *); 108 1.1 bouyer void ykbec_print_bat_info(struct ykbec_softc *); 109 1.1 bouyer u_int ykbec_read(struct ykbec_softc *, u_int); 110 1.1 bouyer u_int ykbec_read16(struct ykbec_softc *, u_int); 111 1.1 bouyer void ykbec_refresh(void *arg); 112 1.1 bouyer void ykbec_write(struct ykbec_softc *, u_int, u_int); 113 1.1 bouyer 114 1.1 bouyer #if NAPM > 0 115 1.1 bouyer struct apm_power_info ykbec_apmdata; 116 1.1 bouyer const char *ykbec_batstate[] = { 117 1.1 bouyer "high", 118 1.1 bouyer "low", 119 1.1 bouyer "critical", 120 1.1 bouyer "charging", 121 1.1 bouyer "unknown" 122 1.1 bouyer }; 123 1.1 bouyer #define BATTERY_STRING(x) ((x) < nitems(ykbec_batstate) ? \ 124 1.1 bouyer ykbec_batstate[x] : ykbec_batstate[4]) 125 1.1 bouyer #endif 126 1.1 bouyer 127 1.1 bouyer int 128 1.2 chs ykbec_match(device_t parent, cfdata_t match, void *aux) 129 1.1 bouyer { 130 1.1 bouyer struct isa_attach_args *ia = aux; 131 1.1 bouyer bus_space_handle_t ioh; 132 1.1 bouyer 133 1.1 bouyer if (sys_platform->system_type != LOONGSON_YEELOONG) 134 1.1 bouyer return (0); 135 1.1 bouyer 136 1.1 bouyer if ((ia->ia_iobase != IOBASEUNK && ia->ia_iobase != IO_YKBEC) || 137 1.1 bouyer /* (ia->ia_iosize != 0 && ia->ia_iosize != IO_YKBECSIZE) || XXX isa.c */ 138 1.1 bouyer ia->ia_maddr != MADDRUNK || ia->ia_msize != 0 || 139 1.1 bouyer ia->ia_irq != IRQUNK || ia->ia_drq != DRQUNK) 140 1.1 bouyer return (0); 141 1.1 bouyer 142 1.1 bouyer if (bus_space_map(ia->ia_iot, IO_YKBEC, IO_YKBECSIZE, 0, &ioh)) 143 1.1 bouyer return (0); 144 1.1 bouyer 145 1.1 bouyer bus_space_unmap(ia->ia_iot, ioh, IO_YKBECSIZE); 146 1.1 bouyer 147 1.1 bouyer ia->ia_iobase = IO_YKBEC; 148 1.1 bouyer ia->ia_iosize = IO_YKBECSIZE; 149 1.1 bouyer 150 1.1 bouyer return (1); 151 1.1 bouyer } 152 1.1 bouyer 153 1.1 bouyer void 154 1.2 chs ykbec_attach(device_t parent, device_t self, void *aux) 155 1.1 bouyer { 156 1.1 bouyer struct isa_attach_args *ia = aux; 157 1.2 chs struct ykbec_softc *sc = device_private(self); 158 1.1 bouyer int i; 159 1.1 bouyer 160 1.1 bouyer sc->sc_iot = ia->ia_iot; 161 1.1 bouyer if (bus_space_map(sc->sc_iot, ia->ia_iobase, ia->ia_iosize, 0, 162 1.1 bouyer &sc->sc_ioh)) { 163 1.1 bouyer aprint_error(": couldn't map I/O space"); 164 1.1 bouyer return; 165 1.1 bouyer } 166 1.1 bouyer 167 1.1 bouyer /* Initialize sensor data. */ 168 1.2 chs strlcpy(sc->sc_sensordev.xname, device_xname(self), 169 1.1 bouyer sizeof(sc->sc_sensordev.xname)); 170 1.1 bouyer if (sensor_task_register(sc, ykbec_refresh, 5) == NULL) { 171 1.1 bouyer aprint_error(", unable to register update task\n"); 172 1.1 bouyer return; 173 1.1 bouyer } 174 1.1 bouyer 175 1.1 bouyer #ifdef DEBUG 176 1.1 bouyer ykbec_print_bat_info(sc); 177 1.1 bouyer #endif 178 1.1 bouyer aprint_normal("\n"); 179 1.1 bouyer 180 1.1 bouyer for (i = 0; i < YKBEC_NSENSORS; i++) { 181 1.1 bouyer sc->sc_sensor[i].type = ykbec_table[i].type; 182 1.1 bouyer if (ykbec_table[i].desc) 183 1.1 bouyer strlcpy(sc->sc_sensor[i].desc, ykbec_table[i].desc, 184 1.1 bouyer sizeof(sc->sc_sensor[i].desc)); 185 1.1 bouyer sensor_attach(&sc->sc_sensordev, &sc->sc_sensor[i]); 186 1.1 bouyer } 187 1.1 bouyer 188 1.1 bouyer sensordev_install(&sc->sc_sensordev); 189 1.1 bouyer 190 1.1 bouyer #if NAPM > 0 191 1.1 bouyer /* make sure we have the apm state initialized before apm attaches */ 192 1.1 bouyer ykbec_refresh(sc); 193 1.1 bouyer apm_setinfohook(ykbec_apminfo); 194 1.1 bouyer #endif 195 1.1 bouyer #if NPCKBD > 0 || NHIDKBD > 0 196 1.1 bouyer timeout_set(&sc->sc_bell_tmo, ykbec_bell_stop, sc); 197 1.1 bouyer #if NPCKBD > 0 198 1.1 bouyer pckbd_hookup_bell(ykbec_bell, sc); 199 1.1 bouyer #endif 200 1.1 bouyer #if NHIDKBD > 0 201 1.1 bouyer hidkbd_hookup_bell(ykbec_bell, sc); 202 1.1 bouyer #endif 203 1.1 bouyer #endif 204 1.1 bouyer ykbec_sc = sc; 205 1.1 bouyer } 206 1.1 bouyer 207 1.1 bouyer void 208 1.1 bouyer ykbec_write(struct ykbec_softc *mcsc, u_int reg, u_int datum) 209 1.1 bouyer { 210 1.1 bouyer struct ykbec_softc *sc = (struct ykbec_softc *)mcsc; 211 1.1 bouyer bus_space_tag_t iot = sc->sc_iot; 212 1.1 bouyer bus_space_handle_t ioh = sc->sc_ioh; 213 1.1 bouyer 214 1.1 bouyer bus_space_write_1(iot, ioh, 0, (reg >> 8) & 0xff); 215 1.1 bouyer bus_space_write_1(iot, ioh, 1, (reg >> 0) & 0xff); 216 1.1 bouyer bus_space_write_1(iot, ioh, 2, datum); 217 1.1 bouyer } 218 1.1 bouyer 219 1.1 bouyer u_int 220 1.1 bouyer ykbec_read(struct ykbec_softc *mcsc, u_int reg) 221 1.1 bouyer { 222 1.1 bouyer struct ykbec_softc *sc = (struct ykbec_softc *)mcsc; 223 1.1 bouyer bus_space_tag_t iot = sc->sc_iot; 224 1.1 bouyer bus_space_handle_t ioh = sc->sc_ioh; 225 1.1 bouyer 226 1.1 bouyer bus_space_write_1(iot, ioh, 0, (reg >> 8) & 0xff); 227 1.1 bouyer bus_space_write_1(iot, ioh, 1, (reg >> 0) & 0xff); 228 1.1 bouyer return bus_space_read_1(iot, ioh, 2); 229 1.1 bouyer } 230 1.1 bouyer 231 1.1 bouyer u_int 232 1.1 bouyer ykbec_read16(struct ykbec_softc *mcsc, u_int reg) 233 1.1 bouyer { 234 1.1 bouyer u_int val; 235 1.1 bouyer 236 1.1 bouyer val = ykbec_read(mcsc, reg); 237 1.1 bouyer return (val << 8) | ykbec_read(mcsc, reg + 1); 238 1.1 bouyer } 239 1.1 bouyer 240 1.1 bouyer #define KB3310_FAN_SPEED_DIVIDER 480000 241 1.1 bouyer 242 1.1 bouyer #define ECTEMP_CURRENT_REG 0xf458 243 1.1 bouyer #define REG_FAN_SPEED_HIGH 0xfe22 244 1.1 bouyer #define REG_FAN_SPEED_LOW 0xfe23 245 1.1 bouyer 246 1.1 bouyer #define REG_DESIGN_CAP_HIGH 0xf77d 247 1.1 bouyer #define REG_DESIGN_CAP_LOW 0xf77e 248 1.1 bouyer #define REG_FULLCHG_CAP_HIGH 0xf780 249 1.1 bouyer #define REG_FULLCHG_CAP_LOW 0xf781 250 1.1 bouyer 251 1.1 bouyer #define REG_DESIGN_VOL_HIGH 0xf782 252 1.1 bouyer #define REG_DESIGN_VOL_LOW 0xf783 253 1.1 bouyer #define REG_CURRENT_HIGH 0xf784 254 1.1 bouyer #define REG_CURRENT_LOW 0xf785 255 1.1 bouyer #define REG_VOLTAGE_HIGH 0xf786 256 1.1 bouyer #define REG_VOLTAGE_LOW 0xf787 257 1.1 bouyer #define REG_TEMPERATURE_HIGH 0xf788 258 1.1 bouyer #define REG_TEMPERATURE_LOW 0xf789 259 1.1 bouyer #define REG_RELATIVE_CAT_HIGH 0xf492 260 1.1 bouyer #define REG_RELATIVE_CAT_LOW 0xf493 261 1.1 bouyer #define REG_BAT_VENDOR 0xf4c4 262 1.1 bouyer #define REG_BAT_CELL_COUNT 0xf4c6 263 1.1 bouyer 264 1.1 bouyer #define REG_BAT_CHARGE 0xf4a2 265 1.1 bouyer #define BAT_CHARGE_AC 0x00 266 1.1 bouyer #define BAT_CHARGE_DISCHARGE 0x01 267 1.1 bouyer #define BAT_CHARGE_CHARGE 0x02 268 1.1 bouyer 269 1.1 bouyer #define REG_POWER_FLAG 0xf440 270 1.1 bouyer #define POWER_FLAG_ADAPTER_IN (1<<0) 271 1.1 bouyer #define POWER_FLAG_POWER_ON (1<<1) 272 1.1 bouyer #define POWER_FLAG_ENTER_SUS (1<<2) 273 1.1 bouyer 274 1.1 bouyer #define REG_BAT_STATUS 0xf4b0 275 1.1 bouyer #define BAT_STATUS_BAT_EXISTS (1<<0) 276 1.1 bouyer #define BAT_STATUS_BAT_FULL (1<<1) 277 1.1 bouyer #define BAT_STATUS_BAT_DESTROY (1<<2) 278 1.1 bouyer #define BAT_STATUS_BAT_LOW (1<<5) 279 1.1 bouyer 280 1.1 bouyer #define REG_CHARGE_STATUS 0xf4b1 281 1.1 bouyer #define CHARGE_STATUS_PRECHARGE (1<<1) 282 1.1 bouyer #define CHARGE_STATUS_OVERHEAT (1<<2) 283 1.1 bouyer 284 1.1 bouyer #define REG_BAT_STATE 0xf482 285 1.1 bouyer #define BAT_STATE_DISCHARGING (1<<0) 286 1.1 bouyer #define BAT_STATE_CHARGING (1<<1) 287 1.1 bouyer 288 1.1 bouyer #define REG_BEEP_CONTROL 0xf4d0 289 1.1 bouyer #define BEEP_ENABLE (1<<0) 290 1.1 bouyer 291 1.1 bouyer #define REG_PMUCFG 0xff0c 292 1.1 bouyer #define PMUCFG_STOP_MODE (1<<7) 293 1.1 bouyer #define PMUCFG_IDLE_MODE (1<<6) 294 1.1 bouyer #define PMUCFG_LPC_WAKEUP (1<<5) 295 1.1 bouyer #define PMUCFG_RESET_8051 (1<<4) 296 1.1 bouyer #define PMUCFG_SCI_WAKEUP (1<<3) 297 1.1 bouyer #define PMUCFG_WDT_WAKEUP (1<<2) 298 1.1 bouyer #define PMUCFG_GPWU_WAKEUP (1<<1) 299 1.1 bouyer #define PMUCFG_IRQ_IDLE (1<<0) 300 1.1 bouyer 301 1.1 bouyer #define REG_USB0 0xf461 302 1.1 bouyer #define REG_USB1 0xf462 303 1.1 bouyer #define REG_USB2 0xf463 304 1.1 bouyer #define USB_FLAG_ON 1 305 1.1 bouyer #define USB_FLAG_OFF 0 306 1.1 bouyer 307 1.1 bouyer #define REG_FAN_CONTROL 0xf4d2 308 1.1 bouyer #define REG_FAN_ON 1 309 1.1 bouyer #define REG_FAN_OFF 0 310 1.1 bouyer 311 1.1 bouyer #define YKBEC_SCI_IRQ 0xa 312 1.1 bouyer 313 1.1 bouyer #ifdef DEBUG 314 1.1 bouyer void 315 1.1 bouyer ykbec_print_bat_info(struct ykbec_softc *sc) 316 1.1 bouyer { 317 1.1 bouyer uint bat_status, count, dvolt, dcap; 318 1.1 bouyer 319 1.1 bouyer printf(": battery "); 320 1.1 bouyer bat_status = ykbec_read(sc, REG_BAT_STATUS); 321 1.1 bouyer if (!ISSET(bat_status, BAT_STATUS_BAT_EXISTS)) { 322 1.1 bouyer printf("absent"); 323 1.1 bouyer return; 324 1.1 bouyer } 325 1.1 bouyer 326 1.1 bouyer count = ykbec_read(sc, REG_BAT_CELL_COUNT); 327 1.1 bouyer dvolt = ykbec_read16(sc, REG_DESIGN_VOL_HIGH); 328 1.1 bouyer dcap = ykbec_read16(sc, REG_DESIGN_CAP_HIGH); 329 1.1 bouyer printf("%d cells, design capacity %dmV %dmAh", count, dvolt, dcap); 330 1.1 bouyer } 331 1.1 bouyer #endif 332 1.1 bouyer 333 1.1 bouyer void 334 1.1 bouyer ykbec_refresh(void *arg) 335 1.1 bouyer { 336 1.1 bouyer struct ykbec_softc *sc = (struct ykbec_softc *)arg; 337 1.1 bouyer u_int val, bat_charge, bat_status, charge_status, bat_state, power_flag; 338 1.1 bouyer u_int cap_pct, fullcap; 339 1.1 bouyer int current; 340 1.1 bouyer #if NAPM > 0 341 1.1 bouyer struct apm_power_info old; 342 1.1 bouyer #endif 343 1.1 bouyer 344 1.1 bouyer val = ykbec_read16(sc, REG_FAN_SPEED_HIGH) & 0xfffff; 345 1.1 bouyer if (val != 0) { 346 1.1 bouyer val = KB3310_FAN_SPEED_DIVIDER / val; 347 1.1 bouyer sc->sc_sensor[YKBEC_FAN].value = val; 348 1.1 bouyer CLR(sc->sc_sensor[YKBEC_FAN].flags, SENSOR_FINVALID); 349 1.1 bouyer } else 350 1.1 bouyer SET(sc->sc_sensor[YKBEC_FAN].flags, SENSOR_FINVALID); 351 1.1 bouyer 352 1.1 bouyer val = ykbec_read(sc, ECTEMP_CURRENT_REG); 353 1.1 bouyer sc->sc_sensor[YKBEC_ITEMP].value = val * 1000000 + 273150000; 354 1.1 bouyer 355 1.1 bouyer fullcap = ykbec_read16(sc, REG_FULLCHG_CAP_HIGH); 356 1.1 bouyer sc->sc_sensor[YKBEC_FCAP].value = fullcap * 1000; 357 1.1 bouyer 358 1.1 bouyer current = ykbec_read16(sc, REG_CURRENT_HIGH); 359 1.1 bouyer /* sign extend short -> int, int -> int64 will be done next statement */ 360 1.1 bouyer current |= -(current & 0x8000); 361 1.1 bouyer sc->sc_sensor[YKBEC_BCURRENT].value = -1000 * current; 362 1.1 bouyer 363 1.1 bouyer sc->sc_sensor[YKBEC_BVOLT].value = ykbec_read16(sc, REG_VOLTAGE_HIGH) * 364 1.1 bouyer 1000; 365 1.1 bouyer 366 1.1 bouyer val = ykbec_read16(sc, REG_TEMPERATURE_HIGH); 367 1.1 bouyer sc->sc_sensor[YKBEC_BTEMP].value = val * 1000000 + 273150000; 368 1.1 bouyer 369 1.1 bouyer cap_pct = ykbec_read16(sc, REG_RELATIVE_CAT_HIGH); 370 1.1 bouyer sc->sc_sensor[YKBEC_CAP].value = cap_pct * 1000; 371 1.1 bouyer 372 1.1 bouyer bat_charge = ykbec_read(sc, REG_BAT_CHARGE); 373 1.1 bouyer bat_status = ykbec_read(sc, REG_BAT_STATUS); 374 1.1 bouyer charge_status = ykbec_read(sc, REG_CHARGE_STATUS); 375 1.1 bouyer bat_state = ykbec_read(sc, REG_BAT_STATE); 376 1.1 bouyer power_flag = ykbec_read(sc, REG_POWER_FLAG); 377 1.1 bouyer 378 1.1 bouyer sc->sc_sensor[YKBEC_CHARGING].value = !!ISSET(bat_state, 379 1.1 bouyer BAT_STATE_CHARGING); 380 1.1 bouyer sc->sc_sensor[YKBEC_AC].value = !!ISSET(power_flag, 381 1.1 bouyer POWER_FLAG_ADAPTER_IN); 382 1.1 bouyer 383 1.1 bouyer sc->sc_sensor[YKBEC_CAP].status = ISSET(bat_status, BAT_STATUS_BAT_LOW) ? 384 1.1 bouyer SENSOR_S_CRIT : SENSOR_S_OK; 385 1.1 bouyer 386 1.1 bouyer #if NAPM > 0 387 1.1 bouyer bcopy(&ykbec_apmdata, &old, sizeof(old)); 388 1.1 bouyer ykbec_apmdata.battery_life = cap_pct; 389 1.1 bouyer ykbec_apmdata.ac_state = ISSET(power_flag, POWER_FLAG_ADAPTER_IN) ? 390 1.1 bouyer APM_AC_ON : APM_AC_OFF; 391 1.1 bouyer if (!ISSET(bat_status, BAT_STATUS_BAT_EXISTS)) { 392 1.1 bouyer ykbec_apmdata.battery_state = APM_BATTERY_ABSENT; 393 1.1 bouyer ykbec_apmdata.minutes_left = 0; 394 1.1 bouyer ykbec_apmdata.battery_life = 0; 395 1.1 bouyer } else { 396 1.1 bouyer if (ISSET(bat_state, BAT_STATE_CHARGING)) 397 1.1 bouyer ykbec_apmdata.battery_state = APM_BATT_CHARGING; 398 1.1 bouyer else if (ISSET(bat_status, BAT_STATUS_BAT_LOW)) 399 1.1 bouyer ykbec_apmdata.battery_state = APM_BATT_CRITICAL; 400 1.1 bouyer /* XXX arbitrary */ 401 1.1 bouyer else if (cap_pct > 60) 402 1.1 bouyer ykbec_apmdata.battery_state = APM_BATT_HIGH; 403 1.1 bouyer else 404 1.1 bouyer ykbec_apmdata.battery_state = APM_BATT_LOW; 405 1.1 bouyer 406 1.1 bouyer /* if charging, current is positive */ 407 1.1 bouyer if (ISSET(bat_state, BAT_STATE_CHARGING)) 408 1.1 bouyer current = 0; 409 1.1 bouyer else 410 1.1 bouyer current = -current; 411 1.1 bouyer /* XXX Yeeloong draw is about 1A */ 412 1.1 bouyer if (current <= 0) 413 1.1 bouyer current = 1000; 414 1.1 bouyer /* XXX at 5?%, the Yeeloong shuts down */ 415 1.1 bouyer if (cap_pct <= 5) 416 1.1 bouyer cap_pct = 0; 417 1.1 bouyer else 418 1.1 bouyer cap_pct -= 5; 419 1.1 bouyer fullcap = cap_pct * 60 * fullcap / 100; 420 1.1 bouyer ykbec_apmdata.minutes_left = fullcap / current; 421 1.1 bouyer 422 1.1 bouyer } 423 1.1 bouyer if (old.ac_state != ykbec_apmdata.ac_state) 424 1.1 bouyer apm_record_event(APM_POWER_CHANGE, "AC power", 425 1.1 bouyer ykbec_apmdata.ac_state ? "restored" : "lost"); 426 1.1 bouyer if (old.battery_state != ykbec_apmdata.battery_state) 427 1.1 bouyer apm_record_event(APM_POWER_CHANGE, "battery", 428 1.1 bouyer BATTERY_STRING(ykbec_apmdata.battery_state)); 429 1.1 bouyer #endif 430 1.1 bouyer } 431 1.1 bouyer 432 1.1 bouyer 433 1.1 bouyer #if NAPM > 0 434 1.1 bouyer int 435 1.1 bouyer ykbec_apminfo(struct apm_power_info *info) 436 1.1 bouyer { 437 1.1 bouyer bcopy(&ykbec_apmdata, info, sizeof(struct apm_power_info)); 438 1.1 bouyer return 0; 439 1.1 bouyer } 440 1.1 bouyer 441 1.1 bouyer int 442 1.1 bouyer ykbec_suspend() 443 1.1 bouyer { 444 1.1 bouyer struct ykbec_softc *sc = ykbec_sc; 445 1.1 bouyer int ctrl; 446 1.1 bouyer 447 1.1 bouyer /* 448 1.1 bouyer * Set up wakeup sources: currently only the internal keyboard. 449 1.1 bouyer */ 450 1.1 bouyer loongson_set_isa_imr(1 << 1); 451 1.1 bouyer 452 1.1 bouyer /* USB */ 453 1.1 bouyer DPRINTF(("USB\n")); 454 1.1 bouyer ykbec_write(sc, REG_USB0, USB_FLAG_OFF); 455 1.1 bouyer ykbec_write(sc, REG_USB1, USB_FLAG_OFF); 456 1.1 bouyer ykbec_write(sc, REG_USB2, USB_FLAG_OFF); 457 1.1 bouyer 458 1.1 bouyer /* EC */ 459 1.1 bouyer DPRINTF(("REG_PMUCFG\n")); 460 1.1 bouyer ctrl = PMUCFG_SCI_WAKEUP | PMUCFG_WDT_WAKEUP | PMUCFG_GPWU_WAKEUP | 461 1.1 bouyer PMUCFG_LPC_WAKEUP | PMUCFG_STOP_MODE | PMUCFG_RESET_8051; 462 1.1 bouyer ykbec_write(sc, REG_PMUCFG, ctrl); 463 1.1 bouyer 464 1.1 bouyer /* FAN */ 465 1.1 bouyer DPRINTF(("FAN\n")); 466 1.1 bouyer ykbec_write(sc, REG_FAN_CONTROL, REG_FAN_OFF); 467 1.1 bouyer 468 1.1 bouyer /* CPU */ 469 1.1 bouyer DPRINTF(("CPU\n")); 470 1.1 bouyer ykbec_chip_config = REGVAL(LOONGSON_CHIP_CONFIG0); 471 1.1 bouyer enableintr(); 472 1.1 bouyer REGVAL(LOONGSON_CHIP_CONFIG0) = ykbec_chip_config & ~0x7; 473 1.1 bouyer (void)REGVAL(LOONGSON_CHIP_CONFIG0); 474 1.1 bouyer 475 1.1 bouyer /* 476 1.1 bouyer * When a resume interrupt fires, we will enter the interrupt 477 1.1 bouyer * dispatcher, which will do nothing because we are at splhigh, 478 1.1 bouyer * and execution flow will return here and continue. 479 1.1 bouyer */ 480 1.1 bouyer (void)disableintr(); 481 1.1 bouyer 482 1.1 bouyer return 0; 483 1.1 bouyer } 484 1.1 bouyer 485 1.1 bouyer int 486 1.1 bouyer ykbec_resume() 487 1.1 bouyer { 488 1.1 bouyer struct ykbec_softc *sc = ykbec_sc; 489 1.1 bouyer 490 1.1 bouyer /* CPU */ 491 1.1 bouyer DPRINTF(("CPU\n")); 492 1.1 bouyer REGVAL(LOONGSON_CHIP_CONFIG0) = ykbec_chip_config; 493 1.1 bouyer (void)REGVAL(LOONGSON_CHIP_CONFIG0); 494 1.1 bouyer 495 1.1 bouyer /* FAN */ 496 1.1 bouyer DPRINTF(("FAN\n")); 497 1.1 bouyer ykbec_write(sc, REG_FAN_CONTROL, REG_FAN_ON); 498 1.1 bouyer 499 1.1 bouyer /* USB */ 500 1.1 bouyer DPRINTF(("USB\n")); 501 1.1 bouyer ykbec_write(sc, REG_USB0, USB_FLAG_ON); 502 1.1 bouyer ykbec_write(sc, REG_USB1, USB_FLAG_ON); 503 1.1 bouyer ykbec_write(sc, REG_USB2, USB_FLAG_ON); 504 1.1 bouyer 505 1.1 bouyer ykbec_refresh(sc); 506 1.1 bouyer 507 1.1 bouyer return 0; 508 1.1 bouyer } 509 1.1 bouyer #endif 510 1.1 bouyer 511 1.1 bouyer #if NPCKBD > 0 || NHIDKBD > 0 512 1.1 bouyer void 513 1.1 bouyer ykbec_bell(void *arg, u_int pitch, u_int period, u_int volume, int poll) 514 1.1 bouyer { 515 1.1 bouyer struct ykbec_softc *sc = (struct ykbec_softc *)arg; 516 1.1 bouyer int bctrl; 517 1.1 bouyer int s; 518 1.1 bouyer 519 1.1 bouyer s = spltty(); 520 1.1 bouyer bctrl = ykbec_read(sc, REG_BEEP_CONTROL); 521 1.1 bouyer if (volume == 0 || timeout_pending(&sc->sc_bell_tmo)) { 522 1.1 bouyer timeout_del(&sc->sc_bell_tmo); 523 1.1 bouyer /* inline ykbec_bell_stop(arg); */ 524 1.1 bouyer ykbec_write(sc, REG_BEEP_CONTROL, bctrl & ~BEEP_ENABLE); 525 1.1 bouyer } 526 1.1 bouyer 527 1.1 bouyer if (volume != 0) { 528 1.1 bouyer ykbec_write(sc, REG_BEEP_CONTROL, bctrl | BEEP_ENABLE); 529 1.1 bouyer if (poll) { 530 1.1 bouyer delay(period * 1000); 531 1.1 bouyer ykbec_write(sc, REG_BEEP_CONTROL, bctrl & ~BEEP_ENABLE); 532 1.1 bouyer } else { 533 1.1 bouyer timeout_add_msec(&sc->sc_bell_tmo, period); 534 1.1 bouyer } 535 1.1 bouyer } 536 1.1 bouyer splx(s); 537 1.1 bouyer } 538 1.1 bouyer 539 1.1 bouyer void 540 1.1 bouyer ykbec_bell_stop(void *arg) 541 1.1 bouyer { 542 1.1 bouyer struct ykbec_softc *sc = (struct ykbec_softc *)arg; 543 1.1 bouyer int s; 544 1.1 bouyer 545 1.1 bouyer s = spltty(); 546 1.1 bouyer ykbec_write(sc, REG_BEEP_CONTROL, 547 1.1 bouyer ykbec_read(sc, REG_BEEP_CONTROL) & ~BEEP_ENABLE); 548 1.1 bouyer splx(s); 549 1.1 bouyer } 550 1.1 bouyer #endif 551