1 /* $NetBSD: pow.c,v 1.22 2008/12/20 13:20:59 isaki Exp $ */
4 * Copyright (c) 1995 MINOURA Makoto.
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.
15 * 3. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed by Minoura Makoto.
18 * 4. The name of the author may not be used to endorse or promote products
19 * derived from this software without specific prior written permission
21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 * Power switch device driver.
36 * 1. accessing boot information.
37 * 2. looking at the front or external power switch.
40 #include <sys/cdefs.h>
41 __KERNEL_RCSID(0, "$NetBSD: pow.c,v 1.22 2008/12/20 13:20:59 isaki Exp $");
43 #include <sys/param.h>
44 #include <sys/systm.h>
45 #include <sys/device.h>
46 #include <sys/ioctl.h>
48 #include <sys/kernel.h>
49 #include <sys/fcntl.h>
50 #include <sys/signalvar.h>
53 #include <sys/device.h>
55 #include <dev/sysmon/sysmonvar.h>
56 #include <dev/sysmon/sysmon_taskq.h>
58 #include <machine/cpu.h>
59 #include <machine/powioctl.h>
60 #include <x68k/dev/intiovar.h>
61 #include <x68k/dev/mfp.h>
62 #include <x68k/dev/powvar.h>
63 #include <x68k/x68k/iodevice.h>
65 #define sramtop (IODEVbase->io_sram)
66 #define rtc (IODEVbase->io_rtc)
68 extern struct cfdriver pow_cd
;
70 static int pow_match(device_t
, cfdata_t
, void *);
71 static void pow_attach(device_t
, device_t
, void *);
72 static int powintr(void *);
73 static int setalarm(struct x68k_alarminfo
*);
74 static void pow_pressed_event(void *);
75 static void pow_check_switch(void *);
77 CFATTACH_DECL_NEW(pow
, sizeof(struct pow_softc
),
78 pow_match
, pow_attach
, NULL
, NULL
);
80 static int pow_attached
;
82 dev_type_open(powopen
);
83 dev_type_close(powclose
);
84 dev_type_ioctl(powioctl
);
86 const struct cdevsw pow_cdevsw
= {
87 powopen
, powclose
, noread
, nowrite
, powioctl
,
88 nostop
, notty
, nopoll
, nommap
, nokqfilter
,
92 pow_match(device_t parent
, cfdata_t cf
, void *aux
)
101 pow_attach(device_t parent
, device_t self
, void *aux
)
103 struct pow_softc
*sc
= device_private(self
);
104 struct mfp_softc
*mfp
= device_private(parent
);
106 sc
->sw
= ~mfp_get_gpip() & 7;
107 /* disable mfp power switch interrupt */
108 mfp_bit_clear_ierb(7);
109 mfp_bit_clear_aer(7);
111 sc
->status
= POW_FREE
;
114 mfp_bit_set_aer(sc
->sw
);
115 mfp_bit_set_ierb(sc
->sw
);
118 sysmon_task_queue_init();
119 sc
->smpsw
.smpsw_name
= device_xname(self
);
120 sc
->smpsw
.smpsw_type
= PSWITCH_TYPE_POWER
;
121 if (sysmon_pswitch_register(&sc
->smpsw
) != 0)
122 panic("can't register with sysmon");
124 /* MFP interrupt #1 for ext, #2 for front power switch */
125 if (intio_intr_establish(mfp
->sc_intr
+ 1, "powext", powintr
, sc
) < 0)
126 panic("%s: can't establish interrupt", device_xname(self
));
127 if (intio_intr_establish(mfp
->sc_intr
+ 2, "powfrt", powintr
, sc
) < 0)
128 panic("%s: can't establish interrupt", device_xname(self
));
130 shutdownhook_establish(pow_check_switch
, 0);
133 printf("%s: started by ", device_xname(self
));
134 if (sc
->sw
& POW_EXTERNALSW
)
135 printf("external power switch.\n");
136 else if (sc
->sw
& POW_FRONTSW
)
137 printf("front power switch.\n");
138 /* XXX: I don't know why POW_ALARMSW should not be checked */
140 else if ((sc
->sw
& POW_ALARMSW
) && sramtop
[0x26] == 0)
141 printf("RTC alarm.\n");
146 printf("RTC alarm.\n");
155 powopen(dev_t dev
, int flags
, int mode
, struct lwp
*l
)
157 struct pow_softc
*sc
;
159 sc
= device_lookup_private(&pow_cd
, minor(dev
));
163 if (sc
->status
== POW_BUSY
)
166 if (sc
->status
== POW_FREE
)
167 sc
->status
= POW_BUSY
;
169 sc
->rw
= (flags
& (FREAD
|FWRITE
));
176 powclose(dev_t dev
, int flags
, int mode
, struct lwp
*l
)
178 struct pow_softc
*sc
;
180 sc
= device_lookup_private(&pow_cd
, minor(dev
));
184 if (sc
->status
== POW_BUSY
)
185 sc
->status
= POW_FREE
;
190 #define SRAMINT(offset) (*((volatile int *) (&sramtop[offset])))
191 #define RTCWAIT DELAY(100)
194 setalarm(struct x68k_alarminfo
*bp
)
200 intio_set_sysport_sramwp(0x31);
202 SRAMINT(0x1e) = bp
->al_dowhat
;
203 SRAMINT(0x22) = bp
->al_ontime
;
204 SRAMINT(0x14) = (bp
->al_offtime
/ 60) - 1;
209 intio_set_sysport_sramwp(0);
217 ontime
= bp
->al_ontime
;
218 if ((ontime
& 0x0f) <= 9)
219 rtc
.bank1
.al_min
= ontime
& 0x0f;
222 if ((ontime
& 0x0f) <= 6)
223 rtc
.bank1
.al_min10
= ontime
& 0x0f;
226 if ((ontime
& 0x0f) <= 9)
227 rtc
.bank1
.al_hour
= ontime
& 0x0f;
230 if ((ontime
& 0x0f) <= 2)
231 rtc
.bank1
.al_hour10
= ontime
& 0x0f;
234 if ((ontime
& 0x0f) <= 9)
235 rtc
.bank1
.al_day
= ontime
& 0x0f;
238 if ((ontime
& 0x0f) <= 3)
239 rtc
.bank1
.al_day10
= ontime
& 0x0f;
242 if ((ontime
& 0x0f) <= 6)
243 rtc
.bank1
.al_week
= ontime
& 0x0f;
245 rtc
.bank1
.clkout
= 0;
247 rtc
.bank1
.mode
= 0x0c;
249 rtc
.bank1
.clkout
= 7;
251 rtc
.bank1
.mode
= 0x08;
261 powioctl(dev_t dev
, u_long cmd
, void *addr
, int flag
, struct lwp
*l
)
263 struct pow_softc
*sc
;
265 sc
= device_lookup_private(&pow_cd
, minor(dev
));
270 case POWIOCGPOWERINFO
:
272 struct x68k_powerinfo
*bp
= (void *)addr
;
273 if (!(sc
->rw
& FREAD
))
275 bp
->pow_switch_boottime
= sc
->sw
;
276 bp
->pow_switch_current
= ~mfp_get_gpip() & 7;
277 bp
->pow_boottime
= boottime
.tv_sec
;
278 bp
->pow_bootcount
= SRAMINT(0x44);
279 bp
->pow_usedtotal
= SRAMINT(0x40) * 60;
283 case POWIOCGALARMINFO
:
285 struct x68k_alarminfo
*bp
= (void *) addr
;
286 if (!(sc
->rw
& FREAD
))
288 bp
->al_enable
= (sramtop
[0x26] == 0);
289 bp
->al_ontime
= SRAMINT(0x22);
290 bp
->al_dowhat
= SRAMINT(0x1e);
291 bp
->al_offtime
= (SRAMINT(0x14) + 1) * 60;
295 case POWIOCSALARMINFO
:
296 if (!(sc
->rw
& FWRITE
))
298 return setalarm ((void *) addr
);
310 struct pow_softc
*sc
= arg
;
313 sw
= ~mfp_get_gpip() & 6;
314 mfp_bit_clear_aer(sw
);
315 mfp_bit_set_ierb(sw
);
317 sysmon_task_queue_sched(0, pow_pressed_event
, sc
);
323 pow_pressed_event(void *arg
)
325 struct pow_softc
*sc
= arg
;
327 sysmon_pswitch_event(&sc
->smpsw
, PSWITCH_EVENT_PRESSED
);
331 pow_check_switch(void *dummy
)
333 extern int power_switch_is_off
;
335 if ((~mfp_get_gpip() & (POW_FRONTSW
| POW_EXTERNALSW
)) == 0)
336 power_switch_is_off
= 1;