xref: /openbsd-src/sys/arch/arm64/dev/aplsmc.c (revision fc405d53b73a2d73393cb97f684863d17b583e38)
1 /*	$OpenBSD: aplsmc.c,v 1.21 2023/01/09 20:29:35 kettenis Exp $	*/
2 /*
3  * Copyright (c) 2021 Mark Kettenis <kettenis@openbsd.org>
4  *
5  * Permission to use, copy, modify, and distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  */
17 
18 #include <sys/param.h>
19 #include <sys/systm.h>
20 #include <sys/device.h>
21 #include <sys/proc.h>
22 #include <sys/sensors.h>
23 #include <sys/signalvar.h>
24 
25 #include <machine/apmvar.h>
26 #include <machine/bus.h>
27 #include <machine/fdt.h>
28 
29 #include <dev/clock_subr.h>
30 #include <dev/ofw/openfirm.h>
31 #include <dev/ofw/ofw_gpio.h>
32 #include <dev/ofw/ofw_misc.h>
33 #include <dev/ofw/fdt.h>
34 
35 #include <arm64/dev/aplmbox.h>
36 #include <arm64/dev/rtkit.h>
37 
38 #include "apm.h"
39 
40 extern int lid_action;
41 extern void (*simplefb_burn_hook)(u_int);
42 
43 extern void (*cpuresetfn)(void);
44 extern void (*powerdownfn)(void);
45 
46 /* SMC mailbox endpoint */
47 #define SMC_EP			32
48 
49 /* SMC commands */
50 #define SMC_CMD(d)		((d) & 0xff)
51 #define SMC_READ_KEY		0x10
52 #define SMC_WRITE_KEY		0x11
53 #define SMC_GET_KEY_BY_INDEX	0x12
54 #define SMC_GET_KEY_INFO	0x13
55 #define SMC_GET_SRAM_ADDR	0x17
56 #define  SMC_SRAM_SIZE		0x4000
57 #define SMC_NOTIFICATION	0x18
58 
59 /* SMC errors */
60 #define SMC_ERROR(d)		((d) & 0xff)
61 #define SMC_OK			0x00
62 #define SMC_KEYNOTFOUND		0x84
63 
64 /* SMC keys */
65 #define SMC_KEY(s)	((s[0] << 24) | (s[1] << 16) | (s[2] << 8) | s[3])
66 
67 struct smc_key_info {
68 	uint8_t		size;
69 	uint8_t		type[4];
70 	uint8_t		flags;
71 };
72 
73 /* SMC GPIO commands */
74 #define SMC_GPIO_CMD_OUTPUT	(0x01 << 24)
75 
76 /* RTC related constants */
77 #define RTC_OFFSET_LEN		6
78 #define SMC_CLKM_LEN		6
79 
80 struct aplsmc_sensor {
81 	const char	*key;
82 	const char	*key_type;
83 	enum sensor_type type;
84 	int		scale;
85 	const char	*desc;
86 	int		flags;
87 };
88 
89 /* SMC events */
90 #define SMC_EV_TYPE(d)		(((d) >> 48) & 0xffff)
91 #define SMC_EV_TYPE_BTN		0x7201
92 #define SMC_EV_TYPE_LID		0x7203
93 #define SMC_EV_SUBTYPE(d)	(((d) >> 40) & 0xff)
94 #define SMC_EV_DATA(d)		(((d) >> 32) & 0xff)
95 
96 /* Button events */
97 #define SMC_PWRBTN_OFF		0x00
98 #define SMC_PWRBTN_SHORT	0x01
99 #define SMC_PWRBTN_TOUCHID	0x06
100 #define SMC_PWRBTN_LONG		0xfe
101 
102 /* Lid events */
103 #define SMC_LID_OPEN		0x00
104 #define SMC_LID_CLOSE		0x01
105 
106 #define APLSMC_BE		(1 << 0)
107 #define APLSMC_HIDDEN		(1 << 1)
108 
109 #define APLSMC_MAX_SENSORS	19
110 
111 struct aplsmc_softc {
112 	struct device		sc_dev;
113 	bus_space_tag_t		sc_iot;
114 	bus_space_handle_t	sc_ioh;
115 	bus_space_handle_t	sc_sram_ioh;
116 
117 	void			*sc_ih;
118 
119 	struct rtkit_state	*sc_rs;
120 	uint8_t			sc_msgid;
121 	uint64_t		sc_data;
122 
123 	struct gpio_controller	sc_gc;
124 
125 	int			sc_rtc_node;
126 	struct todr_chip_handle sc_todr;
127 
128 	int			sc_reboot_node;
129 
130 	struct aplsmc_sensor	*sc_smcsensors[APLSMC_MAX_SENSORS];
131 	struct ksensor		sc_sensors[APLSMC_MAX_SENSORS];
132 	int			sc_nsensors;
133 	struct ksensordev	sc_sensordev;
134 };
135 
136 struct aplsmc_softc *aplsmc_sc;
137 
138 #ifndef SMALL_KERNEL
139 
140 struct aplsmc_sensor aplsmc_sensors[] = {
141 	{ "ACDI", "ui16", SENSOR_INDICATOR, 1, "power supply" },
142 	{ "B0RM", "ui16", SENSOR_AMPHOUR, 1000, "remaining battery capacity",
143 	  APLSMC_BE },
144 	{ "B0FC", "ui16", SENSOR_AMPHOUR, 1000, "last full battery capacity" },
145 	{ "B0DC", "ui16", SENSOR_AMPHOUR, 1000, "battery design capacity" },
146 	{ "B0AV", "ui16", SENSOR_VOLTS_DC, 1000, "battery" },
147 	{ "B0CT", "ui16", SENSOR_INTEGER, 1, "battery discharge cycles" },
148 	{ "B0TF", "ui16", SENSOR_INTEGER, 1, "battery time-to-full",
149 	  APLSMC_HIDDEN },
150 	{ "B0TE", "ui16", SENSOR_INTEGER, 1, "battery time-to-empty",
151 	  APLSMC_HIDDEN },
152 	{ "F0Ac", "flt ", SENSOR_FANRPM, 1, "" },
153 	{ "ID0R", "flt ", SENSOR_AMPS, 1000000, "input" },
154 	{ "PDTR", "flt ", SENSOR_WATTS, 1000000, "input" },
155 	{ "PSTR", "flt ", SENSOR_WATTS, 1000000, "system" },
156 	{ "TB0T", "flt ", SENSOR_TEMP, 1000000, "battery" },
157 	{ "TCHP", "flt ", SENSOR_TEMP, 1000000, "charger" },
158 	{ "TW0P", "flt ", SENSOR_TEMP, 1000000, "wireless" },
159 	{ "Ts0P", "flt ", SENSOR_TEMP, 1000000, "palm rest" },
160 	{ "Ts1P", "flt ", SENSOR_TEMP, 1000000, "palm rest" },
161 	{ "VD0R", "flt ", SENSOR_VOLTS_DC, 1000000, "input" },
162 };
163 
164 #endif
165 
166 int	aplsmc_match(struct device *, void *, void *);
167 void	aplsmc_attach(struct device *, struct device *, void *);
168 
169 const struct cfattach aplsmc_ca = {
170 	sizeof (struct aplsmc_softc), aplsmc_match, aplsmc_attach
171 };
172 
173 struct cfdriver aplsmc_cd = {
174 	NULL, "aplsmc", DV_DULL
175 };
176 
177 void	aplsmc_callback(void *, uint64_t);
178 int	aplsmc_send_cmd(struct aplsmc_softc *, uint16_t, uint32_t, uint16_t);
179 int	aplsmc_wait_cmd(struct aplsmc_softc *sc);
180 int	aplsmc_read_key(struct aplsmc_softc *, uint32_t, void *, size_t);
181 int	aplsmc_write_key(struct aplsmc_softc *, uint32_t, void *, size_t);
182 void	aplsmc_refresh_sensors(void *);
183 int	aplsmc_apminfo(struct apm_power_info *);
184 void	aplsmc_set_pin(void *, uint32_t *, int);
185 int	aplsmc_gettime(struct todr_chip_handle *, struct timeval *);
186 int	aplsmc_settime(struct todr_chip_handle *, struct timeval *);
187 void	aplsmc_reset(void);
188 void	aplsmc_powerdown(void);
189 void	aplsmc_reboot_attachhook(struct device *);
190 
191 int
192 aplsmc_match(struct device *parent, void *match, void *aux)
193 {
194 	struct fdt_attach_args *faa = aux;
195 
196 	return OF_is_compatible(faa->fa_node, "apple,smc");
197 }
198 
199 void
200 aplsmc_attach(struct device *parent, struct device *self, void *aux)
201 {
202 	struct aplsmc_softc *sc = (struct aplsmc_softc *)self;
203 	struct fdt_attach_args *faa = aux;
204 	uint8_t data[SMC_CLKM_LEN];
205 	uint8_t ntap;
206 	int error, node;
207 #ifndef SMALL_KERNEL
208 	int i;
209 #endif
210 
211 	if (faa->fa_nreg < 1) {
212 		printf(": no registers\n");
213 		return;
214 	}
215 
216 	sc->sc_iot = faa->fa_iot;
217 	if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr,
218 	    faa->fa_reg[0].size, 0, &sc->sc_ioh)) {
219 		printf(": can't map registers\n");
220 		return;
221 	}
222 
223 	sc->sc_rs = rtkit_init(faa->fa_node, NULL, RK_WAKEUP, NULL);
224 	if (sc->sc_rs == NULL) {
225 		printf(": can't map mailbox channel\n");
226 		return;
227 	}
228 
229 	error = rtkit_boot(sc->sc_rs);
230 	if (error) {
231 		printf(": can't boot firmware\n");
232 		return;
233 	}
234 
235 	error = rtkit_start_endpoint(sc->sc_rs, SMC_EP, aplsmc_callback, sc);
236 	if (error) {
237 		printf(": can't start SMC endpoint\n");
238 		return;
239 	}
240 
241 	aplsmc_send_cmd(sc, SMC_GET_SRAM_ADDR, 0, 0);
242 	error = aplsmc_wait_cmd(sc);
243 	if (error) {
244 		printf(": can't get SRAM address\n");
245 		return;
246 	}
247 
248 	if (bus_space_map(sc->sc_iot, sc->sc_data,
249 	    SMC_SRAM_SIZE, 0, &sc->sc_sram_ioh)) {
250 		printf(": can't map SRAM\n");
251 		return;
252 	}
253 
254 	printf("\n");
255 
256 	aplsmc_sc = sc;
257 
258 	node = OF_getnodebyname(faa->fa_node, "gpio");
259 	if (node) {
260 		sc->sc_gc.gc_node = node;
261 		sc->sc_gc.gc_cookie = sc;
262 		sc->sc_gc.gc_set_pin = aplsmc_set_pin;
263 		gpio_controller_register(&sc->sc_gc);
264 	}
265 
266 	/*
267 	 * Only provide TODR implementation if the "CLKM" key is
268 	 * supported by the SMC firmware.
269 	 */
270 	error = aplsmc_read_key(sc, SMC_KEY("CLKM"), &data, SMC_CLKM_LEN);
271 	node = OF_getnodebyname(faa->fa_node, "rtc");
272 	if (node && error == 0) {
273 		sc->sc_rtc_node = node;
274 		sc->sc_todr.cookie = sc;
275 		sc->sc_todr.todr_gettime = aplsmc_gettime;
276 		sc->sc_todr.todr_settime = aplsmc_settime;
277 		sc->sc_todr.todr_quality = 1000;
278 		todr_attach(&sc->sc_todr);
279 	}
280 
281 	node = OF_getnodebyname(faa->fa_node, "reboot");
282 	if (node) {
283 		sc->sc_reboot_node = node;
284 		cpuresetfn = aplsmc_reset;
285 		powerdownfn = aplsmc_powerdown;
286 		config_mountroot(self, aplsmc_reboot_attachhook);
287 	}
288 
289 	/* Enable notifications. */
290 	ntap = 1;
291 	aplsmc_write_key(sc, SMC_KEY("NTAP"), &ntap, sizeof(ntap));
292 
293 #ifndef SMALL_KERNEL
294 
295 	for (i = 0; i < nitems(aplsmc_sensors); i++) {
296 		struct smc_key_info info;
297 
298 		aplsmc_send_cmd(sc, SMC_GET_KEY_INFO,
299 		    SMC_KEY(aplsmc_sensors[i].key), 0);
300 		error = aplsmc_wait_cmd(sc);
301 		if (error || SMC_ERROR(sc->sc_data) != SMC_OK)
302 			continue;
303 
304 		bus_space_read_region_1(sc->sc_iot, sc->sc_sram_ioh, 0,
305 		    (uint8_t *)&info, sizeof(info));
306 
307 		/* Skip if the key type doesn't match. */
308 		if (memcmp(aplsmc_sensors[i].key_type, info.type,
309 		    sizeof(info.type)) != 0)
310 			continue;
311 
312 		if (sc->sc_nsensors >= APLSMC_MAX_SENSORS) {
313 			printf("%s: maximum number of sensors exceeded\n",
314 			    sc->sc_dev.dv_xname);
315 			break;
316 		}
317 
318 		sc->sc_smcsensors[sc->sc_nsensors] = &aplsmc_sensors[i];
319 		strlcpy(sc->sc_sensors[sc->sc_nsensors].desc,
320 		    aplsmc_sensors[i].desc, sizeof(sc->sc_sensors[0].desc));
321 		sc->sc_sensors[sc->sc_nsensors].type = aplsmc_sensors[i].type;
322 		if (!(aplsmc_sensors[i].flags & APLSMC_HIDDEN)) {
323 			sensor_attach(&sc->sc_sensordev,
324 			    &sc->sc_sensors[sc->sc_nsensors]);
325 		}
326 		sc->sc_nsensors++;
327 	}
328 
329 	aplsmc_refresh_sensors(sc);
330 
331 	strlcpy(sc->sc_sensordev.xname, sc->sc_dev.dv_xname,
332 	    sizeof(sc->sc_sensordev.xname));
333 	sensordev_install(&sc->sc_sensordev);
334 	sensor_task_register(sc, aplsmc_refresh_sensors, 5);
335 
336 #if NAPM > 0
337 	apm_setinfohook(aplsmc_apminfo);
338 #endif
339 
340 #endif
341 
342 #ifdef SUSPEND
343 	device_register_wakeup(&sc->sc_dev);
344 #endif
345 }
346 
347 void
348 aplsmc_handle_notification(struct aplsmc_softc *sc, uint64_t data)
349 {
350 	extern int allowpowerdown;
351 #ifdef SUSPEND
352 	extern int cpu_suspended;
353 	extern void suspend(void);
354 
355 	if (cpu_suspended) {
356 		switch (SMC_EV_TYPE(data)) {
357 		case SMC_EV_TYPE_BTN:
358 			switch (SMC_EV_SUBTYPE(data)) {
359 			case SMC_PWRBTN_SHORT:
360 			case SMC_PWRBTN_TOUCHID:
361 				cpu_suspended = 0;
362 				break;
363 			}
364 			break;
365 		case SMC_EV_TYPE_LID:
366 			switch (SMC_EV_SUBTYPE(data)) {
367 			case SMC_LID_OPEN:
368 				cpu_suspended = 0;
369 				break;
370 			}
371 			break;
372 		}
373 
374 		return;
375 	}
376 #endif
377 
378 	switch (SMC_EV_TYPE(data)) {
379 	case SMC_EV_TYPE_BTN:
380 		switch (SMC_EV_SUBTYPE(data)) {
381 		case SMC_PWRBTN_SHORT:
382 		case SMC_PWRBTN_TOUCHID:
383 			if (SMC_EV_DATA(data) == 1) {
384 				if (allowpowerdown) {
385 					allowpowerdown = 0;
386 					prsignal(initprocess, SIGUSR2);
387 				}
388 			}
389 			break;
390 		case SMC_PWRBTN_LONG:
391 			break;
392 		case SMC_PWRBTN_OFF:
393 			/* XXX Do emergency shutdown? */
394 			break;
395 		default:
396 			printf("%s: SMV_EV_TYPE_BTN 0x%016llx\n",
397 			       sc->sc_dev.dv_xname, data);
398 			break;
399 		}
400 		break;
401 	case SMC_EV_TYPE_LID:
402 		switch (lid_action) {
403 		case 0:
404 			switch (SMC_EV_SUBTYPE(data)) {
405 			case SMC_LID_OPEN:
406 				if (simplefb_burn_hook)
407 					simplefb_burn_hook(1);
408 				break;
409 			case SMC_LID_CLOSE:
410 				if (simplefb_burn_hook)
411 					simplefb_burn_hook(0);
412 				break;
413 			default:
414 				printf("%s: SMV_EV_TYPE_LID 0x%016llx\n",
415 				       sc->sc_dev.dv_xname, data);
416 				break;
417 			}
418 		case 1:
419 #ifdef SUSPEND
420 			suspend();
421 #endif
422 			break;
423 		case 2:
424 			/* XXX: hibernate */
425 			break;
426 		}
427 		break;
428 	default:
429 #ifdef APLSMC_DEBUG
430 		printf("%s: unhandled event 0x%016llx\n",
431 		    sc->sc_dev.dv_xname, data);
432 #endif
433 		break;
434 	}
435 }
436 
437 void
438 aplsmc_callback(void *arg, uint64_t data)
439 {
440 	struct aplsmc_softc *sc = arg;
441 
442 	if (SMC_CMD(data) == SMC_NOTIFICATION) {
443 		aplsmc_handle_notification(sc, data);
444 		return;
445 	}
446 
447 	sc->sc_data = data;
448 	wakeup(&sc->sc_data);
449 }
450 
451 int
452 aplsmc_send_cmd(struct aplsmc_softc *sc, uint16_t cmd, uint32_t key,
453     uint16_t len)
454 {
455 	uint64_t data;
456 
457 	data = cmd;
458 	data |= (uint64_t)len << 16;
459 	data |= (uint64_t)key << 32;
460 	data |= (sc->sc_msgid++ & 0xf) << 12;
461 
462 	return rtkit_send_endpoint(sc->sc_rs, SMC_EP, data);
463 }
464 
465 int
466 aplsmc_wait_cmd(struct aplsmc_softc *sc)
467 {
468 	if (cold) {
469 		int error, timo;
470 
471 		/* Poll for completion. */
472 		for (timo = 1000; timo > 0; timo--) {
473 			error = rtkit_poll(sc->sc_rs);
474 			if (error == 0)
475 				return 0;
476 			delay(10);
477 		}
478 
479 		return EWOULDBLOCK;
480 	}
481 
482 	/* Sleep until the callback wakes us up. */
483 	return tsleep_nsec(&sc->sc_data, PWAIT, "apsmc", 10000000);
484 }
485 
486 int
487 aplsmc_read_key(struct aplsmc_softc *sc, uint32_t key, void *data, size_t len)
488 {
489 	int error;
490 
491 	aplsmc_send_cmd(sc, SMC_READ_KEY, key, len);
492 	error = aplsmc_wait_cmd(sc);
493 	if (error)
494 		return error;
495 	switch (SMC_ERROR(sc->sc_data)) {
496 	case SMC_OK:
497 		break;
498 	case SMC_KEYNOTFOUND:
499 		return EINVAL;
500 		break;
501 	default:
502 		return EIO;
503 		break;
504 	}
505 
506 	len = min(len, (sc->sc_data >> 16) & 0xffff);
507 	if (len > sizeof(uint32_t)) {
508 		bus_space_read_region_1(sc->sc_iot, sc->sc_sram_ioh, 0,
509 		    data, len);
510 	} else {
511 		uint32_t tmp = (sc->sc_data >> 32);
512 		memcpy(data, &tmp, len);
513 	}
514 
515 	return 0;
516 }
517 
518 int
519 aplsmc_write_key(struct aplsmc_softc *sc, uint32_t key, void *data, size_t len)
520 {
521 	bus_space_write_region_1(sc->sc_iot, sc->sc_sram_ioh, 0, data, len);
522 	bus_space_barrier(sc->sc_iot, sc->sc_sram_ioh, 0, len,
523 	    BUS_SPACE_BARRIER_WRITE);
524 	aplsmc_send_cmd(sc, SMC_WRITE_KEY, key, len);
525 	return aplsmc_wait_cmd(sc);
526 }
527 
528 #ifndef SMALL_KERNEL
529 
530 void
531 aplsmc_refresh_sensors(void *arg)
532 {
533 	extern int hw_power;
534 	struct aplsmc_softc *sc = arg;
535 	struct aplsmc_sensor *sensor;
536 	int64_t value;
537 	uint32_t key;
538 	int i, error;
539 
540 	for (i = 0; i < sc->sc_nsensors; i++) {
541 		sensor = sc->sc_smcsensors[i];
542 		key = SMC_KEY(sensor->key);
543 
544 		if (strcmp(sensor->key_type, "ui8 ") == 0) {
545 			uint8_t ui8;
546 
547 			error = aplsmc_read_key(sc, key, &ui8, sizeof(ui8));
548 			value = (int64_t)ui8 * sensor->scale;
549 		} else if (strcmp(sensor->key_type, "ui16") == 0) {
550 			uint16_t ui16;
551 
552 			error = aplsmc_read_key(sc, key, &ui16, sizeof(ui16));
553 			if (sensor->flags & APLSMC_BE)
554 				ui16 = betoh16(ui16);
555 			value = (int64_t)ui16 * sensor->scale;
556 		} else if (strcmp(sensor->key_type, "flt ") == 0) {
557 			uint32_t flt;
558 			int64_t mant;
559 			int sign, exp;
560 
561 			error = aplsmc_read_key(sc, key, &flt, sizeof(flt));
562 			if (sensor->flags & APLSMC_BE)
563 				flt = betoh32(flt);
564 
565 			/*
566 			 * Convert floating-point to integer, trying
567 			 * to keep as much resolution as possible
568 			 * given the scaling factor for this sensor.
569 			 */
570 			sign = (flt >> 31) ? -1 : 1;
571 			exp = ((flt >> 23) & 0xff) - 127;
572 			mant = (flt & 0x7fffff) | 0x800000;
573 			mant *= sensor->scale;
574 			if (exp < 23)
575 				value = sign * (mant >> (23 - exp));
576 			else
577 				value = sign * (mant << (exp - 23));
578 		}
579 
580 		/* Apple reports temperatures in degC. */
581 		if (sensor->type == SENSOR_TEMP)
582 			value += 273150000;
583 
584 		if (error) {
585 			sc->sc_sensors[i].flags |= SENSOR_FUNKNOWN;
586 		} else {
587 			sc->sc_sensors[i].flags &= ~SENSOR_FUNKNOWN;
588 			sc->sc_sensors[i].value = value;
589 		}
590 
591 		if (strcmp(sensor->key, "ACDI") == 0)
592 			hw_power = (value > 0);
593 	}
594 }
595 
596 #if NAPM > 0
597 
598 int
599 aplsmc_apminfo(struct apm_power_info *info)
600 {
601 	struct aplsmc_sensor *sensor;
602 	struct ksensor *ksensor;
603 	struct aplsmc_softc *sc = aplsmc_sc;
604 	int remaining = -1, capacity = -1, i;
605 
606 	info->battery_state = APM_BATT_UNKNOWN;
607 	info->ac_state = APM_AC_UNKNOWN;
608 	info->battery_life = 0;
609 	info->minutes_left = -1;
610 
611 	for (i = 0; i < sc->sc_nsensors; i++) {
612 		sensor = sc->sc_smcsensors[i];
613 		ksensor = &sc->sc_sensors[i];
614 
615 		if (ksensor->flags & SENSOR_FUNKNOWN)
616 			continue;
617 
618 		if (strcmp(sensor->key, "ACDI") == 0) {
619 			info->ac_state = ksensor->value ?
620 				APM_AC_ON : APM_AC_OFF;
621 		} else if (strcmp(sensor->key, "B0RM") == 0)
622 			remaining = ksensor->value;
623 		else if (strcmp(sensor->key, "B0FC") == 0)
624 			capacity = ksensor->value;
625 		else if ((strcmp(sensor->key, "B0TE") == 0) &&
626 			 (ksensor->value != 0xffff))
627 			info->minutes_left = ksensor->value;
628 		else if ((strcmp(sensor->key, "B0TF") == 0) &&
629 			 (ksensor->value != 0xffff)) {
630 			info->battery_state = APM_BATT_CHARGING;
631 			info->minutes_left = ksensor->value;
632 		}
633 	}
634 
635 	/* calculate remaining battery if we have sane values */
636 	if (remaining > -1 && capacity > 0) {
637 		info->battery_life = ((remaining * 100) / capacity);
638 		if (info->battery_state != APM_BATT_CHARGING) {
639 			if (info->battery_life > 50)
640 				info->battery_state = APM_BATT_HIGH;
641 			else if (info->battery_life > 25)
642 				info->battery_state = APM_BATT_LOW;
643 			else
644 				info->battery_state = APM_BATT_CRITICAL;
645 		}
646 	}
647 
648 	return 0;
649 }
650 
651 #endif
652 #endif
653 
654 void
655 aplsmc_set_pin(void *cookie, uint32_t *cells, int val)
656 {
657 	struct aplsmc_softc *sc = cookie;
658 	static char *digits = "0123456789abcdef";
659 	uint32_t pin = cells[0];
660 	uint32_t flags = cells[1];
661 	uint32_t key = SMC_KEY("gP\0\0");
662 	uint32_t data;
663 
664 	KASSERT(pin < 256);
665 
666 	key |= (digits[(pin >> 0) & 0xf] << 0);
667 	key |= (digits[(pin >> 4) & 0xf] << 8);
668 
669 	if (flags & GPIO_ACTIVE_LOW)
670 		val = !val;
671 	data = SMC_GPIO_CMD_OUTPUT | !!val;
672 
673 	aplsmc_write_key(sc, key, &data, sizeof(data));
674 }
675 
676 int
677 aplsmc_gettime(struct todr_chip_handle *handle, struct timeval *tv)
678 {
679 	struct aplsmc_softc *sc = handle->cookie;
680 	uint8_t data[8] = {};
681 	uint64_t offset, time;
682 	int error;
683 
684 	error = nvmem_read_cell(sc->sc_rtc_node, "rtc_offset", &data,
685 	    RTC_OFFSET_LEN);
686 	if (error)
687 		return error;
688 	offset = lemtoh64(data);
689 
690 	error = aplsmc_read_key(sc, SMC_KEY("CLKM"), &data, SMC_CLKM_LEN);
691 	if (error)
692 		return error;
693 	time = lemtoh64(data) + offset;
694 
695 	tv->tv_sec = (time >> 15);
696 	tv->tv_usec = (((time & 0x7fff) * 1000000) >> 15);
697 	return 0;
698 }
699 
700 int
701 aplsmc_settime(struct todr_chip_handle *handle, struct timeval *tv)
702 {
703 	struct aplsmc_softc *sc = handle->cookie;
704 	uint8_t data[8] = {};
705 	uint64_t offset, time;
706 	int error;
707 
708 	error = aplsmc_read_key(sc, SMC_KEY("CLKM"), &data, SMC_CLKM_LEN);
709 	if (error)
710 		return error;
711 
712 	time = ((uint64_t)tv->tv_sec << 15);
713 	time |= ((uint64_t)tv->tv_usec << 15) / 1000000;
714 	offset = time - lemtoh64(data);
715 
716 	htolem64(data, offset);
717 	return nvmem_write_cell(sc->sc_rtc_node, "rtc_offset", &data,
718 	    RTC_OFFSET_LEN);
719 }
720 
721 void
722 aplsmc_reboot_attachhook(struct device *self)
723 {
724 	struct aplsmc_softc *sc = (struct aplsmc_softc *)self;
725 	uint8_t count = 0;
726 
727 	/* Reset error counters. */
728 	nvmem_write_cell(sc->sc_reboot_node, "boot_error_count",
729 	    &count, sizeof(count));
730 	nvmem_write_cell(sc->sc_reboot_node, "panic_count",
731 	    &count, sizeof(count));
732 }
733 
734 void
735 aplsmc_reset(void)
736 {
737 	struct aplsmc_softc *sc = aplsmc_sc;
738 	uint32_t key = SMC_KEY("MBSE");
739 	uint32_t rest = SMC_KEY("rest");
740 	uint32_t phra = SMC_KEY("phra");
741 	uint8_t boot_stage = 0;
742 
743 	aplsmc_write_key(sc, key, &rest, sizeof(rest));
744 	nvmem_write_cell(sc->sc_reboot_node, "boot_stage",
745 	    &boot_stage, sizeof(boot_stage));
746 	aplsmc_write_key(sc, key, &phra, sizeof(phra));
747 }
748 
749 void
750 aplsmc_powerdown(void)
751 {
752 	struct aplsmc_softc *sc = aplsmc_sc;
753 	uint32_t key = SMC_KEY("MBSE");
754 	uint32_t offw = SMC_KEY("offw");
755 	uint32_t off1 = SMC_KEY("off1");
756 	uint8_t boot_stage = 0;
757 	uint8_t shutdown_flag = 1;
758 
759 	aplsmc_write_key(sc, key, &offw, sizeof(offw));
760 	nvmem_write_cell(sc->sc_reboot_node, "boot_stage",
761 	    &boot_stage, sizeof(boot_stage));
762 	nvmem_write_cell(sc->sc_reboot_node, "shutdown_flag",
763 	    &shutdown_flag, sizeof(shutdown_flag));
764 	aplsmc_write_key(sc, key, &off1, sizeof(off1));
765 }
766