Home | History | Annotate | Line # | Download | only in dev
      1  1.1  jdc /*	$NetBSD: envmon_ebus.c,v 1.1 2026/09/07 07:35:13 jdc Exp $	*/
      2  1.1  jdc 
      3  1.1  jdc /*-
      4  1.1  jdc  * Copyright (c) 2026 The NetBSD Foundation, Inc.
      5  1.1  jdc  * All rights reserved.
      6  1.1  jdc  *
      7  1.1  jdc  * This code is derived from software contributed to The NetBSD Foundation
      8  1.1  jdc  * by Julian Coleman.
      9  1.1  jdc  *
     10  1.1  jdc  * Redistribution and use in source and binary forms, with or without
     11  1.1  jdc  * modification, are permitted provided that the following conditions
     12  1.1  jdc  * are met:
     13  1.1  jdc  * 1. Redistributions of source code must retain the above copyright
     14  1.1  jdc  *    notice, this list of conditions and the following disclaimer.
     15  1.1  jdc  * 2. Redistributions in binary form must reproduce the above copyright
     16  1.1  jdc  *    notice, this list of conditions and the following disclaimer in the
     17  1.1  jdc  *    documentation and/or other materials provided with the distribution.
     18  1.1  jdc  *
     19  1.1  jdc  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     20  1.1  jdc  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     21  1.1  jdc  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     22  1.1  jdc  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     23  1.1  jdc  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     24  1.1  jdc  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     25  1.1  jdc  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     26  1.1  jdc  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     27  1.1  jdc  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     28  1.1  jdc  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     29  1.1  jdc  * POSSIBILITY OF SUCH DAMAGE.
     30  1.1  jdc  */
     31  1.1  jdc 
     32  1.1  jdc #include <sys/cdefs.h>
     33  1.1  jdc __KERNEL_RCSID(0, "$NetBSD: envmon_ebus.c,v 1.1 2026/09/07 07:35:13 jdc Exp $");
     34  1.1  jdc 
     35  1.1  jdc #include <sys/param.h>
     36  1.1  jdc #include <sys/kernel.h>
     37  1.1  jdc #include <sys/device.h>
     38  1.1  jdc #include <sys/proc.h>
     39  1.1  jdc #include <sys/types.h>
     40  1.1  jdc 
     41  1.1  jdc #include <sys/bus.h>
     42  1.1  jdc #include <machine/autoconf.h>
     43  1.1  jdc 
     44  1.1  jdc #include <dev/ebus/ebusreg.h>
     45  1.1  jdc #include <dev/ebus/ebusvar.h>
     46  1.1  jdc 
     47  1.1  jdc #include <dev/led.h>
     48  1.1  jdc #include <dev/sysmon/sysmonvar.h>
     49  1.1  jdc 
     50  1.1  jdc #include <arch/sparc64/dev/envmon_ebusreg.h>
     51  1.1  jdc 
     52  1.1  jdc #define ENVMON_MACHINE_U25	0x19
     53  1.1  jdc #define ENVMON_MACHINE_U45	0x2d
     54  1.1  jdc #define ENVMON_MACHINE_V215	0xd7
     55  1.1  jdc #define ENVMON_MACHINE_V245	0xf5
     56  1.1  jdc 
     57  1.1  jdc #define ENVMON_PIC_MAX_TEMPS	1
     58  1.1  jdc #define ENVMON_PIC_WMIN_TEMP		273150000	/* 0C from Solaris */
     59  1.1  jdc #define ENVMON_PIC_WMAX_TEMP		318150000	/* 45C from Solaris */
     60  1.1  jdc #define ENVMON_PIC_CRIT_TEMP		338150000	/* 65C from Solaris */
     61  1.1  jdc 
     62  1.1  jdc struct envmon_epic_fans {
     63  1.1  jdc 	const uint8_t	reg;
     64  1.1  jdc 	const char	*desc;
     65  1.1  jdc };
     66  1.1  jdc static struct envmon_epic_fans envmon_epic_fans_table[] = {
     67  1.1  jdc 	{ ENVMON_EPC_FAN_FT0_F0, "FT0.F0" },
     68  1.1  jdc 	{ ENVMON_EPC_FAN_FT1_F0, "FT1.F0" },
     69  1.1  jdc 	{ ENVMON_EPC_FAN_FT2_F0, "FT2.F0" },
     70  1.1  jdc 	{ ENVMON_EPC_FAN_FT3_F0, "FT3.F0" },
     71  1.1  jdc 	{ ENVMON_EPC_FAN_FT4_F0, "FT4.F0" },
     72  1.1  jdc 	{ ENVMON_EPC_FAN_FT5_F0, "FT5.F0" },
     73  1.1  jdc 	{ ENVMON_EPC_FAN_FT0_F1, "FT0.F1" },
     74  1.1  jdc 	{ ENVMON_EPC_FAN_FT1_F1, "FT1.F1" },
     75  1.1  jdc 	{ ENVMON_EPC_FAN_FT2_F1, "FT2.F1" },
     76  1.1  jdc 	{ ENVMON_EPC_FAN_FT3_F1, "FT3.F1" },
     77  1.1  jdc 	{ ENVMON_EPC_FAN_FT4_F1, "FT4.F1" },
     78  1.1  jdc 	{ ENVMON_EPC_FAN_FT5_F1, "FT5.F1" },
     79  1.1  jdc };
     80  1.1  jdc #define ENVMON_EPC_MAX_FANS	(sizeof(envmon_epic_fans_table) / \
     81  1.1  jdc 				    sizeof(envmon_epic_fans_table[0]))
     82  1.1  jdc #define ENVMON_EPC_DIV_V245		5625
     83  1.1  jdc #define ENVMON_EPC_DIV_V215		11250
     84  1.1  jdc #define ENVMON_EPC_CRIT_SPEED_V245	2022		/* From ALOM */
     85  1.1  jdc #define ENVMON_EPC_CRIT_SPEED_V215	5012		/* From ALOM */
     86  1.1  jdc #define ENVMON_EPC_WMIN_TEMP		273150000	/* 0C from ALOM */
     87  1.1  jdc #define ENVMON_EPC_WMAX_TEMP		318150000	/* 45C from ALOM */
     88  1.1  jdc #define ENVMON_EPC_CRIT_TEMP		323150000	/* 50C from ALOM */
     89  1.1  jdc #define ENVMON_EPC_VAL_TO_SPEED(div, val)	((div * 60) / val)
     90  1.1  jdc 
     91  1.1  jdc #define ENVMON_EPC_MAX_FAULTS	1
     92  1.1  jdc 
     93  1.1  jdc #define ENVMON_EPC_MAX_TEMPS	1
     94  1.1  jdc 
     95  1.1  jdc struct envmon_epic_ind {
     96  1.1  jdc 	uint8_t		reg, set;
     97  1.1  jdc 	const char	*desc;
     98  1.1  jdc };
     99  1.1  jdc static struct envmon_epic_ind envmon_epic_inds_table[] = {
    100  1.1  jdc 	{ ENVMON_EPC_KEYSW, ENVMON_EPC_KEYSW_NORM, "keyswitch normal/diag" },
    101  1.1  jdc 	{ ENVMON_EPC_KEYSW, ENVMON_EPC_KEYSW_LOCK, "keyswitch locked" },
    102  1.1  jdc };
    103  1.1  jdc 
    104  1.1  jdc #define ENVMON_EPC_MAX_INDS	(sizeof(envmon_epic_inds_table) / \
    105  1.1  jdc 				    sizeof(envmon_epic_inds_table[0]))
    106  1.1  jdc 
    107  1.1  jdc struct envmon_epic_led {
    108  1.1  jdc 	uint8_t		reg, v_on;
    109  1.1  jdc 	const char	*desc;
    110  1.1  jdc };
    111  1.1  jdc static struct envmon_epic_led envmon_epic_led_table[] = {
    112  1.1  jdc 	{ ENVMON_EPC_LED6, ENVMON_EPC_LED6_LOC, "locator" },
    113  1.1  jdc 	{ ENVMON_EPC_LED6, ENVMON_EPC_LED6_SRV, "service" },
    114  1.1  jdc 	{ ENVMON_EPC_LED6, ENVMON_EPC_LED6_SRV_FSH, "service_flash" },
    115  1.1  jdc 	{ ENVMON_EPC_LED6, ENVMON_EPC_LED6_PWR, "power" },
    116  1.1  jdc 	{ ENVMON_EPC_LED6, ENVMON_EPC_LED6_TF_FLT, "top_fan_fault" },
    117  1.1  jdc 	{ ENVMON_EPC_LED6, ENVMON_EPC_LED6_TF_FLT_FSH, "top_fan_fault_flash" },
    118  1.1  jdc 	{ ENVMON_EPC_LED7, ENVMON_EPC_LED7_PSU, "psu_fault" },
    119  1.1  jdc 	{ ENVMON_EPC_LED7, ENVMON_EPC_LED7_PSU_FSH, "psu_fault_flash" },
    120  1.1  jdc 	{ ENVMON_EPC_LED7, ENVMON_EPC_LED7_CTEMP, "cpu_overtemp" },
    121  1.1  jdc 	{ ENVMON_EPC_LED7, ENVMON_EPC_LED7_CTEMP_FSH, "cpu_overtemp_flash" },
    122  1.1  jdc };
    123  1.1  jdc #define ENVMON_EPC_MAX_LEDS	(sizeof(envmon_epic_led_table) / \
    124  1.1  jdc 				    sizeof(envmon_epic_led_table[0]))
    125  1.1  jdc 
    126  1.1  jdc #define ENVMON_EPC_MAX_SENSORS	\
    127  1.1  jdc     (ENVMON_EPC_MAX_FANS + ENVMON_EPC_MAX_FAULTS + \
    128  1.1  jdc     ENVMON_EPC_MAX_TEMPS + ENVMON_EPC_MAX_INDS)
    129  1.1  jdc 
    130  1.1  jdc #define ENVMON_MAX_TEMPS \
    131  1.1  jdc      MAX(ENVMON_PIC_MAX_TEMPS, ENVMON_EPC_MAX_TEMPS)
    132  1.1  jdc #define ENVMON_MAX_SENSORS \
    133  1.1  jdc     MAX(ENVMON_PIC_MAX_TEMPS, ENVMON_EPC_MAX_SENSORS)
    134  1.1  jdc 
    135  1.1  jdc struct envmon_sc_fan {
    136  1.1  jdc 	uint8_t		reg;
    137  1.1  jdc 	int		cmin;
    138  1.1  jdc };
    139  1.1  jdc 
    140  1.1  jdc struct envmon_sc_temp {
    141  1.1  jdc 	uint8_t		reg;
    142  1.1  jdc 	int		wmin, wmax, cmax;
    143  1.1  jdc };
    144  1.1  jdc 
    145  1.1  jdc struct envmon_sc_ind {
    146  1.1  jdc 	uint8_t		reg, set;
    147  1.1  jdc };
    148  1.1  jdc struct envmon_sc_led {
    149  1.1  jdc 	void			*cookie;
    150  1.1  jdc 	struct led_device	*led;
    151  1.1  jdc 	uint8_t			reg, v_on;
    152  1.1  jdc };
    153  1.1  jdc 
    154  1.1  jdc struct envmon_softc {
    155  1.1  jdc 	device_t		sc_dev;
    156  1.1  jdc 
    157  1.1  jdc 	bus_space_tag_t		sc_bst;
    158  1.1  jdc 	bus_space_handle_t	sc_bsh;
    159  1.1  jdc 
    160  1.1  jdc 	int			sc_machine_type, sc_nfans;
    161  1.1  jdc 	struct envmon_sc_fan	sc_fan[ENVMON_EPC_MAX_FANS];
    162  1.1  jdc 	struct envmon_sc_temp	sc_temp[ENVMON_MAX_TEMPS];
    163  1.1  jdc 	struct envmon_sc_ind	sc_ind[ENVMON_EPC_MAX_INDS];
    164  1.1  jdc 	struct envmon_sc_led	sc_led[ENVMON_EPC_MAX_LEDS];
    165  1.1  jdc 	struct sysmon_envsys	*sc_sme;
    166  1.1  jdc 	envsys_data_t		sc_sensor[ENVMON_MAX_SENSORS];
    167  1.1  jdc 
    168  1.1  jdc #ifdef ENVMON_DEBUG
    169  1.1  jdc 	#define ENVMON_MAX_REG	0x3d
    170  1.1  jdc 	uint8_t			sc_reg[ENVMON_MAX_REG];
    171  1.1  jdc 	#define ENVMON_TIMER	60
    172  1.1  jdc 	callout_t		sc_timer;
    173  1.1  jdc #endif
    174  1.1  jdc };
    175  1.1  jdc 
    176  1.1  jdc static int envmon_ebus_match(device_t, cfdata_t, void *);
    177  1.1  jdc static void envmon_ebus_attach(device_t, device_t, void *);
    178  1.1  jdc static void envmon_pic_attach(struct envmon_softc *, int);
    179  1.1  jdc static void envmon_epic_attach(struct envmon_softc *, int);
    180  1.1  jdc void envmon_pic_refresh(struct sysmon_envsys *, envsys_data_t *);
    181  1.1  jdc void envmon_epic_refresh(struct sysmon_envsys *, envsys_data_t *);
    182  1.1  jdc void envmon_epic_refresh_fan(struct envmon_softc *, envsys_data_t *);
    183  1.1  jdc void envmon_epic_refresh_fault(struct envmon_softc *, envsys_data_t *);
    184  1.1  jdc void envmon_refresh_temp(struct envmon_softc *, envsys_data_t *);
    185  1.1  jdc void envmon_epic_refresh_ind(struct envmon_softc *, envsys_data_t *);
    186  1.1  jdc void envmon_pic_get_limits(struct sysmon_envsys *, envsys_data_t *,
    187  1.1  jdc     sysmon_envsys_lim_t *, uint32_t *);
    188  1.1  jdc void envmon_pic_set_limits(struct sysmon_envsys *, envsys_data_t *,
    189  1.1  jdc     sysmon_envsys_lim_t *, uint32_t *);
    190  1.1  jdc void envmon_epic_get_limits(struct sysmon_envsys *, envsys_data_t *,
    191  1.1  jdc     sysmon_envsys_lim_t *, uint32_t *);
    192  1.1  jdc void envmon_epic_set_limits(struct sysmon_envsys *, envsys_data_t *,
    193  1.1  jdc     sysmon_envsys_lim_t *, uint32_t *);
    194  1.1  jdc static void envmon_epic_get_fan_limits(struct envmon_softc *,
    195  1.1  jdc     envsys_data_t *, sysmon_envsys_lim_t *, uint32_t *);
    196  1.1  jdc static void envmon_get_temp_limits(struct envmon_softc *,
    197  1.1  jdc     envsys_data_t *, sysmon_envsys_lim_t *, uint32_t *);
    198  1.1  jdc static void envmon_epic_set_fan_limits(struct envmon_softc *,
    199  1.1  jdc     envsys_data_t *, sysmon_envsys_lim_t *, uint32_t *);
    200  1.1  jdc static void envmon_set_temp_limits(struct envmon_softc *,
    201  1.1  jdc     envsys_data_t *, sysmon_envsys_lim_t *, uint32_t *);
    202  1.1  jdc int envmon_epic_get_led(void *);
    203  1.1  jdc void envmon_epic_set_led(void *, int);
    204  1.1  jdc #ifdef ENVMON_DEBUG
    205  1.1  jdc static void envmon_timeout(void *);
    206  1.1  jdc #endif
    207  1.1  jdc 
    208  1.1  jdc CFATTACH_DECL_NEW(envmon_ebus, sizeof(struct envmon_softc),
    209  1.1  jdc     envmon_ebus_match, envmon_ebus_attach, NULL, NULL);
    210  1.1  jdc 
    211  1.1  jdc #define	envmon_read(sc, reg) \
    212  1.1  jdc     bus_space_read_1(sc->sc_bst, sc->sc_bsh, reg)
    213  1.1  jdc #define envmon_write(sc, reg, val) \
    214  1.1  jdc     bus_space_write_1(sc->sc_bst, sc->sc_bsh, reg, val)
    215  1.1  jdc 
    216  1.1  jdc static int
    217  1.1  jdc envmon_ebus_match(device_t parent, cfdata_t cf, void *aux)
    218  1.1  jdc {
    219  1.1  jdc 	struct ebus_attach_args *ea = aux;
    220  1.1  jdc 	char *compat;
    221  1.1  jdc 
    222  1.1  jdc 	if (strcmp("env-monitor", ea->ea_name) != 0)
    223  1.1  jdc 		return 0;
    224  1.1  jdc 
    225  1.1  jdc 	compat = prom_getpropstring(ea->ea_node, "compatible");
    226  1.1  jdc 	if (compat != NULL && (!strcmp(compat, "SUNW,ebus-pic16f747-env") ||
    227  1.1  jdc 	    !strcmp(compat, "epic")))
    228  1.1  jdc 		return 1;
    229  1.1  jdc 
    230  1.1  jdc 	return 0;
    231  1.1  jdc }
    232  1.1  jdc 
    233  1.1  jdc static void
    234  1.1  jdc envmon_ebus_attach(device_t parent, device_t self, void *aux)
    235  1.1  jdc {
    236  1.1  jdc 	struct envmon_softc *sc = device_private(self);
    237  1.1  jdc 	struct ebus_attach_args *ea = aux;
    238  1.1  jdc 	char compat[32];
    239  1.1  jdc 	int sz;
    240  1.1  jdc #ifdef ENVMON_DEBUG
    241  1.1  jdc 	uint8_t	reg;
    242  1.1  jdc #endif
    243  1.1  jdc 
    244  1.1  jdc 	sc->sc_dev = self;
    245  1.1  jdc 	sc->sc_bst = ea->ea_bustag;
    246  1.1  jdc 
    247  1.1  jdc 	sz = ea->ea_reg[0].size;
    248  1.1  jdc 
    249  1.1  jdc 	if (bus_space_map(sc->sc_bst,
    250  1.1  jdc 			 EBUS_ADDR_FROM_REG(&ea->ea_reg[0]),
    251  1.1  jdc 			 sz, 0,
    252  1.1  jdc 			 &sc->sc_bsh) != 0) {
    253  1.1  jdc 		aprint_error(": can't map register\n");
    254  1.1  jdc 		return;
    255  1.1  jdc 	}
    256  1.1  jdc 
    257  1.1  jdc 	sc->sc_sme = sysmon_envsys_create();
    258  1.1  jdc 	sc->sc_sme->sme_name = device_xname(self);
    259  1.1  jdc 	sc->sc_sme->sme_cookie = sc;
    260  1.1  jdc 
    261  1.1  jdc 	OF_getprop(ea->ea_node, "compatible", compat, sizeof(compat));
    262  1.1  jdc 
    263  1.1  jdc 	if (!strcmp(compat, "SUNW,ebus-pic16f747-env")) {
    264  1.1  jdc 		envmon_pic_attach(sc, ea->ea_node);
    265  1.1  jdc 	}
    266  1.1  jdc 	if (!strcmp(compat, "epic")) {
    267  1.1  jdc 		envmon_epic_attach(sc, ea->ea_node);
    268  1.1  jdc 	}
    269  1.1  jdc 
    270  1.1  jdc #ifdef ENVMON_DEBUG
    271  1.1  jdc 	for (reg = 0; reg < ENVMON_MAX_REG; reg++) {
    272  1.1  jdc 		envmon_write(sc, ENVMON_ADDR, reg);
    273  1.1  jdc 		sc->sc_reg[reg] = envmon_read(sc, ENVMON_DATA);
    274  1.1  jdc 	}
    275  1.1  jdc 	callout_init(&sc->sc_timer, CALLOUT_MPSAFE);
    276  1.1  jdc 	callout_reset(&sc->sc_timer, hz * ENVMON_TIMER, envmon_timeout, sc);
    277  1.1  jdc #endif
    278  1.1  jdc }
    279  1.1  jdc 
    280  1.1  jdc /*
    281  1.1  jdc  * We only add the front panel temperature here.
    282  1.1  jdc  * Other U45 sensors are handled by the ADT7462 driver.
    283  1.1  jdc  */
    284  1.1  jdc static void
    285  1.1  jdc envmon_pic_attach(struct envmon_softc *sc, int node)
    286  1.1  jdc {
    287  1.1  jdc 	int32_t vers;
    288  1.1  jdc 
    289  1.1  jdc 	vers = prom_getpropint(node, "version", 0);
    290  1.1  jdc 	aprint_normal(": pic16f747 (ver. %d)\n", vers);
    291  1.1  jdc 
    292  1.1  jdc 	if (!strcmp(machine_model, "SUNW,A70")) {
    293  1.1  jdc 		sc->sc_machine_type = ENVMON_MACHINE_U45;
    294  1.1  jdc 	} else if (!strcmp(machine_model, "SUNW,Ultra-25")) {
    295  1.1  jdc 		sc->sc_machine_type = ENVMON_MACHINE_U25;
    296  1.1  jdc 	} else {
    297  1.1  jdc 		aprint_error_dev(sc->sc_dev, "unsupported machine model\n");
    298  1.1  jdc 		return;
    299  1.1  jdc 	}
    300  1.1  jdc 
    301  1.1  jdc 	sc->sc_sme->sme_refresh = envmon_pic_refresh;
    302  1.1  jdc 	sc->sc_sme->sme_get_limits = envmon_pic_get_limits;
    303  1.1  jdc 	sc->sc_sme->sme_set_limits = envmon_pic_set_limits;
    304  1.1  jdc 
    305  1.1  jdc 	strlcpy(sc->sc_sensor[0].desc, "Front_panel",
    306  1.1  jdc 	    sizeof(sc->sc_sensor[0].desc));
    307  1.1  jdc 	sc->sc_sensor[0].units = ENVSYS_STEMP;
    308  1.1  jdc 	sc->sc_sensor[0].state = ENVSYS_SINVALID;
    309  1.1  jdc 	sc->sc_sensor[0].flags = ENVSYS_FHAS_ENTROPY | ENVSYS_FMONLIMITS |
    310  1.1  jdc 	    ENVSYS_FMONCRITICAL;
    311  1.1  jdc 	sc->sc_temp[0].reg = ENVMON_PIC_TEMP_FP;
    312  1.1  jdc 	sc->sc_temp[0].wmin = ENVMON_PIC_WMIN_TEMP;
    313  1.1  jdc 	sc->sc_temp[0].wmax = ENVMON_PIC_WMAX_TEMP;
    314  1.1  jdc 	sc->sc_temp[0].cmax = ENVMON_PIC_CRIT_TEMP;
    315  1.1  jdc 	if (sysmon_envsys_sensor_attach(sc->sc_sme, &sc->sc_sensor[0])) {
    316  1.1  jdc 		sysmon_envsys_destroy(sc->sc_sme);
    317  1.1  jdc 		sc->sc_sme = NULL;
    318  1.1  jdc 		aprint_error_dev(sc->sc_dev,
    319  1.1  jdc 		    "unable to attach sensor to sysmon\n");
    320  1.1  jdc 		return;
    321  1.1  jdc 	}
    322  1.1  jdc 
    323  1.1  jdc 	if (sysmon_envsys_register(sc->sc_sme)) {
    324  1.1  jdc 		aprint_error_dev(sc->sc_dev,
    325  1.1  jdc 		    "unable to register with sysmon\n");
    326  1.1  jdc 		sysmon_envsys_destroy(sc->sc_sme);
    327  1.1  jdc 		sc->sc_sme = NULL;
    328  1.1  jdc 		return;
    329  1.1  jdc 	}
    330  1.1  jdc 
    331  1.1  jdc 	return;
    332  1.1  jdc }
    333  1.1  jdc 
    334  1.1  jdc static void
    335  1.1  jdc envmon_epic_attach(struct envmon_softc *sc, int node)
    336  1.1  jdc {
    337  1.1  jdc 	const char *vers;
    338  1.1  jdc 	int cmin, i, j;
    339  1.1  jdc 
    340  1.1  jdc 	vers = prom_getpropstring(node, "version");
    341  1.1  jdc 	aprint_normal(": epic (ver. %s)\n", vers);
    342  1.1  jdc 
    343  1.1  jdc 	/* Fans */
    344  1.1  jdc 	if (!strcmp(machine_model, "SUNW,Sun-Fire-V245")) {
    345  1.1  jdc 		sc->sc_machine_type = ENVMON_MACHINE_V245;
    346  1.1  jdc 		sc->sc_nfans = 6;
    347  1.1  jdc 		cmin = ENVMON_EPC_CRIT_SPEED_V245;
    348  1.1  jdc 	} else if (!strcmp(machine_model, "SUNW,Sun-Fire-V215")) {
    349  1.1  jdc 		sc->sc_machine_type = ENVMON_MACHINE_V215;
    350  1.1  jdc 		sc->sc_nfans = 12;
    351  1.1  jdc 		cmin = ENVMON_EPC_CRIT_SPEED_V215;
    352  1.1  jdc 	} else {
    353  1.1  jdc 		aprint_error_dev(sc->sc_dev, "unsupported machine model\n");
    354  1.1  jdc 		return;
    355  1.1  jdc 	}
    356  1.1  jdc 
    357  1.1  jdc 	sc->sc_sme->sme_refresh = envmon_epic_refresh;
    358  1.1  jdc 	sc->sc_sme->sme_get_limits = envmon_epic_get_limits;
    359  1.1  jdc 	sc->sc_sme->sme_set_limits = envmon_epic_set_limits;
    360  1.1  jdc 
    361  1.1  jdc 	for (i = 0; i < sc->sc_nfans; i++) {
    362  1.1  jdc 		strlcpy(sc->sc_sensor[i].desc, envmon_epic_fans_table[i].desc,
    363  1.1  jdc 		    sizeof(sc->sc_sensor[i].desc));
    364  1.1  jdc 		sc->sc_sensor[i].units = ENVSYS_SFANRPM;
    365  1.1  jdc 		sc->sc_sensor[i].state = ENVSYS_SINVALID;
    366  1.1  jdc 		sc->sc_sensor[i].flags = ENVSYS_FMONLIMITS |
    367  1.1  jdc 		    ENVSYS_FMONCRITICAL;
    368  1.1  jdc 		sc->sc_fan[i].reg = envmon_epic_fans_table[i].reg;
    369  1.1  jdc 		sc->sc_fan[i].cmin = cmin;
    370  1.1  jdc 		if (sysmon_envsys_sensor_attach(sc->sc_sme,
    371  1.1  jdc 		    &sc->sc_sensor[i])) {
    372  1.1  jdc 			sysmon_envsys_destroy(sc->sc_sme);
    373  1.1  jdc 			sc->sc_sme = NULL;
    374  1.1  jdc 			aprint_error_dev(sc->sc_dev,
    375  1.1  jdc 			    "unable to attach sensor to sysmon\n");
    376  1.1  jdc 			goto leds;
    377  1.1  jdc 		}
    378  1.1  jdc 	}
    379  1.1  jdc 
    380  1.1  jdc 	/* Fan fault */
    381  1.1  jdc 	i = sc->sc_nfans;
    382  1.1  jdc 	strlcpy(sc->sc_sensor[i].desc, "fan fault",
    383  1.1  jdc 	    sizeof(sc->sc_sensor[i].desc));
    384  1.1  jdc 	sc->sc_sensor[i].units = ENVSYS_INTEGER;
    385  1.1  jdc 	sc->sc_sensor[i].state = ENVSYS_SINVALID;
    386  1.1  jdc 	sc->sc_sensor[i].flags = ENVSYS_FMONCRITICAL;
    387  1.1  jdc 	if (sysmon_envsys_sensor_attach(
    388  1.1  jdc 	    sc->sc_sme, &sc->sc_sensor[i])) {
    389  1.1  jdc 		aprint_error_dev(sc->sc_dev,
    390  1.1  jdc 		    "unable to attach fan fault at sysmon\n");
    391  1.1  jdc 		goto leds;
    392  1.1  jdc 	}
    393  1.1  jdc 	i++;
    394  1.1  jdc 
    395  1.1  jdc 	/* Temperature */
    396  1.1  jdc 	strlcpy(sc->sc_sensor[i].desc, "FIOB.T_AMB",
    397  1.1  jdc 	    sizeof(sc->sc_sensor[i].desc));
    398  1.1  jdc 	sc->sc_sensor[i].units = ENVSYS_STEMP;
    399  1.1  jdc 	sc->sc_sensor[i].state = ENVSYS_SINVALID;
    400  1.1  jdc 	sc->sc_sensor[i].flags = ENVSYS_FHAS_ENTROPY | ENVSYS_FMONLIMITS |
    401  1.1  jdc 	    ENVSYS_FMONCRITICAL;
    402  1.1  jdc 	sc->sc_temp[0].reg = ENVMON_EPC_TEMP_FP;
    403  1.1  jdc 	sc->sc_temp[0].wmin = ENVMON_EPC_WMIN_TEMP;
    404  1.1  jdc 	sc->sc_temp[0].wmax = ENVMON_EPC_WMAX_TEMP;
    405  1.1  jdc 	sc->sc_temp[0].cmax = ENVMON_EPC_CRIT_TEMP;
    406  1.1  jdc 	if (sysmon_envsys_sensor_attach(sc->sc_sme, &sc->sc_sensor[i])) {
    407  1.1  jdc 		sysmon_envsys_destroy(sc->sc_sme);
    408  1.1  jdc 		sc->sc_sme = NULL;
    409  1.1  jdc 		aprint_error_dev(sc->sc_dev,
    410  1.1  jdc 			    "unable to attach sensor to sysmon\n");
    411  1.1  jdc 		goto leds;
    412  1.1  jdc 	}
    413  1.1  jdc 	i++;
    414  1.1  jdc 
    415  1.1  jdc 	/* Indicators */
    416  1.1  jdc 	for (j = 0; j < ENVMON_EPC_MAX_INDS; j++, i++) {
    417  1.1  jdc 		strlcpy(sc->sc_sensor[i].desc, envmon_epic_inds_table[j].desc,
    418  1.1  jdc 		    sizeof(sc->sc_sensor[i].desc));
    419  1.1  jdc 		sc->sc_sensor[i].units = ENVSYS_INDICATOR;
    420  1.1  jdc 		sc->sc_sensor[i].state = ENVSYS_SINVALID;
    421  1.1  jdc 		sc->sc_ind[j].reg = envmon_epic_inds_table[j].reg;
    422  1.1  jdc 		sc->sc_ind[j].set = envmon_epic_inds_table[j].set;
    423  1.1  jdc 		if (sysmon_envsys_sensor_attach(sc->sc_sme,
    424  1.1  jdc 		    &sc->sc_sensor[i])) {
    425  1.1  jdc 			sysmon_envsys_destroy(sc->sc_sme);
    426  1.1  jdc 			sc->sc_sme = NULL;
    427  1.1  jdc 			aprint_error_dev(sc->sc_dev,
    428  1.1  jdc 			    "unable to attach sensor to sysmon\n");
    429  1.1  jdc 			goto leds;
    430  1.1  jdc 		}
    431  1.1  jdc 	}
    432  1.1  jdc 
    433  1.1  jdc 	if (sysmon_envsys_register(sc->sc_sme)) {
    434  1.1  jdc 		aprint_error_dev(sc->sc_dev,
    435  1.1  jdc 		    "unable to register with sysmon\n");
    436  1.1  jdc 		sysmon_envsys_destroy(sc->sc_sme);
    437  1.1  jdc 		sc->sc_sme = NULL;
    438  1.1  jdc 	}
    439  1.1  jdc 
    440  1.1  jdc leds:
    441  1.1  jdc 	/* LED's */
    442  1.1  jdc 	for (i = 0; i < ENVMON_EPC_MAX_LEDS; i++) {
    443  1.1  jdc 		sc->sc_led[i].cookie = sc;
    444  1.1  jdc 		sc->sc_led[i].reg = envmon_epic_led_table[i].reg;
    445  1.1  jdc 		sc->sc_led[i].v_on = envmon_epic_led_table[i].v_on;
    446  1.1  jdc 		led_attach(envmon_epic_led_table[i].desc,
    447  1.1  jdc 		    &sc->sc_led[i], envmon_epic_get_led, envmon_epic_set_led);
    448  1.1  jdc 	}
    449  1.1  jdc 
    450  1.1  jdc 	return;
    451  1.1  jdc }
    452  1.1  jdc 
    453  1.1  jdc void
    454  1.1  jdc envmon_pic_refresh(struct sysmon_envsys *sme, envsys_data_t *edata)
    455  1.1  jdc {
    456  1.1  jdc 	struct envmon_softc *sc = sme->sme_cookie;
    457  1.1  jdc 
    458  1.1  jdc 	envmon_refresh_temp(sc, edata);
    459  1.1  jdc }
    460  1.1  jdc 
    461  1.1  jdc void
    462  1.1  jdc envmon_epic_refresh(struct sysmon_envsys *sme, envsys_data_t *edata)
    463  1.1  jdc {
    464  1.1  jdc 	struct envmon_softc *sc = sme->sme_cookie;
    465  1.1  jdc 
    466  1.1  jdc 	if (edata->sensor < sc->sc_nfans)
    467  1.1  jdc 		envmon_epic_refresh_fan(sc, edata);
    468  1.1  jdc 	else if (edata->sensor < sc->sc_nfans + ENVMON_EPC_MAX_FAULTS)
    469  1.1  jdc 		envmon_epic_refresh_fault(sc, edata);
    470  1.1  jdc 	else if (edata->sensor <
    471  1.1  jdc 	    sc->sc_nfans + ENVMON_EPC_MAX_FAULTS + ENVMON_EPC_MAX_TEMPS)
    472  1.1  jdc 		envmon_refresh_temp(sc, edata);
    473  1.1  jdc 	else
    474  1.1  jdc 		envmon_epic_refresh_ind(sc, edata);
    475  1.1  jdc 
    476  1.1  jdc 	return;
    477  1.1  jdc }
    478  1.1  jdc 
    479  1.1  jdc void
    480  1.1  jdc envmon_epic_refresh_fan(struct envmon_softc *sc, envsys_data_t *edata)
    481  1.1  jdc {
    482  1.1  jdc 	uint8_t val;
    483  1.1  jdc 	int div;
    484  1.1  jdc 
    485  1.1  jdc 	if (sc->sc_machine_type == ENVMON_MACHINE_V245)
    486  1.1  jdc 		div = ENVMON_EPC_DIV_V245;
    487  1.1  jdc 	else
    488  1.1  jdc 		div = ENVMON_EPC_DIV_V215;
    489  1.1  jdc 
    490  1.1  jdc 	envmon_write(sc, ENVMON_ADDR, sc->sc_fan[edata->sensor].reg);
    491  1.1  jdc 	val = envmon_read(sc, ENVMON_DATA);
    492  1.1  jdc 	if (val == 0xff || val == 0x0)
    493  1.1  jdc 		edata->value_cur = 0;
    494  1.1  jdc 	else {
    495  1.1  jdc 		edata->value_cur = ENVMON_EPC_VAL_TO_SPEED(div, val);
    496  1.1  jdc 	}
    497  1.1  jdc 	if (edata->value_cur < sc->sc_fan[edata->sensor].cmin)
    498  1.1  jdc 		edata->state = ENVSYS_SCRITICAL;
    499  1.1  jdc 	else
    500  1.1  jdc 		edata->state = ENVSYS_SVALID;
    501  1.1  jdc }
    502  1.1  jdc 
    503  1.1  jdc void
    504  1.1  jdc envmon_epic_refresh_fault(struct envmon_softc *sc, envsys_data_t *edata)
    505  1.1  jdc {
    506  1.1  jdc 	uint8_t val;
    507  1.1  jdc 	int32_t which, total;
    508  1.1  jdc 	int i, j;
    509  1.1  jdc 
    510  1.1  jdc 	envmon_write(sc, ENVMON_ADDR, ENVMON_EPC_FAN_FLT);
    511  1.1  jdc 	val = envmon_read(sc, ENVMON_DATA);
    512  1.1  jdc 
    513  1.1  jdc 	total = 0;
    514  1.1  jdc 	if (val == ENVMON_EPC_FAN_FLT_NONE) {
    515  1.1  jdc 		edata->state = ENVSYS_SVALID;
    516  1.1  jdc 	} else {
    517  1.1  jdc 		edata->state = ENVSYS_SCRITICAL;
    518  1.1  jdc 		for (i = 0; i < ENVMON_EPC_NUM_FAN_FLTS; i++) {
    519  1.1  jdc 			if (!(val & __BIT(i))) {
    520  1.1  jdc 				which = 1;
    521  1.1  jdc 				for (j = 0; j < i; j++)
    522  1.1  jdc 					which *= 10;
    523  1.1  jdc 				total += which;
    524  1.1  jdc 			}
    525  1.1  jdc 		}
    526  1.1  jdc 	}
    527  1.1  jdc 	edata->value_cur = total;
    528  1.1  jdc }
    529  1.1  jdc 
    530  1.1  jdc void
    531  1.1  jdc envmon_refresh_temp(struct envmon_softc *sc, envsys_data_t *edata)
    532  1.1  jdc {
    533  1.1  jdc 	uint8_t val;
    534  1.1  jdc 
    535  1.1  jdc 	/* We currently only have 1 temperature sensor */
    536  1.1  jdc 	envmon_write(sc, ENVMON_ADDR, sc->sc_temp[0].reg);
    537  1.1  jdc 	val = envmon_read(sc, ENVMON_DATA);
    538  1.1  jdc 	edata->value_cur = ENVMON_TEMP_BASE + val * 1000000;
    539  1.1  jdc 	if (edata->value_cur > sc->sc_temp[0].cmax)
    540  1.1  jdc 		edata->state = ENVSYS_SCRITICAL;
    541  1.1  jdc 	else
    542  1.1  jdc 		edata->state = ENVSYS_SVALID;
    543  1.1  jdc }
    544  1.1  jdc 
    545  1.1  jdc void
    546  1.1  jdc envmon_epic_refresh_ind(struct envmon_softc *sc, envsys_data_t *edata)
    547  1.1  jdc {
    548  1.1  jdc 	int ind = edata->sensor -
    549  1.1  jdc 	    sc->sc_nfans - ENVMON_EPC_MAX_TEMPS - ENVMON_EPC_MAX_FAULTS;
    550  1.1  jdc 	uint8_t val;
    551  1.1  jdc 
    552  1.1  jdc 	envmon_write(sc, ENVMON_ADDR, sc->sc_ind[ind].reg);
    553  1.1  jdc 	val = envmon_read(sc, ENVMON_DATA);
    554  1.1  jdc 
    555  1.1  jdc 	if (val == sc->sc_ind[ind].set)
    556  1.1  jdc 		edata->value_cur = TRUE;
    557  1.1  jdc 	else
    558  1.1  jdc 		edata->value_cur = FALSE;
    559  1.1  jdc 	edata->state = ENVSYS_SVALID;
    560  1.1  jdc }
    561  1.1  jdc 
    562  1.1  jdc void
    563  1.1  jdc envmon_pic_get_limits(struct sysmon_envsys *sme, envsys_data_t *edata,
    564  1.1  jdc     sysmon_envsys_lim_t *limits, uint32_t *props)
    565  1.1  jdc {
    566  1.1  jdc 	struct envmon_softc *sc = sme->sme_cookie;
    567  1.1  jdc 
    568  1.1  jdc 	envmon_get_temp_limits(sc, edata, limits, props);
    569  1.1  jdc }
    570  1.1  jdc 
    571  1.1  jdc void
    572  1.1  jdc envmon_pic_set_limits(struct sysmon_envsys *sme, envsys_data_t *edata,
    573  1.1  jdc     sysmon_envsys_lim_t *limits, uint32_t *props)
    574  1.1  jdc {
    575  1.1  jdc 	struct envmon_softc *sc = sme->sme_cookie;
    576  1.1  jdc 
    577  1.1  jdc 	envmon_set_temp_limits(sc, edata, limits, props);
    578  1.1  jdc }
    579  1.1  jdc 
    580  1.1  jdc void
    581  1.1  jdc envmon_epic_get_limits(struct sysmon_envsys *sme, envsys_data_t *edata,
    582  1.1  jdc     sysmon_envsys_lim_t *limits, uint32_t *props)
    583  1.1  jdc {
    584  1.1  jdc 	struct envmon_softc *sc = sme->sme_cookie;
    585  1.1  jdc 
    586  1.1  jdc 	if (edata->sensor < sc->sc_nfans)
    587  1.1  jdc 		envmon_epic_get_fan_limits(sc, edata, limits, props);
    588  1.1  jdc 	else if (edata->sensor < sc->sc_nfans + ENVMON_EPC_MAX_TEMPS)
    589  1.1  jdc 		envmon_get_temp_limits(sc, edata, limits, props);
    590  1.1  jdc }
    591  1.1  jdc 
    592  1.1  jdc void
    593  1.1  jdc envmon_epic_set_limits(struct sysmon_envsys *sme, envsys_data_t *edata,
    594  1.1  jdc     sysmon_envsys_lim_t *limits, uint32_t *props)
    595  1.1  jdc {
    596  1.1  jdc 	struct envmon_softc *sc = sme->sme_cookie;
    597  1.1  jdc 
    598  1.1  jdc 	if (edata->sensor < sc->sc_nfans)
    599  1.1  jdc 		envmon_epic_set_fan_limits(sc, edata, limits, props);
    600  1.1  jdc 	else if (edata->sensor < sc->sc_nfans + ENVMON_EPC_MAX_TEMPS)
    601  1.1  jdc 		envmon_set_temp_limits(sc, edata, limits, props);
    602  1.1  jdc }
    603  1.1  jdc 
    604  1.1  jdc static void
    605  1.1  jdc envmon_epic_get_fan_limits(struct envmon_softc *sc,
    606  1.1  jdc     envsys_data_t *edata, sysmon_envsys_lim_t *limits, uint32_t *props)
    607  1.1  jdc {
    608  1.1  jdc 
    609  1.1  jdc 	*props = PROP_CRITMIN;
    610  1.1  jdc 	limits->sel_critmin = sc->sc_fan[edata->sensor].cmin;
    611  1.1  jdc }
    612  1.1  jdc 
    613  1.1  jdc static void
    614  1.1  jdc envmon_get_temp_limits(struct envmon_softc *sc,
    615  1.1  jdc     envsys_data_t *edata, sysmon_envsys_lim_t *limits, uint32_t *props)
    616  1.1  jdc {
    617  1.1  jdc 
    618  1.1  jdc 	*props = PROP_WARNMIN | PROP_WARNMAX | PROP_CRITMAX;
    619  1.1  jdc 	limits->sel_warnmin = sc->sc_temp[0].wmin;
    620  1.1  jdc 	limits->sel_warnmax = sc->sc_temp[0].wmax;
    621  1.1  jdc 	limits->sel_critmax = sc->sc_temp[0].cmax;
    622  1.1  jdc }
    623  1.1  jdc 
    624  1.1  jdc static void
    625  1.1  jdc envmon_epic_set_fan_limits(struct envmon_softc *sc,
    626  1.1  jdc     envsys_data_t *edata, sysmon_envsys_lim_t *limits, uint32_t *props)
    627  1.1  jdc {
    628  1.1  jdc 
    629  1.1  jdc 	if (limits == NULL || *props & PROP_CRITMIN) {
    630  1.1  jdc 		if (limits == NULL)	/* Restore defaults */
    631  1.1  jdc 			switch (sc->sc_machine_type) {
    632  1.1  jdc 				case ENVMON_MACHINE_V215:
    633  1.1  jdc 					sc->sc_fan[edata->sensor].cmin =
    634  1.1  jdc 					    ENVMON_EPC_CRIT_SPEED_V215;
    635  1.1  jdc 					break;
    636  1.1  jdc 				case ENVMON_MACHINE_V245:
    637  1.1  jdc 					sc->sc_fan[edata->sensor].cmin =
    638  1.1  jdc 					    ENVMON_EPC_CRIT_SPEED_V245;
    639  1.1  jdc 					break;
    640  1.1  jdc 			}
    641  1.1  jdc 		else
    642  1.1  jdc 			sc->sc_fan[edata->sensor].cmin = limits->sel_critmin;
    643  1.1  jdc 	}
    644  1.1  jdc }
    645  1.1  jdc 
    646  1.1  jdc static void
    647  1.1  jdc envmon_set_temp_limits(struct envmon_softc *sc,
    648  1.1  jdc     envsys_data_t *edata, sysmon_envsys_lim_t *limits, uint32_t *props)
    649  1.1  jdc {
    650  1.1  jdc 
    651  1.1  jdc 	if (limits == NULL || *props & PROP_CRITMAX) {
    652  1.1  jdc 		if (limits == NULL)	/* Restore defaults */
    653  1.1  jdc 			switch (sc->sc_machine_type) {
    654  1.1  jdc 				case ENVMON_MACHINE_U25:
    655  1.1  jdc 				case ENVMON_MACHINE_U45:
    656  1.1  jdc 					sc->sc_temp[0].cmax =
    657  1.1  jdc 					    ENVMON_PIC_CRIT_TEMP;
    658  1.1  jdc 					break;
    659  1.1  jdc 				case ENVMON_MACHINE_V215:
    660  1.1  jdc 				case ENVMON_MACHINE_V245:
    661  1.1  jdc 					sc->sc_temp[0].cmax =
    662  1.1  jdc 					    ENVMON_EPC_CRIT_TEMP;
    663  1.1  jdc 					break;
    664  1.1  jdc 			}
    665  1.1  jdc 		else
    666  1.1  jdc 			sc->sc_temp[edata->sensor].cmax = limits->sel_critmax;
    667  1.1  jdc 	}
    668  1.1  jdc 
    669  1.1  jdc 	if (limits == NULL || *props & PROP_WARNMAX) {
    670  1.1  jdc 		if (limits == NULL)	/* Restore defaults */
    671  1.1  jdc 			switch (sc->sc_machine_type) {
    672  1.1  jdc 				case ENVMON_MACHINE_U25:
    673  1.1  jdc 				case ENVMON_MACHINE_U45:
    674  1.1  jdc 					sc->sc_temp[0].wmax =
    675  1.1  jdc 					    ENVMON_PIC_WMAX_TEMP;
    676  1.1  jdc 					break;
    677  1.1  jdc 				case ENVMON_MACHINE_V215:
    678  1.1  jdc 				case ENVMON_MACHINE_V245:
    679  1.1  jdc 					sc->sc_temp[0].wmax =
    680  1.1  jdc 					    ENVMON_EPC_WMAX_TEMP;
    681  1.1  jdc 					break;
    682  1.1  jdc 			}
    683  1.1  jdc 		else
    684  1.1  jdc 			sc->sc_temp[edata->sensor].wmax = limits->sel_warnmax;
    685  1.1  jdc 	}
    686  1.1  jdc 
    687  1.1  jdc 	if (limits == NULL || *props & PROP_WARNMIN) {
    688  1.1  jdc 		if (limits == NULL)	/* Restore defaults */
    689  1.1  jdc 			switch (sc->sc_machine_type) {
    690  1.1  jdc 				case ENVMON_MACHINE_U25:
    691  1.1  jdc 				case ENVMON_MACHINE_U45:
    692  1.1  jdc 					sc->sc_temp[0].wmin =
    693  1.1  jdc 					    ENVMON_PIC_WMIN_TEMP;
    694  1.1  jdc 					break;
    695  1.1  jdc 				case ENVMON_MACHINE_V215:
    696  1.1  jdc 				case ENVMON_MACHINE_V245:
    697  1.1  jdc 					sc->sc_temp[0].wmin =
    698  1.1  jdc 					    ENVMON_EPC_WMIN_TEMP;
    699  1.1  jdc 					break;
    700  1.1  jdc 			}
    701  1.1  jdc 		else
    702  1.1  jdc 			sc->sc_temp[edata->sensor].wmin = limits->sel_warnmin;
    703  1.1  jdc 	}
    704  1.1  jdc 
    705  1.1  jdc }
    706  1.1  jdc 
    707  1.1  jdc int
    708  1.1  jdc envmon_epic_get_led(void *cookie)
    709  1.1  jdc {
    710  1.1  jdc 	struct envmon_sc_led *l = cookie;
    711  1.1  jdc 	struct envmon_softc *sc = l->cookie;
    712  1.1  jdc 	uint8_t val;
    713  1.1  jdc 
    714  1.1  jdc 	envmon_write(sc, ENVMON_ADDR, l->reg);
    715  1.1  jdc 	val = envmon_read(sc, ENVMON_DATA);
    716  1.1  jdc 	return ((val & l->v_on) == l->v_on);
    717  1.1  jdc }
    718  1.1  jdc 
    719  1.1  jdc void
    720  1.1  jdc envmon_epic_set_led(void *cookie, int val)
    721  1.1  jdc {
    722  1.1  jdc 	struct envmon_sc_led *l = cookie;
    723  1.1  jdc 	struct envmon_softc *sc = l->cookie;
    724  1.1  jdc 	uint8_t oldval, newval;
    725  1.1  jdc 
    726  1.1  jdc 	envmon_write(sc, ENVMON_ADDR, l->reg);
    727  1.1  jdc 	oldval = envmon_read(sc, ENVMON_DATA);
    728  1.1  jdc 	newval = oldval & ~(l->v_on);
    729  1.1  jdc 	newval |= val ? l->v_on : 0x0;
    730  1.1  jdc 	if (newval != oldval) {
    731  1.1  jdc 		envmon_write(sc, ENVMON_EPC_LED_MASK, l->v_on);
    732  1.1  jdc 		envmon_write(sc, ENVMON_ADDR, l->reg);
    733  1.1  jdc 		delay(10000);
    734  1.1  jdc 		envmon_write(sc, ENVMON_DATA, newval);
    735  1.1  jdc 	}
    736  1.1  jdc }
    737  1.1  jdc 
    738  1.1  jdc #ifdef ENVMON_DEBUG
    739  1.1  jdc static void
    740  1.1  jdc envmon_timeout(void *v)
    741  1.1  jdc {
    742  1.1  jdc 	struct envmon_softc *sc = v;
    743  1.1  jdc 	uint8_t reg, val;
    744  1.1  jdc 
    745  1.1  jdc 	for (reg = 0; reg < ENVMON_MAX_REG; reg++) {
    746  1.1  jdc 		envmon_write(sc, ENVMON_ADDR, reg);
    747  1.1  jdc 		val = envmon_read(sc, ENVMON_DATA);
    748  1.1  jdc 		if (val != sc->sc_reg[reg]) {
    749  1.1  jdc 			printf("%s: reg 0x%02x: 0x%02x > 0x%02x\n",
    750  1.1  jdc 			    device_xname(sc->sc_dev), reg,
    751  1.1  jdc 			    sc->sc_reg[reg], val);
    752  1.1  jdc 			sc->sc_reg[reg] = val;
    753  1.1  jdc 		}
    754  1.1  jdc 	}
    755  1.1  jdc 	callout_reset(&sc->sc_timer, hz * ENVMON_TIMER, envmon_timeout, sc);
    756  1.1  jdc }
    757  1.1  jdc #endif
    758