Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 8 May 2009 15:22:10 +0100 (BST)
From:      Gavin Atkinson <gavin@FreeBSD.org>
To:        FreeBSD-gnats-submit@FreeBSD.org
Subject:   arm/134368: [patch] nslu2_led driver for the LEDs on the NSLU2
Message-ID:  <200905081422.n48EMArP073408@buffy.york.ac.uk>
Resent-Message-ID: <200905081430.n48EU2rD066149@freefall.freebsd.org>

next in thread | raw e-mail | index | archive | help

>Number:         134368
>Category:       arm
>Synopsis:       [patch] nslu2_led driver for the LEDs on the NSLU2
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    freebsd-arm
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Fri May 08 14:30:02 UTC 2009
>Closed-Date:
>Last-Modified:
>Originator:     Gavin Atkinson
>Release:        FreeBSD 7.1-STABLE amd64
>Organization:
>Environment:
System: FreeBSD buffy.york.ac.uk 7.1-STABLE FreeBSD 7.1-STABLE #5: Fri Feb 13 11:25:58 GMT 2009 root@buffy.york.ac.uk:/usr/obj/usr/src/sys/GENERIC amd64

>Description:
	Simple driver for the LEDs on the NSLU2.  This uses the led(4)
API and provides devices under /dev/led/ to set the state of the four
LEDs.  It also switches the power LED to green on boot and to amber
on shutdown, like the original NSLU2 does.  Note that this requires
the GPIO locking changes submitted in PR arm/134338.

I've also created a new "files.nslu2" and "std.nslu2" file, as I have
drivers for the buttons and RTC to be submitted soon, so it makes
sense to factor NSLU out from the avila config now.

Written by myself, under the 2-clause BSD license.
>How-To-Repeat:
	N/A
>Fix:

--- nslu2_led.diff begins here ---
Index: sys/arm/conf/NSLU
===================================================================
RCS file: /home/ncvs/src/sys/arm/conf/NSLU,v
retrieving revision 1.6
diff -u -r1.6 NSLU
--- sys/arm/conf/NSLU	23 Feb 2009 18:34:56 -0000	1.6
+++ sys/arm/conf/NSLU	8 May 2009 14:12:48 -0000
@@ -30,6 +30,7 @@
 include		"../xscale/ixp425/std.ixp425"
 # NB: memory mapping is defined in std.avila (see also comment above)
 include		"../xscale/ixp425/std.avila"
+include		"../xscale/ixp425/std.nslu2"
 options 	XSCALE_CACHE_READ_WRITE_ALLOCATE
 #To statically compile in device wiring instead of /boot/device.hints
 hints		"NSLU.hints"		#Default places to look for devices.
@@ -91,6 +92,8 @@
 device		ixpiic		# I2C bus glue
 device		ixpwdog		# watchdog timer
 
+device		nslu2_led	# NSLU2 LEDs
+
 device		npe		# Network Processing Engine
 device		npe_fw
 device		firmware
Index: sys/arm/conf/NSLU.hints
===================================================================
RCS file: /home/ncvs/src/sys/arm/conf/NSLU.hints,v
retrieving revision 1.2
diff -u -r1.2 NSLU.hints
--- sys/arm/conf/NSLU.hints	6 May 2009 20:24:17 -0000	1.2
+++ sys/arm/conf/NSLU.hints	8 May 2009 13:14:07 -0000
@@ -34,5 +34,6 @@
 #hint.xrtc.0.at="iicbus0"
 #hint.xrtc.0.addr=0xde
 # Slug LED
+hint.nslu2_led.0.at="ixp0"
 # Slug button
 # Slug Buzzer
--- /dev/null	2009-05-08 15:11:01.000000000 +0100
+++ sys/arm/xscale/ixp425/nslu2_led.c	2009-05-08 15:14:11.000000000 +0100
@@ -0,0 +1,232 @@
+/*-
+ * Copyright (c) 2009, Gavin Atkinson <gavin@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+
+#include <sys/bus.h>
+#include <sys/eventhandler.h>
+#include <sys/lock.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/mutex.h>
+#include <sys/systm.h>
+
+#include <arm/xscale/ixp425/ixp425reg.h>
+#include <arm/xscale/ixp425/ixp425var.h>
+
+#include <dev/led/led.h>
+
+#define	GPIO_LED_STATUS_RED	0
+#define	GPIO_LED_STATUS_GREEN	1
+#define	GPIO_LED_DISK2		2
+#define	GPIO_LED_DISK1		3
+
+#define	GPIO_LED_STATUS_RED_BIT		(1U << GPIO_LED_STATUS_RED)
+#define	GPIO_LED_STATUS_GREEN_BIT	(1U << GPIO_LED_STATUS_GREEN)
+#define	GPIO_LED_DISK2_BIT		(1U << GPIO_LED_DISK2)
+#define	GPIO_LED_DISK1_BIT		(1U << GPIO_LED_DISK1)
+
+/* Amber is produced by switching both red and green LEDs on */
+#define	GPIO_LED_STATUS_AMBER_BITS	(GPIO_LED_STATUS_RED_BIT | \
+					 GPIO_LED_STATUS_GREEN_BIT)
+
+#define	GPIO_ALL_LED_BITS		(GPIO_LED_STATUS_RED_BIT | \
+					 GPIO_LED_STATUS_GREEN_BIT | \
+					 GPIO_LED_DISK2_BIT | \
+					 GPIO_LED_DISK1_BIT)
+
+struct nslu2_led_softc {
+	device_t		sc_dev;
+	bus_space_tag_t		sc_iot;
+	bus_space_handle_t	sc_gpio_ioh;
+	eventhandler_tag	sc_shutdown_eh;
+	struct cdev		*sc_srled;
+	struct cdev		*sc_saled;
+	struct cdev		*sc_sgled;
+	struct cdev		*sc_d1led;
+	struct cdev		*sc_d2led;
+};
+
+extern struct mtx ixp425_gpio_mtx;
+
+static void
+nslu2_led_set(struct nslu2_led_softc *sc, int leds, int mask) 
+{
+	uint32_t reg;
+
+	/* On the NSLU2 hardware, a "1" written to the status LED outputs
+	 * will switch the LEDs on, but for the disk LEDs a "1" switches
+	 * them off. Handle that here, so the rest of the code doesn't
+	 * have to deal with this detail.
+	 */
+	leds ^= (GPIO_LED_DISK1_BIT | GPIO_LED_DISK2_BIT);
+
+	mtx_lock(&ixp425_gpio_mtx);
+	reg = GPIO_CONF_READ_4(sc, IXP425_GPIO_GPOUTR);
+	reg &= ~mask;
+	reg |= (leds & mask);
+	GPIO_CONF_WRITE_4(sc, IXP425_GPIO_GPOUTR, reg);
+	mtx_unlock(&ixp425_gpio_mtx);
+}
+
+static void
+nslu2_led_status_red_func(void *arg, int onoff)
+{
+	struct nslu2_led_softc *sc = arg;
+
+	nslu2_led_set(sc, (onoff ? GPIO_LED_STATUS_RED_BIT : 0),
+	    GPIO_LED_STATUS_RED_BIT);
+}
+
+static void
+nslu2_led_status_amber_func(void *arg, int onoff)
+{
+	struct nslu2_led_softc *sc = arg;
+
+	/* XXX: Ideally this should be done through the led(4) interface,
+	 * but there isn't currently a published interface to change
+	 * state from the kernel, so we go behind led(4)'s back.
+	 */
+	nslu2_led_set(sc, (onoff ? GPIO_LED_STATUS_AMBER_BITS : 0),
+	    GPIO_LED_STATUS_AMBER_BITS);
+}
+
+static void
+nslu2_led_status_green_func(void *arg, int onoff)
+{
+	struct nslu2_led_softc *sc = arg;
+
+	nslu2_led_set(sc, (onoff ? GPIO_LED_STATUS_GREEN_BIT : 0),
+	    GPIO_LED_STATUS_GREEN_BIT);
+}
+
+static void
+nslu2_led_status_disk1_func(void *arg, int onoff)
+{
+	struct nslu2_led_softc *sc = arg;
+
+	nslu2_led_set(sc, (onoff ? GPIO_LED_DISK1_BIT : 0),
+	    GPIO_LED_DISK1_BIT);
+}
+
+static void
+nslu2_led_status_disk2_func(void *arg, int onoff)
+{
+	struct nslu2_led_softc *sc = arg;
+
+	nslu2_led_set(sc, (onoff ? GPIO_LED_DISK2_BIT : 0),
+	    GPIO_LED_DISK2_BIT);
+}
+
+static void
+nslu2_led_shutdown(void *arg)
+{
+	struct nslu2_led_softc *sc = arg;
+
+	EVENTHANDLER_DEREGISTER(shutdown_pre_sync, sc->sc_shutdown_eh);
+
+	/* Shutting down...  Set status to amber */
+	nslu2_led_set(sc, GPIO_LED_STATUS_AMBER_BITS,
+	    GPIO_LED_STATUS_AMBER_BITS);
+}
+
+static int
+nslu2_led_probe(device_t dev)
+{
+	device_set_desc(dev, "NSLU2 LEDs");
+	return (BUS_PROBE_DEFAULT);
+}
+
+static int
+nslu2_led_attach(device_t dev)
+{
+	struct nslu2_led_softc *sc = device_get_softc(dev);
+	struct ixp425_softc *sa = device_get_softc(device_get_parent(dev));
+
+	sc->sc_dev = dev;
+	sc->sc_iot = sa->sc_iot;
+	sc->sc_gpio_ioh = sa->sc_gpio_ioh;
+
+	/* Configure LED GPIO pins as output */
+	mtx_lock(&ixp425_gpio_mtx);
+	GPIO_CONF_WRITE_4(sc, IXP425_GPIO_GPOER,
+	    GPIO_CONF_READ_4(sc, IXP425_GPIO_GPOER) &~ GPIO_ALL_LED_BITS);
+	mtx_unlock(&ixp425_gpio_mtx);
+
+	/* Start with status LED green and disk LEDs off */
+	sc->sc_srled = led_create_state(nslu2_led_status_red_func,
+	    sc, "status-red", 0);
+	sc->sc_saled = led_create_state(nslu2_led_status_amber_func,
+	    sc, "status-amber", 0);
+	sc->sc_sgled = led_create_state(nslu2_led_status_green_func,
+	    sc, "status-green", 1);
+	sc->sc_d1led = led_create_state(nslu2_led_status_disk1_func,
+	    sc, "disk1", 0);
+	sc->sc_d2led = led_create_state(nslu2_led_status_disk2_func,
+	    sc, "disk2", 0);
+
+	sc->sc_shutdown_eh = EVENTHANDLER_REGISTER(shutdown_pre_sync,
+	    nslu2_led_shutdown, sc, SHUTDOWN_PRI_FIRST);
+	return (0);
+}
+
+static void
+nslu2_led_detach(device_t dev)
+{
+	struct nslu2_led_softc *sc = device_get_softc(dev);
+
+	if (sc->sc_shutdown_eh)
+	    EVENTHANDLER_DEREGISTER(shutdown_pre_sync, sc->sc_shutdown_eh);
+	if (sc->sc_srled != NULL)
+	    led_destroy(sc->sc_srled);
+	if (sc->sc_saled != NULL)
+	    led_destroy(sc->sc_saled);
+	if (sc->sc_sgled != NULL)
+	    led_destroy(sc->sc_sgled);
+	if (sc->sc_d1led != NULL)
+	    led_destroy(sc->sc_d1led);
+	if (sc->sc_d2led != NULL)
+	    led_destroy(sc->sc_d2led);
+}
+
+static device_method_t nslu2_led_methods[] = {
+	DEVMETHOD(device_probe,		nslu2_led_probe),
+	DEVMETHOD(device_attach,	nslu2_led_attach),
+	DEVMETHOD(device_detach,	nslu2_led_detach),
+
+	{0, 0},
+};
+
+static driver_t nslu2_led_driver = {
+	"nslu2_led",
+	nslu2_led_methods,
+	sizeof(struct nslu2_led_softc),
+};
+static devclass_t nslu2_led_devclass;
+
+DRIVER_MODULE(nslu2_led, ixp, nslu2_led_driver, nslu2_led_devclass, 0, 0);
--- /dev/null	2009-05-08 15:11:01.000000000 +0100
+++ sys/arm/xscale/ixp425/std.nslu2	2009-05-08 14:14:50.000000000 +0100
@@ -0,0 +1,7 @@
+#$FreeBSD$
+
+#
+# Linksys NSLU2 board configuration
+#
+files		"../xscale/ixp425/files.nslu2"
+#
--- /dev/null	2009-05-08 15:11:01.000000000 +0100
+++ sys/arm/xscale/ixp425/files.nslu2	2009-05-08 14:14:55.000000000 +0100
@@ -0,0 +1,2 @@
+#$FreeBSD$
+arm/xscale/ixp425/nslu2_led.c		optional nslu2_led
--- nslu2_led.diff ends here ---


>Release-Note:
>Audit-Trail:
>Unformatted:



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200905081422.n48EMArP073408>