1 /* $OpenBSD: led.c,v 1.3 2021/10/24 17:05:03 mpi Exp $ */
2
3 /*
4 * Copyright (c) 2007 Mark Kettenis
5 *
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18
19 /*
20 * Driver for leds on Fire V215/V245.
21 */
22
23 #include <sys/param.h>
24 #include <sys/kernel.h>
25 #include <sys/device.h>
26 #include <sys/malloc.h>
27 #include <sys/systm.h>
28 #include <sys/timeout.h>
29
30 #include <machine/autoconf.h>
31 #include <machine/bus.h>
32 #include <machine/cpu.h>
33
34 #include <sparc64/dev/ebusreg.h>
35 #include <sparc64/dev/ebusvar.h>
36
37 /*
38 * Register access is indirect, through an address and data port.
39 */
40
41 #define EPIC_DATA 0x40
42 #define EPIC_ADDR 0x41
43 #define EPIC_WRITE_MASK 0x80
44
45 #define EPIC_FW_VERSION 0x05
46 #define EPIC_LED_STATE0 0x06
47
48 #define EPIC_ALERT_LED_MASK 0x0C
49 #define EPIC_ALERT_LED_OFF 0x00
50 #define EPIC_ALERT_LED_ON 0x04
51
52 #define EPIC_POWER_LED_MASK 0x30
53 #define EPIC_POWER_LED_OFF 0x00
54 #define EPIC_POWER_LED_ON 0x10
55 #define EPIC_POWER_LED_SB_BLINK 0x20
56 #define EPIC_POWER_LED_FAST_BLINK 0x30
57
58 struct led_softc {
59 struct device sc_dv;
60 bus_space_tag_t sc_iot;
61 bus_space_handle_t sc_ioh;
62
63 struct timeout sc_to;
64 int sc_on;
65 struct blink_led sc_blink;
66 };
67
68 int led_match(struct device *, void *, void *);
69 void led_attach(struct device *, struct device *, void *);
70
71 const struct cfattach led_ca = {
72 sizeof(struct led_softc), led_match, led_attach
73 };
74
75 struct cfdriver led_cd = {
76 NULL, "led", DV_DULL
77 };
78
79 void led_blink(void *, int);
80 void led_blink_finish(void *);
81
82 int
led_match(struct device * parent,void * cf,void * aux)83 led_match(struct device *parent, void *cf, void *aux)
84 {
85 struct ebus_attach_args *ea = aux;
86 char *str;
87
88 if (strcmp("env-monitor", ea->ea_name) != 0)
89 return (0);
90
91 str = getpropstring(ea->ea_node, "compatible");
92 if (strcmp(str, "epic") == 0)
93 return (1);
94
95 return (0);
96 }
97
98 void
led_attach(struct device * parent,struct device * self,void * aux)99 led_attach(struct device *parent, struct device *self, void *aux)
100 {
101 struct led_softc *sc = (void *)self;
102 struct ebus_attach_args *ea = aux;
103 int rev;
104
105 if (ebus_bus_map(ea->ea_iotag, 0,
106 EBUS_PADDR_FROM_REG(&ea->ea_regs[0]),
107 ea->ea_regs[0].size, 0, 0, &sc->sc_ioh) == 0) {
108 sc->sc_iot = ea->ea_iotag;
109 } else if (ebus_bus_map(ea->ea_memtag, 0,
110 EBUS_PADDR_FROM_REG(&ea->ea_regs[0]),
111 ea->ea_regs[0].size, 0, 0, &sc->sc_ioh) == 0) {
112 sc->sc_iot = ea->ea_memtag;
113 } else {
114 printf("%s: can't map register space\n", self->dv_xname);
115 return;
116 }
117
118 bus_space_write_1(sc->sc_iot, sc->sc_ioh, EPIC_ADDR, EPIC_FW_VERSION);
119 delay(10000);
120 rev = bus_space_read_1(sc->sc_iot, sc->sc_ioh, EPIC_DATA);
121 printf(": rev 0x%02x\n", rev);
122
123 /* Turn off the alert LED. */
124 bus_space_write_1(sc->sc_iot, sc->sc_ioh,
125 EPIC_WRITE_MASK, EPIC_ALERT_LED_MASK);
126 bus_space_write_1(sc->sc_iot, sc->sc_ioh,
127 EPIC_ADDR, EPIC_LED_STATE0);
128 delay(10000);
129 bus_space_write_1(sc->sc_iot, sc->sc_ioh,
130 EPIC_DATA, EPIC_ALERT_LED_OFF);
131
132 timeout_set(&sc->sc_to, led_blink_finish, sc);
133
134 sc->sc_blink.bl_func = led_blink;
135 sc->sc_blink.bl_arg = sc;
136 blink_led_register(&sc->sc_blink);
137 }
138
139 void
led_blink(void * v,int on)140 led_blink(void *v, int on)
141 {
142 struct led_softc *sc = v;
143
144 sc->sc_on = on;
145 bus_space_write_1(sc->sc_iot, sc->sc_ioh, EPIC_ADDR, EPIC_LED_STATE0);
146 timeout_add_msec(&sc->sc_to, 10);
147 }
148
149 void
led_blink_finish(void * v)150 led_blink_finish(void *v)
151 {
152 struct led_softc *sc = v;
153 u_int8_t reg;
154
155 if (sc->sc_on)
156 reg = EPIC_ALERT_LED_ON;
157 else
158 reg = EPIC_ALERT_LED_OFF;
159
160 bus_space_write_1(sc->sc_iot, sc->sc_ioh, EPIC_DATA, reg);
161 }
162