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