xref: /netbsd-src/sys/arch/macppc/dev/pmu.c (revision b1c86f5f087524e68db12794ee9c3e3da1ab17a0)
1 /*	$NetBSD: pmu.c,v 1.17 2009/12/12 14:44:09 tsutsui Exp $ */
2 
3 /*-
4  * Copyright (c) 2006 Michael Lorenz
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
17  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
20  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26  * POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 #include <sys/cdefs.h>
30 __KERNEL_RCSID(0, "$NetBSD: pmu.c,v 1.17 2009/12/12 14:44:09 tsutsui Exp $");
31 
32 #include <sys/param.h>
33 #include <sys/systm.h>
34 #include <sys/kernel.h>
35 #include <sys/device.h>
36 #include <sys/proc.h>
37 #include <sys/kthread.h>
38 
39 #include <machine/bus.h>
40 #include <machine/pio.h>
41 #include <machine/autoconf.h>
42 #include <dev/clock_subr.h>
43 #include <dev/i2c/i2cvar.h>
44 
45 #include <macppc/dev/viareg.h>
46 #include <macppc/dev/pmuvar.h>
47 #include <macppc/dev/batteryvar.h>
48 
49 #include <dev/ofw/openfirm.h>
50 #include <dev/adb/adbvar.h>
51 #include "opt_pmu.h"
52 #include "nadb.h"
53 
54 #ifdef PMU_DEBUG
55 #define DPRINTF printf
56 #else
57 #define DPRINTF while (0) printf
58 #endif
59 
60 #define PMU_NOTREADY	0x1	/* has not been initialized yet */
61 #define PMU_IDLE	0x2	/* the bus is currently idle */
62 #define PMU_OUT		0x3	/* sending out a command */
63 #define PMU_IN		0x4	/* receiving data */
64 
65 static void pmu_attach(struct device *, struct device *, void *);
66 static int pmu_match(struct device *, struct cfdata *, void *);
67 static void pmu_autopoll(void *, int);
68 
69 static int pmu_intr(void *);
70 
71 struct pmu_softc {
72 	struct device sc_dev;
73 	void *sc_ih;
74 	struct todr_chip_handle sc_todr;
75 	struct adb_bus_accessops sc_adbops;
76 	struct i2c_controller sc_i2c;
77 	struct pmu_ops sc_pmu_ops;
78 	bus_space_tag_t sc_memt;
79 	bus_space_handle_t sc_memh;
80 	uint32_t sc_flags;
81 #define PMU_HAS_BACKLIGHT_CONTROL	1
82 	int sc_node;
83 	int sc_iic_done;
84 	int sc_error;
85 	int sc_autopoll;
86 	int sc_pending_eject;
87 	int sc_brightness, sc_brightness_wanted;
88 	int sc_volume, sc_volume_wanted;
89 	/* deferred processing */
90 	lwp_t *sc_thread;
91 	/* signalling the event thread */
92 	int sc_event;
93 	/* ADB */
94 	void (*sc_adb_handler)(void *, int, uint8_t *);
95 	void *sc_adb_cookie;
96 	void (*sc_callback)(void *);
97 	void *sc_cb_cookie;
98 };
99 
100 CFATTACH_DECL(pmu, sizeof(struct pmu_softc),
101     pmu_match, pmu_attach, NULL, NULL);
102 
103 static inline void pmu_write_reg(struct pmu_softc *, int, uint8_t);
104 static inline uint8_t pmu_read_reg(struct pmu_softc *, int);
105 static void pmu_in(struct pmu_softc *);
106 static void pmu_out(struct pmu_softc *);
107 static void pmu_ack_off(struct pmu_softc *);
108 static void pmu_ack_on(struct pmu_softc *);
109 static int pmu_intr_state(struct pmu_softc *);
110 
111 static void pmu_init(struct pmu_softc *);
112 static void pmu_thread(void *);
113 static void pmu_eject_card(struct pmu_softc *, int);
114 static void pmu_update_brightness(struct pmu_softc *);
115 static void pmu_register_callback(void *, void (*)(void *), void *);
116 /*
117  * send a message to the PMU.
118  */
119 static int pmu_send(void *, int, int, uint8_t *, int, uint8_t *);
120 static void pmu_adb_poll(void *);
121 static int pmu_todr_set(todr_chip_handle_t, struct timeval *);
122 static int pmu_todr_get(todr_chip_handle_t, struct timeval *);
123 
124 static int pmu_adb_handler(void *, int, uint8_t *);
125 
126 static struct pmu_softc *pmu0 = NULL;
127 
128 /* ADB bus attachment stuff */
129 static 	int pmu_adb_send(void *, int, int, int, uint8_t *);
130 static	int pmu_adb_set_handler(void *, void (*)(void *, int, uint8_t *), void *);
131 
132 /* i2c stuff */
133 #if 0
134 static int pmu_i2c_acquire_bus(void *, int);
135 static void pmu_i2c_release_bus(void *, int);
136 static int pmu_i2c_exec(void *, i2c_op_t, i2c_addr_t, const void *, size_t,
137 		    void *, size_t, int);
138 #endif
139 
140 static void pmu_attach_legacy_battery(struct pmu_softc *);
141 static void pmu_attach_smart_battery(struct pmu_softc *, int);
142 static int  pmu_print(void *, const char *);
143 
144 /* these values shows that number of data returned after 'send' cmd is sent */
145 static signed char pm_send_cmd_type[] = {
146 	  -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
147 	  -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
148 	0x01, 0x01,   -1,   -1,   -1,   -1,   -1,   -1,
149 	0x00, 0x00,   -1,   -1,   -1,   -1,   -1, 0x00,
150 	  -1, 0x00, 0x02, 0x01, 0x01,   -1,   -1,   -1,
151 	0x00,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
152 	0x04, 0x14,   -1, 0x03,   -1,   -1,   -1,   -1,
153 	0x00, 0x00, 0x02, 0x02,   -1,   -1,   -1,   -1,
154 	0x01, 0x01,   -1,   -1,   -1,   -1,   -1,   -1,
155 	0x00, 0x00,   -1,   -1, 0x01,   -1,   -1,   -1,
156 	0x01, 0x00, 0x02, 0x02,   -1, 0x01, 0x03, 0x01,
157 	0x00, 0x01, 0x00, 0x00, 0x00,   -1,   -1,   -1,
158 	0x02,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
159 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00,   -1,   -1,
160 	0x01, 0x01, 0x01,   -1,   -1,   -1,   -1,   -1,
161 	0x00, 0x00,   -1,   -1,   -1,   -1, 0x04, 0x04,
162 	0x04,   -1, 0x00,   -1,   -1,   -1,   -1,   -1,
163 	0x00,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
164 	0x01, 0x02,   -1,   -1,   -1,   -1,   -1,   -1,
165 	0x00, 0x00,   -1,   -1,   -1,   -1,   -1,   -1,
166 	0x02, 0x02, 0x02, 0x04,   -1, 0x00,   -1,   -1,
167 	0x01, 0x01, 0x03, 0x02,   -1,   -1,   -1,   -1,
168 	  -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
169 	  -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
170 	  -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
171 	  -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
172 	0x00,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
173 	0x01, 0x01,   -1,   -1, 0x00, 0x00,   -1,   -1,
174 	  -1, 0x04, 0x00,   -1,   -1,   -1,   -1,   -1,
175 	0x03,   -1, 0x00,   -1, 0x00,   -1,   -1, 0x00,
176 	  -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
177 	  -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1
178 };
179 
180 /* these values shows that number of data returned after 'receive' cmd is sent */
181 static signed char pm_receive_cmd_type[] = {
182 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
183 	  -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
184 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
185 	0x02, 0x02,   -1,   -1,   -1,   -1,   -1, 0x00,
186 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
187 	  -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
188 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
189 	0x05, 0x15,   -1, 0x02,   -1,   -1,   -1,   -1,
190 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
191 	0x02, 0x02,   -1,   -1,   -1,   -1,   -1,   -1,
192 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
193 	0x02, 0x00, 0x03, 0x03,   -1,   -1,   -1,   -1,
194 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
195 	0x04, 0x04, 0x03, 0x09,   -1,   -1,   -1,   -1,
196 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
197 	  -1,   -1,   -1,   -1,   -1,   -1, 0x01, 0x01,
198 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
199 	0x06,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
200 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
201 	0x02, 0x02,   -1,   -1,   -1,   -1,   -1,   -1,
202 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
203 	0x02, 0x00, 0x00, 0x00,   -1,   -1,   -1,   -1,
204 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
205 	  -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
206 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
207 	  -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
208 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
209 	0x02, 0x02,   -1,   -1, 0x02,   -1,   -1,   -1,
210 	0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
211 	  -1,   -1, 0x02,   -1,   -1,   -1,   -1, 0x00,
212 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
213 	  -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
214 };
215 
216 static const char *has_legacy_battery[] = {
217 	"AAPL,3500",
218 	"AAPL,3400/2400",
219 	NULL };
220 
221 static const char *has_two_smart_batteries[] = {
222 	"AAPL,PowerBook1998",
223 	"PowerBook1,1",
224 	NULL };
225 
226 static int
227 pmu_match(struct device *parent, struct cfdata *cf, void *aux)
228 {
229 	struct confargs *ca = aux;
230 
231 	if (ca->ca_nreg < 8)
232 		return 0;
233 
234 	if (ca->ca_nintr < 4)
235 		return 0;
236 
237 	if (strcmp(ca->ca_name, "via-pmu") == 0) {
238 		return 10;
239 	}
240 
241 	return 0;
242 }
243 
244 static void
245 pmu_attach(struct device *parent, struct device *dev, void *aux)
246 {
247 	struct confargs *ca = aux;
248 	struct pmu_softc *sc = (struct pmu_softc *)dev;
249 #if notyet
250 	struct i2cbus_attach_args iba;
251 #endif
252 	uint32_t regs[16];
253 	int irq = ca->ca_intr[0];
254 	int node, extint_node, root_node;
255 	int nbat = 1, i, pmnode;
256 	int type = IST_EDGE;
257 	uint8_t cmd[2] = {2, 0};
258 	uint8_t resp[16];
259 	char name[256];
260 
261 	extint_node = of_getnode_byname(OF_parent(ca->ca_node), "extint-gpio1");
262 	if (extint_node) {
263 
264 		OF_getprop(extint_node, "interrupts", &irq, 4);
265 		type = IST_LEVEL;
266 	}
267 
268 	printf(" irq %d: ", irq);
269 
270 	sc->sc_node = ca->ca_node;
271 	sc->sc_memt = ca->ca_tag;
272 
273 	root_node = OF_finddevice("/");
274 
275 	sc->sc_error = 0;
276 	sc->sc_autopoll = 0;
277 	sc->sc_pending_eject = 0;
278 	sc->sc_brightness = sc->sc_brightness_wanted = 0x80;
279 	sc->sc_volume = sc->sc_volume_wanted = 0x80;
280 	sc->sc_flags = 0;
281 	sc->sc_callback = NULL;
282 
283 	if (bus_space_map(sc->sc_memt, ca->ca_reg[0] + ca->ca_baseaddr,
284 	    ca->ca_reg[1], 0, &sc->sc_memh) != 0) {
285 
286 		printf("%s: unable to map registers\n", dev->dv_xname);
287 		return;
288 	}
289 	sc->sc_ih = intr_establish(irq, type, IPL_TTY, pmu_intr, sc);
290 
291 	pmu_init(sc);
292 
293 	sc->sc_pmu_ops.cookie = sc;
294 	sc->sc_pmu_ops.do_command = pmu_send;
295 	sc->sc_pmu_ops.register_callback = pmu_register_callback;
296 
297 	if (pmu0 == NULL)
298 		pmu0 = sc;
299 
300 	pmu_send(sc, PMU_SYSTEM_READY, 1, cmd, 16, resp);
301 
302 	/* check what kind of PMU we're talking to */
303 	if (pmu_send(sc, PMU_GET_VERSION, 0, cmd, 16, resp) > 1)
304 		printf(" rev. %d", resp[1]);
305 	printf("\n");
306 
307 	node = OF_child(sc->sc_node);
308 
309 	while (node != 0) {
310 
311 		if (OF_getprop(node, "name", name, 256) == 0)
312 			goto next;
313 
314 		if (strncmp(name, "pmu-i2c", 8) == 0) {
315 
316 			printf("%s: initializing IIC bus\n",
317 			    sc->sc_dev.dv_xname);
318 			goto next;
319 		}
320 		if (strncmp(name, "adb", 4) == 0) {
321 
322 			printf("%s: initializing ADB\n", sc->sc_dev.dv_xname);
323 			sc->sc_adbops.cookie = sc;
324 			sc->sc_adbops.send = pmu_adb_send;
325 			sc->sc_adbops.poll = pmu_adb_poll;
326 			sc->sc_adbops.autopoll = pmu_autopoll;
327 			sc->sc_adbops.set_handler = pmu_adb_set_handler;
328 #if NNADB > 0
329 			config_found_ia(dev, "adb_bus", &sc->sc_adbops,
330 			    nadb_print);
331 #endif
332 			goto next;
333 		}
334 		if (strncmp(name, "rtc", 4) == 0) {
335 
336 			printf("%s: initializing RTC\n", sc->sc_dev.dv_xname);
337 			sc->sc_todr.todr_gettime = pmu_todr_get;
338 			sc->sc_todr.todr_settime = pmu_todr_set;
339 			sc->sc_todr.cookie = sc;
340 			todr_attach(&sc->sc_todr);
341 			goto next;
342 		}
343 		if (strncmp(name, "battery", 8) == 0)
344 			goto next;
345 
346 		printf("%s: %s not configured\n", sc->sc_dev.dv_xname, name);
347 next:
348 		node = OF_peer(node);
349 	}
350 
351 	if (OF_finddevice("/bandit/ohare") != -1) {
352 		printf("%s: enabling ohare backlight control\n",
353 		    device_xname(dev));
354 		sc->sc_flags |= PMU_HAS_BACKLIGHT_CONTROL;
355 		cmd[0] = 0;
356 		cmd[1] = 0;
357 		memset(resp, 0, 6);
358 		if (pmu_send(sc, PMU_READ_BRIGHTNESS, 1, cmd, 16, resp) > 1) {
359 			sc->sc_brightness_wanted = resp[1];
360 			pmu_update_brightness(sc);
361 		}
362 	}
363 
364 	/* attach batteries */
365 	if (of_compatible(root_node, has_legacy_battery) != -1) {
366 
367 		pmu_attach_legacy_battery(sc);
368 	} else if (of_compatible(root_node, has_two_smart_batteries) != -1) {
369 
370 		pmu_attach_smart_battery(sc, 0);
371 		pmu_attach_smart_battery(sc, 1);
372 	} else {
373 
374 		/* check how many batteries we have */
375 		pmnode = of_getnode_byname(ca->ca_node, "power-mgt");
376 		if (pmnode == -1)
377 			goto bat_done;
378 		if (OF_getprop(pmnode, "prim-info", regs, sizeof(regs)) < 24)
379 			goto bat_done;
380 		nbat = regs[6] >> 16;
381 		for (i = 0; i < nbat; i++)
382 			pmu_attach_smart_battery(sc, i);
383 	}
384 bat_done:
385 
386 #if notyet
387 	iba.iba_tag = &sc->sc_i2c;
388 	sc->sc_i2c.ic_cookie = sc;
389 	sc->sc_i2c.ic_acquire_bus = pmu_i2c_acquire_bus;
390 	sc->sc_i2c.ic_release_bus = pmu_i2c_release_bus;
391 	sc->sc_i2c.ic_send_start = NULL;
392 	sc->sc_i2c.ic_send_stop = NULL;
393 	sc->sc_i2c.ic_initiate_xfer = NULL;
394 	sc->sc_i2c.ic_read_byte = NULL;
395 	sc->sc_i2c.ic_write_byte = NULL;
396 	sc->sc_i2c.ic_exec = pmu_i2c_exec;
397 	config_found_ia(&sc->sc_dev, "i2cbus", &iba, iicbus_print);
398 #endif
399 
400 	if (kthread_create(PRI_NONE, 0, NULL, pmu_thread, sc, &sc->sc_thread,
401 	    "%s", "pmu") != 0) {
402 		printf("pmu: unable to create event kthread");
403 	}
404 }
405 
406 static void
407 pmu_register_callback(void *pmu_cookie, void (*cb)(void *), void *cookie)
408 {
409 	struct pmu_softc *sc = pmu_cookie;
410 
411 	sc->sc_callback = cb;
412 	sc->sc_cb_cookie = cookie;
413 }
414 
415 static void
416 pmu_init(struct pmu_softc *sc)
417 {
418 	uint8_t pmu_imask, resp[16];
419 
420 	pmu_imask =
421 	    PMU_INT_PCEJECT | PMU_INT_SNDBRT | PMU_INT_ADB/* | PMU_INT_TICK*/;
422 	pmu_imask |= PMU_INT_BATTERY;
423 	pmu_imask |= PMU_INT_ENVIRONMENT;
424 	pmu_send(sc, PMU_SET_IMASK, 1, &pmu_imask, 16, resp);
425 
426 	pmu_write_reg(sc, vIER, 0x90);	/* enable VIA interrupts */
427 }
428 
429 static inline void
430 pmu_write_reg(struct pmu_softc *sc, int offset, uint8_t value)
431 {
432 
433 	bus_space_write_1(sc->sc_memt, sc->sc_memh, offset, value);
434 }
435 
436 static inline uint8_t
437 pmu_read_reg(struct pmu_softc *sc, int offset)
438 {
439 
440 	return bus_space_read_1(sc->sc_memt, sc->sc_memh, offset);
441 }
442 
443 static inline int
444 pmu_send_byte(struct pmu_softc *sc, uint8_t data)
445 {
446 
447 	pmu_out(sc);
448 	pmu_write_reg(sc, vSR, data);
449 	pmu_ack_off(sc);
450 	/* wait for intr to come up */
451 	/* XXX should add a timeout and bail if it expires */
452 	do {} while (pmu_intr_state(sc) == 0);
453 	pmu_ack_on(sc);
454 	do {} while (pmu_intr_state(sc));
455 	pmu_ack_on(sc);
456 	DPRINTF(" %02x>", data);
457 	return 0;
458 }
459 
460 static inline int
461 pmu_read_byte(struct pmu_softc *sc, uint8_t *data)
462 {
463 	volatile uint8_t scratch;
464 	pmu_in(sc);
465 	scratch = pmu_read_reg(sc, vSR);
466 	pmu_ack_off(sc);
467 	/* wait for intr to come up */
468 	do {} while (pmu_intr_state(sc) == 0);
469 	pmu_ack_on(sc);
470 	do {} while (pmu_intr_state(sc));
471 	*data = pmu_read_reg(sc, vSR);
472 	DPRINTF(" <%02x", *data);
473 	return 0;
474 }
475 
476 static int
477 pmu_send(void *cookie, int cmd, int length, uint8_t *in_msg, int rlen,
478     uint8_t *out_msg)
479 {
480 	struct pmu_softc *sc = cookie;
481 	int i, rcv_len = -1, s;
482 	uint8_t out_len, intreg;
483 
484 	DPRINTF("pmu_send: ");
485 
486 	s = splhigh();
487 	intreg = pmu_read_reg(sc, vIER);
488 	intreg &= 0x10;
489 	pmu_write_reg(sc, vIER, intreg);
490 
491 	/* wait idle */
492 	do {} while (pmu_intr_state(sc));
493 	sc->sc_error = 0;
494 
495 	/* send command */
496 	pmu_send_byte(sc, cmd);
497 
498 	/* send length if necessary */
499 	if (pm_send_cmd_type[cmd] < 0) {
500 		pmu_send_byte(sc, length);
501 	}
502 
503 	for (i = 0; i < length; i++) {
504 		pmu_send_byte(sc, in_msg[i]);
505 		DPRINTF(" next ");
506 	}
507 	DPRINTF("done sending\n");
508 
509 	/* see if there's data to read */
510 	rcv_len = pm_receive_cmd_type[cmd];
511 	if (rcv_len == 0)
512 		goto done;
513 
514 	/* read command */
515 	if (rcv_len == 1) {
516 		pmu_read_byte(sc, out_msg);
517 		goto done;
518 	} else
519 		out_msg[0] = cmd;
520 	if (rcv_len < 0) {
521 		pmu_read_byte(sc, &out_len);
522 		rcv_len = out_len + 1;
523 	}
524 	for (i = 1; i < min(rcv_len, rlen); i++)
525 		pmu_read_byte(sc, &out_msg[i]);
526 
527 done:
528 	DPRINTF("\n");
529 	pmu_write_reg(sc, vIER, (intreg == 0) ? 0 : 0x90);
530 	splx(s);
531 
532 	return rcv_len;
533 }
534 
535 static void
536 pmu_adb_poll(void *cookie)
537 {
538 	struct pmu_softc *sc = cookie;
539 	int s;
540 
541 	s = spltty();
542 	pmu_intr(sc);
543 	splx(s);
544 }
545 
546 static void
547 pmu_in(struct pmu_softc *sc)
548 {
549 	uint8_t reg;
550 
551 	reg = pmu_read_reg(sc, vACR);
552 	reg &= ~vSR_OUT;
553 	reg |= 0x0c;
554 	pmu_write_reg(sc, vACR, reg);
555 }
556 
557 static void
558 pmu_out(struct pmu_softc *sc)
559 {
560 	uint8_t reg;
561 
562 	reg = pmu_read_reg(sc, vACR);
563 	reg |= vSR_OUT;
564 	reg |= 0x0c;
565 	pmu_write_reg(sc, vACR, reg);
566 }
567 
568 static void
569 pmu_ack_off(struct pmu_softc *sc)
570 {
571 	uint8_t reg;
572 
573 	reg = pmu_read_reg(sc, vBufB);
574 	reg &= ~vPB4;
575 	pmu_write_reg(sc, vBufB, reg);
576 }
577 
578 static void
579 pmu_ack_on(struct pmu_softc *sc)
580 {
581 	uint8_t reg;
582 
583 	reg = pmu_read_reg(sc, vBufB);
584 	reg |= vPB4;
585 	pmu_write_reg(sc, vBufB, reg);
586 }
587 
588 static int
589 pmu_intr_state(struct pmu_softc *sc)
590 {
591 	return ((pmu_read_reg(sc, vBufB) & vPB3) == 0);
592 }
593 
594 static int
595 pmu_intr(void *arg)
596 {
597 	struct pmu_softc *sc = arg;
598 	unsigned int len, i;
599 	uint8_t resp[16];
600 
601 	DPRINTF(":");
602 
603 	pmu_write_reg(sc, vIFR, 0x90);	/* Clear 'em */
604 	len = pmu_send(sc, PMU_INT_ACK, 0, NULL, 16, resp);
605 	if ((len < 1) || (resp[1] == 0))
606 		goto done;
607 #ifdef PMU_DEBUG
608 	{
609 		DPRINTF("intr: %02x", resp[0]);
610 		for (i = 1; i < len; i++)
611 			DPRINTF(" %02x", resp[i]);
612 		DPRINTF("\n");
613 	}
614 #endif
615 	if (resp[1] & PMU_INT_ADB) {
616 		pmu_adb_handler(sc, len - 1, &resp[1]);
617 		goto done;
618 	}
619 	if (resp[1] & PMU_INT_SNDBRT) {
620 		/* deal with the brightness / volume control buttons */
621 		DPRINTF("brightness: %d volume %d\n", resp[2], resp[3]);
622 		sc->sc_brightness_wanted = resp[2];
623 		sc->sc_volume_wanted = resp[3];
624 		wakeup(&sc->sc_event);
625 		goto done;
626 	}
627 	if (resp[1] & PMU_INT_PCEJECT) {
628 		/* deal with PCMCIA eject buttons */
629 		DPRINTF("card eject %d\n", resp[3]);
630 		sc->sc_pending_eject |= (resp[3] & 3);
631 		wakeup(&sc->sc_event);
632 		goto done;
633 	}
634 	if (resp[1] & PMU_INT_BATTERY) {
635 		/* deal with battery messages */
636 		printf("battery:");
637 		for (i = 2; i < len; i++)
638 			printf(" %02x", resp[i]);
639 		printf("\n");
640 		goto done;
641 	}
642 	if (resp[1] & PMU_INT_ENVIRONMENT) {
643 #ifdef PMU_VERBOSE
644 		/* deal with environment messages */
645 		printf("environment:");
646 		for (i = 2; i < len; i++)
647 			printf(" %02x", resp[i]);
648 		printf("\n");
649 #endif
650 		goto done;
651 	}
652 	if (resp[1] & PMU_INT_TICK) {
653 		/* don't bother */
654 		goto done;
655 	}
656 
657 	/* unknown interrupt code?! */
658 #ifdef PMU_DEBUG
659 	printf("pmu intr: %02x:", resp[1]);
660 	for (i = 2; i < len; i++)
661 		printf(" %02x", resp[i]);
662 	printf("\n");
663 #endif
664 done:
665 	return 1;
666 }
667 
668 #if 0
669 static int
670 pmu_error_handler(void *cookie, int len, uint8_t *data)
671 {
672 	struct pmu_softc *sc = cookie;
673 
674 	/*
675 	 * something went wrong
676 	 * byte 3 seems to be the failed command
677 	 */
678 	sc->sc_error = 1;
679 	wakeup(&sc->sc_todev);
680 	return 0;
681 }
682 #endif
683 #define DIFF19041970 2082844800
684 
685 static int
686 pmu_todr_get(todr_chip_handle_t tch, struct timeval *tvp)
687 {
688 	struct pmu_softc *sc = tch->cookie;
689 	uint32_t sec;
690 	uint8_t resp[16];
691 
692 	DPRINTF("pmu_todr_get\n");
693 	pmu_send(sc, PMU_READ_RTC, 0, NULL, 16, resp);
694 
695 	memcpy(&sec, &resp[1], 4);
696 	tvp->tv_sec = sec - DIFF19041970;
697 	DPRINTF("tod: %" PRIo64 "\n", tvp->tv_sec);
698 	tvp->tv_usec = 0;
699 	return 0;
700 }
701 
702 static int
703 pmu_todr_set(todr_chip_handle_t tch, struct timeval *tvp)
704 {
705 	struct pmu_softc *sc = tch->cookie;
706 	uint32_t sec;
707 	uint8_t resp[16];
708 
709 	sec = tvp->tv_sec + DIFF19041970;
710 	if (pmu_send(sc, PMU_SET_RTC, 4, (uint8_t *)&sec, 16, resp) >= 0)
711 		return 0;
712 	return -1;
713 }
714 
715 void
716 pmu_poweroff(void)
717 {
718 	struct pmu_softc *sc;
719 	uint8_t cmd[] = {'M', 'A', 'T', 'T'};
720 	uint8_t resp[16];
721 
722 	if (pmu0 == NULL)
723 		return;
724 	sc = pmu0;
725 	if (pmu_send(sc, PMU_POWER_OFF, 4, cmd, 16, resp) >= 0)
726 		while (1);
727 }
728 
729 void
730 pmu_restart(void)
731 {
732 	struct pmu_softc *sc;
733 	uint8_t resp[16];
734 
735 	if (pmu0 == NULL)
736 		return;
737 	sc = pmu0;
738 	if (pmu_send(sc, PMU_RESET_CPU, 0, NULL, 16, resp) >= 0)
739 		while (1);
740 }
741 
742 static void
743 pmu_autopoll(void *cookie, int flag)
744 {
745 	struct pmu_softc *sc = cookie;
746 	/* magical incantation to re-enable autopolling */
747 	uint8_t cmd[] = {0, PMU_SET_POLL_MASK, (flag >> 8) & 0xff, flag & 0xff};
748 	uint8_t resp[16];
749 
750 	if (sc->sc_autopoll == flag)
751 		return;
752 
753 	if (flag) {
754 		pmu_send(sc, PMU_ADB_CMD, 4, cmd, 16, resp);
755 	} else {
756 		pmu_send(sc, PMU_ADB_POLL_OFF, 0, NULL, 16, resp);
757 	}
758 	sc->sc_autopoll = flag & 0xffff;
759 }
760 
761 static int
762 pmu_adb_handler(void *cookie, int len, uint8_t *data)
763 {
764 	struct pmu_softc *sc = cookie;
765 	uint8_t resp[16];
766 
767 	if (sc->sc_adb_handler != NULL) {
768 		sc->sc_adb_handler(sc->sc_adb_cookie, len, data);
769 		/*
770 		 * the PMU will turn off autopolling after each LISTEN so we
771 		 * need to re-enable it here whenever we receive an ACK for a
772 		 * LISTEN command
773 		 */
774 		if ((data[1] & 0x0c) == 0x08) {
775 			uint8_t cmd[] = {0, 0x86, (sc->sc_autopoll >> 8) & 0xff,
776 			    sc->sc_autopoll & 0xff};
777 			pmu_send(sc, PMU_ADB_CMD, 4, cmd, 16, resp);
778 		}
779 		return 0;
780 	}
781 	return -1;
782 }
783 
784 static int
785 pmu_adb_send(void *cookie, int poll, int command, int len, uint8_t *data)
786 {
787 	struct pmu_softc *sc = cookie;
788 	int i, replen;
789 	uint8_t packet[16], resp[16];
790 
791 	/* construct an ADB command packet and send it */
792 	packet[0] = command;
793 	packet[1] = 0;
794 	packet[2] = len;
795 	for (i = 0; i < len; i++)
796 		packet[i + 3] = data[i];
797 	replen = pmu_send(sc, PMU_ADB_CMD, len + 3, packet, 16, resp);
798 
799 	return 0;
800 }
801 
802 static int
803 pmu_adb_set_handler(void *cookie, void (*handler)(void *, int, uint8_t *),
804     void *hcookie)
805 {
806 	struct pmu_softc *sc = cookie;
807 
808 	/* register a callback for incoming ADB messages */
809 	sc->sc_adb_handler = handler;
810 	sc->sc_adb_cookie = hcookie;
811 	return 0;
812 }
813 #if 0
814 static int
815 pmu_i2c_acquire_bus(void *cookie, int flags)
816 {
817 	/* nothing yet */
818 	return 0;
819 }
820 
821 static void
822 pmu_i2c_release_bus(void *cookie, int flags)
823 {
824 	/* nothing here either */
825 }
826 
827 static int
828 pmu_i2c_exec(void *cookie, i2c_op_t op, i2c_addr_t addr, const void *_send,
829     size_t send_len, void *_recv, size_t recv_len, int flags)
830 {
831 #if 0
832 	struct pmu_softc *sc = cookie;
833 	const uint8_t *send = _send;
834 	uint8_t *recv = _recv;
835 	uint8_t command[16] = {PMU_POWERMGR, PMGR_IIC};
836 
837 	DPRINTF("pmu_i2c_exec(%02x)\n", addr);
838 	command[2] = addr;
839 
840 	memcpy(&command[3], send, min((int)send_len, 12));
841 
842 	sc->sc_iic_done = 0;
843 	pmu_send(sc, sc->sc_polling, send_len + 3, command);
844 
845 	while ((sc->sc_iic_done == 0) && (sc->sc_error == 0)) {
846 		if (sc->sc_polling) {
847 			pmu_poll(sc);
848 		} else
849 			tsleep(&sc->sc_todev, 0, "i2c", 1000);
850 	}
851 
852 	if (sc->sc_error) {
853 		sc->sc_error = 0;
854 		return -1;
855 	}
856 
857 	/* see if we're supposed to do a read */
858 	if (recv_len > 0) {
859 		sc->sc_iic_done = 0;
860 		command[2] |= 1;
861 		command[3] = 0;
862 
863 		/*
864 		 * XXX we need to do something to limit the size of the answer
865 		 * - apparently the chip keeps sending until we tell it to stop
866 		 */
867 		pmu_send(sc, sc->sc_polling, 3, command);
868 		while ((sc->sc_iic_done == 0) && (sc->sc_error == 0)) {
869 			if (sc->sc_polling) {
870 				pmu_poll(sc);
871 			} else
872 				tsleep(&sc->sc_todev, 0, "i2c", 1000);
873 		}
874 
875 		if (sc->sc_error) {
876 			printf("error trying to read\n");
877 			sc->sc_error = 0;
878 			return -1;
879 		}
880 	}
881 
882 	if ((sc->sc_iic_done > 3) && (recv_len > 0)) {
883 		/* we got an answer */
884 		recv[0] = sc->sc_iic_val;
885 		printf("ret: %02x\n", sc->sc_iic_val);
886 		return 1;
887 	}
888 #endif
889 	return 0;
890 }
891 #endif
892 
893 static void
894 pmu_eject_card(struct pmu_softc *sc, int socket)
895 {
896 	int s;
897 	uint8_t buf[] = {socket | 4};
898 	uint8_t res[4];
899 
900 	s = splhigh();
901 	sc->sc_pending_eject &= ~socket;
902 	splx(s);
903 	pmu_send(sc, PMU_EJECT_PCMCIA, 1, buf, 4, res);
904 }
905 
906 static void
907 pmu_update_brightness(struct pmu_softc *sc)
908 {
909 	int val;
910 	uint8_t cmd[2], resp[16];
911 
912 	if (sc->sc_brightness == sc->sc_brightness_wanted)
913 		return;
914 
915 	if ((sc->sc_flags & PMU_HAS_BACKLIGHT_CONTROL) == 0) {
916 
917 		printf("%s: this PMU doesn't support backlight control\n",
918 			sc->sc_dev.dv_xname);
919 		sc->sc_brightness = sc->sc_brightness_wanted;
920 		return;
921 	}
922 
923 	if (sc->sc_brightness_wanted == 0) {
924 
925 		/* turn backlight off completely */
926 		cmd[0] = PMU_POW_OFF | PMU_POW_BACKLIGHT;
927 		pmu_send(sc, PMU_POWER_CTRL, 1, cmd, 16, resp);
928 		sc->sc_brightness = sc->sc_brightness_wanted;
929 
930 		/* don't bother with brightness */
931 		return;
932 	}
933 
934 	/* turn backlight on if needed */
935 	if (sc->sc_brightness == 0) {
936 		cmd[0] = PMU_POW_ON | PMU_POW_BACKLIGHT;
937 		pmu_send(sc, PMU_POWER_CTRL, 1, cmd, 16, resp);
938 	}
939 
940 	DPRINTF("pmu_update_brightness: %d -> %d\n", sc->sc_brightness,
941 	    sc->sc_brightness_wanted);
942 
943 	val = 0x7f - (sc->sc_brightness_wanted >> 1);
944 	if (val < 0x08)
945 		val = 0x08;
946 	if (val > 0x78)
947 		val = 0x78;
948 	cmd[0] = val;
949 	pmu_send(sc, PMU_SET_BRIGHTNESS, 1, cmd, 16, resp);
950 
951 	sc->sc_brightness = sc->sc_brightness_wanted;
952 }
953 
954 static void
955 pmu_thread(void *cookie)
956 {
957 	struct pmu_softc *sc = cookie;
958 	//time_t time_bat = time_second;
959 	int ticks = hz, i;
960 
961 	while (1) {
962 		tsleep(&sc->sc_event, PWAIT, "wait", ticks);
963 		if (sc->sc_pending_eject != 0) {
964 			DPRINTF("eject %d\n", sc->sc_pending_eject);
965 			for (i = 1; i < 3; i++) {
966 				if (i & sc->sc_pending_eject)
967 					pmu_eject_card(sc, i);
968 			}
969 		}
970 
971 		/* see if we need to update brightness */
972 		if (sc->sc_brightness_wanted != sc->sc_brightness) {
973 			pmu_update_brightness(sc);
974 		}
975 
976 		/* see if we need to update audio volume */
977 		if (sc->sc_volume_wanted != sc->sc_volume) {
978 #if 0
979 			set_volume(sc->sc_volume_wanted);
980 #endif
981 			sc->sc_volume = sc->sc_volume_wanted;
982 		}
983 
984 		if (sc->sc_callback != NULL)
985 			sc->sc_callback(sc->sc_cb_cookie);
986 	}
987 }
988 
989 static int
990 pmu_print(void *aux, const char *what)
991 {
992 
993 	return 0;
994 }
995 
996 static void
997 pmu_attach_legacy_battery(struct pmu_softc *sc)
998 {
999 	struct battery_attach_args baa;
1000 
1001 	baa.baa_type = BATTERY_TYPE_LEGACY;
1002 	baa.baa_pmu_ops = &sc->sc_pmu_ops;
1003 	config_found_ia(&sc->sc_dev, "pmu_bus", &baa, pmu_print);
1004 }
1005 
1006 static void
1007 pmu_attach_smart_battery(struct pmu_softc *sc, int num)
1008 {
1009 	struct battery_attach_args baa;
1010 
1011 	baa.baa_type = BATTERY_TYPE_SMART;
1012 	baa.baa_pmu_ops = &sc->sc_pmu_ops;
1013 	baa.baa_num = num;
1014 	config_found_ia(&sc->sc_dev, "pmu_bus", &baa, pmu_print);
1015 }
1016