nslu2_buttons.c revision 1.1
11.1Sscw/*	$NetBSD: nslu2_buttons.c,v 1.1 2006/02/28 20:40:33 scw Exp $	*/
21.1Sscw
31.1Sscw/*-
41.1Sscw * Copyright (c) 2006 The NetBSD Foundation, Inc.
51.1Sscw * All rights reserved.
61.1Sscw *
71.1Sscw * This code is derived from software contributed to The NetBSD Foundation
81.1Sscw * by Steve C. Woodford.
91.1Sscw *
101.1Sscw * Redistribution and use in source and binary forms, with or without
111.1Sscw * modification, are permitted provided that the following conditions
121.1Sscw * are met:
131.1Sscw * 1. Redistributions of source code must retain the above copyright
141.1Sscw *    notice, this list of conditions and the following disclaimer.
151.1Sscw * 2. Redistributions in binary form must reproduce the above copyright
161.1Sscw *    notice, this list of conditions and the following disclaimer in the
171.1Sscw *    documentation and/or other materials provided with the distribution.
181.1Sscw * 3. All advertising materials mentioning features or use of this software
191.1Sscw *    must display the following acknowledgement:
201.1Sscw *        This product includes software developed by the NetBSD
211.1Sscw *        Foundation, Inc. and its contributors.
221.1Sscw * 4. Neither the name of The NetBSD Foundation nor the names of its
231.1Sscw *    contributors may be used to endorse or promote products derived
241.1Sscw *    from this software without specific prior written permission.
251.1Sscw *
261.1Sscw * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
271.1Sscw * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
281.1Sscw * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
291.1Sscw * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
301.1Sscw * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
311.1Sscw * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
321.1Sscw * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
331.1Sscw * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
341.1Sscw * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
351.1Sscw * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
361.1Sscw * POSSIBILITY OF SUCH DAMAGE.
371.1Sscw */
381.1Sscw
391.1Sscw#include <sys/cdefs.h>
401.1Sscw__KERNEL_RCSID(0, "$NetBSD: nslu2_buttons.c,v 1.1 2006/02/28 20:40:33 scw Exp $");
411.1Sscw
421.1Sscw#include <sys/param.h>
431.1Sscw#include <sys/systm.h>
441.1Sscw#include <sys/device.h>
451.1Sscw
461.1Sscw#include <dev/sysmon/sysmonvar.h>
471.1Sscw#include <dev/sysmon/sysmon_taskq.h>
481.1Sscw
491.1Sscw#include <arm/xscale/ixp425reg.h>
501.1Sscw#include <arm/xscale/ixp425var.h>
511.1Sscw
521.1Sscw#include <evbarm/nslu2/nslu2reg.h>
531.1Sscw
541.1Sscwstruct slugbutt_softc {
551.1Sscw	struct device sc_dev;
561.1Sscw	struct sysmon_pswitch sc_smpwr;
571.1Sscw	struct sysmon_pswitch sc_smrst;
581.1Sscw};
591.1Sscw
601.1Sscwstatic int slugbutt_attached;
611.1Sscw
621.1Sscwstatic void
631.1Sscwpower_event(void *arg)
641.1Sscw{
651.1Sscw	struct slugbutt_softc *sc = arg;
661.1Sscw
671.1Sscw	sysmon_pswitch_event(&sc->sc_smpwr, PSWITCH_EVENT_PRESSED);
681.1Sscw}
691.1Sscw
701.1Sscwstatic int
711.1Sscwpower_intr(void *arg)
721.1Sscw{
731.1Sscw	struct slugbutt_softc *sc = arg;
741.1Sscw	int rv;
751.1Sscw
761.1Sscw	GPIO_CONF_WRITE_4(ixp425_softc, IXP425_GPIO_GPISR,
771.1Sscw	    1u << GPIO_BUTTON_PWR);
781.1Sscw
791.1Sscw	rv = sysmon_task_queue_sched(0, power_event, sc);
801.1Sscw	if (rv) {
811.1Sscw		printf("%s: WARNING: unable to queue power button "
821.1Sscw		    "callback: %d\n", sc->sc_dev.dv_xname, rv);
831.1Sscw	}
841.1Sscw
851.1Sscw	return (1);
861.1Sscw}
871.1Sscw
881.1Sscwstatic void
891.1Sscwreset_event(void *arg)
901.1Sscw{
911.1Sscw	struct slugbutt_softc *sc = arg;
921.1Sscw
931.1Sscw	sysmon_pswitch_event(&sc->sc_smrst, PSWITCH_EVENT_PRESSED);
941.1Sscw}
951.1Sscw
961.1Sscwstatic int
971.1Sscwreset_intr(void *arg)
981.1Sscw{
991.1Sscw	struct slugbutt_softc *sc = arg;
1001.1Sscw	int rv;
1011.1Sscw
1021.1Sscw	GPIO_CONF_WRITE_4(ixp425_softc, IXP425_GPIO_GPISR,
1031.1Sscw	    1u << GPIO_BUTTON_RST);
1041.1Sscw
1051.1Sscw	rv = sysmon_task_queue_sched(0, reset_event, sc);
1061.1Sscw	if (rv) {
1071.1Sscw		printf("%s: WARNING: unable to queue reset button "
1081.1Sscw		    "callback: %d\n", sc->sc_dev.dv_xname, rv);
1091.1Sscw	}
1101.1Sscw
1111.1Sscw	return (1);
1121.1Sscw}
1131.1Sscw
1141.1Sscwstatic void
1151.1Sscwslugbutt_deferred(struct device *self)
1161.1Sscw{
1171.1Sscw	struct slugbutt_softc *sc = (struct slugbutt_softc *) self;
1181.1Sscw	struct ixp425_softc *ixsc = ixp425_softc;
1191.1Sscw	uint32_t reg;
1201.1Sscw
1211.1Sscw	/* Configure the GPIO pins as inputs */
1221.1Sscw	reg = GPIO_CONF_READ_4(ixsc, IXP425_GPIO_GPOER);
1231.1Sscw	reg |= GPIO_BUTTON_PWR | GPIO_BUTTON_RST;
1241.1Sscw	GPIO_CONF_WRITE_4(ixsc, IXP425_GPIO_GPOER, reg);
1251.1Sscw
1261.1Sscw	/* Configure the input type: Falling edge */
1271.1Sscw	reg = GPIO_CONF_READ_4(ixsc, GPIO_TYPE_REG(GPIO_BUTTON_PWR));
1281.1Sscw	reg &= ~GPIO_TYPE(GPIO_BUTTON_PWR, GPIO_TYPE_MASK);
1291.1Sscw	reg |= GPIO_TYPE(GPIO_BUTTON_PWR, GPIO_TYPE_EDG_FALLING);
1301.1Sscw	GPIO_CONF_WRITE_4(ixsc, GPIO_TYPE_REG(GPIO_BUTTON_PWR), reg);
1311.1Sscw
1321.1Sscw	reg = GPIO_CONF_READ_4(ixsc, GPIO_TYPE_REG(GPIO_BUTTON_RST));
1331.1Sscw	reg &= ~GPIO_TYPE(GPIO_BUTTON_RST, GPIO_TYPE_MASK);
1341.1Sscw	reg |= GPIO_TYPE(GPIO_BUTTON_RST, GPIO_TYPE_EDG_FALLING);
1351.1Sscw	GPIO_CONF_WRITE_4(ixsc, GPIO_TYPE_REG(GPIO_BUTTON_RST), reg);
1361.1Sscw
1371.1Sscw	/* Clear any existing interrupt */
1381.1Sscw	GPIO_CONF_WRITE_4(ixsc, IXP425_GPIO_GPISR, (1u << GPIO_BUTTON_PWR) |
1391.1Sscw	    (1u << GPIO_BUTTON_RST));
1401.1Sscw
1411.1Sscw	sysmon_task_queue_init();
1421.1Sscw
1431.1Sscw	sc->sc_smpwr.smpsw_name = sc->sc_dev.dv_xname;
1441.1Sscw	sc->sc_smpwr.smpsw_type = PSWITCH_TYPE_POWER;
1451.1Sscw
1461.1Sscw	if (sysmon_pswitch_register(&sc->sc_smpwr) != 0) {
1471.1Sscw		printf("%s: unable to register power button with sysmon\n",
1481.1Sscw		    sc->sc_dev.dv_xname);
1491.1Sscw		return;
1501.1Sscw	}
1511.1Sscw
1521.1Sscw	sc->sc_smrst.smpsw_name = sc->sc_dev.dv_xname;
1531.1Sscw	sc->sc_smrst.smpsw_type = PSWITCH_TYPE_RESET;
1541.1Sscw
1551.1Sscw	if (sysmon_pswitch_register(&sc->sc_smrst) != 0) {
1561.1Sscw		printf("%s: unable to register reset button with sysmon\n",
1571.1Sscw		    sc->sc_dev.dv_xname);
1581.1Sscw		return;
1591.1Sscw	}
1601.1Sscw
1611.1Sscw	/* Hook the interrupts */
1621.1Sscw	ixp425_intr_establish(BUTTON_PWR_INT, IPL_TTY, power_intr, sc);
1631.1Sscw	ixp425_intr_establish(BUTTON_RST_INT, IPL_TTY, reset_intr, sc);
1641.1Sscw}
1651.1Sscw
1661.1Sscw
1671.1Sscwstatic int
1681.1Sscwslugbutt_match(struct device *parent, struct cfdata *cf, void *arg)
1691.1Sscw{
1701.1Sscw
1711.1Sscw	return (slugbutt_attached == 0);
1721.1Sscw}
1731.1Sscw
1741.1Sscwstatic void
1751.1Sscwslugbutt_attach(struct device *parent, struct device *self, void *arg)
1761.1Sscw{
1771.1Sscw
1781.1Sscw	slugbutt_attached = 1;
1791.1Sscw
1801.1Sscw	aprint_normal(": Power and Reset buttons\n");
1811.1Sscw
1821.1Sscw	/* Defer, to ensure ixp425_softc has been initialised */
1831.1Sscw	config_interrupts(self, slugbutt_deferred);
1841.1Sscw}
1851.1Sscw
1861.1SscwCFATTACH_DECL(slugbutt, sizeof(struct slugbutt_softc),
1871.1Sscw    slugbutt_match, slugbutt_attach, NULL, NULL);
188