1 /* $OpenBSD: led.c,v 1.2 2019/06/21 08:12:35 kn 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 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 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 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 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 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