xref: /netbsd-src/sys/arch/sparc64/dev/psm.c (revision 8bc54e5be648e06e7c6b48f7611f8bccfda032d4)
1*8bc54e5bSmsaitoh /* $NetBSD: psm.c,v 1.11 2016/07/07 06:55:38 msaitoh Exp $ */
2d3788a85Sgdamore /*
3d3788a85Sgdamore  * Copyright (c) 2006 Itronix Inc.
4d3788a85Sgdamore  * All rights reserved.
5d3788a85Sgdamore  *
6d3788a85Sgdamore  * Ported from Tadpole Solaris sources by Garrett D'Amore for Itronix Inc.
7d3788a85Sgdamore  *
8d3788a85Sgdamore  * Redistribution and use in source and binary forms, with or without
9d3788a85Sgdamore  * modification, are permitted provided that the following conditions
10d3788a85Sgdamore  * are met:
11d3788a85Sgdamore  * 1. Redistributions of source code must retain the above copyright
12d3788a85Sgdamore  *    notice, this list of conditions and the following disclaimer.
13d3788a85Sgdamore  * 2. Redistributions in binary form must reproduce the above copyright
14d3788a85Sgdamore  *    notice, this list of conditions and the following disclaimer in the
15d3788a85Sgdamore  *    documentation and/or other materials provided with the distribution.
16d3788a85Sgdamore  * 3. The name of Itronix Inc. may not be used to endorse
17d3788a85Sgdamore  *    or promote products derived from this software without specific
18d3788a85Sgdamore  *    prior written permission.
19d3788a85Sgdamore  *
20d3788a85Sgdamore  * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND
21d3788a85Sgdamore  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22d3788a85Sgdamore  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23d3788a85Sgdamore  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY
24d3788a85Sgdamore  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
25d3788a85Sgdamore  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
26d3788a85Sgdamore  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
27d3788a85Sgdamore  * ON ANY THEORY OF LIABILITY, WHETHER IN
28d3788a85Sgdamore  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29d3788a85Sgdamore  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30d3788a85Sgdamore  * POSSIBILITY OF SUCH DAMAGE.
31d3788a85Sgdamore  */
32d3788a85Sgdamore /*
33d3788a85Sgdamore  * Tadpole-RDI Ultrabook IIi (huxley) power management.  Note that
34d3788a85Sgdamore  * there is a lot of stuff still missing here, due in part to the confusion
35d3788a85Sgdamore  * that exists with the NetBSD power management framework.  I'm not wasting
36d3788a85Sgdamore  * time with APM at this point, and some of sysmon seems "lacking".
37d3788a85Sgdamore  */
38d3788a85Sgdamore #include <sys/cdefs.h>
39*8bc54e5bSmsaitoh __KERNEL_RCSID(0, "$NetBSD: psm.c,v 1.11 2016/07/07 06:55:38 msaitoh Exp $");
40d3788a85Sgdamore 
41d3788a85Sgdamore #include <sys/param.h>
42d3788a85Sgdamore #include <sys/systm.h>
43d3788a85Sgdamore #include <sys/proc.h>
44d3788a85Sgdamore #include <sys/kernel.h>
45d3788a85Sgdamore #include <sys/kthread.h>
46d3788a85Sgdamore #include <sys/types.h>
47d3788a85Sgdamore #include <sys/device.h>
48d3788a85Sgdamore #include <sys/poll.h>
49d3788a85Sgdamore #include <sys/kauth.h>
50d3788a85Sgdamore 
51d3788a85Sgdamore #include <machine/autoconf.h>
52b6584574Sdyoung #include <sys/bus.h>
53d3788a85Sgdamore #include <machine/intr.h>
54d3788a85Sgdamore 
55d3788a85Sgdamore #include <dev/ebus/ebusreg.h>
56d3788a85Sgdamore #include <dev/ebus/ebusvar.h>
57d3788a85Sgdamore 
58d3788a85Sgdamore #include <dev/sysmon/sysmonvar.h>
59d3788a85Sgdamore 
60d3788a85Sgdamore #include <sparc64/dev/psmreg.h>
61d3788a85Sgdamore 
62d3788a85Sgdamore struct psm_softc {
6388655ce2Schristos 	device_t		sc_dev;
64d3788a85Sgdamore 	bus_space_tag_t		sc_memt;
65d3788a85Sgdamore 	bus_space_handle_t	sc_memh;
66d3788a85Sgdamore 
67d3788a85Sgdamore 	int			sc_event;
68d3788a85Sgdamore 	int			sc_flags;
69d3788a85Sgdamore 	struct sysmon_pswitch	sc_sm_pbutton;
70d3788a85Sgdamore 	struct sysmon_pswitch	sc_sm_lid;
71d3788a85Sgdamore 	struct sysmon_pswitch	sc_sm_ac;
72d3788a85Sgdamore 	struct evcnt		sc_intrcnt;
7388ab7da9Sad 	lwp_t			*sc_thread;
74d3788a85Sgdamore };
75d3788a85Sgdamore 
76d3788a85Sgdamore #define	PUT8(sc, r, v)		\
77d3788a85Sgdamore 	bus_space_write_1(sc->sc_memt, sc->sc_memh, r, v)
78d3788a85Sgdamore #define	GET8(sc, r)		\
79d3788a85Sgdamore 	bus_space_read_1(sc->sc_memt, sc->sc_memh, r)
80d3788a85Sgdamore 
81d3788a85Sgdamore #define	WAIT_DELAY		1000
82d3788a85Sgdamore #define	WAIT_RETRIES		1000
83d3788a85Sgdamore 
84d3788a85Sgdamore #define	RESET_DELAY		200
85d3788a85Sgdamore #define	CMD_DELAY		10
86d3788a85Sgdamore #define	CMD_RETRIES		5
87d3788a85Sgdamore 
88d3788a85Sgdamore #ifdef	DEBUG
89d3788a85Sgdamore #define	STATIC
90d3788a85Sgdamore #else
91d3788a85Sgdamore #define	STATIC	static
92d3788a85Sgdamore #endif
93d3788a85Sgdamore 
94d3788a85Sgdamore /* flags indicating state */
95d3788a85Sgdamore #define	PSM_FLAG_ACPWR		0x1
96d3788a85Sgdamore #define	PSM_FLAG_LIDCLOSED	0x2
97d3788a85Sgdamore #define	PSM_FLAG_DOCKED		0x4
98d3788a85Sgdamore 
99d3788a85Sgdamore /* system events -- causes activity in the event thread */
100d3788a85Sgdamore #define	PSM_EV_PBUTTON		0x1
101d3788a85Sgdamore #define	PSM_EV_LID		0x2
102d3788a85Sgdamore #define	PSM_EV_ACPWR		0x4
103d3788a85Sgdamore #define	PSM_EV_BATT		0x8
104d3788a85Sgdamore #define	PSM_EV_TEMP		0x10
105d3788a85Sgdamore 
106d3788a85Sgdamore STATIC void psm_sysmon_setup(struct psm_softc *);
107d3788a85Sgdamore STATIC void psm_event_thread(void *);
108d3788a85Sgdamore STATIC int psm_init(struct psm_softc *);
109d3788a85Sgdamore STATIC void psm_reset(struct psm_softc *);
110d3788a85Sgdamore STATIC void psm_poll_acpower(struct psm_softc *);
111d3788a85Sgdamore STATIC int psm_intr(void *);
112d3788a85Sgdamore STATIC int psm_misc_rd(struct psm_softc *, uint8_t, uint8_t *);
113d3788a85Sgdamore STATIC int psm_misc_wr(struct psm_softc *, uint8_t, uint8_t);
114d3788a85Sgdamore STATIC int psm_wait(struct psm_softc *, uint8_t);
115d3788a85Sgdamore #if 0
116d3788a85Sgdamore STATIC int psm_ecmd_rd16(struct psm_softc *, uint16_t *, uint8_t, uint8_t,
117d3788a85Sgdamore     uint8_t);
118d3788a85Sgdamore #endif
119d3788a85Sgdamore STATIC int psm_ecmd_rd8(struct psm_softc *, uint8_t *, uint8_t, uint8_t,
120d3788a85Sgdamore     uint8_t);
121d3788a85Sgdamore STATIC int psm_ecmd_wr8(struct psm_softc *, uint8_t, uint8_t, uint8_t,
122d3788a85Sgdamore     uint8_t);
12388655ce2Schristos STATIC int psm_match(device_t, cfdata_t, void *);
12488655ce2Schristos STATIC void psm_attach(device_t, device_t, void *);
125d3788a85Sgdamore 
12688655ce2Schristos CFATTACH_DECL_NEW(psm, sizeof(struct psm_softc),
127d3788a85Sgdamore     psm_match, psm_attach, NULL, NULL);
128d3788a85Sgdamore 
129d3788a85Sgdamore 
130d08d7d8eSjnemeth int
psm_match(device_t parent,cfdata_t cf,void * aux)131cbab9cadSchs psm_match(device_t parent, cfdata_t cf, void *aux)
132d3788a85Sgdamore {
133d3788a85Sgdamore 	struct ebus_attach_args *ea = aux;
134d3788a85Sgdamore 
135d3788a85Sgdamore 	if (strcmp(ea->ea_name, "psm") != 0)
136d3788a85Sgdamore 		return (0);
137d3788a85Sgdamore 	return (1);
138d3788a85Sgdamore }
139d3788a85Sgdamore 
140d08d7d8eSjnemeth void
psm_attach(device_t parent,device_t self,void * aux)141cbab9cadSchs psm_attach(device_t parent, device_t self, void *aux)
142d3788a85Sgdamore {
14388655ce2Schristos 	struct psm_softc	*sc = device_private(self);
144d3788a85Sgdamore 	struct ebus_attach_args	*ea = aux;
145d3788a85Sgdamore 	bus_addr_t		devaddr;
14609275ba7Scegger 	const char		*xname;
147d3788a85Sgdamore 
148d3788a85Sgdamore 
14988655ce2Schristos 	sc->sc_dev = self;
150d3788a85Sgdamore 	sc->sc_memt = ea->ea_bustag;
151d3788a85Sgdamore 	devaddr = EBUS_ADDR_FROM_REG(&ea->ea_reg[0]);
152d3788a85Sgdamore 
15388655ce2Schristos 	xname = device_xname(sc->sc_dev);
154d3788a85Sgdamore 	if (bus_space_map(sc->sc_memt, devaddr, ea->ea_reg[0].size,
155d3788a85Sgdamore 		0, &sc->sc_memh) != 0) {
156d3788a85Sgdamore 		printf(": unable to map device registers\n");
157d3788a85Sgdamore 		return;
158d3788a85Sgdamore 	}
159d3788a85Sgdamore 	if (psm_init(sc) != 0) {
160d3788a85Sgdamore 		printf(": unable to initialize device\n");
161d3788a85Sgdamore 		return;
162d3788a85Sgdamore 	}
163d3788a85Sgdamore 
164d3788a85Sgdamore 	printf(": UltraBook IIi power control\n");
165d3788a85Sgdamore 
166d3788a85Sgdamore 	psm_sysmon_setup(sc);
167d3788a85Sgdamore 
16888ab7da9Sad 	if (kthread_create(PRI_NONE, 0, NULL, psm_event_thread, sc,
16988655ce2Schristos 	    &sc->sc_thread, "%s", xname) != 0) {
17088655ce2Schristos 		aprint_error_dev(sc->sc_dev, "unable to create event kthread\n");
17188ab7da9Sad 	}
172d3788a85Sgdamore 
173d3788a85Sgdamore 	/*
174d3788a85Sgdamore 	 * Establish device interrupts
175d3788a85Sgdamore 	 */
176d3788a85Sgdamore 	(void) bus_intr_establish(sc->sc_memt, ea->ea_intr[0], IPL_HIGH,
177d3788a85Sgdamore 	    psm_intr, sc);
178d3788a85Sgdamore 	evcnt_attach_dynamic(&sc->sc_intrcnt, EVCNT_TYPE_INTR, NULL,
17988655ce2Schristos 	    xname, "intr");
180d3788a85Sgdamore }
181d3788a85Sgdamore 
182d3788a85Sgdamore /*
183d3788a85Sgdamore  * Register sensors and events with sysmon.
184d3788a85Sgdamore  */
185d3788a85Sgdamore void
psm_sysmon_setup(struct psm_softc * sc)186d3788a85Sgdamore psm_sysmon_setup(struct psm_softc *sc)
187d3788a85Sgdamore {
18888655ce2Schristos 	const char	*xname	= device_xname(sc->sc_dev);
189d3788a85Sgdamore 
190d3788a85Sgdamore 
191d3788a85Sgdamore 	/*
192d3788a85Sgdamore 	 * XXX: Register sysmon environment.
193d3788a85Sgdamore 	 */
194d3788a85Sgdamore 
195d3788a85Sgdamore 	/*
196d3788a85Sgdamore 	 * Register sysmon events
197d3788a85Sgdamore 	 */
198d3788a85Sgdamore 	sc->sc_sm_pbutton.smpsw_name = xname;
199d3788a85Sgdamore 	sc->sc_sm_pbutton.smpsw_type = PSWITCH_TYPE_POWER;
200d3788a85Sgdamore 	if (sysmon_pswitch_register(&sc->sc_sm_pbutton) != 0)
201d3788a85Sgdamore 		printf("%s: unable to register power button\n", xname);
202d3788a85Sgdamore 
203d3788a85Sgdamore 	sc->sc_sm_lid.smpsw_name = xname;
204d3788a85Sgdamore 	sc->sc_sm_lid.smpsw_type = PSWITCH_TYPE_LID;
205d3788a85Sgdamore 	if (sysmon_pswitch_register(&sc->sc_sm_lid) != 0)
206d3788a85Sgdamore 		printf("%s: unable to register lid switch\n", xname);
207d3788a85Sgdamore 
208d3788a85Sgdamore 	sc->sc_sm_ac.smpsw_name = xname;
209d3788a85Sgdamore 	sc->sc_sm_ac.smpsw_type = PSWITCH_TYPE_ACADAPTER;
210d3788a85Sgdamore 	if (sysmon_pswitch_register(&sc->sc_sm_ac) != 0)
211d3788a85Sgdamore 		printf("%s: unable to register AC adapter\n", xname);
212d3788a85Sgdamore }
213d3788a85Sgdamore 
214d3788a85Sgdamore void
psm_event_thread(void * arg)215d3788a85Sgdamore psm_event_thread(void *arg)
216d3788a85Sgdamore {
217d3788a85Sgdamore 	struct psm_softc *sc = arg;
218d3788a85Sgdamore 	int	x;
219d3788a85Sgdamore 	int	event;
220d3788a85Sgdamore 	int	flags;
221d3788a85Sgdamore 
222d3788a85Sgdamore 	for (;;) {
223d3788a85Sgdamore 		x = splhigh();
224d3788a85Sgdamore 		/* check for AC power.  sets event if there is a change */
225d3788a85Sgdamore 		psm_poll_acpower(sc);
226d3788a85Sgdamore 
227d3788a85Sgdamore 		/* read and clear events */
228d3788a85Sgdamore 		event = sc->sc_event;
229d3788a85Sgdamore 		flags = sc->sc_flags;
230d3788a85Sgdamore 		sc->sc_event = 0;
231d3788a85Sgdamore 		splx(x);
232d3788a85Sgdamore 
233d3788a85Sgdamore 		if (event & PSM_EV_PBUTTON) {
234d3788a85Sgdamore 			sysmon_pswitch_event(&sc->sc_sm_pbutton,
235d3788a85Sgdamore 			    PSWITCH_EVENT_PRESSED);
236d3788a85Sgdamore 		}
237d3788a85Sgdamore 
238d3788a85Sgdamore 		if (event & PSM_EV_LID) {
239d3788a85Sgdamore 			sysmon_pswitch_event(&sc->sc_sm_lid,
240d3788a85Sgdamore 			    flags & PSM_FLAG_LIDCLOSED ?
24119b01fa4Sxtraeme 			    PSWITCH_EVENT_PRESSED : PSWITCH_EVENT_RELEASED);
242d3788a85Sgdamore 		}
243d3788a85Sgdamore 
244d3788a85Sgdamore 		if (event & PSM_EV_ACPWR) {
245d3788a85Sgdamore 			sysmon_pswitch_event(&sc->sc_sm_ac,
246d3788a85Sgdamore 			    flags & PSM_FLAG_ACPWR ?
24719b01fa4Sxtraeme 			    PSWITCH_EVENT_PRESSED : PSWITCH_EVENT_RELEASED);
248d3788a85Sgdamore 		}
249d3788a85Sgdamore 
250d3788a85Sgdamore 		/* XXX: handle PSM_EV_TEMP */
251d3788a85Sgdamore 
252d3788a85Sgdamore 		/* one second interval between probes of power */
253d3788a85Sgdamore 		tsleep(&sc, PWAIT, "psm", hz);
254d3788a85Sgdamore 	}
255d3788a85Sgdamore }
256d3788a85Sgdamore 
257d3788a85Sgdamore int
psm_init(struct psm_softc * sc)258d3788a85Sgdamore psm_init(struct psm_softc *sc)
259d3788a85Sgdamore {
260d3788a85Sgdamore 	int	x;
2612fe9781dSgdamore 	uint8_t	batt = 0xff;	/* keep GCC 4.x happy */
262d3788a85Sgdamore 
263d3788a85Sgdamore 	/* clear interrupts */
264d3788a85Sgdamore 	x = splhigh();
265d3788a85Sgdamore 	PUT8(sc, PSM_ICR, 0xff);
266d3788a85Sgdamore 	splx(x);
267d3788a85Sgdamore 
268d3788a85Sgdamore 	/* enable interrupts */
269d3788a85Sgdamore 	if (psm_misc_wr(sc, PSM_MISC_IMR, PSM_IMR_ALL))
270d3788a85Sgdamore 		return (-1);
271d3788a85Sgdamore 
272d3788a85Sgdamore 	/* make sure that UPS battery is reasonable */
273d3788a85Sgdamore 	if (psm_misc_rd(sc, PSM_MISC_UPS, &batt) || (batt > PSM_MAX_BATTERIES))
274d3788a85Sgdamore 		if (psm_misc_wr(sc, PSM_MISC_UPS, batt))
27588655ce2Schristos 			aprint_error_dev(sc->sc_dev, "cannot set UPS battery");
276d3788a85Sgdamore 
277d3788a85Sgdamore 	return (0);
278d3788a85Sgdamore }
279d3788a85Sgdamore 
280d3788a85Sgdamore void
psm_reset(struct psm_softc * sc)281d3788a85Sgdamore psm_reset(struct psm_softc *sc)
282d3788a85Sgdamore {
283d3788a85Sgdamore 
284d3788a85Sgdamore 	PUT8(sc, PSM_MCR, PSM_MCR_RST);
285d3788a85Sgdamore 	delay(RESET_DELAY);
286d3788a85Sgdamore }
287d3788a85Sgdamore 
288d3788a85Sgdamore void
psm_poll_acpower(struct psm_softc * sc)289d3788a85Sgdamore psm_poll_acpower(struct psm_softc *sc)
290d3788a85Sgdamore {
291d3788a85Sgdamore 	int	flags = sc->sc_flags;
292d3788a85Sgdamore 
293d3788a85Sgdamore 	if (GET8(sc, PSM_STAT) & PSM_STAT_AC) {
294d3788a85Sgdamore 		sc->sc_flags |= PSM_FLAG_ACPWR;
295d3788a85Sgdamore 	} else {
296d3788a85Sgdamore 		sc->sc_flags &= ~PSM_FLAG_ACPWR;
297d3788a85Sgdamore 	}
298d3788a85Sgdamore 	if (flags != sc->sc_flags)
299d3788a85Sgdamore 		sc->sc_event |= PSM_EV_ACPWR;
300d3788a85Sgdamore }
301d3788a85Sgdamore 
302d3788a85Sgdamore int
psm_misc_rd(struct psm_softc * sc,uint8_t mreg,uint8_t * data)303d3788a85Sgdamore psm_misc_rd(struct psm_softc *sc, uint8_t mreg, uint8_t *data)
304d3788a85Sgdamore {
305d3788a85Sgdamore 
306d3788a85Sgdamore 	return (psm_ecmd_rd8(sc, data, mreg, PSM_MODE_MISC, 0));
307d3788a85Sgdamore }
308d3788a85Sgdamore 
309d3788a85Sgdamore int
psm_misc_wr(struct psm_softc * sc,uint8_t mreg,uint8_t data)310d3788a85Sgdamore psm_misc_wr(struct psm_softc *sc, uint8_t mreg, uint8_t data)
311d3788a85Sgdamore {
312d3788a85Sgdamore 
313d3788a85Sgdamore 	return (psm_ecmd_wr8(sc, data, mreg, PSM_MODE_MISC, 0));
314d3788a85Sgdamore }
315d3788a85Sgdamore 
316d3788a85Sgdamore int
psm_wait(struct psm_softc * sc,uint8_t flag)317d3788a85Sgdamore psm_wait(struct psm_softc *sc, uint8_t flag)
318d3788a85Sgdamore {
319d3788a85Sgdamore     int retr = WAIT_RETRIES;
320d3788a85Sgdamore 
321d3788a85Sgdamore     while (GET8(sc, PSM_STAT) & flag) {
322d3788a85Sgdamore 	    if (!(retr--)) {
323d3788a85Sgdamore 		    return (-1);
324d3788a85Sgdamore 	    }
325d3788a85Sgdamore 	    delay(WAIT_DELAY);
326d3788a85Sgdamore     }
327d3788a85Sgdamore     return (0);
328d3788a85Sgdamore }
329d3788a85Sgdamore 
330d3788a85Sgdamore #if 0
331d3788a85Sgdamore int
332d3788a85Sgdamore psm_ecmd_rd16(struct psm_softc *sc, uint16_t *data, uint8_t iar, uint8_t mode,
333d3788a85Sgdamore     uint8_t addr)
334d3788a85Sgdamore {
335d3788a85Sgdamore 	uint8_t	cmr = PSM_CMR_DATA(mode, PSM_L_16, PSM_D_RD, addr);
336d3788a85Sgdamore 	int	x, rc, retr = CMD_RETRIES;
337d3788a85Sgdamore 
338d3788a85Sgdamore 	x = splhigh();
339d3788a85Sgdamore 
340d3788a85Sgdamore 	do {
341d3788a85Sgdamore 		if ((rc = psm_wait(sc, PSM_STAT_RDA)) != 0) {
342d3788a85Sgdamore 			psm_reset(sc);
343d3788a85Sgdamore 			continue;
344d3788a85Sgdamore 		}
345d3788a85Sgdamore 
346d3788a85Sgdamore 		PUT8(sc, PSM_IAR, iar);
347d3788a85Sgdamore 		PUT8(sc, PSM_CMR, cmr);
348d3788a85Sgdamore 
349d3788a85Sgdamore 		delay(CMD_DELAY);
350d3788a85Sgdamore 
351d3788a85Sgdamore 		if ((rc = psm_wait(sc, PSM_STAT_RDA)) == 0) {
352d3788a85Sgdamore 			*data = GET8(sc, PSM_PWDL) | (GET8(sc, PSM_PWDU) << 8);
353d3788a85Sgdamore 			break;
354d3788a85Sgdamore 		}
355d3788a85Sgdamore 
356d3788a85Sgdamore 		psm_reset(sc);
357d3788a85Sgdamore 
358d3788a85Sgdamore 	} while (--retr);
359d3788a85Sgdamore 
360d3788a85Sgdamore 	splx(x);
361d3788a85Sgdamore 	return (rc);
362d3788a85Sgdamore }
363d3788a85Sgdamore #endif
364d3788a85Sgdamore 
365d3788a85Sgdamore int
psm_ecmd_rd8(struct psm_softc * sc,uint8_t * data,uint8_t iar,uint8_t mode,uint8_t addr)366d3788a85Sgdamore psm_ecmd_rd8(struct psm_softc *sc, uint8_t *data, uint8_t iar, uint8_t mode,
367d3788a85Sgdamore     uint8_t addr)
368d3788a85Sgdamore {
369d3788a85Sgdamore 	uint8_t	cmr = PSM_CMR_DATA(mode, PSM_L_8, PSM_D_RD, addr);
370d3788a85Sgdamore 	int	x, rc, retr = CMD_RETRIES;
371d3788a85Sgdamore 
372d3788a85Sgdamore 	x = splhigh();
373d3788a85Sgdamore 
374d3788a85Sgdamore 	do {
375d3788a85Sgdamore 		if ((rc = psm_wait(sc, PSM_STAT_RDA)) != 0) {
376d3788a85Sgdamore 			psm_reset(sc);
377d3788a85Sgdamore 			continue;
378d3788a85Sgdamore 		}
379d3788a85Sgdamore 
380d3788a85Sgdamore 		PUT8(sc, PSM_IAR, iar);
381d3788a85Sgdamore 		PUT8(sc, PSM_CMR, cmr);
382d3788a85Sgdamore 
383d3788a85Sgdamore 		delay(CMD_DELAY);
384d3788a85Sgdamore 
385d3788a85Sgdamore 		if ((rc = psm_wait(sc, PSM_STAT_RDA)) == 0) {
386d3788a85Sgdamore 			(void) GET8(sc, PSM_PWDU);
387d3788a85Sgdamore 			*data = GET8(sc, PSM_PWDL);
388d3788a85Sgdamore 			break;
389d3788a85Sgdamore 		}
390d3788a85Sgdamore 
391d3788a85Sgdamore 		psm_reset(sc);
392d3788a85Sgdamore 
393d3788a85Sgdamore 	} while (--retr);
394d3788a85Sgdamore 
395d3788a85Sgdamore 	splx(x);
396d3788a85Sgdamore 	return (rc);
397d3788a85Sgdamore }
398d3788a85Sgdamore 
399d3788a85Sgdamore int
psm_ecmd_wr8(struct psm_softc * sc,uint8_t data,uint8_t iar,uint8_t mode,uint8_t addr)400d3788a85Sgdamore psm_ecmd_wr8(struct psm_softc *sc, uint8_t data, uint8_t iar, uint8_t mode,
401d3788a85Sgdamore     uint8_t addr)
402d3788a85Sgdamore {
403d3788a85Sgdamore 	uint8_t	cmr = PSM_CMR_DATA(mode, PSM_L_8, PSM_D_WR, addr);
404d3788a85Sgdamore 	int	x, rc, retr = CMD_RETRIES;
405d3788a85Sgdamore 
406d3788a85Sgdamore 	x = splhigh();
407d3788a85Sgdamore 
408d3788a85Sgdamore 	do {
409d3788a85Sgdamore 		if ((rc = psm_wait(sc, PSM_STAT_WBF)) != 0) {
410d3788a85Sgdamore 			psm_reset(sc);
411d3788a85Sgdamore 			continue;
412d3788a85Sgdamore 		}
413d3788a85Sgdamore 
414d3788a85Sgdamore 		PUT8(sc, PSM_PWDU, 0);
415d3788a85Sgdamore 		PUT8(sc, PSM_PWDL, data);
416d3788a85Sgdamore 		PUT8(sc, PSM_IAR, iar);
417d3788a85Sgdamore 		PUT8(sc, PSM_CMR, cmr);
418d3788a85Sgdamore 
419d3788a85Sgdamore 		delay(CMD_DELAY);
420d3788a85Sgdamore 
421d3788a85Sgdamore 		if ((rc = psm_wait(sc, PSM_STAT_WBF)) == 0) {
422d3788a85Sgdamore 			break;
423d3788a85Sgdamore 		}
424d3788a85Sgdamore 
425d3788a85Sgdamore 		psm_reset(sc);
426d3788a85Sgdamore 	} while (--retr);
427d3788a85Sgdamore 
428d3788a85Sgdamore 	splx(x);
429d3788a85Sgdamore 
430d3788a85Sgdamore 	return (rc);
431d3788a85Sgdamore }
432d3788a85Sgdamore 
433d3788a85Sgdamore int
psm_intr(void * arg)434d3788a85Sgdamore psm_intr(void *arg)
435d3788a85Sgdamore {
436d3788a85Sgdamore 	struct psm_softc *sc = arg;
437d3788a85Sgdamore 	uint8_t	isr;
438d3788a85Sgdamore 
439d3788a85Sgdamore 	isr = GET8(sc, PSM_ISR);
440d3788a85Sgdamore 	if (isr & PSM_ISR_PO) {
441d3788a85Sgdamore 		PUT8(sc, PSM_ICR, PSM_ISR_PO);
442d3788a85Sgdamore 		sc->sc_event |= PSM_EV_PBUTTON;
443d3788a85Sgdamore 	}
444d3788a85Sgdamore 	if (isr & PSM_ISR_DK) {
445d3788a85Sgdamore 		PUT8(sc, PSM_ICR, PSM_ISR_DK);
446d3788a85Sgdamore 		sc->sc_flags |= PSM_FLAG_DOCKED;
447d3788a85Sgdamore 	}
448d3788a85Sgdamore 	if (isr & PSM_ISR_UDK) {
449d3788a85Sgdamore 		PUT8(sc, PSM_ICR, PSM_ISR_UDK);
450d3788a85Sgdamore 		sc->sc_flags &= ~PSM_FLAG_DOCKED;
451d3788a85Sgdamore 	}
452d3788a85Sgdamore 	if (isr & PSM_ISR_LIDC) {
453d3788a85Sgdamore 		PUT8(sc, PSM_ICR, PSM_ISR_LIDC);
454d3788a85Sgdamore 		sc->sc_flags |= PSM_FLAG_LIDCLOSED;
455d3788a85Sgdamore 		sc->sc_event |= PSM_EV_LID;
456d3788a85Sgdamore 	}
457d3788a85Sgdamore 	if (isr & PSM_ISR_LIDO) {
458d3788a85Sgdamore 		PUT8(sc, PSM_ICR, PSM_ISR_LIDO);
459d3788a85Sgdamore 		sc->sc_flags &= ~PSM_FLAG_LIDCLOSED;
460d3788a85Sgdamore 		sc->sc_event |= PSM_EV_LID;
461d3788a85Sgdamore 	}
462d3788a85Sgdamore 	if (isr & PSM_ISR_TMP) {
463d3788a85Sgdamore 		/* Over temperature */
464d3788a85Sgdamore 		PUT8(sc, PSM_ICR, PSM_ISR_TMP);
465d3788a85Sgdamore 		sc->sc_event |= PSM_EV_TEMP;
466d3788a85Sgdamore 	}
467d3788a85Sgdamore 	if (isr & PSM_ISR_BCC) {
468d3788a85Sgdamore 		/* battery config changed */
469d3788a85Sgdamore 		PUT8(sc, PSM_ICR, PSM_ISR_BCC);
470d3788a85Sgdamore 		sc->sc_event |= PSM_EV_BATT;
471d3788a85Sgdamore 	}
472d3788a85Sgdamore 	if (isr & PSM_ISR_RPD) {
473d3788a85Sgdamore 		/* request to power down */
474d3788a85Sgdamore 		sc->sc_event |= PSM_EV_PBUTTON;
475d3788a85Sgdamore 	}
476d3788a85Sgdamore 	if (sc->sc_event) {
477d3788a85Sgdamore 		/* wake up the thread */
478d3788a85Sgdamore 		wakeup(sc);
479d3788a85Sgdamore 	}
480d3788a85Sgdamore 	return (1);
481d3788a85Sgdamore }
482