1 /* $NetBSD: pmu.c,v 1.16 2009/03/18 10:22:32 cegger Exp $ */
4 * Copyright (c) 2006 Michael Lorenz
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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.
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.
29 #include <sys/cdefs.h>
30 __KERNEL_RCSID(0, "$NetBSD: pmu.c,v 1.16 2009/03/18 10:22:32 cegger Exp $");
32 #include <sys/param.h>
33 #include <sys/systm.h>
34 #include <sys/kernel.h>
35 #include <sys/device.h>
37 #include <sys/kthread.h>
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>
45 #include <macppc/dev/viareg.h>
46 #include <macppc/dev/pmuvar.h>
47 #include <macppc/dev/batteryvar.h>
49 #include <dev/ofw/openfirm.h>
50 #include <dev/adb/adbvar.h>
55 #define DPRINTF printf
57 #define DPRINTF while (0) printf
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 */
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);
69 static int pmu_intr(void *);
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
;
81 #define PMU_HAS_BACKLIGHT_CONTROL 1
87 int sc_brightness
, sc_brightness_wanted
;
88 int sc_volume
, sc_volume_wanted
;
89 /* deferred processing */
91 /* signalling the event thread */
94 void (*sc_adb_handler
)(void *, int, uint8_t *);
96 void (*sc_callback
)(void *);
100 CFATTACH_DECL(pmu
, sizeof(struct pmu_softc
),
101 pmu_match
, pmu_attach
, NULL
, NULL
);
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
*);
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 *);
117 * send a message to the PMU.
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
*);
124 static int pmu_adb_handler(void *, int, uint8_t *);
126 static struct pmu_softc
*pmu0
= NULL
;
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 *);
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);
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 *);
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
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,
216 static const char *has_legacy_battery
[] = {
221 static const char *has_two_smart_batteries
[] = {
222 "AAPL,PowerBook1998",
227 pmu_match(struct device
*parent
, struct cfdata
*cf
, void *aux
)
229 struct confargs
*ca
= aux
;
234 if (ca
->ca_nintr
< 4)
237 if (strcmp(ca
->ca_name
, "via-pmu") == 0) {
245 pmu_attach(struct device
*parent
, struct device
*dev
, void *aux
)
247 struct confargs
*ca
= aux
;
248 struct pmu_softc
*sc
= (struct pmu_softc
*)dev
;
250 struct i2cbus_attach_args iba
;
253 int irq
= ca
->ca_intr
[0];
254 int node
, extint_node
, root_node
;
255 int nbat
= 1, i
, pmnode
;
257 uint8_t cmd
[2] = {2, 0};
261 extint_node
= of_getnode_byname(OF_parent(ca
->ca_node
), "extint-gpio1");
264 OF_getprop(extint_node
, "interrupts", &irq
, 4);
268 printf(" irq %d: ", irq
);
270 sc
->sc_node
= ca
->ca_node
;
271 sc
->sc_memt
= ca
->ca_tag
;
273 root_node
= OF_finddevice("/");
277 sc
->sc_pending_eject
= 0;
278 sc
->sc_brightness
= sc
->sc_brightness_wanted
= 0x80;
279 sc
->sc_volume
= sc
->sc_volume_wanted
= 0x80;
281 sc
->sc_callback
= NULL
;
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) {
286 printf("%s: unable to map registers\n", dev
->dv_xname
);
289 sc
->sc_ih
= intr_establish(irq
, type
, IPL_TTY
, pmu_intr
, sc
);
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
;
300 pmu_send(sc
, PMU_SYSTEM_READY
, 1, cmd
, 16, resp
);
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]);
307 node
= OF_child(sc
->sc_node
);
311 if (OF_getprop(node
, "name", name
, 256) == 0)
314 if (strncmp(name
, "pmu-i2c", 8) == 0) {
316 printf("%s: initializing IIC bus\n",
317 sc
->sc_dev
.dv_xname
);
320 if (strncmp(name
, "adb", 4) == 0) {
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
;
329 config_found_ia(dev
, "adb_bus", &sc
->sc_adbops
,
334 if (strncmp(name
, "rtc", 4) == 0) {
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
);
343 if (strncmp(name
, "battery", 8) == 0)
346 printf("%s: %s not configured\n", sc
->sc_dev
.dv_xname
, name
);
348 node
= OF_peer(node
);
351 if (OF_finddevice("/bandit/ohare") != -1) {
352 printf("%s: enabling ohare backlight control\n",
354 sc
->sc_flags
|= PMU_HAS_BACKLIGHT_CONTROL
;
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
);
364 /* attach batteries */
365 if (of_compatible(root_node
, has_legacy_battery
) != -1) {
367 pmu_attach_legacy_battery(sc
);
368 } else if (of_compatible(root_node
, has_two_smart_batteries
) != -1) {
370 pmu_attach_smart_battery(sc
, 0);
371 pmu_attach_smart_battery(sc
, 1);
374 /* check how many batteries we have */
375 pmnode
= of_getnode_byname(ca
->ca_node
, "power-mgt");
378 if (OF_getprop(pmnode
, "prim-info", regs
, sizeof(regs
)) < 24)
380 nbat
= regs
[6] >> 16;
381 for (i
= 0; i
< nbat
; i
++)
382 pmu_attach_smart_battery(sc
, i
);
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
);
400 if (kthread_create(PRI_NONE
, 0, NULL
, pmu_thread
, sc
, &sc
->sc_thread
,
402 printf("pmu: unable to create event kthread");
407 pmu_register_callback(void *pmu_cookie
, void (*cb
)(void *), void *cookie
)
409 struct pmu_softc
*sc
= pmu_cookie
;
411 sc
->sc_callback
= cb
;
412 sc
->sc_cb_cookie
= cookie
;
416 pmu_init(struct pmu_softc
*sc
)
418 uint8_t pmu_imask
, resp
[16];
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
);
426 pmu_write_reg(sc
, vIER
, 0x90); /* enable VIA interrupts */
430 pmu_write_reg(struct pmu_softc
*sc
, int offset
, uint8_t value
)
433 bus_space_write_1(sc
->sc_memt
, sc
->sc_memh
, offset
, value
);
436 static inline uint8_t
437 pmu_read_reg(struct pmu_softc
*sc
, int offset
)
440 return bus_space_read_1(sc
->sc_memt
, sc
->sc_memh
, offset
);
444 pmu_send_byte(struct pmu_softc
*sc
, uint8_t data
)
448 pmu_write_reg(sc
, vSR
, data
);
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);
454 do {} while (pmu_intr_state(sc
));
456 DPRINTF(" %02x>", data
);
461 pmu_read_byte(struct pmu_softc
*sc
, uint8_t *data
)
463 volatile uint8_t scratch
;
465 scratch
= pmu_read_reg(sc
, vSR
);
467 /* wait for intr to come up */
468 do {} while (pmu_intr_state(sc
) == 0);
470 do {} while (pmu_intr_state(sc
));
471 *data
= pmu_read_reg(sc
, vSR
);
472 DPRINTF(" <%02x", *data
);
477 pmu_send(void *cookie
, int cmd
, int length
, uint8_t *in_msg
, int rlen
,
480 struct pmu_softc
*sc
= cookie
;
481 int i
, rcv_len
= -1, s
;
482 uint8_t out_len
, intreg
;
484 DPRINTF("pmu_send: ");
487 intreg
= pmu_read_reg(sc
, vIER
);
489 pmu_write_reg(sc
, vIER
, intreg
);
492 do {} while (pmu_intr_state(sc
));
496 pmu_send_byte(sc
, cmd
);
498 /* send length if necessary */
499 if (pm_send_cmd_type
[cmd
] < 0) {
500 pmu_send_byte(sc
, length
);
503 for (i
= 0; i
< length
; i
++) {
504 pmu_send_byte(sc
, in_msg
[i
]);
507 DPRINTF("done sending\n");
509 /* see if there's data to read */
510 rcv_len
= pm_receive_cmd_type
[cmd
];
516 pmu_read_byte(sc
, out_msg
);
521 pmu_read_byte(sc
, &out_len
);
522 rcv_len
= out_len
+ 1;
524 for (i
= 1; i
< min(rcv_len
, rlen
); i
++)
525 pmu_read_byte(sc
, &out_msg
[i
]);
529 pmu_write_reg(sc
, vIER
, (intreg
== 0) ? 0 : 0x90);
536 pmu_adb_poll(void *cookie
)
538 struct pmu_softc
*sc
= cookie
;
547 pmu_in(struct pmu_softc
*sc
)
551 reg
= pmu_read_reg(sc
, vACR
);
554 pmu_write_reg(sc
, vACR
, reg
);
558 pmu_out(struct pmu_softc
*sc
)
562 reg
= pmu_read_reg(sc
, vACR
);
565 pmu_write_reg(sc
, vACR
, reg
);
569 pmu_ack_off(struct pmu_softc
*sc
)
573 reg
= pmu_read_reg(sc
, vBufB
);
575 pmu_write_reg(sc
, vBufB
, reg
);
579 pmu_ack_on(struct pmu_softc
*sc
)
583 reg
= pmu_read_reg(sc
, vBufB
);
585 pmu_write_reg(sc
, vBufB
, reg
);
589 pmu_intr_state(struct pmu_softc
*sc
)
591 return ((pmu_read_reg(sc
, vBufB
) & vPB3
) == 0);
597 struct pmu_softc
*sc
= arg
;
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))
609 DPRINTF("intr: %02x", resp
[0]);
610 for (i
= 1; i
< len
; i
++)
611 DPRINTF(" %02x", resp
[i
]);
615 if (resp
[1] & PMU_INT_ADB
) {
616 pmu_adb_handler(sc
, len
- 1, &resp
[1]);
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
);
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
);
634 if (resp
[1] & PMU_INT_BATTERY
) {
635 /* deal with battery messages */
637 for (i
= 2; i
< len
; i
++)
638 printf(" %02x", resp
[i
]);
642 if (resp
[1] & PMU_INT_ENVIRONMENT
) {
644 /* deal with environment messages */
645 printf("environment:");
646 for (i
= 2; i
< len
; i
++)
647 printf(" %02x", resp
[i
]);
652 if (resp
[1] & PMU_INT_TICK
) {
657 /* unknown interrupt code?! */
659 printf("pmu intr: %02x:", resp
[1]);
660 for (i
= 2; i
< len
; i
++)
661 printf(" %02x", resp
[i
]);
670 pmu_error_handler(void *cookie
, int len
, uint8_t *data
)
672 struct pmu_softc
*sc
= cookie
;
675 * something went wrong
676 * byte 3 seems to be the failed command
679 wakeup(&sc
->sc_todev
);
683 #define DIFF19041970 2082844800
686 pmu_todr_get(todr_chip_handle_t tch
, struct timeval
*tvp
)
688 struct pmu_softc
*sc
= tch
->cookie
;
692 DPRINTF("pmu_todr_get\n");
693 pmu_send(sc
, PMU_READ_RTC
, 0, NULL
, 16, resp
);
695 memcpy(&sec
, &resp
[1], 4);
696 tvp
->tv_sec
= sec
- DIFF19041970
;
697 DPRINTF("tod: %" PRIo64
"\n", tvp
->tv_sec
);
703 pmu_todr_set(todr_chip_handle_t tch
, struct timeval
*tvp
)
705 struct pmu_softc
*sc
= tch
->cookie
;
709 sec
= tvp
->tv_sec
+ DIFF19041970
;
710 if (pmu_send(sc
, PMU_SET_RTC
, 4, (uint8_t *)&sec
, 16, resp
) >= 0)
718 struct pmu_softc
*sc
;
719 uint8_t cmd
[] = {'M', 'A', 'T', 'T'};
725 if (pmu_send(sc
, PMU_POWER_OFF
, 4, cmd
, 16, resp
) >= 0)
732 struct pmu_softc
*sc
;
738 if (pmu_send(sc
, PMU_RESET_CPU
, 0, NULL
, 16, resp
) >= 0)
743 pmu_autopoll(void *cookie
, int flag
)
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};
750 if (sc
->sc_autopoll
== flag
)
754 pmu_send(sc
, PMU_ADB_CMD
, 4, cmd
, 16, resp
);
756 pmu_send(sc
, PMU_ADB_POLL_OFF
, 0, NULL
, 16, resp
);
758 sc
->sc_autopoll
= flag
& 0xffff;
762 pmu_adb_handler(void *cookie
, int len
, uint8_t *data
)
764 struct pmu_softc
*sc
= cookie
;
767 if (sc
->sc_adb_handler
!= NULL
) {
768 sc
->sc_adb_handler(sc
->sc_adb_cookie
, len
, data
);
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
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
);
785 pmu_adb_send(void *cookie
, int poll
, int command
, int len
, uint8_t *data
)
787 struct pmu_softc
*sc
= cookie
;
789 uint8_t packet
[16], resp
[16];
791 /* construct an ADB command packet and send it */
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
);
803 pmu_adb_set_handler(void *cookie
, void (*handler
)(void *, int, uint8_t *),
806 struct pmu_softc
*sc
= cookie
;
808 /* register a callback for incoming ADB messages */
809 sc
->sc_adb_handler
= handler
;
810 sc
->sc_adb_cookie
= hcookie
;
815 pmu_i2c_acquire_bus(void *cookie
, int flags
)
822 pmu_i2c_release_bus(void *cookie
, int flags
)
824 /* nothing here either */
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
)
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
};
837 DPRINTF("pmu_i2c_exec(%02x)\n", addr
);
840 memcpy(&command
[3], send
, min((int)send_len
, 12));
843 pmu_send(sc
, sc
->sc_polling
, send_len
+ 3, command
);
845 while ((sc
->sc_iic_done
== 0) && (sc
->sc_error
== 0)) {
846 if (sc
->sc_polling
) {
849 tsleep(&sc
->sc_todev
, 0, "i2c", 1000);
857 /* see if we're supposed to do a read */
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
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
) {
872 tsleep(&sc
->sc_todev
, 0, "i2c", 1000);
876 printf("error trying to read\n");
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
);
894 pmu_eject_card(struct pmu_softc
*sc
, int socket
)
897 uint8_t buf
[] = {socket
| 4};
901 sc
->sc_pending_eject
&= ~socket
;
903 pmu_send(sc
, PMU_EJECT_PCMCIA
, 1, buf
, 4, res
);
907 pmu_update_brightness(struct pmu_softc
*sc
)
910 uint8_t cmd
[2], resp
[16];
912 if (sc
->sc_brightness
== sc
->sc_brightness_wanted
)
915 if ((sc
->sc_flags
& PMU_HAS_BACKLIGHT_CONTROL
) == 0) {
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
;
923 if (sc
->sc_brightness_wanted
== 0) {
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
;
930 /* don't bother with brightness */
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
);
940 DPRINTF("pmu_update_brightness: %d -> %d\n", sc
->sc_brightness
,
941 sc
->sc_brightness_wanted
);
943 val
= 0x7f - (sc
->sc_brightness_wanted
>> 1);
949 pmu_send(sc
, PMU_SET_BRIGHTNESS
, 1, cmd
, 16, resp
);
951 sc
->sc_brightness
= sc
->sc_brightness_wanted
;
955 pmu_thread(void *cookie
)
957 struct pmu_softc
*sc
= cookie
;
958 //time_t time_bat = time_second;
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
);
971 /* see if we need to update brightness */
972 if (sc
->sc_brightness_wanted
!= sc
->sc_brightness
) {
973 pmu_update_brightness(sc
);
976 /* see if we need to update audio volume */
977 if (sc
->sc_volume_wanted
!= sc
->sc_volume
) {
979 set_volume(sc
->sc_volume_wanted
);
981 sc
->sc_volume
= sc
->sc_volume_wanted
;
984 if (sc
->sc_callback
!= NULL
)
985 sc
->sc_callback(sc
->sc_cb_cookie
);
990 pmu_print(void *aux
, const char *what
)
997 pmu_attach_legacy_battery(struct pmu_softc
*sc
)
999 struct battery_attach_args baa
;
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
);
1007 pmu_attach_smart_battery(struct pmu_softc
*sc
, int num
)
1009 struct battery_attach_args baa
;
1011 baa
.baa_type
= BATTERY_TYPE_SMART
;
1012 baa
.baa_pmu_ops
= &sc
->sc_pmu_ops
;
1014 config_found_ia(&sc
->sc_dev
, "pmu_bus", &baa
, pmu_print
);