1*093389c9Sjsg /* $OpenBSD: aps.c,v 1.13 2007/01/05 07:00:37 jsg Exp $ */ 24569cca6Sjsg /* 34569cca6Sjsg * Copyright (c) 2005 Jonathan Gray <jsg@openbsd.org> 44569cca6Sjsg * 54569cca6Sjsg * Permission to use, copy, modify, and distribute this software for any 64569cca6Sjsg * purpose with or without fee is hereby granted, provided that the above 74569cca6Sjsg * copyright notice and this permission notice appear in all copies. 84569cca6Sjsg * 94569cca6Sjsg * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 104569cca6Sjsg * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 114569cca6Sjsg * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 124569cca6Sjsg * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 134569cca6Sjsg * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 144569cca6Sjsg * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 154569cca6Sjsg * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 164569cca6Sjsg */ 174569cca6Sjsg 184569cca6Sjsg /* 194569cca6Sjsg * A driver for the ThinkPad Active Protection System based on notes from 2067ee430bSjsg * http://www.almaden.ibm.com/cs/people/marksmith/tpaps.html 214569cca6Sjsg */ 224569cca6Sjsg 234569cca6Sjsg #include <sys/param.h> 244569cca6Sjsg #include <sys/systm.h> 254569cca6Sjsg #include <sys/device.h> 264569cca6Sjsg #include <sys/kernel.h> 274569cca6Sjsg #include <sys/sensors.h> 284569cca6Sjsg #include <sys/timeout.h> 294569cca6Sjsg #include <machine/bus.h> 304569cca6Sjsg 314569cca6Sjsg #include <dev/isa/isareg.h> 324569cca6Sjsg #include <dev/isa/isavar.h> 334569cca6Sjsg 344569cca6Sjsg #if defined(APSDEBUG) 354569cca6Sjsg #define DPRINTF(x) do { printf x; } while (0) 364569cca6Sjsg #else 374569cca6Sjsg #define DPRINTF(x) 384569cca6Sjsg #endif 394569cca6Sjsg 40*093389c9Sjsg #define APS_ACCEL_STATE 0x04 41*093389c9Sjsg #define APS_INIT 0x10 42*093389c9Sjsg #define APS_STATE 0x11 43*093389c9Sjsg #define APS_XACCEL 0x12 44*093389c9Sjsg #define APS_YACCEL 0x14 45*093389c9Sjsg #define APS_TEMP 0x16 46*093389c9Sjsg #define APS_XVAR 0x17 47*093389c9Sjsg #define APS_YVAR 0x19 48*093389c9Sjsg #define APS_TEMP2 0x1b 49*093389c9Sjsg #define APS_UNKNOWN 0x1c 50*093389c9Sjsg #define APS_INPUT 0x1d 51*093389c9Sjsg #define APS_CMD 0x1f 52*093389c9Sjsg 53*093389c9Sjsg #define APS_STATE_NEWDATA 0x50 54*093389c9Sjsg 55*093389c9Sjsg #define APS_CMD_START 0x01 56*093389c9Sjsg 57*093389c9Sjsg #define APS_INPUT_KB (1 << 5) 58*093389c9Sjsg #define APS_INPUT_MS (1 << 6) 59*093389c9Sjsg #define APS_INPUT_LIDOPEN (1 << 7) 60*093389c9Sjsg 61*093389c9Sjsg #define APS_ADDR_SIZE 0x1f 62*093389c9Sjsg 63*093389c9Sjsg struct sensor_rec { 64*093389c9Sjsg u_int8_t state; 65*093389c9Sjsg u_int16_t x_accel; 66*093389c9Sjsg u_int16_t y_accel; 67*093389c9Sjsg u_int8_t temp1; 68*093389c9Sjsg u_int16_t x_var; 69*093389c9Sjsg u_int16_t y_var; 70*093389c9Sjsg u_int8_t temp2; 71*093389c9Sjsg u_int8_t unk; 72*093389c9Sjsg u_int8_t input; 73*093389c9Sjsg }; 74*093389c9Sjsg 75*093389c9Sjsg #define APS_NUM_SENSORS 9 76*093389c9Sjsg 77*093389c9Sjsg #define APS_SENSOR_XACCEL 0 78*093389c9Sjsg #define APS_SENSOR_YACCEL 1 79*093389c9Sjsg #define APS_SENSOR_XVAR 2 80*093389c9Sjsg #define APS_SENSOR_YVAR 3 81*093389c9Sjsg #define APS_SENSOR_TEMP1 4 82*093389c9Sjsg #define APS_SENSOR_TEMP2 5 83*093389c9Sjsg #define APS_SENSOR_KBACT 6 84*093389c9Sjsg #define APS_SENSOR_MSACT 7 85*093389c9Sjsg #define APS_SENSOR_LIDOPEN 8 86*093389c9Sjsg 87*093389c9Sjsg struct aps_softc { 88*093389c9Sjsg struct device sc_dev; 89*093389c9Sjsg 90*093389c9Sjsg bus_space_tag_t aps_iot; 91*093389c9Sjsg bus_space_handle_t aps_ioh; 92*093389c9Sjsg 93*093389c9Sjsg struct sensor sensors[APS_NUM_SENSORS]; 94*093389c9Sjsg struct sensordev sensordev; 95*093389c9Sjsg void (*refresh_sensor_data)(struct aps_softc *); 96*093389c9Sjsg 97*093389c9Sjsg struct sensor_rec aps_data; 98*093389c9Sjsg }; 99*093389c9Sjsg 1004569cca6Sjsg int aps_match(struct device *, void *, void *); 1014569cca6Sjsg void aps_attach(struct device *, struct device *, void *); 1024569cca6Sjsg 103721d5653Sdjm int aps_init(bus_space_tag_t, bus_space_handle_t); 1044569cca6Sjsg u_int8_t aps_mem_read_1(bus_space_tag_t, bus_space_handle_t, int, u_int8_t); 1054569cca6Sjsg int aps_read_data(struct aps_softc *); 1064569cca6Sjsg void aps_refresh_sensor_data(struct aps_softc *sc); 1074569cca6Sjsg void aps_refresh(void *); 108721d5653Sdjm void aps_power(int, void *); 1094569cca6Sjsg 1104569cca6Sjsg struct cfattach aps_ca = { 1114569cca6Sjsg sizeof(struct aps_softc), 1124569cca6Sjsg aps_match, 1134569cca6Sjsg aps_attach 1144569cca6Sjsg }; 1154569cca6Sjsg 1164569cca6Sjsg struct cfdriver aps_cd = { 1174569cca6Sjsg NULL, "aps", DV_DULL 1184569cca6Sjsg }; 1194569cca6Sjsg 1204569cca6Sjsg struct timeout aps_timeout; 1214569cca6Sjsg 1224569cca6Sjsg int 1234569cca6Sjsg aps_match(struct device *parent, void *match, void *aux) 1244569cca6Sjsg { 1254569cca6Sjsg bus_space_tag_t iot; 1264569cca6Sjsg bus_space_handle_t ioh; 1274569cca6Sjsg struct isa_attach_args *ia = aux; 1284569cca6Sjsg int iobase, i; 1294569cca6Sjsg u_int8_t cr; 1304569cca6Sjsg 1314569cca6Sjsg iot = ia->ia_iot; 1324569cca6Sjsg iobase = ia->ipa_io[0].base; 1334569cca6Sjsg 1344569cca6Sjsg if (bus_space_map(iot, iobase, APS_ADDR_SIZE, 0, &ioh)) { 1354569cca6Sjsg DPRINTF(("aps: can't map i/o space\n")); 1364569cca6Sjsg return (0); 1374569cca6Sjsg } 1384569cca6Sjsg 1394569cca6Sjsg /* See if this machine has APS */ 1404569cca6Sjsg bus_space_write_1(iot, ioh, APS_INIT, 0x13); 1414569cca6Sjsg bus_space_write_1(iot, ioh, APS_CMD, 0x01); 14233972537Sjsg 14333972537Sjsg /* ask again as the X40 is slightly deaf in one ear */ 1441c54b514Sjsg bus_space_read_1(iot, ioh, APS_CMD); 14533972537Sjsg bus_space_write_1(iot, ioh, APS_INIT, 0x13); 14633972537Sjsg bus_space_write_1(iot, ioh, APS_CMD, 0x01); 14733972537Sjsg 1484569cca6Sjsg if (!aps_mem_read_1(iot, ioh, APS_CMD, 0x00)) { 1494569cca6Sjsg bus_space_unmap(iot, ioh, APS_ADDR_SIZE); 1504569cca6Sjsg return (0); 1514569cca6Sjsg } 1524569cca6Sjsg 1534569cca6Sjsg /* 1544569cca6Sjsg * Observed values from Linux driver: 1554569cca6Sjsg * 0x01: T42 1564569cca6Sjsg * 0x02: chip already initialised 1574569cca6Sjsg * 0x03: T41 1584569cca6Sjsg */ 1594569cca6Sjsg for (i = 0; i < 10; i++) { 1604569cca6Sjsg cr = bus_space_read_1(iot, ioh, APS_STATE); 1614569cca6Sjsg if (cr > 0 && cr < 4) 1624569cca6Sjsg break; 1634569cca6Sjsg delay(5 * 1000); 1644569cca6Sjsg } 1654569cca6Sjsg 1664569cca6Sjsg bus_space_unmap(iot, ioh, APS_ADDR_SIZE); 1674569cca6Sjsg DPRINTF(("aps: state register 0x%x\n", cr)); 1684569cca6Sjsg if (cr < 1 || cr > 3) { 1694569cca6Sjsg DPRINTF(("aps0: unsupported state %d\n", cr)); 1704569cca6Sjsg return (0); 1714569cca6Sjsg } 1724569cca6Sjsg 1734569cca6Sjsg ia->ipa_nio = 1; 1744569cca6Sjsg ia->ipa_io[0].length = APS_ADDR_SIZE; 1754569cca6Sjsg ia->ipa_nmem = 0; 1764569cca6Sjsg ia->ipa_nirq = 0; 1774569cca6Sjsg ia->ipa_ndrq = 0; 1784569cca6Sjsg 1794569cca6Sjsg return (1); 1804569cca6Sjsg } 1814569cca6Sjsg 1824569cca6Sjsg void 1834569cca6Sjsg aps_attach(struct device *parent, struct device *self, void *aux) 1844569cca6Sjsg { 1854569cca6Sjsg struct aps_softc *sc = (void *)self; 1864569cca6Sjsg int iobase, i; 1874569cca6Sjsg bus_space_tag_t iot; 1884569cca6Sjsg bus_space_handle_t ioh; 1894569cca6Sjsg struct isa_attach_args *ia = aux; 1904569cca6Sjsg 1914569cca6Sjsg iobase = ia->ipa_io[0].base; 1924569cca6Sjsg iot = sc->aps_iot = ia->ia_iot; 1934569cca6Sjsg 1944569cca6Sjsg if (bus_space_map(iot, iobase, APS_ADDR_SIZE, 0, &sc->aps_ioh)) { 1954569cca6Sjsg printf(": can't map i/o space\n"); 1964569cca6Sjsg return; 1974569cca6Sjsg } 1984569cca6Sjsg 1994569cca6Sjsg ioh = sc->aps_ioh; 2004569cca6Sjsg 2014569cca6Sjsg printf("\n"); 2024569cca6Sjsg 203721d5653Sdjm if (!aps_init(iot, ioh)) 2044569cca6Sjsg goto out; 2054569cca6Sjsg 2064569cca6Sjsg sc->sensors[APS_SENSOR_XACCEL].type = SENSOR_INTEGER; 2074569cca6Sjsg snprintf(sc->sensors[APS_SENSOR_XACCEL].desc, 2084569cca6Sjsg sizeof(sc->sensors[APS_SENSOR_XACCEL].desc), "X_ACCEL"); 2094569cca6Sjsg 2104569cca6Sjsg sc->sensors[APS_SENSOR_YACCEL].type = SENSOR_INTEGER; 2114569cca6Sjsg snprintf(sc->sensors[APS_SENSOR_YACCEL].desc, 2124569cca6Sjsg sizeof(sc->sensors[APS_SENSOR_YACCEL].desc), "Y_ACCEL"); 2134569cca6Sjsg 2144569cca6Sjsg sc->sensors[APS_SENSOR_TEMP1].type = SENSOR_TEMP; 2154569cca6Sjsg sc->sensors[APS_SENSOR_TEMP2].type = SENSOR_TEMP; 2164569cca6Sjsg 2174569cca6Sjsg sc->sensors[APS_SENSOR_XVAR].type = SENSOR_INTEGER; 2184569cca6Sjsg snprintf(sc->sensors[APS_SENSOR_XVAR].desc, 2194569cca6Sjsg sizeof(sc->sensors[APS_SENSOR_XVAR].desc), "X_VAR"); 2204569cca6Sjsg 2214569cca6Sjsg sc->sensors[APS_SENSOR_YVAR].type = SENSOR_INTEGER; 2224569cca6Sjsg snprintf(sc->sensors[APS_SENSOR_YVAR].desc, 2234569cca6Sjsg sizeof(sc->sensors[APS_SENSOR_YVAR].desc), "Y_VAR"); 2244569cca6Sjsg 225569d7da4Sjsg sc->sensors[APS_SENSOR_KBACT].type = SENSOR_INDICATOR; 2264569cca6Sjsg snprintf(sc->sensors[APS_SENSOR_KBACT].desc, 227aafcf214Sderaadt sizeof(sc->sensors[APS_SENSOR_KBACT].desc), "Keyboard Active"); 2284569cca6Sjsg 229569d7da4Sjsg sc->sensors[APS_SENSOR_MSACT].type = SENSOR_INDICATOR; 2304569cca6Sjsg snprintf(sc->sensors[APS_SENSOR_MSACT].desc, 231aafcf214Sderaadt sizeof(sc->sensors[APS_SENSOR_MSACT].desc), "Mouse Active"); 2324569cca6Sjsg 233569d7da4Sjsg sc->sensors[APS_SENSOR_LIDOPEN].type = SENSOR_INDICATOR; 2344569cca6Sjsg snprintf(sc->sensors[APS_SENSOR_LIDOPEN].desc, 235aafcf214Sderaadt sizeof(sc->sensors[APS_SENSOR_LIDOPEN].desc), "Lid Open"); 2364569cca6Sjsg 2374569cca6Sjsg /* stop hiding and report to the authorities */ 23827515a6bSderaadt strlcpy(sc->sensordev.xname, sc->sc_dev.dv_xname, 23927515a6bSderaadt sizeof(sc->sensordev.xname)); 24052a6f82eSjsg for (i = 0; i < APS_NUM_SENSORS ; i++) { 24127515a6bSderaadt sensor_attach(&sc->sensordev, &sc->sensors[i]); 2424569cca6Sjsg } 24327515a6bSderaadt sensordev_install(&sc->sensordev); 2444569cca6Sjsg 245721d5653Sdjm powerhook_establish(aps_power, (void *)sc); 246721d5653Sdjm 2474569cca6Sjsg /* Refresh sensor data every 0.5 seconds */ 2484569cca6Sjsg timeout_set(&aps_timeout, aps_refresh, sc); 2494569cca6Sjsg timeout_add(&aps_timeout, (5 * hz) / 10); 2504569cca6Sjsg return; 2514569cca6Sjsg out: 2524569cca6Sjsg printf("%s: failed to initialise\n", sc->sc_dev.dv_xname); 2534569cca6Sjsg return; 2544569cca6Sjsg } 2554569cca6Sjsg 256721d5653Sdjm int 257721d5653Sdjm aps_init(bus_space_tag_t iot, bus_space_handle_t ioh) 258721d5653Sdjm { 259721d5653Sdjm bus_space_write_1(iot, ioh, APS_INIT, 0x17); 260721d5653Sdjm bus_space_write_1(iot, ioh, APS_STATE, 0x81); 261721d5653Sdjm bus_space_write_1(iot, ioh, APS_CMD, 0x01); 262721d5653Sdjm if (!aps_mem_read_1(iot, ioh, APS_CMD, 0x00)) 263721d5653Sdjm return (0); 264721d5653Sdjm if (!aps_mem_read_1(iot, ioh, APS_STATE, 0x00)) 265721d5653Sdjm return (0); 266721d5653Sdjm if (!aps_mem_read_1(iot, ioh, APS_XACCEL, 0x60)) 267721d5653Sdjm return (0); 268721d5653Sdjm if (!aps_mem_read_1(iot, ioh, APS_XACCEL + 1, 0x00)) 269721d5653Sdjm return (0); 270721d5653Sdjm bus_space_write_1(iot, ioh, APS_INIT, 0x14); 271721d5653Sdjm bus_space_write_1(iot, ioh, APS_STATE, 0x01); 272721d5653Sdjm bus_space_write_1(iot, ioh, APS_CMD, 0x01); 273721d5653Sdjm if (!aps_mem_read_1(iot, ioh, APS_CMD, 0x00)) 274721d5653Sdjm return (0); 275721d5653Sdjm bus_space_write_1(iot, ioh, APS_INIT, 0x10); 276721d5653Sdjm bus_space_write_1(iot, ioh, APS_STATE, 0xc8); 277721d5653Sdjm bus_space_write_1(iot, ioh, APS_XACCEL, 0x00); 278721d5653Sdjm bus_space_write_1(iot, ioh, APS_XACCEL + 1, 0x02); 279721d5653Sdjm bus_space_write_1(iot, ioh, APS_CMD, 0x01); 280721d5653Sdjm if (!aps_mem_read_1(iot, ioh, APS_CMD, 0x00)) 281721d5653Sdjm return (0); 282721d5653Sdjm /* refresh data */ 283721d5653Sdjm bus_space_write_1(iot, ioh, APS_INIT, 0x11); 284721d5653Sdjm bus_space_write_1(iot, ioh, APS_CMD, 0x01); 285721d5653Sdjm if (!aps_mem_read_1(iot, ioh, APS_ACCEL_STATE, 0x50)) 286721d5653Sdjm return (0); 287721d5653Sdjm if (!aps_mem_read_1(iot, ioh, APS_STATE, 0x00)) 288721d5653Sdjm return (0); 289721d5653Sdjm 290721d5653Sdjm return (1); 291721d5653Sdjm } 292721d5653Sdjm 2934569cca6Sjsg u_int8_t 2944569cca6Sjsg aps_mem_read_1(bus_space_tag_t iot, bus_space_handle_t ioh, int reg, 2954569cca6Sjsg u_int8_t val) 2964569cca6Sjsg { 2974569cca6Sjsg int i; 2984569cca6Sjsg u_int8_t cr; 2994569cca6Sjsg /* should take no longer than 50 microseconds */ 3004569cca6Sjsg for (i = 0; i < 10; i++) { 3014569cca6Sjsg cr = bus_space_read_1(iot, ioh, reg); 3024569cca6Sjsg if (cr == val) 3034569cca6Sjsg return (1); 3044569cca6Sjsg delay(5 * 1000); 3054569cca6Sjsg } 3064569cca6Sjsg DPRINTF(("aps: reg 0x%x not val 0x%x!\n", reg, val)); 3074569cca6Sjsg return (0); 3084569cca6Sjsg } 3094569cca6Sjsg 3104569cca6Sjsg int 3114569cca6Sjsg aps_read_data(struct aps_softc *sc) 3124569cca6Sjsg { 3134569cca6Sjsg bus_space_tag_t iot = sc->aps_iot; 3144569cca6Sjsg bus_space_handle_t ioh = sc->aps_ioh; 3154569cca6Sjsg 3164569cca6Sjsg sc->aps_data.state = bus_space_read_1(iot, ioh, APS_STATE); 3174569cca6Sjsg sc->aps_data.x_accel = bus_space_read_2(iot, ioh, APS_XACCEL); 3184569cca6Sjsg sc->aps_data.y_accel = bus_space_read_2(iot, ioh, APS_YACCEL); 3194569cca6Sjsg sc->aps_data.temp1 = bus_space_read_1(iot, ioh, APS_TEMP); 3204569cca6Sjsg sc->aps_data.x_var = bus_space_read_2(iot, ioh, APS_XVAR); 3214569cca6Sjsg sc->aps_data.y_var = bus_space_read_2(iot, ioh, APS_YVAR); 3224569cca6Sjsg sc->aps_data.temp2 = bus_space_read_1(iot, ioh, APS_TEMP2); 3234569cca6Sjsg sc->aps_data.input = bus_space_read_1(iot, ioh, APS_INPUT); 3244569cca6Sjsg 3254569cca6Sjsg return (1); 3264569cca6Sjsg } 3274569cca6Sjsg 3284569cca6Sjsg void 3294569cca6Sjsg aps_refresh_sensor_data(struct aps_softc *sc) 3304569cca6Sjsg { 3314569cca6Sjsg bus_space_tag_t iot = sc->aps_iot; 3324569cca6Sjsg bus_space_handle_t ioh = sc->aps_ioh; 3334569cca6Sjsg int64_t temp; 3344569cca6Sjsg int i; 3354569cca6Sjsg 3364569cca6Sjsg /* ask for new data */ 3374569cca6Sjsg bus_space_write_1(iot, ioh, APS_INIT, 0x11); 3384569cca6Sjsg bus_space_write_1(iot, ioh, APS_CMD, 0x01); 3394569cca6Sjsg if (!aps_mem_read_1(iot, ioh, APS_ACCEL_STATE, 0x50)) 3404569cca6Sjsg return; 3414569cca6Sjsg aps_read_data(sc); 3424569cca6Sjsg bus_space_write_1(iot, ioh, APS_INIT, 0x11); 3434569cca6Sjsg bus_space_write_1(iot, ioh, APS_CMD, 0x01); 3444569cca6Sjsg 3454569cca6Sjsg /* tell accelerometer we're done reading from it */ 3464569cca6Sjsg bus_space_read_1(iot, ioh, APS_CMD); 3474569cca6Sjsg bus_space_read_1(iot, ioh, APS_ACCEL_STATE); 3484569cca6Sjsg 3494569cca6Sjsg for (i = 0; i < APS_NUM_SENSORS; i++) { 3504569cca6Sjsg sc->sensors[i].flags &= ~SENSOR_FINVALID; 3514569cca6Sjsg } 3524569cca6Sjsg 3534569cca6Sjsg sc->sensors[APS_SENSOR_XACCEL].value = sc->aps_data.x_accel; 3544569cca6Sjsg sc->sensors[APS_SENSOR_YACCEL].value = sc->aps_data.y_accel; 3554569cca6Sjsg 3564569cca6Sjsg /* convert to micro (mu) degrees */ 3574569cca6Sjsg temp = sc->aps_data.temp1 * 1000000; 3584569cca6Sjsg /* convert to kelvin */ 3594569cca6Sjsg temp += 273150000; 3604569cca6Sjsg sc->sensors[APS_SENSOR_TEMP1].value = temp; 3614569cca6Sjsg 3624569cca6Sjsg /* convert to micro (mu) degrees */ 3634569cca6Sjsg temp = sc->aps_data.temp2 * 1000000; 3644569cca6Sjsg /* convert to kelvin */ 3654569cca6Sjsg temp += 273150000; 3664569cca6Sjsg sc->sensors[APS_SENSOR_TEMP2].value = temp; 3674569cca6Sjsg 3684569cca6Sjsg sc->sensors[APS_SENSOR_XVAR].value = sc->aps_data.x_var; 3694569cca6Sjsg sc->sensors[APS_SENSOR_YVAR].value = sc->aps_data.y_var; 3704569cca6Sjsg sc->sensors[APS_SENSOR_KBACT].value = 3714569cca6Sjsg (sc->aps_data.input & APS_INPUT_KB) ? 1 : 0; 3724569cca6Sjsg sc->sensors[APS_SENSOR_MSACT].value = 3734569cca6Sjsg (sc->aps_data.input & APS_INPUT_MS) ? 1 : 0; 3744569cca6Sjsg sc->sensors[APS_SENSOR_LIDOPEN].value = 3754569cca6Sjsg (sc->aps_data.input & APS_INPUT_LIDOPEN) ? 1 : 0; 3764569cca6Sjsg } 3774569cca6Sjsg 3784569cca6Sjsg void 3794569cca6Sjsg aps_refresh(void *arg) 3804569cca6Sjsg { 3814569cca6Sjsg struct aps_softc *sc = (struct aps_softc *)arg; 3824569cca6Sjsg 3834569cca6Sjsg aps_refresh_sensor_data(sc); 3844569cca6Sjsg timeout_add(&aps_timeout, (5 * hz) / 10); 3854569cca6Sjsg } 386721d5653Sdjm 387721d5653Sdjm void 388721d5653Sdjm aps_power(int why, void *arg) 389721d5653Sdjm { 390721d5653Sdjm struct aps_softc *sc = (struct aps_softc *)arg; 391721d5653Sdjm bus_space_tag_t iot = sc->aps_iot; 392721d5653Sdjm bus_space_handle_t ioh = sc->aps_ioh; 393721d5653Sdjm 394721d5653Sdjm if (why != PWR_RESUME) { 395721d5653Sdjm if (timeout_pending(&aps_timeout)) 396721d5653Sdjm timeout_del(&aps_timeout); 397721d5653Sdjm } else { 398721d5653Sdjm /* 399721d5653Sdjm * Redo the init sequence on resume, because APS is 400721d5653Sdjm * as forgetful as it is deaf. 401721d5653Sdjm */ 402721d5653Sdjm bus_space_write_1(iot, ioh, APS_INIT, 0x13); 403721d5653Sdjm bus_space_write_1(iot, ioh, APS_CMD, 0x01); 404721d5653Sdjm bus_space_read_1(iot, ioh, APS_CMD); 405721d5653Sdjm bus_space_write_1(iot, ioh, APS_INIT, 0x13); 406721d5653Sdjm bus_space_write_1(iot, ioh, APS_CMD, 0x01); 407721d5653Sdjm 408721d5653Sdjm if (aps_mem_read_1(iot, ioh, APS_CMD, 0x00) && 409721d5653Sdjm aps_init(iot, ioh)) 410721d5653Sdjm timeout_add(&aps_timeout, (5 * hz) / 10); 411721d5653Sdjm else 412721d5653Sdjm printf("aps: failed to wake up\n"); 413721d5653Sdjm } 414721d5653Sdjm } 415721d5653Sdjm 416