aps.c revision 1.2.6.3 1 1.2.6.3 matt /* $NetBSD: aps.c,v 1.2.6.3 2008/01/09 01:53:11 matt Exp $ */
2 1.2.6.2 matt /* $OpenBSD: aps.c,v 1.15 2007/05/19 19:14:11 tedu Exp $ */
3 1.2.6.2 matt
4 1.2.6.2 matt /*
5 1.2.6.2 matt * Copyright (c) 2005 Jonathan Gray <jsg (at) openbsd.org>
6 1.2.6.2 matt *
7 1.2.6.2 matt * Permission to use, copy, modify, and distribute this software for any
8 1.2.6.2 matt * purpose with or without fee is hereby granted, provided that the above
9 1.2.6.2 matt * copyright notice and this permission notice appear in all copies.
10 1.2.6.2 matt *
11 1.2.6.2 matt * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 1.2.6.2 matt * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 1.2.6.2 matt * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 1.2.6.2 matt * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 1.2.6.2 matt * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 1.2.6.2 matt * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 1.2.6.2 matt * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 1.2.6.2 matt */
19 1.2.6.2 matt
20 1.2.6.2 matt /*
21 1.2.6.2 matt * A driver for the ThinkPad Active Protection System based on notes from
22 1.2.6.2 matt * http://www.almaden.ibm.com/cs/people/marksmith/tpaps.html
23 1.2.6.2 matt */
24 1.2.6.2 matt
25 1.2.6.2 matt #include <sys/cdefs.h>
26 1.2.6.3 matt __KERNEL_RCSID(0, "$NetBSD: aps.c,v 1.2.6.3 2008/01/09 01:53:11 matt Exp $");
27 1.2.6.2 matt
28 1.2.6.2 matt #include <sys/param.h>
29 1.2.6.2 matt #include <sys/systm.h>
30 1.2.6.2 matt #include <sys/device.h>
31 1.2.6.2 matt #include <sys/kernel.h>
32 1.2.6.2 matt #include <sys/callout.h>
33 1.2.6.2 matt
34 1.2.6.2 matt #include <sys/bus.h>
35 1.2.6.2 matt
36 1.2.6.2 matt #include <dev/sysmon/sysmonvar.h>
37 1.2.6.2 matt
38 1.2.6.2 matt #include <dev/isa/isareg.h>
39 1.2.6.2 matt #include <dev/isa/isavar.h>
40 1.2.6.2 matt
41 1.2.6.2 matt #if defined(APSDEBUG)
42 1.2.6.2 matt #define DPRINTF(x) do { printf x; } while (0)
43 1.2.6.2 matt #else
44 1.2.6.2 matt #define DPRINTF(x)
45 1.2.6.2 matt #endif
46 1.2.6.2 matt
47 1.2.6.2 matt #define APS_ACCEL_STATE 0x04
48 1.2.6.2 matt #define APS_INIT 0x10
49 1.2.6.2 matt #define APS_STATE 0x11
50 1.2.6.2 matt #define APS_XACCEL 0x12
51 1.2.6.2 matt #define APS_YACCEL 0x14
52 1.2.6.2 matt #define APS_TEMP 0x16
53 1.2.6.2 matt #define APS_XVAR 0x17
54 1.2.6.2 matt #define APS_YVAR 0x19
55 1.2.6.2 matt #define APS_TEMP2 0x1b
56 1.2.6.2 matt #define APS_UNKNOWN 0x1c
57 1.2.6.2 matt #define APS_INPUT 0x1d
58 1.2.6.2 matt #define APS_CMD 0x1f
59 1.2.6.2 matt
60 1.2.6.2 matt #define APS_STATE_NEWDATA 0x50
61 1.2.6.2 matt
62 1.2.6.2 matt #define APS_CMD_START 0x01
63 1.2.6.2 matt
64 1.2.6.2 matt #define APS_INPUT_KB (1 << 5)
65 1.2.6.2 matt #define APS_INPUT_MS (1 << 6)
66 1.2.6.2 matt #define APS_INPUT_LIDOPEN (1 << 7)
67 1.2.6.2 matt
68 1.2.6.2 matt #define APS_ADDR_SIZE 0x1f
69 1.2.6.2 matt
70 1.2.6.2 matt struct sensor_rec {
71 1.2.6.2 matt uint8_t state;
72 1.2.6.2 matt uint16_t x_accel;
73 1.2.6.2 matt uint16_t y_accel;
74 1.2.6.2 matt uint8_t temp1;
75 1.2.6.2 matt uint16_t x_var;
76 1.2.6.2 matt uint16_t y_var;
77 1.2.6.2 matt uint8_t temp2;
78 1.2.6.2 matt uint8_t unk;
79 1.2.6.2 matt uint8_t input;
80 1.2.6.2 matt };
81 1.2.6.2 matt
82 1.2.6.2 matt enum aps_sensors {
83 1.2.6.2 matt APS_SENSOR_XACCEL = 0,
84 1.2.6.2 matt APS_SENSOR_YACCEL,
85 1.2.6.2 matt APS_SENSOR_XVAR,
86 1.2.6.2 matt APS_SENSOR_YVAR,
87 1.2.6.2 matt APS_SENSOR_TEMP1,
88 1.2.6.2 matt APS_SENSOR_TEMP2,
89 1.2.6.2 matt APS_SENSOR_KBACT,
90 1.2.6.2 matt APS_SENSOR_MSACT,
91 1.2.6.2 matt APS_SENSOR_LIDOPEN,
92 1.2.6.2 matt APS_NUM_SENSORS
93 1.2.6.2 matt };
94 1.2.6.2 matt
95 1.2.6.2 matt struct aps_softc {
96 1.2.6.2 matt struct device sc_dev;
97 1.2.6.2 matt
98 1.2.6.2 matt bus_space_tag_t sc_iot;
99 1.2.6.2 matt bus_space_handle_t sc_ioh;
100 1.2.6.2 matt
101 1.2.6.3 matt struct sysmon_envsys *sc_sme;
102 1.2.6.3 matt envsys_data_t sc_sensor[APS_NUM_SENSORS];
103 1.2.6.2 matt struct callout sc_callout;
104 1.2.6.2 matt
105 1.2.6.2 matt struct sensor_rec aps_data;
106 1.2.6.2 matt };
107 1.2.6.2 matt
108 1.2.6.2 matt static int aps_match(struct device *, struct cfdata *, void *);
109 1.2.6.2 matt static void aps_attach(struct device *, struct device *, void *);
110 1.2.6.2 matt static int aps_detach(struct device *, int);
111 1.2.6.2 matt
112 1.2.6.2 matt static int aps_init(struct aps_softc *);
113 1.2.6.2 matt static uint8_t aps_mem_read_1(bus_space_tag_t, bus_space_handle_t,
114 1.2.6.2 matt int, uint8_t);
115 1.2.6.2 matt static void aps_refresh_sensor_data(struct aps_softc *sc);
116 1.2.6.2 matt static void aps_refresh(void *);
117 1.2.6.3 matt static bool aps_suspend(device_t);
118 1.2.6.3 matt static bool aps_resume(device_t);
119 1.2.6.2 matt
120 1.2.6.2 matt CFATTACH_DECL(aps, sizeof(struct aps_softc),
121 1.2.6.2 matt aps_match, aps_attach, aps_detach, NULL);
122 1.2.6.2 matt
123 1.2.6.2 matt int
124 1.2.6.2 matt aps_match(struct device *parent, struct cfdata *match, void *aux)
125 1.2.6.2 matt {
126 1.2.6.2 matt struct isa_attach_args *ia = aux;
127 1.2.6.2 matt bus_space_tag_t iot = ia->ia_iot;
128 1.2.6.2 matt bus_space_handle_t ioh;
129 1.2.6.2 matt int iobase, i;
130 1.2.6.2 matt uint8_t cr;
131 1.2.6.2 matt
132 1.2.6.2 matt /* Must supply an address */
133 1.2.6.2 matt if (ia->ia_nio < 1)
134 1.2.6.2 matt return 0;
135 1.2.6.2 matt
136 1.2.6.2 matt if (ISA_DIRECT_CONFIG(ia))
137 1.2.6.2 matt return 0;
138 1.2.6.2 matt
139 1.2.6.2 matt if (ia->ia_io[0].ir_addr == ISA_UNKNOWN_PORT)
140 1.2.6.2 matt return 0;
141 1.2.6.2 matt
142 1.2.6.2 matt iobase = ia->ia_io[0].ir_addr;
143 1.2.6.2 matt
144 1.2.6.2 matt if (bus_space_map(iot, iobase, APS_ADDR_SIZE, 0, &ioh)) {
145 1.2.6.2 matt aprint_error("aps: can't map i/o space\n");
146 1.2.6.2 matt return 0;
147 1.2.6.2 matt }
148 1.2.6.2 matt
149 1.2.6.2 matt /* See if this machine has APS */
150 1.2.6.2 matt bus_space_write_1(iot, ioh, APS_INIT, 0x13);
151 1.2.6.2 matt bus_space_write_1(iot, ioh, APS_CMD, 0x01);
152 1.2.6.2 matt
153 1.2.6.2 matt /* ask again as the X40 is slightly deaf in one ear */
154 1.2.6.2 matt bus_space_read_1(iot, ioh, APS_CMD);
155 1.2.6.2 matt bus_space_write_1(iot, ioh, APS_INIT, 0x13);
156 1.2.6.2 matt bus_space_write_1(iot, ioh, APS_CMD, 0x01);
157 1.2.6.2 matt
158 1.2.6.2 matt if (!aps_mem_read_1(iot, ioh, APS_CMD, 0x00)) {
159 1.2.6.2 matt bus_space_unmap(iot, ioh, APS_ADDR_SIZE);
160 1.2.6.2 matt return 0;
161 1.2.6.2 matt }
162 1.2.6.2 matt
163 1.2.6.2 matt /*
164 1.2.6.2 matt * Observed values from Linux driver:
165 1.2.6.2 matt * 0x01: T42
166 1.2.6.2 matt * 0x02: chip already initialised
167 1.2.6.2 matt * 0x03: T41
168 1.2.6.2 matt */
169 1.2.6.2 matt for (i = 0; i < 10; i++) {
170 1.2.6.2 matt cr = bus_space_read_1(iot, ioh, APS_STATE);
171 1.2.6.2 matt if (cr > 0 && cr < 6)
172 1.2.6.2 matt break;
173 1.2.6.2 matt delay(5 * 1000);
174 1.2.6.2 matt }
175 1.2.6.2 matt
176 1.2.6.2 matt bus_space_unmap(iot, ioh, APS_ADDR_SIZE);
177 1.2.6.2 matt DPRINTF(("aps: state register 0x%x\n", cr));
178 1.2.6.2 matt if (cr < 1 || cr > 5) {
179 1.2.6.2 matt DPRINTF(("aps0: unsupported state %d\n", cr));
180 1.2.6.2 matt return 0;
181 1.2.6.2 matt }
182 1.2.6.2 matt
183 1.2.6.2 matt ia->ia_nio = 1;
184 1.2.6.2 matt ia->ia_io[0].ir_size = APS_ADDR_SIZE;
185 1.2.6.2 matt ia->ia_niomem = 0;
186 1.2.6.2 matt ia->ia_nirq = 0;
187 1.2.6.2 matt ia->ia_ndrq = 0;
188 1.2.6.2 matt
189 1.2.6.2 matt return 1;
190 1.2.6.2 matt }
191 1.2.6.2 matt
192 1.2.6.2 matt void
193 1.2.6.2 matt aps_attach(struct device *parent, struct device *self, void *aux)
194 1.2.6.2 matt {
195 1.2.6.2 matt struct aps_softc *sc = (void *)self;
196 1.2.6.2 matt struct isa_attach_args *ia = aux;
197 1.2.6.2 matt int iobase, i;
198 1.2.6.2 matt
199 1.2.6.2 matt sc->sc_iot = ia->ia_iot;
200 1.2.6.2 matt iobase = ia->ia_io[0].ir_addr;
201 1.2.6.2 matt
202 1.2.6.2 matt if (bus_space_map(sc->sc_iot, iobase, APS_ADDR_SIZE, 0, &sc->sc_ioh)) {
203 1.2.6.2 matt aprint_error(": can't map i/o space\n");
204 1.2.6.2 matt return;
205 1.2.6.2 matt }
206 1.2.6.2 matt
207 1.2.6.2 matt aprint_naive("\n");
208 1.2.6.2 matt aprint_normal("\n");
209 1.2.6.2 matt
210 1.2.6.2 matt if (!aps_init(sc)) {
211 1.2.6.2 matt aprint_error("%s: failed to initialise\n",
212 1.2.6.2 matt device_xname(&sc->sc_dev));
213 1.2.6.2 matt return;
214 1.2.6.2 matt }
215 1.2.6.2 matt
216 1.2.6.2 matt /* Initialize sensors */
217 1.2.6.2 matt #define INITDATA(idx, unit, string) \
218 1.2.6.3 matt sc->sc_sensor[idx].units = unit; \
219 1.2.6.3 matt strlcpy(sc->sc_sensor[idx].desc, string, \
220 1.2.6.3 matt sizeof(sc->sc_sensor[idx].desc));
221 1.2.6.2 matt
222 1.2.6.2 matt INITDATA(APS_SENSOR_XACCEL, ENVSYS_INTEGER, "X_ACCEL");
223 1.2.6.2 matt INITDATA(APS_SENSOR_YACCEL, ENVSYS_INTEGER, "Y_ACCEL");
224 1.2.6.2 matt INITDATA(APS_SENSOR_TEMP1, ENVSYS_STEMP, "TEMP_1");
225 1.2.6.2 matt INITDATA(APS_SENSOR_TEMP2, ENVSYS_STEMP, "TEMP_2");
226 1.2.6.2 matt INITDATA(APS_SENSOR_XVAR, ENVSYS_INTEGER, "X_VAR");
227 1.2.6.2 matt INITDATA(APS_SENSOR_YVAR, ENVSYS_INTEGER, "Y_VAR");
228 1.2.6.2 matt INITDATA(APS_SENSOR_KBACT, ENVSYS_INDICATOR, "Keyboard Active");
229 1.2.6.2 matt INITDATA(APS_SENSOR_MSACT, ENVSYS_INDICATOR, "Mouse Active");
230 1.2.6.2 matt INITDATA(APS_SENSOR_LIDOPEN, ENVSYS_INDICATOR, "Lid Open");
231 1.2.6.2 matt
232 1.2.6.3 matt sc->sc_sme = sysmon_envsys_create();
233 1.2.6.3 matt for (i = 0; i < APS_NUM_SENSORS; i++) {
234 1.2.6.3 matt sc->sc_sensor[i].state = ENVSYS_SVALID;
235 1.2.6.3 matt if (sysmon_envsys_sensor_attach(sc->sc_sme,
236 1.2.6.3 matt &sc->sc_sensor[i])) {
237 1.2.6.3 matt sysmon_envsys_destroy(sc->sc_sme);
238 1.2.6.3 matt return;
239 1.2.6.3 matt }
240 1.2.6.3 matt }
241 1.2.6.2 matt /*
242 1.2.6.2 matt * Register with the sysmon_envsys(9) framework.
243 1.2.6.2 matt */
244 1.2.6.3 matt sc->sc_sme->sme_name = sc->sc_dev.dv_xname;
245 1.2.6.3 matt sc->sc_sme->sme_flags |= SME_DISABLE_REFRESH;
246 1.2.6.2 matt
247 1.2.6.3 matt if ((i = sysmon_envsys_register(sc->sc_sme))) {
248 1.2.6.2 matt aprint_error("%s: unable to register with sysmon (%d)\n",
249 1.2.6.2 matt device_xname(&sc->sc_dev), i);
250 1.2.6.3 matt sysmon_envsys_destroy(sc->sc_sme);
251 1.2.6.2 matt return;
252 1.2.6.2 matt }
253 1.2.6.2 matt
254 1.2.6.3 matt if (!pmf_device_register(self, aps_suspend, aps_resume))
255 1.2.6.3 matt aprint_error_dev(self, "couldn't establish power handler\n");
256 1.2.6.2 matt
257 1.2.6.2 matt /* Refresh sensor data every 0.5 seconds */
258 1.2.6.2 matt callout_init(&sc->sc_callout, 0);
259 1.2.6.2 matt callout_setfunc(&sc->sc_callout, aps_refresh, sc);
260 1.2.6.2 matt callout_schedule(&sc->sc_callout, (hz) / 2);
261 1.2.6.2 matt
262 1.2.6.2 matt aprint_normal("%s: Thinkpad Active Protection System\n",
263 1.2.6.2 matt device_xname(&sc->sc_dev));
264 1.2.6.2 matt }
265 1.2.6.2 matt
266 1.2.6.2 matt static int
267 1.2.6.2 matt aps_init(struct aps_softc *sc)
268 1.2.6.2 matt {
269 1.2.6.2 matt bus_space_write_1(sc->sc_iot, sc->sc_ioh, APS_INIT, 0x17);
270 1.2.6.2 matt bus_space_write_1(sc->sc_iot, sc->sc_ioh, APS_STATE, 0x81);
271 1.2.6.2 matt bus_space_write_1(sc->sc_iot, sc->sc_ioh, APS_CMD, 0x01);
272 1.2.6.2 matt if (!aps_mem_read_1(sc->sc_iot, sc->sc_ioh, APS_CMD, 0x00))
273 1.2.6.2 matt return 0;
274 1.2.6.2 matt if (!aps_mem_read_1(sc->sc_iot, sc->sc_ioh, APS_STATE, 0x00))
275 1.2.6.2 matt return 0;
276 1.2.6.2 matt if (!aps_mem_read_1(sc->sc_iot, sc->sc_ioh, APS_XACCEL, 0x60))
277 1.2.6.2 matt return 0;
278 1.2.6.2 matt if (!aps_mem_read_1(sc->sc_iot, sc->sc_ioh, APS_XACCEL + 1, 0x00))
279 1.2.6.2 matt return 0;
280 1.2.6.2 matt bus_space_write_1(sc->sc_iot, sc->sc_ioh, APS_INIT, 0x14);
281 1.2.6.2 matt bus_space_write_1(sc->sc_iot, sc->sc_ioh, APS_STATE, 0x01);
282 1.2.6.2 matt bus_space_write_1(sc->sc_iot, sc->sc_ioh, APS_CMD, 0x01);
283 1.2.6.2 matt if (!aps_mem_read_1(sc->sc_iot, sc->sc_ioh, APS_CMD, 0x00))
284 1.2.6.2 matt return 0;
285 1.2.6.2 matt bus_space_write_1(sc->sc_iot, sc->sc_ioh, APS_INIT, 0x10);
286 1.2.6.2 matt bus_space_write_1(sc->sc_iot, sc->sc_ioh, APS_STATE, 0xc8);
287 1.2.6.2 matt bus_space_write_1(sc->sc_iot, sc->sc_ioh, APS_XACCEL, 0x00);
288 1.2.6.2 matt bus_space_write_1(sc->sc_iot, sc->sc_ioh, APS_XACCEL + 1, 0x02);
289 1.2.6.2 matt bus_space_write_1(sc->sc_iot, sc->sc_ioh, APS_CMD, 0x01);
290 1.2.6.2 matt if (!aps_mem_read_1(sc->sc_iot, sc->sc_ioh, APS_CMD, 0x00))
291 1.2.6.2 matt return 0;
292 1.2.6.2 matt /* refresh data */
293 1.2.6.2 matt bus_space_write_1(sc->sc_iot, sc->sc_ioh, APS_INIT, 0x11);
294 1.2.6.2 matt bus_space_write_1(sc->sc_iot, sc->sc_ioh, APS_CMD, 0x01);
295 1.2.6.2 matt if (!aps_mem_read_1(sc->sc_iot, sc->sc_ioh, APS_ACCEL_STATE, 0x50))
296 1.2.6.2 matt return 0;
297 1.2.6.2 matt if (!aps_mem_read_1(sc->sc_iot, sc->sc_ioh, APS_STATE, 0x00))
298 1.2.6.2 matt return 0;
299 1.2.6.2 matt
300 1.2.6.2 matt return 1;
301 1.2.6.2 matt }
302 1.2.6.2 matt
303 1.2.6.2 matt static int
304 1.2.6.2 matt aps_detach(struct device *self, int flags)
305 1.2.6.2 matt {
306 1.2.6.2 matt struct aps_softc *sc = device_private(self);
307 1.2.6.2 matt
308 1.2.6.2 matt callout_stop(&sc->sc_callout);
309 1.2.6.2 matt callout_destroy(&sc->sc_callout);
310 1.2.6.3 matt sysmon_envsys_unregister(sc->sc_sme);
311 1.2.6.2 matt bus_space_unmap(sc->sc_iot, sc->sc_ioh, APS_ADDR_SIZE);
312 1.2.6.2 matt
313 1.2.6.2 matt return 0;
314 1.2.6.2 matt }
315 1.2.6.2 matt
316 1.2.6.2 matt static uint8_t
317 1.2.6.2 matt aps_mem_read_1(bus_space_tag_t iot, bus_space_handle_t ioh, int reg,
318 1.2.6.2 matt uint8_t val)
319 1.2.6.2 matt {
320 1.2.6.2 matt int i;
321 1.2.6.2 matt uint8_t cr;
322 1.2.6.2 matt /* should take no longer than 50 microseconds */
323 1.2.6.2 matt for (i = 0; i < 10; i++) {
324 1.2.6.2 matt cr = bus_space_read_1(iot, ioh, reg);
325 1.2.6.2 matt if (cr == val)
326 1.2.6.2 matt return 1;
327 1.2.6.2 matt delay(5 * 1000);
328 1.2.6.2 matt }
329 1.2.6.2 matt
330 1.2.6.2 matt DPRINTF(("aps: reg 0x%x not val 0x%x!\n", reg, val));
331 1.2.6.2 matt return 0;
332 1.2.6.2 matt }
333 1.2.6.2 matt
334 1.2.6.2 matt static void
335 1.2.6.2 matt aps_refresh_sensor_data(struct aps_softc *sc)
336 1.2.6.2 matt {
337 1.2.6.2 matt int64_t temp;
338 1.2.6.2 matt
339 1.2.6.2 matt /* ask for new data */
340 1.2.6.2 matt bus_space_write_1(sc->sc_iot, sc->sc_ioh, APS_INIT, 0x11);
341 1.2.6.2 matt bus_space_write_1(sc->sc_iot, sc->sc_ioh, APS_CMD, 0x01);
342 1.2.6.2 matt if (!aps_mem_read_1(sc->sc_iot, sc->sc_ioh, APS_ACCEL_STATE, 0x50))
343 1.2.6.2 matt return;
344 1.2.6.2 matt
345 1.2.6.2 matt sc->aps_data.state =
346 1.2.6.2 matt bus_space_read_1(sc->sc_iot, sc->sc_ioh, APS_STATE);
347 1.2.6.2 matt sc->aps_data.x_accel =
348 1.2.6.2 matt bus_space_read_2(sc->sc_iot, sc->sc_ioh, APS_XACCEL);
349 1.2.6.2 matt sc->aps_data.y_accel =
350 1.2.6.2 matt bus_space_read_2(sc->sc_iot, sc->sc_ioh, APS_YACCEL);
351 1.2.6.2 matt sc->aps_data.temp1 =
352 1.2.6.2 matt bus_space_read_1(sc->sc_iot, sc->sc_ioh, APS_TEMP);
353 1.2.6.2 matt sc->aps_data.x_var =
354 1.2.6.2 matt bus_space_read_2(sc->sc_iot, sc->sc_ioh, APS_XVAR);
355 1.2.6.2 matt sc->aps_data.y_var =
356 1.2.6.2 matt bus_space_read_2(sc->sc_iot, sc->sc_ioh, APS_YVAR);
357 1.2.6.2 matt sc->aps_data.temp2 =
358 1.2.6.2 matt bus_space_read_1(sc->sc_iot, sc->sc_ioh, APS_TEMP2);
359 1.2.6.2 matt sc->aps_data.input =
360 1.2.6.2 matt bus_space_read_1(sc->sc_iot, sc->sc_ioh, APS_INPUT);
361 1.2.6.2 matt
362 1.2.6.2 matt bus_space_write_1(sc->sc_iot, sc->sc_ioh, APS_INIT, 0x11);
363 1.2.6.2 matt bus_space_write_1(sc->sc_iot, sc->sc_ioh, APS_CMD, 0x01);
364 1.2.6.2 matt
365 1.2.6.2 matt /* tell accelerometer we're done reading from it */
366 1.2.6.2 matt bus_space_read_1(sc->sc_iot, sc->sc_ioh, APS_CMD);
367 1.2.6.2 matt bus_space_read_1(sc->sc_iot, sc->sc_ioh, APS_ACCEL_STATE);
368 1.2.6.2 matt
369 1.2.6.3 matt sc->sc_sensor[APS_SENSOR_XACCEL].value_cur = sc->aps_data.x_accel;
370 1.2.6.3 matt sc->sc_sensor[APS_SENSOR_YACCEL].value_cur = sc->aps_data.y_accel;
371 1.2.6.2 matt
372 1.2.6.2 matt /* convert to micro (mu) degrees */
373 1.2.6.2 matt temp = sc->aps_data.temp1 * 1000000;
374 1.2.6.2 matt /* convert to kelvin */
375 1.2.6.2 matt temp += 273150000;
376 1.2.6.3 matt sc->sc_sensor[APS_SENSOR_TEMP1].value_cur = temp;
377 1.2.6.2 matt
378 1.2.6.2 matt /* convert to micro (mu) degrees */
379 1.2.6.2 matt temp = sc->aps_data.temp2 * 1000000;
380 1.2.6.2 matt /* convert to kelvin */
381 1.2.6.2 matt temp += 273150000;
382 1.2.6.3 matt sc->sc_sensor[APS_SENSOR_TEMP2].value_cur = temp;
383 1.2.6.2 matt
384 1.2.6.3 matt sc->sc_sensor[APS_SENSOR_XVAR].value_cur = sc->aps_data.x_var;
385 1.2.6.3 matt sc->sc_sensor[APS_SENSOR_YVAR].value_cur = sc->aps_data.y_var;
386 1.2.6.3 matt sc->sc_sensor[APS_SENSOR_KBACT].value_cur =
387 1.2.6.2 matt (sc->aps_data.input & APS_INPUT_KB) ? 1 : 0;
388 1.2.6.3 matt sc->sc_sensor[APS_SENSOR_MSACT].value_cur =
389 1.2.6.2 matt (sc->aps_data.input & APS_INPUT_MS) ? 1 : 0;
390 1.2.6.3 matt sc->sc_sensor[APS_SENSOR_LIDOPEN].value_cur =
391 1.2.6.2 matt (sc->aps_data.input & APS_INPUT_LIDOPEN) ? 1 : 0;
392 1.2.6.2 matt }
393 1.2.6.2 matt
394 1.2.6.2 matt static void
395 1.2.6.2 matt aps_refresh(void *arg)
396 1.2.6.2 matt {
397 1.2.6.2 matt struct aps_softc *sc = (struct aps_softc *)arg;
398 1.2.6.2 matt
399 1.2.6.2 matt aps_refresh_sensor_data(sc);
400 1.2.6.2 matt callout_schedule(&sc->sc_callout, (hz) / 2);
401 1.2.6.2 matt }
402 1.2.6.2 matt
403 1.2.6.3 matt static bool
404 1.2.6.3 matt aps_suspend(device_t dv)
405 1.2.6.2 matt {
406 1.2.6.3 matt struct aps_softc *sc = device_private(dv);
407 1.2.6.2 matt
408 1.2.6.3 matt callout_stop(&sc->sc_callout);
409 1.2.6.3 matt
410 1.2.6.3 matt return true;
411 1.2.6.3 matt }
412 1.2.6.3 matt
413 1.2.6.3 matt static bool
414 1.2.6.3 matt aps_resume(device_t dv)
415 1.2.6.3 matt {
416 1.2.6.3 matt struct aps_softc *sc = device_private(dv);
417 1.2.6.3 matt
418 1.2.6.3 matt /*
419 1.2.6.3 matt * Redo the init sequence on resume, because APS is
420 1.2.6.3 matt * as forgetful as it is deaf.
421 1.2.6.3 matt */
422 1.2.6.3 matt bus_space_write_1(sc->sc_iot, sc->sc_ioh, APS_INIT, 0x13);
423 1.2.6.3 matt bus_space_write_1(sc->sc_iot, sc->sc_ioh, APS_CMD, 0x01);
424 1.2.6.3 matt bus_space_read_1(sc->sc_iot, sc->sc_ioh, APS_CMD);
425 1.2.6.3 matt bus_space_write_1(sc->sc_iot, sc->sc_ioh, APS_INIT, 0x13);
426 1.2.6.3 matt bus_space_write_1(sc->sc_iot, sc->sc_ioh, APS_CMD, 0x01);
427 1.2.6.3 matt
428 1.2.6.3 matt if (aps_mem_read_1(sc->sc_iot, sc->sc_ioh, APS_CMD, 0x00) &&
429 1.2.6.3 matt aps_init(sc))
430 1.2.6.3 matt callout_schedule(&sc->sc_callout, (hz) / 2);
431 1.2.6.3 matt else
432 1.2.6.3 matt aprint_error_dev(dv, "failed to wake up\n");
433 1.2.6.3 matt
434 1.2.6.3 matt return true;
435 1.2.6.2 matt }
436