xref: /openbsd/sys/arch/sparc64/dev/power.c (revision 73471bf0)
1 /*	$OpenBSD: power.c,v 1.9 2021/10/24 17:05:04 mpi Exp $	*/
2 
3 /*
4  * Copyright (c) 2006 Jason L. Wright (jason@thought.net)
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
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  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
20  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
24  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
25  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26  * POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 /*
30  * Driver for power-button device on U5, U10, etc.
31  */
32 
33 #include <sys/param.h>
34 #include <sys/systm.h>
35 #include <sys/kernel.h>
36 #include <sys/device.h>
37 #include <sys/conf.h>
38 #include <sys/timeout.h>
39 #include <sys/proc.h>
40 #include <sys/signalvar.h>
41 
42 #include <machine/bus.h>
43 #include <machine/autoconf.h>
44 #include <machine/openfirm.h>
45 
46 #include <sparc64/dev/ebusreg.h>
47 #include <sparc64/dev/ebusvar.h>
48 
49 #define	POWER_REG		0
50 
51 #define	POWER_REG_CPWR_OFF	0x00000002	/* courtesy power off */
52 #define	POWER_REG_SPWR_OFF	0x00000001	/* system power off */
53 
54 struct power_softc {
55 	struct device		sc_dev;
56 	bus_space_tag_t		sc_iot;
57 	bus_space_handle_t	sc_ioh;
58 	struct intrhand		*sc_ih;
59 };
60 
61 int	power_match(struct device *, void *, void *);
62 void	power_attach(struct device *, struct device *, void *);
63 int	power_intr(void *);
64 
65 const struct cfattach power_ca = {
66 	sizeof(struct power_softc), power_match, power_attach
67 };
68 
69 struct cfdriver power_cd = {
70 	NULL, "power", DV_DULL
71 };
72 
73 int
74 power_match(parent, match, aux)
75 	struct device *parent;
76 	void *match;
77 	void *aux;
78 {
79 	struct ebus_attach_args *ea = aux;
80 
81 	if (strcmp(ea->ea_name, "power") == 0)
82 		return (1);
83 	return (0);
84 }
85 
86 void
87 power_attach(parent, self, aux)
88 	struct device *parent, *self;
89 	void *aux;
90 {
91 	struct power_softc *sc = (void *)self;
92 	struct ebus_attach_args *ea = aux;
93 
94 	if (ea->ea_nregs < 1) {
95 		printf(": no registers\n");
96 		return;
97 	}
98 
99 	/* Use prom address if available, otherwise map it. */
100 	if (ea->ea_nvaddrs) {
101 		if (bus_space_map(ea->ea_memtag, ea->ea_vaddrs[0], 0,
102 		    BUS_SPACE_MAP_PROMADDRESS, &sc->sc_ioh)) {
103 			printf(": can't map PROM register space\n");
104 			return;
105 		}
106 		sc->sc_iot = ea->ea_memtag;
107 	} else if (ebus_bus_map(ea->ea_iotag, 0,
108 	    EBUS_PADDR_FROM_REG(&ea->ea_regs[0]),
109 	    ea->ea_regs[0].size, 0, 0, &sc->sc_ioh) == 0) {
110 		sc->sc_iot = ea->ea_iotag;
111 	} else if (ebus_bus_map(ea->ea_memtag, 0,
112 	    EBUS_PADDR_FROM_REG(&ea->ea_regs[0]),
113 	    ea->ea_regs[0].size, 0, 0, &sc->sc_ioh) == 0) {
114 		sc->sc_iot = ea->ea_memtag;
115 	} else {
116 		printf("%s: can't map register space\n", self->dv_xname);
117 		return;
118 	}
119 
120 	if (ea->ea_nintrs > 0 && OF_getproplen(ea->ea_node, "button") >= 0) {
121 	        sc->sc_ih = bus_intr_establish(sc->sc_iot, ea->ea_intrs[0],
122 		    IPL_BIO, 0, power_intr, sc, self->dv_xname);
123 		if (sc->sc_ih == NULL) {
124 			printf(": can't establish interrupt\n");
125 			return;
126 		}
127 	}
128 	printf("\n");
129 }
130 
131 int
132 power_intr(void *vsc)
133 {
134 	extern int allowpowerdown;
135 
136 	if (allowpowerdown == 1) {
137 		allowpowerdown = 0;
138 		prsignal(initprocess, SIGUSR2);
139 	}
140 	return (1);
141 }
142