1/*	$OpenBSD: power.c,v 1.10 2022/10/16 01:22:39 jsg 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
54struct 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
61int	power_match(struct device *, void *, void *);
62void	power_attach(struct device *, struct device *, void *);
63int	power_intr(void *);
64
65const struct cfattach power_ca = {
66	sizeof(struct power_softc), power_match, power_attach
67};
68
69struct cfdriver power_cd = {
70	NULL, "power", DV_DULL
71};
72
73int
74power_match(struct device *parent, void *match, void *aux)
75{
76	struct ebus_attach_args *ea = aux;
77
78	if (strcmp(ea->ea_name, "power") == 0)
79		return (1);
80	return (0);
81}
82
83void
84power_attach(struct device *parent, struct device *self, void *aux)
85{
86	struct power_softc *sc = (void *)self;
87	struct ebus_attach_args *ea = aux;
88
89	if (ea->ea_nregs < 1) {
90		printf(": no registers\n");
91		return;
92	}
93
94	/* Use prom address if available, otherwise map it. */
95	if (ea->ea_nvaddrs) {
96		if (bus_space_map(ea->ea_memtag, ea->ea_vaddrs[0], 0,
97		    BUS_SPACE_MAP_PROMADDRESS, &sc->sc_ioh)) {
98			printf(": can't map PROM register space\n");
99			return;
100		}
101		sc->sc_iot = ea->ea_memtag;
102	} else if (ebus_bus_map(ea->ea_iotag, 0,
103	    EBUS_PADDR_FROM_REG(&ea->ea_regs[0]),
104	    ea->ea_regs[0].size, 0, 0, &sc->sc_ioh) == 0) {
105		sc->sc_iot = ea->ea_iotag;
106	} else if (ebus_bus_map(ea->ea_memtag, 0,
107	    EBUS_PADDR_FROM_REG(&ea->ea_regs[0]),
108	    ea->ea_regs[0].size, 0, 0, &sc->sc_ioh) == 0) {
109		sc->sc_iot = ea->ea_memtag;
110	} else {
111		printf("%s: can't map register space\n", self->dv_xname);
112		return;
113	}
114
115	if (ea->ea_nintrs > 0 && OF_getproplen(ea->ea_node, "button") >= 0) {
116	        sc->sc_ih = bus_intr_establish(sc->sc_iot, ea->ea_intrs[0],
117		    IPL_BIO, 0, power_intr, sc, self->dv_xname);
118		if (sc->sc_ih == NULL) {
119			printf(": can't establish interrupt\n");
120			return;
121		}
122	}
123	printf("\n");
124}
125
126int
127power_intr(void *vsc)
128{
129	extern int allowpowerdown;
130
131	if (allowpowerdown == 1) {
132		allowpowerdown = 0;
133		prsignal(initprocess, SIGUSR2);
134	}
135	return (1);
136}
137