Home | History | Annotate | Line # | Download | only in nslu2
nslu2_leds.c revision 1.1
      1 /*	$NetBSD: nslu2_leds.c,v 1.1 2006/02/28 20:40:33 scw Exp $	*/
      2 
      3 /*-
      4  * Copyright (c) 2006 The NetBSD Foundation, Inc.
      5  * All rights reserved.
      6  *
      7  * This code is derived from software contributed to The NetBSD Foundation
      8  * by Steve C. Woodford.
      9  *
     10  * Redistribution and use in source and binary forms, with or without
     11  * modification, are permitted provided that the following conditions
     12  * are met:
     13  * 1. Redistributions of source code must retain the above copyright
     14  *    notice, this list of conditions and the following disclaimer.
     15  * 2. Redistributions in binary form must reproduce the above copyright
     16  *    notice, this list of conditions and the following disclaimer in the
     17  *    documentation and/or other materials provided with the distribution.
     18  * 3. All advertising materials mentioning features or use of this software
     19  *    must display the following acknowledgement:
     20  *        This product includes software developed by the NetBSD
     21  *        Foundation, Inc. and its contributors.
     22  * 4. Neither the name of The NetBSD Foundation nor the names of its
     23  *    contributors may be used to endorse or promote products derived
     24  *    from this software without specific prior written permission.
     25  *
     26  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     27  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     28  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     29  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     30  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     31  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     32  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     33  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     34  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     35  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     36  * POSSIBILITY OF SUCH DAMAGE.
     37  */
     38 
     39 #include <sys/cdefs.h>
     40 __KERNEL_RCSID(0, "$NetBSD: nslu2_leds.c,v 1.1 2006/02/28 20:40:33 scw Exp $");
     41 
     42 #include <sys/param.h>
     43 #include <sys/systm.h>
     44 #include <sys/kernel.h>
     45 #include <sys/device.h>
     46 #include <sys/callout.h>
     47 #include <sys/disk.h>
     48 
     49 #include <arm/xscale/ixp425var.h>
     50 
     51 #include <evbarm/nslu2/nslu2reg.h>
     52 
     53 #define	SLUGLED_NLEDS		2
     54 #define	SLUGLED_DISKNAMES	"sd%d"	/* XXX: Make this configurable! */
     55 
     56 #define	SLUGLED_POLL		(hz/10)	/* Poll disks 10 times per second */
     57 #define	SLUGLED_FLASH_LEN	2	/* How long, in terms of SLUGLED_POLL,
     58 					   to light up an LED */
     59 #define	SLUGLED_READY_FLASH	3	/* Ditto for flashing Ready LED */
     60 
     61 #define	LEDBITS_DISK0		(1u << GPIO_LED_DISK1)
     62 #define	LEDBITS_DISK1		(1u << GPIO_LED_DISK2)
     63 
     64 /*
     65  * The Ready/Status bits control a tricolour LED.
     66  * Ready is green, status is red.
     67  */
     68 #define	LEDBITS_READY		(1u << GPIO_LED_READY)
     69 #define	LEDBITS_STATUS		(1u << GPIO_LED_STATUS)
     70 
     71 struct slugled_softc {
     72 	struct device sc_dev;
     73 	struct callout sc_co;
     74 	struct {
     75 		char sc_dk_name[DK_DISKNAMELEN];
     76 		struct timeval sc_dk_time;
     77 		int sc_dk_flash;	/* Countdown to LED clear */
     78 	} sc_dk[SLUGLED_NLEDS];
     79 	uint32_t sc_state;
     80 	int sc_count;
     81 };
     82 
     83 static int slugled_attached;
     84 
     85 static void
     86 slugled_callout(void *arg)
     87 {
     88 	struct slugled_softc *sc = arg;
     89 	struct timeval t;
     90 	struct disk *dk;
     91 	uint32_t reg, bit, new_state;
     92 	int s, i, dkbusy;
     93 
     94 	new_state = sc->sc_state;
     95 
     96 	for (i = 0; i < SLUGLED_NLEDS; i++) {
     97 		bit = i ? LEDBITS_DISK1 : LEDBITS_DISK0;
     98 
     99 		s = splbio();
    100 		if ((dk = disk_find(sc->sc_dk[i].sc_dk_name)) == NULL) {
    101 			splx(s);
    102 			if (sc->sc_dk[i].sc_dk_flash > 0) {
    103 				new_state |= bit;
    104 				sc->sc_dk[i].sc_dk_flash = 0;
    105 				sc->sc_dk[i].sc_dk_time = mono_time;
    106 			}
    107 
    108 			continue;
    109 		}
    110 
    111 		dkbusy = dk->dk_busy;
    112 		t = dk->dk_timestamp;
    113 		splx(s);
    114 
    115 		if (dkbusy || t.tv_sec != sc->sc_dk[i].sc_dk_time.tv_sec ||
    116 		    t.tv_usec != sc->sc_dk[i].sc_dk_time.tv_usec) {
    117 			sc->sc_dk[i].sc_dk_flash = SLUGLED_FLASH_LEN;
    118 			sc->sc_dk[i].sc_dk_time = t;
    119 			new_state &= ~bit;
    120 		} else
    121 		if (sc->sc_dk[i].sc_dk_flash > 0 &&
    122 		    --(sc->sc_dk[i].sc_dk_flash) == 0)
    123 			new_state |= bit;
    124 	}
    125 
    126 	if ((++(sc->sc_count) % SLUGLED_READY_FLASH) == 0)
    127 		new_state ^= LEDBITS_READY;
    128 
    129 	if (sc->sc_state != new_state) {
    130 		sc->sc_state = new_state;
    131 		s = splhigh();
    132 		reg = GPIO_CONF_READ_4(ixp425_softc, IXP425_GPIO_GPOUTR);
    133 		reg &= ~(LEDBITS_DISK0 | LEDBITS_DISK1 | LEDBITS_READY);
    134 		reg |= new_state;
    135 		GPIO_CONF_WRITE_4(ixp425_softc, IXP425_GPIO_GPOUTR, reg);
    136 		splx(s);
    137 	}
    138 
    139 	callout_schedule(&sc->sc_co, SLUGLED_POLL);
    140 }
    141 
    142 static void
    143 slugled_shutdown(void *arg)
    144 {
    145 	struct slugled_softc *sc = arg;
    146 	uint32_t reg;
    147 	int s;
    148 
    149 	/* Cancel the disk activity callout */
    150 	s = splsoftclock();
    151 	callout_stop(&sc->sc_co);
    152 	splx(s);
    153 
    154 	/* Turn off the disk LEDs, and set Ready/Status to red */
    155 	s = splhigh();
    156 	reg = GPIO_CONF_READ_4(ixp425_softc,IXP425_GPIO_GPOUTR);
    157 	reg &= ~LEDBITS_READY;
    158 	reg |= LEDBITS_DISK0 | LEDBITS_DISK1 | LEDBITS_STATUS;
    159 	GPIO_CONF_WRITE_4(ixp425_softc,IXP425_GPIO_GPOUTR, reg);
    160 	splx(s);
    161 }
    162 
    163 static void
    164 slugled_defer(struct device *self)
    165 {
    166 	struct slugled_softc *sc = (struct slugled_softc *) self;
    167 	struct ixp425_softc *ixsc = ixp425_softc;
    168 	uint32_t reg;
    169 	int i, s;
    170 
    171 	s = splhigh();
    172 
    173 	/* Configure LED GPIO pins as output */
    174 	reg = GPIO_CONF_READ_4(ixsc, IXP425_GPIO_GPOER);
    175 	reg &= ~(LEDBITS_DISK0 | LEDBITS_DISK1);
    176 	reg &= ~(LEDBITS_READY | LEDBITS_STATUS);
    177 	GPIO_CONF_WRITE_4(ixsc, IXP425_GPIO_GPOER, reg);
    178 
    179 	/* All LEDs off, except Ready LED */
    180 	reg = GPIO_CONF_READ_4(ixsc, IXP425_GPIO_GPOUTR);
    181 	reg |= LEDBITS_DISK0 | LEDBITS_DISK1 | LEDBITS_READY;
    182 	reg &= ~LEDBITS_STATUS;
    183 	GPIO_CONF_WRITE_4(ixsc, IXP425_GPIO_GPOUTR, reg);
    184 
    185 	splx(s);
    186 
    187 	for (i = 0; i < SLUGLED_NLEDS; i++) {
    188 		sprintf(sc->sc_dk[i].sc_dk_name, SLUGLED_DISKNAMES, i);
    189 		sc->sc_dk[i].sc_dk_flash = 0;
    190 		sc->sc_dk[i].sc_dk_time = mono_time;
    191 	}
    192 
    193 	sc->sc_state = LEDBITS_DISK0 | LEDBITS_DISK1 | LEDBITS_READY;
    194 	sc->sc_count = 0;
    195 
    196 	if (shutdownhook_establish(slugled_shutdown, sc) == NULL)
    197 		aprint_error("%s: WARNING - Failed to register shutdown hook\n",
    198 		    sc->sc_dev.dv_xname);
    199 
    200 	callout_init(&sc->sc_co);
    201 	callout_setfunc(&sc->sc_co, slugled_callout, sc);
    202 	callout_schedule(&sc->sc_co, SLUGLED_POLL);
    203 }
    204 
    205 static int
    206 slugled_match(struct device *parent, struct cfdata *match, void *aux)
    207 {
    208 
    209 	return (slugled_attached == 0);
    210 }
    211 
    212 static void
    213 slugled_attach(struct device *parent, struct device *self, void *aux)
    214 {
    215 
    216 	aprint_normal(": LED support\n");
    217 
    218 	slugled_attached = 1;
    219 
    220 	config_interrupts(self, slugled_defer);
    221 }
    222 
    223 CFATTACH_DECL(slugled, sizeof(struct slugled_softc),
    224     slugled_match, slugled_attach, NULL, NULL);
    225