nslu2_buttons.c revision 1.4
11.4Smsaitoh/*	$NetBSD: nslu2_buttons.c,v 1.4 2012/10/14 14:20:58 msaitoh 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 *
191.1Sscw * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
201.1Sscw * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
211.1Sscw * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
221.1Sscw * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
231.1Sscw * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
241.1Sscw * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
251.1Sscw * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
261.1Sscw * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
271.1Sscw * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
281.1Sscw * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
291.1Sscw * POSSIBILITY OF SUCH DAMAGE.
301.1Sscw */
311.1Sscw
321.1Sscw#include <sys/cdefs.h>
331.4Smsaitoh__KERNEL_RCSID(0, "$NetBSD: nslu2_buttons.c,v 1.4 2012/10/14 14:20:58 msaitoh Exp $");
341.1Sscw
351.1Sscw#include <sys/param.h>
361.1Sscw#include <sys/systm.h>
371.1Sscw#include <sys/device.h>
381.1Sscw
391.1Sscw#include <dev/sysmon/sysmonvar.h>
401.1Sscw#include <dev/sysmon/sysmon_taskq.h>
411.1Sscw
421.1Sscw#include <arm/xscale/ixp425reg.h>
431.1Sscw#include <arm/xscale/ixp425var.h>
441.1Sscw
451.1Sscw#include <evbarm/nslu2/nslu2reg.h>
461.1Sscw
471.1Sscwstruct slugbutt_softc {
481.4Smsaitoh	device_t sc_dev;
491.1Sscw	struct sysmon_pswitch sc_smpwr;
501.1Sscw	struct sysmon_pswitch sc_smrst;
511.1Sscw};
521.1Sscw
531.1Sscwstatic int slugbutt_attached;
541.1Sscw
551.2Sscw#define	SLUGBUTT_PWR_BIT	(1u << GPIO_BUTTON_PWR)
561.2Sscw#define	SLUGBUTT_RST_BIT	(1u << GPIO_BUTTON_RST)
571.2Sscw
581.1Sscwstatic void
591.1Sscwpower_event(void *arg)
601.1Sscw{
611.1Sscw	struct slugbutt_softc *sc = arg;
621.1Sscw
631.1Sscw	sysmon_pswitch_event(&sc->sc_smpwr, PSWITCH_EVENT_PRESSED);
641.1Sscw}
651.1Sscw
661.1Sscwstatic int
671.1Sscwpower_intr(void *arg)
681.1Sscw{
691.1Sscw	struct slugbutt_softc *sc = arg;
701.1Sscw	int rv;
711.1Sscw
721.2Sscw	GPIO_CONF_WRITE_4(ixp425_softc, IXP425_GPIO_GPISR, SLUGBUTT_PWR_BIT);
731.1Sscw
741.1Sscw	rv = sysmon_task_queue_sched(0, power_event, sc);
751.1Sscw	if (rv) {
761.1Sscw		printf("%s: WARNING: unable to queue power button "
771.4Smsaitoh		    "callback: %d\n", device_xname(sc->sc_dev), rv);
781.1Sscw	}
791.1Sscw
801.1Sscw	return (1);
811.1Sscw}
821.1Sscw
831.1Sscwstatic void
841.1Sscwreset_event(void *arg)
851.1Sscw{
861.1Sscw	struct slugbutt_softc *sc = arg;
871.1Sscw
881.1Sscw	sysmon_pswitch_event(&sc->sc_smrst, PSWITCH_EVENT_PRESSED);
891.1Sscw}
901.1Sscw
911.1Sscwstatic int
921.1Sscwreset_intr(void *arg)
931.1Sscw{
941.1Sscw	struct slugbutt_softc *sc = arg;
951.1Sscw	int rv;
961.1Sscw
971.2Sscw	GPIO_CONF_WRITE_4(ixp425_softc, IXP425_GPIO_GPISR, SLUGBUTT_RST_BIT);
981.1Sscw
991.1Sscw	rv = sysmon_task_queue_sched(0, reset_event, sc);
1001.1Sscw	if (rv) {
1011.1Sscw		printf("%s: WARNING: unable to queue reset button "
1021.4Smsaitoh		    "callback: %d\n", device_xname(sc->sc_dev), rv);
1031.1Sscw	}
1041.1Sscw
1051.1Sscw	return (1);
1061.1Sscw}
1071.1Sscw
1081.1Sscwstatic void
1091.4Smsaitohslugbutt_deferred(device_t self)
1101.1Sscw{
1111.4Smsaitoh	struct slugbutt_softc *sc = device_private(self);
1121.1Sscw	struct ixp425_softc *ixsc = ixp425_softc;
1131.1Sscw	uint32_t reg;
1141.1Sscw
1151.4Smsaitoh	sc->sc_dev = self;
1161.4Smsaitoh
1171.1Sscw	/* Configure the GPIO pins as inputs */
1181.1Sscw	reg = GPIO_CONF_READ_4(ixsc, IXP425_GPIO_GPOER);
1191.2Sscw	reg |= SLUGBUTT_PWR_BIT | SLUGBUTT_RST_BIT;
1201.1Sscw	GPIO_CONF_WRITE_4(ixsc, IXP425_GPIO_GPOER, reg);
1211.1Sscw
1221.1Sscw	/* Configure the input type: Falling edge */
1231.1Sscw	reg = GPIO_CONF_READ_4(ixsc, GPIO_TYPE_REG(GPIO_BUTTON_PWR));
1241.1Sscw	reg &= ~GPIO_TYPE(GPIO_BUTTON_PWR, GPIO_TYPE_MASK);
1251.1Sscw	reg |= GPIO_TYPE(GPIO_BUTTON_PWR, GPIO_TYPE_EDG_FALLING);
1261.1Sscw	GPIO_CONF_WRITE_4(ixsc, GPIO_TYPE_REG(GPIO_BUTTON_PWR), reg);
1271.1Sscw
1281.1Sscw	reg = GPIO_CONF_READ_4(ixsc, GPIO_TYPE_REG(GPIO_BUTTON_RST));
1291.1Sscw	reg &= ~GPIO_TYPE(GPIO_BUTTON_RST, GPIO_TYPE_MASK);
1301.1Sscw	reg |= GPIO_TYPE(GPIO_BUTTON_RST, GPIO_TYPE_EDG_FALLING);
1311.1Sscw	GPIO_CONF_WRITE_4(ixsc, GPIO_TYPE_REG(GPIO_BUTTON_RST), reg);
1321.1Sscw
1331.1Sscw	/* Clear any existing interrupt */
1341.2Sscw	GPIO_CONF_WRITE_4(ixsc, IXP425_GPIO_GPISR, SLUGBUTT_PWR_BIT |
1351.2Sscw	    SLUGBUTT_RST_BIT);
1361.1Sscw
1371.1Sscw	sysmon_task_queue_init();
1381.1Sscw
1391.4Smsaitoh	sc->sc_smpwr.smpsw_name = device_xname(sc->sc_dev);
1401.1Sscw	sc->sc_smpwr.smpsw_type = PSWITCH_TYPE_POWER;
1411.1Sscw
1421.1Sscw	if (sysmon_pswitch_register(&sc->sc_smpwr) != 0) {
1431.1Sscw		printf("%s: unable to register power button with sysmon\n",
1441.4Smsaitoh		    device_xname(sc->sc_dev));
1451.1Sscw		return;
1461.1Sscw	}
1471.1Sscw
1481.4Smsaitoh	sc->sc_smrst.smpsw_name = device_xname(sc->sc_dev);
1491.1Sscw	sc->sc_smrst.smpsw_type = PSWITCH_TYPE_RESET;
1501.1Sscw
1511.1Sscw	if (sysmon_pswitch_register(&sc->sc_smrst) != 0) {
1521.1Sscw		printf("%s: unable to register reset button with sysmon\n",
1531.4Smsaitoh		    device_xname(sc->sc_dev));
1541.1Sscw		return;
1551.1Sscw	}
1561.1Sscw
1571.1Sscw	/* Hook the interrupts */
1581.1Sscw	ixp425_intr_establish(BUTTON_PWR_INT, IPL_TTY, power_intr, sc);
1591.1Sscw	ixp425_intr_establish(BUTTON_RST_INT, IPL_TTY, reset_intr, sc);
1601.1Sscw}
1611.1Sscw
1621.1Sscw
1631.1Sscwstatic int
1641.4Smsaitohslugbutt_match(device_t parent, cfdata_t cf, void *aux)
1651.1Sscw{
1661.1Sscw
1671.1Sscw	return (slugbutt_attached == 0);
1681.1Sscw}
1691.1Sscw
1701.1Sscwstatic void
1711.4Smsaitohslugbutt_attach(device_t parent, device_t self, void *aux)
1721.1Sscw{
1731.1Sscw
1741.1Sscw	slugbutt_attached = 1;
1751.1Sscw
1761.1Sscw	aprint_normal(": Power and Reset buttons\n");
1771.1Sscw
1781.1Sscw	/* Defer, to ensure ixp425_softc has been initialised */
1791.1Sscw	config_interrupts(self, slugbutt_deferred);
1801.1Sscw}
1811.1Sscw
1821.4SmsaitohCFATTACH_DECL_NEW(slugbutt, sizeof(struct slugbutt_softc),
1831.1Sscw    slugbutt_match, slugbutt_attach, NULL, NULL);
184