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