xref: /openbsd/sys/dev/isa/aps.c (revision 093389c9)
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