nslu2_buttons.c revision 1.2
11.2Sscw/*	$NetBSD: nslu2_buttons.c,v 1.2 2006/03/01 21:02:50 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.2Sscw__KERNEL_RCSID(0, "$NetBSD: nslu2_buttons.c,v 1.2 2006/03/01 21:02:50 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.2Sscw#define	SLUGBUTT_PWR_BIT	(1u << GPIO_BUTTON_PWR)
631.2Sscw#define	SLUGBUTT_RST_BIT	(1u << GPIO_BUTTON_RST)
641.2Sscw
651.1Sscwstatic void
661.1Sscwpower_event(void *arg)
671.1Sscw{
681.1Sscw	struct slugbutt_softc *sc = arg;
691.1Sscw
701.1Sscw	sysmon_pswitch_event(&sc->sc_smpwr, PSWITCH_EVENT_PRESSED);
711.1Sscw}
721.1Sscw
731.1Sscwstatic int
741.1Sscwpower_intr(void *arg)
751.1Sscw{
761.1Sscw	struct slugbutt_softc *sc = arg;
771.1Sscw	int rv;
781.1Sscw
791.2Sscw	GPIO_CONF_WRITE_4(ixp425_softc, IXP425_GPIO_GPISR, SLUGBUTT_PWR_BIT);
801.1Sscw
811.1Sscw	rv = sysmon_task_queue_sched(0, power_event, sc);
821.1Sscw	if (rv) {
831.1Sscw		printf("%s: WARNING: unable to queue power button "
841.1Sscw		    "callback: %d\n", sc->sc_dev.dv_xname, rv);
851.1Sscw	}
861.1Sscw
871.1Sscw	return (1);
881.1Sscw}
891.1Sscw
901.1Sscwstatic void
911.1Sscwreset_event(void *arg)
921.1Sscw{
931.1Sscw	struct slugbutt_softc *sc = arg;
941.1Sscw
951.1Sscw	sysmon_pswitch_event(&sc->sc_smrst, PSWITCH_EVENT_PRESSED);
961.1Sscw}
971.1Sscw
981.1Sscwstatic int
991.1Sscwreset_intr(void *arg)
1001.1Sscw{
1011.1Sscw	struct slugbutt_softc *sc = arg;
1021.1Sscw	int rv;
1031.1Sscw
1041.2Sscw	GPIO_CONF_WRITE_4(ixp425_softc, IXP425_GPIO_GPISR, SLUGBUTT_RST_BIT);
1051.1Sscw
1061.1Sscw	rv = sysmon_task_queue_sched(0, reset_event, sc);
1071.1Sscw	if (rv) {
1081.1Sscw		printf("%s: WARNING: unable to queue reset button "
1091.1Sscw		    "callback: %d\n", sc->sc_dev.dv_xname, rv);
1101.1Sscw	}
1111.1Sscw
1121.1Sscw	return (1);
1131.1Sscw}
1141.1Sscw
1151.1Sscwstatic void
1161.1Sscwslugbutt_deferred(struct device *self)
1171.1Sscw{
1181.1Sscw	struct slugbutt_softc *sc = (struct slugbutt_softc *) self;
1191.1Sscw	struct ixp425_softc *ixsc = ixp425_softc;
1201.1Sscw	uint32_t reg;
1211.1Sscw
1221.1Sscw	/* Configure the GPIO pins as inputs */
1231.1Sscw	reg = GPIO_CONF_READ_4(ixsc, IXP425_GPIO_GPOER);
1241.2Sscw	reg |= SLUGBUTT_PWR_BIT | SLUGBUTT_RST_BIT;
1251.1Sscw	GPIO_CONF_WRITE_4(ixsc, IXP425_GPIO_GPOER, reg);
1261.1Sscw
1271.1Sscw	/* Configure the input type: Falling edge */
1281.1Sscw	reg = GPIO_CONF_READ_4(ixsc, GPIO_TYPE_REG(GPIO_BUTTON_PWR));
1291.1Sscw	reg &= ~GPIO_TYPE(GPIO_BUTTON_PWR, GPIO_TYPE_MASK);
1301.1Sscw	reg |= GPIO_TYPE(GPIO_BUTTON_PWR, GPIO_TYPE_EDG_FALLING);
1311.1Sscw	GPIO_CONF_WRITE_4(ixsc, GPIO_TYPE_REG(GPIO_BUTTON_PWR), reg);
1321.1Sscw
1331.1Sscw	reg = GPIO_CONF_READ_4(ixsc, GPIO_TYPE_REG(GPIO_BUTTON_RST));
1341.1Sscw	reg &= ~GPIO_TYPE(GPIO_BUTTON_RST, GPIO_TYPE_MASK);
1351.1Sscw	reg |= GPIO_TYPE(GPIO_BUTTON_RST, GPIO_TYPE_EDG_FALLING);
1361.1Sscw	GPIO_CONF_WRITE_4(ixsc, GPIO_TYPE_REG(GPIO_BUTTON_RST), reg);
1371.1Sscw
1381.1Sscw	/* Clear any existing interrupt */
1391.2Sscw	GPIO_CONF_WRITE_4(ixsc, IXP425_GPIO_GPISR, SLUGBUTT_PWR_BIT |
1401.2Sscw	    SLUGBUTT_RST_BIT);
1411.1Sscw
1421.1Sscw	sysmon_task_queue_init();
1431.1Sscw
1441.1Sscw	sc->sc_smpwr.smpsw_name = sc->sc_dev.dv_xname;
1451.1Sscw	sc->sc_smpwr.smpsw_type = PSWITCH_TYPE_POWER;
1461.1Sscw
1471.1Sscw	if (sysmon_pswitch_register(&sc->sc_smpwr) != 0) {
1481.1Sscw		printf("%s: unable to register power button with sysmon\n",
1491.1Sscw		    sc->sc_dev.dv_xname);
1501.1Sscw		return;
1511.1Sscw	}
1521.1Sscw
1531.1Sscw	sc->sc_smrst.smpsw_name = sc->sc_dev.dv_xname;
1541.1Sscw	sc->sc_smrst.smpsw_type = PSWITCH_TYPE_RESET;
1551.1Sscw
1561.1Sscw	if (sysmon_pswitch_register(&sc->sc_smrst) != 0) {
1571.1Sscw		printf("%s: unable to register reset button with sysmon\n",
1581.1Sscw		    sc->sc_dev.dv_xname);
1591.1Sscw		return;
1601.1Sscw	}
1611.1Sscw
1621.1Sscw	/* Hook the interrupts */
1631.1Sscw	ixp425_intr_establish(BUTTON_PWR_INT, IPL_TTY, power_intr, sc);
1641.1Sscw	ixp425_intr_establish(BUTTON_RST_INT, IPL_TTY, reset_intr, sc);
1651.1Sscw}
1661.1Sscw
1671.1Sscw
1681.1Sscwstatic int
1691.1Sscwslugbutt_match(struct device *parent, struct cfdata *cf, void *arg)
1701.1Sscw{
1711.1Sscw
1721.1Sscw	return (slugbutt_attached == 0);
1731.1Sscw}
1741.1Sscw
1751.1Sscwstatic void
1761.1Sscwslugbutt_attach(struct device *parent, struct device *self, void *arg)
1771.1Sscw{
1781.1Sscw
1791.1Sscw	slugbutt_attached = 1;
1801.1Sscw
1811.1Sscw	aprint_normal(": Power and Reset buttons\n");
1821.1Sscw
1831.1Sscw	/* Defer, to ensure ixp425_softc has been initialised */
1841.1Sscw	config_interrupts(self, slugbutt_deferred);
1851.1Sscw}
1861.1Sscw
1871.1SscwCFATTACH_DECL(slugbutt, sizeof(struct slugbutt_softc),
1881.1Sscw    slugbutt_match, slugbutt_attach, NULL, NULL);
189