xref: /openbsd/sys/dev/fdt/dapmic.c (revision 0701a158)
1*0701a158Skettenis /*	$OpenBSD: dapmic.c,v 1.4 2022/10/12 13:39:50 kettenis Exp $	*/
29b3c43d5Skettenis /*
39b3c43d5Skettenis  * Copyright (c) 2021 Mark Kettenis <kettenis@openbsd.org>
49b3c43d5Skettenis  *
59b3c43d5Skettenis  * Permission to use, copy, modify, and distribute this software for any
69b3c43d5Skettenis  * purpose with or without fee is hereby granted, provided that the above
79b3c43d5Skettenis  * copyright notice and this permission notice appear in all copies.
89b3c43d5Skettenis  *
99b3c43d5Skettenis  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
109b3c43d5Skettenis  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
119b3c43d5Skettenis  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
129b3c43d5Skettenis  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
139b3c43d5Skettenis  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
149b3c43d5Skettenis  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
159b3c43d5Skettenis  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
169b3c43d5Skettenis  */
179b3c43d5Skettenis 
189b3c43d5Skettenis #include <sys/param.h>
199b3c43d5Skettenis #include <sys/systm.h>
209b3c43d5Skettenis #include <sys/device.h>
219b3c43d5Skettenis #include <sys/malloc.h>
226311c331Sjca #include <sys/task.h>
236311c331Sjca #include <sys/proc.h>
246311c331Sjca #include <sys/signalvar.h>
259b3c43d5Skettenis 
269b3c43d5Skettenis #include <dev/ofw/openfirm.h>
279b3c43d5Skettenis #include <dev/ofw/ofw_regulator.h>
289b3c43d5Skettenis #include <dev/ofw/fdt.h>
299b3c43d5Skettenis 
309b3c43d5Skettenis #include <dev/i2c/i2cvar.h>
319b3c43d5Skettenis 
329b3c43d5Skettenis #include <dev/clock_subr.h>
339b3c43d5Skettenis 
346311c331Sjca #include <machine/fdt.h>
356311c331Sjca 
369b3c43d5Skettenis extern void (*cpuresetfn)(void);
379b3c43d5Skettenis extern void (*powerdownfn)(void);
389b3c43d5Skettenis 
399b3c43d5Skettenis /* Registers */
406311c331Sjca #define FAULT_LOG		0x05
419b3c43d5Skettenis #define EVENT_A			0x06
426311c331Sjca #define  EVENT_A_EVENTS_D		(1 << 7)
436311c331Sjca #define  EVENT_A_EVENTS_C		(1 << 6)
446311c331Sjca #define  EVENT_A_EVENTS_B		(1 << 5)
456311c331Sjca #define  EVENT_A_E_nONKEY		(1 << 0)
466311c331Sjca #define EVENT_B			0x07
476311c331Sjca #define EVENT_C			0x08
486311c331Sjca #define EVENT_D			0x09
496311c331Sjca #define IRQ_MASK_A		0x0a
506311c331Sjca #define  IRQ_MASK_A_M_RESERVED		((1 << 7) | (1 << 6) | (1 << 5))
516311c331Sjca #define  IRQ_MASK_A_M_SEQ_RDY		(1 << 4)
526311c331Sjca #define  IRQ_MASK_A_M_ADC_RDY		(1 << 3)
536311c331Sjca #define  IRQ_MASK_A_M_TICK		(1 << 2)
546311c331Sjca #define  IRQ_MASK_A_M_ALARM		(1 << 1)
556311c331Sjca #define  IRQ_MASK_A_M_nONKEY		(1 << 0)
566311c331Sjca #define IRQ_MASK_B		0x0b
576311c331Sjca #define IRQ_MASK_C		0x0c
586311c331Sjca #define IRQ_MASK_D		0x0d
599b3c43d5Skettenis #define CONTROL_F		0x13
609b3c43d5Skettenis #define  CONTROL_F_WAKE_UP		(1 << 2)
619b3c43d5Skettenis #define  CONTROL_F_SHUTDOWN		(1 << 1)
629b3c43d5Skettenis #define COUNT_S			0x40
639b3c43d5Skettenis #define  COUNT_S_COUNT_SEC		0x3f
649b3c43d5Skettenis #define COUNT_MI		0x41
659b3c43d5Skettenis #define  COUNT_MI_COUNT_MIN		0x3f
669b3c43d5Skettenis #define COUNT_H			0x42
679b3c43d5Skettenis #define  COUNT_H_COUNT_HOUR		0x1f
689b3c43d5Skettenis #define COUNT_D			0x43
699b3c43d5Skettenis #define  COUNT_D_COUNT_DAY		0x1f
709b3c43d5Skettenis #define COUNT_MO		0x44
719b3c43d5Skettenis #define  COUNT_MO_COUNT_MONTH		0x0f
729b3c43d5Skettenis #define COUNT_Y			0x45
739b3c43d5Skettenis #define  COUNT_Y_MONITOR		(1 << 6)
749b3c43d5Skettenis #define  COUNT_Y_COUNT_YEAR		0x3f
759b3c43d5Skettenis #define ALARM_MO		0x4a
769b3c43d5Skettenis #define  ALARM_MO_TICK_WAKE		(1 << 5)
779b3c43d5Skettenis #define  ALARM_MO_TICK_TYPE		(1 << 4)
789b3c43d5Skettenis #define ALARM_Y			0x4b
799b3c43d5Skettenis #define  ALARM_Y_TICK_ON		(1 << 7)
809b3c43d5Skettenis 
816311c331Sjca #ifdef DAPMIC_DEBUG
826311c331Sjca # define DPRINTF(args) do { printf args; } while (0)
836311c331Sjca #else
846311c331Sjca # define DPRINTF(args) do {} while (0)
856311c331Sjca #endif
866311c331Sjca 
879b3c43d5Skettenis struct dapmic_softc {
889b3c43d5Skettenis 	struct device sc_dev;
899b3c43d5Skettenis 	i2c_tag_t sc_tag;
909b3c43d5Skettenis 	i2c_addr_t sc_addr;
919b3c43d5Skettenis 
926311c331Sjca 	int (*sc_ih)(void *);
936311c331Sjca 	struct task sc_task;
946311c331Sjca 
959b3c43d5Skettenis 	struct todr_chip_handle sc_todr;
969b3c43d5Skettenis };
979b3c43d5Skettenis 
989b3c43d5Skettenis int	dapmic_match(struct device *, void *, void *);
999b3c43d5Skettenis void	dapmic_attach(struct device *, struct device *, void *);
1009b3c43d5Skettenis 
101471aeecfSnaddy const struct cfattach dapmic_ca = {
1029b3c43d5Skettenis 	sizeof(struct dapmic_softc), dapmic_match, dapmic_attach
1039b3c43d5Skettenis };
1049b3c43d5Skettenis 
1059b3c43d5Skettenis struct cfdriver dapmic_cd = {
1069b3c43d5Skettenis 	NULL, "dapmic", DV_DULL
1079b3c43d5Skettenis };
1089b3c43d5Skettenis 
1099b3c43d5Skettenis uint8_t	dapmic_reg_read(struct dapmic_softc *, int);
1109b3c43d5Skettenis void	dapmic_reg_write(struct dapmic_softc *, int, uint8_t);
1119b3c43d5Skettenis int	dapmic_clock_read(struct dapmic_softc *, struct clock_ymdhms *);
1129b3c43d5Skettenis int	dapmic_clock_write(struct dapmic_softc *, struct clock_ymdhms *);
1139b3c43d5Skettenis int	dapmic_gettime(struct todr_chip_handle *, struct timeval *);
1149b3c43d5Skettenis int	dapmic_settime(struct todr_chip_handle *, struct timeval *);
1156311c331Sjca void	dapmic_reset_irq_mask(struct dapmic_softc *);
1169b3c43d5Skettenis void	dapmic_reset(void);
1179b3c43d5Skettenis void	dapmic_powerdown(void);
1186311c331Sjca int	dapmic_intr(void *);
1196311c331Sjca void	dapmic_shutdown_task(void *);
1209b3c43d5Skettenis 
1219b3c43d5Skettenis int
dapmic_match(struct device * parent,void * match,void * aux)1229b3c43d5Skettenis dapmic_match(struct device *parent, void *match, void *aux)
1239b3c43d5Skettenis {
1249b3c43d5Skettenis 	struct i2c_attach_args *ia = aux;
1259b3c43d5Skettenis 
1269b3c43d5Skettenis 	return (strcmp(ia->ia_name, "dlg,da9063") == 0);
1279b3c43d5Skettenis }
1289b3c43d5Skettenis 
1299b3c43d5Skettenis void
dapmic_attach(struct device * parent,struct device * self,void * aux)1309b3c43d5Skettenis dapmic_attach(struct device *parent, struct device *self, void *aux)
1319b3c43d5Skettenis {
1329b3c43d5Skettenis 	struct dapmic_softc *sc = (struct dapmic_softc *)self;
1339b3c43d5Skettenis 	struct i2c_attach_args *ia = aux;
1346311c331Sjca 	int node = *(int *)ia->ia_cookie;
1359b3c43d5Skettenis 
1369b3c43d5Skettenis 	sc->sc_tag = ia->ia_tag;
1379b3c43d5Skettenis 	sc->sc_addr = ia->ia_addr;
1389b3c43d5Skettenis 
1399b3c43d5Skettenis 	sc->sc_todr.cookie = sc;
1409b3c43d5Skettenis 	sc->sc_todr.todr_gettime = dapmic_gettime;
1419b3c43d5Skettenis 	sc->sc_todr.todr_settime = dapmic_settime;
142*0701a158Skettenis 	sc->sc_todr.todr_quality = 0;
1439b3c43d5Skettenis 	todr_attach(&sc->sc_todr);
1449b3c43d5Skettenis 
1459b3c43d5Skettenis 	if (cpuresetfn == NULL)
1469b3c43d5Skettenis 		cpuresetfn = dapmic_reset;
1479b3c43d5Skettenis 	if (powerdownfn == NULL)
1489b3c43d5Skettenis 		powerdownfn = dapmic_powerdown;
1496311c331Sjca 
1506311c331Sjca 	task_set(&sc->sc_task, dapmic_shutdown_task, sc);
1516311c331Sjca 
1526311c331Sjca 	/* Mask away events we don't care about */
1536311c331Sjca 	dapmic_reg_write(sc, IRQ_MASK_A,
1546311c331Sjca 	    0xff & ~(IRQ_MASK_A_M_RESERVED | IRQ_MASK_A_M_nONKEY));
1556311c331Sjca 	dapmic_reg_write(sc, IRQ_MASK_B, 0xff);
1566311c331Sjca 	dapmic_reg_write(sc, IRQ_MASK_C, 0xff);
1576311c331Sjca 	dapmic_reg_write(sc, IRQ_MASK_D, 0xff);
1586311c331Sjca 
1596311c331Sjca 	/* Clear past faults and events. */
1606311c331Sjca 	dapmic_reg_write(sc, FAULT_LOG, dapmic_reg_read(sc, FAULT_LOG));
1616311c331Sjca 	dapmic_reg_write(sc, EVENT_A, dapmic_reg_read(sc, EVENT_A));
1626311c331Sjca 	dapmic_reg_write(sc, EVENT_B, dapmic_reg_read(sc, EVENT_B));
1636311c331Sjca 	dapmic_reg_write(sc, EVENT_C, dapmic_reg_read(sc, EVENT_C));
1646311c331Sjca 	dapmic_reg_write(sc, EVENT_D, dapmic_reg_read(sc, EVENT_D));
1656311c331Sjca 
1666311c331Sjca 	if (node != 0) {
1676311c331Sjca                 sc->sc_ih = fdt_intr_establish_idx(node, 0, IPL_CLOCK,
1686311c331Sjca 		    dapmic_intr, sc, sc->sc_dev.dv_xname);
1696311c331Sjca                 if (sc->sc_ih == NULL)
1706311c331Sjca                         printf(", can't establish interrupt");
1716311c331Sjca         }
1726311c331Sjca 
1736311c331Sjca 	printf("\n");
1749b3c43d5Skettenis }
1759b3c43d5Skettenis 
1769b3c43d5Skettenis uint8_t
dapmic_reg_read(struct dapmic_softc * sc,int reg)1779b3c43d5Skettenis dapmic_reg_read(struct dapmic_softc *sc, int reg)
1789b3c43d5Skettenis {
1799b3c43d5Skettenis 	uint8_t cmd = reg;
1809b3c43d5Skettenis 	uint8_t val;
1819b3c43d5Skettenis 	int error;
1829b3c43d5Skettenis 
1839b3c43d5Skettenis 	iic_acquire_bus(sc->sc_tag, I2C_F_POLL);
1849b3c43d5Skettenis 	error = iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, sc->sc_addr,
1859b3c43d5Skettenis 	    &cmd, sizeof cmd, &val, sizeof val, I2C_F_POLL);
1869b3c43d5Skettenis 	iic_release_bus(sc->sc_tag, I2C_F_POLL);
1879b3c43d5Skettenis 
1889b3c43d5Skettenis 	if (error) {
1899b3c43d5Skettenis 		printf("%s: can't read register 0x%02x\n",
1909b3c43d5Skettenis 		    sc->sc_dev.dv_xname, reg);
1919b3c43d5Skettenis 		val = 0xff;
1929b3c43d5Skettenis 	}
1939b3c43d5Skettenis 
1949b3c43d5Skettenis 	return val;
1959b3c43d5Skettenis }
1969b3c43d5Skettenis 
1979b3c43d5Skettenis void
dapmic_reg_write(struct dapmic_softc * sc,int reg,uint8_t val)1989b3c43d5Skettenis dapmic_reg_write(struct dapmic_softc *sc, int reg, uint8_t val)
1999b3c43d5Skettenis {
2009b3c43d5Skettenis 	uint8_t cmd = reg;
2019b3c43d5Skettenis 	int error;
2029b3c43d5Skettenis 
2039b3c43d5Skettenis 	iic_acquire_bus(sc->sc_tag, I2C_F_POLL);
2049b3c43d5Skettenis 	error = iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP, sc->sc_addr,
2059b3c43d5Skettenis 	    &cmd, sizeof cmd, &val, sizeof val, I2C_F_POLL);
2069b3c43d5Skettenis 	iic_release_bus(sc->sc_tag, I2C_F_POLL);
2079b3c43d5Skettenis 
2089b3c43d5Skettenis 	if (error) {
2099b3c43d5Skettenis 		printf("%s: can't write register 0x%02x\n",
2109b3c43d5Skettenis 		    sc->sc_dev.dv_xname, reg);
2119b3c43d5Skettenis 	}
2129b3c43d5Skettenis }
2139b3c43d5Skettenis 
2149b3c43d5Skettenis int
dapmic_clock_read(struct dapmic_softc * sc,struct clock_ymdhms * dt)2159b3c43d5Skettenis dapmic_clock_read(struct dapmic_softc *sc, struct clock_ymdhms *dt)
2169b3c43d5Skettenis {
2179b3c43d5Skettenis 	uint8_t regs[6];
2189b3c43d5Skettenis 	uint8_t cmd = COUNT_S;
2199b3c43d5Skettenis 	int error;
2209b3c43d5Skettenis 
2219b3c43d5Skettenis 	iic_acquire_bus(sc->sc_tag, I2C_F_POLL);
2229b3c43d5Skettenis 	error = iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, sc->sc_addr,
2239b3c43d5Skettenis 	    &cmd, sizeof(cmd), regs, sizeof(regs), I2C_F_POLL);
2249b3c43d5Skettenis 	iic_release_bus(sc->sc_tag, I2C_F_POLL);
2259b3c43d5Skettenis 
2269b3c43d5Skettenis 	if (error)
2279b3c43d5Skettenis 		return error;
2289b3c43d5Skettenis 
2299b3c43d5Skettenis 	dt->dt_sec = (regs[0] & COUNT_S_COUNT_SEC);
2309b3c43d5Skettenis 	dt->dt_min = (regs[1] & COUNT_MI_COUNT_MIN);
2319b3c43d5Skettenis 	dt->dt_hour = (regs[2] & COUNT_H_COUNT_HOUR);
2329b3c43d5Skettenis 	dt->dt_day = (regs[3] & COUNT_D_COUNT_DAY);
2339b3c43d5Skettenis 	dt->dt_mon = (regs[4] & COUNT_MO_COUNT_MONTH);
2349b3c43d5Skettenis 	dt->dt_year = (regs[5] & COUNT_Y_COUNT_YEAR) + 2000;
2359b3c43d5Skettenis 
2369b3c43d5Skettenis 	/* Consider the time to be invalid if the MONITOR bit isn't set. */
2379b3c43d5Skettenis 	if ((regs[5] & COUNT_Y_MONITOR) == 0)
2389b3c43d5Skettenis 		return EINVAL;
2399b3c43d5Skettenis 
2409b3c43d5Skettenis 	return 0;
2419b3c43d5Skettenis }
2429b3c43d5Skettenis 
2439b3c43d5Skettenis int
dapmic_clock_write(struct dapmic_softc * sc,struct clock_ymdhms * dt)2449b3c43d5Skettenis dapmic_clock_write(struct dapmic_softc *sc, struct clock_ymdhms *dt)
2459b3c43d5Skettenis {
2469b3c43d5Skettenis 	uint8_t regs[6];
2479b3c43d5Skettenis 	uint8_t cmd = COUNT_S;
2489b3c43d5Skettenis 	int error;
2499b3c43d5Skettenis 
2509b3c43d5Skettenis 	regs[0] = dt->dt_sec;
2519b3c43d5Skettenis 	regs[1] = dt->dt_min;
2529b3c43d5Skettenis 	regs[2] = dt->dt_hour;
2539b3c43d5Skettenis 	regs[3] = dt->dt_day;
2549b3c43d5Skettenis 	regs[4] = dt->dt_mon;
2559b3c43d5Skettenis 	regs[5] = (dt->dt_year - 2000) | COUNT_Y_MONITOR;
2569b3c43d5Skettenis 
2579b3c43d5Skettenis 	iic_acquire_bus(sc->sc_tag, I2C_F_POLL);
2589b3c43d5Skettenis 	error = iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP, sc->sc_addr,
2599b3c43d5Skettenis 	    &cmd, sizeof(cmd), regs, sizeof(regs), I2C_F_POLL);
2609b3c43d5Skettenis 	iic_release_bus(sc->sc_tag, I2C_F_POLL);
2619b3c43d5Skettenis 
2629b3c43d5Skettenis 	if (error)
2639b3c43d5Skettenis 		return error;
2649b3c43d5Skettenis 
2659b3c43d5Skettenis 	return 0;
2669b3c43d5Skettenis }
2679b3c43d5Skettenis 
2689b3c43d5Skettenis int
dapmic_gettime(struct todr_chip_handle * handle,struct timeval * tv)2699b3c43d5Skettenis dapmic_gettime(struct todr_chip_handle *handle, struct timeval *tv)
2709b3c43d5Skettenis {
2719b3c43d5Skettenis 	struct dapmic_softc *sc = handle->cookie;
2729b3c43d5Skettenis 	struct clock_ymdhms dt;
2739b3c43d5Skettenis 	int error;
2749b3c43d5Skettenis 
2759b3c43d5Skettenis 	error = dapmic_clock_read(sc, &dt);
2769b3c43d5Skettenis 	if (error)
2779b3c43d5Skettenis 		return error;
2789b3c43d5Skettenis 
2799b3c43d5Skettenis 	if (dt.dt_sec > 59 || dt.dt_min > 59 || dt.dt_hour > 23 ||
2809b3c43d5Skettenis 	    dt.dt_day > 31 || dt.dt_day == 0 ||
2819b3c43d5Skettenis 	    dt.dt_mon > 12 || dt.dt_mon == 0 ||
2829b3c43d5Skettenis 	    dt.dt_year < POSIX_BASE_YEAR)
2839b3c43d5Skettenis 		return EINVAL;
2849b3c43d5Skettenis 
2859b3c43d5Skettenis 	tv->tv_sec = clock_ymdhms_to_secs(&dt);
2869b3c43d5Skettenis 	tv->tv_usec = 0;
2879b3c43d5Skettenis 	return 0;
2889b3c43d5Skettenis }
2899b3c43d5Skettenis 
2909b3c43d5Skettenis int
dapmic_settime(struct todr_chip_handle * handle,struct timeval * tv)2919b3c43d5Skettenis dapmic_settime(struct todr_chip_handle *handle, struct timeval *tv)
2929b3c43d5Skettenis {
2939b3c43d5Skettenis 	struct dapmic_softc *sc = handle->cookie;
2949b3c43d5Skettenis 	struct clock_ymdhms dt;
2959b3c43d5Skettenis 
2969b3c43d5Skettenis 	clock_secs_to_ymdhms(tv->tv_sec, &dt);
2979b3c43d5Skettenis 
2989b3c43d5Skettenis 	return dapmic_clock_write(sc, &dt);
2999b3c43d5Skettenis }
3009b3c43d5Skettenis 
3019b3c43d5Skettenis void
dapmic_reset_irq_mask(struct dapmic_softc * sc)3026311c331Sjca dapmic_reset_irq_mask(struct dapmic_softc *sc)
3036311c331Sjca {
3046311c331Sjca 	dapmic_reg_write(sc, IRQ_MASK_A, 0);
3056311c331Sjca 	dapmic_reg_write(sc, IRQ_MASK_B, 0);
3066311c331Sjca 	dapmic_reg_write(sc, IRQ_MASK_C, 0);
3076311c331Sjca 	dapmic_reg_write(sc, IRQ_MASK_D, 0);
3086311c331Sjca }
3096311c331Sjca 
3106311c331Sjca void
dapmic_reset(void)3119b3c43d5Skettenis dapmic_reset(void)
3129b3c43d5Skettenis {
3139b3c43d5Skettenis 	struct dapmic_softc *sc = dapmic_cd.cd_devs[0];
3149b3c43d5Skettenis 	uint8_t reg;
3159b3c43d5Skettenis 
3166311c331Sjca 	/* Re-enable irqs and the associated wake-up events. */
3176311c331Sjca 	dapmic_reset_irq_mask(sc);
3186311c331Sjca 
3199b3c43d5Skettenis 	/* Enable tick alarm wakeup with a one second interval. */
3209b3c43d5Skettenis 	reg = dapmic_reg_read(sc, ALARM_MO);
3219b3c43d5Skettenis 	reg &= ~ALARM_MO_TICK_TYPE;
3229b3c43d5Skettenis 	reg |= ALARM_MO_TICK_WAKE;
3239b3c43d5Skettenis 	dapmic_reg_write(sc, ALARM_MO, reg);
3249b3c43d5Skettenis 
3259b3c43d5Skettenis 	/* Enable tick function. */
3269b3c43d5Skettenis 	reg = dapmic_reg_read(sc, ALARM_Y);
3279b3c43d5Skettenis 	reg |= ALARM_Y_TICK_ON;
3289b3c43d5Skettenis 	dapmic_reg_write(sc, ALARM_Y, reg);
3299b3c43d5Skettenis 
3309b3c43d5Skettenis 	/* Clear events such that we wake up again. */
3319b3c43d5Skettenis 	dapmic_reg_write(sc, EVENT_A, dapmic_reg_read(sc, EVENT_A));
3329b3c43d5Skettenis 	dapmic_reg_write(sc, CONTROL_F, CONTROL_F_SHUTDOWN);
3339b3c43d5Skettenis }
3349b3c43d5Skettenis 
3359b3c43d5Skettenis void
dapmic_powerdown(void)3369b3c43d5Skettenis dapmic_powerdown(void)
3379b3c43d5Skettenis {
3389b3c43d5Skettenis 	struct dapmic_softc *sc = dapmic_cd.cd_devs[0];
3399b3c43d5Skettenis 	uint8_t reg;
3409b3c43d5Skettenis 
3416311c331Sjca 	/* Re-enable irqs and the associated wake-up events. */
3426311c331Sjca 	dapmic_reset_irq_mask(sc);
3436311c331Sjca 
3449b3c43d5Skettenis 	/* Disable tick function such that it doesn't wake us up. */
3459b3c43d5Skettenis 	reg = dapmic_reg_read(sc, ALARM_Y);
3469b3c43d5Skettenis 	reg &= ~ALARM_Y_TICK_ON;
3479b3c43d5Skettenis 	dapmic_reg_write(sc, ALARM_Y, reg);
3489b3c43d5Skettenis 
3499b3c43d5Skettenis 	dapmic_reg_write(sc, CONTROL_F, CONTROL_F_SHUTDOWN);
3509b3c43d5Skettenis }
3516311c331Sjca 
3526311c331Sjca void
dapmic_shutdown_task(void * arg)3536311c331Sjca dapmic_shutdown_task(void *arg)
3546311c331Sjca {
3556311c331Sjca 	extern int allowpowerdown;
3566311c331Sjca 
3576311c331Sjca 	if (allowpowerdown == 1) {
3586311c331Sjca 		allowpowerdown = 0;
3596311c331Sjca 		prsignal(initprocess, SIGUSR2);
3606311c331Sjca 	}
3616311c331Sjca }
3626311c331Sjca 
3636311c331Sjca int
dapmic_intr(void * arg)3646311c331Sjca dapmic_intr(void *arg)
3656311c331Sjca {
3666311c331Sjca 	struct dapmic_softc *sc = arg;
3676311c331Sjca 	uint8_t event_a, event_b, event_c, event_d, fault;
3686311c331Sjca 
3696311c331Sjca 	event_b = event_c = event_d = 0;
3706311c331Sjca 
3716311c331Sjca 	event_a = dapmic_reg_read(sc, EVENT_A);
3726311c331Sjca 	DPRINTF(("%s: %s: event_a %#02.2hhx", sc->sc_dev.dv_xname, __func__,
3736311c331Sjca 	    event_a));
3746311c331Sjca 
3756311c331Sjca 	/* Acknowledge all events. */
3766311c331Sjca 	if (event_a & EVENT_A_EVENTS_B) {
3776311c331Sjca 		event_b = dapmic_reg_read(sc, EVENT_B);
3786311c331Sjca 		DPRINTF((", event_b %#02.2hhx", event_b));
3796311c331Sjca 		if (event_b != 0)
3806311c331Sjca 			dapmic_reg_write(sc, EVENT_B, event_b);
3816311c331Sjca 	}
3826311c331Sjca 	if (event_a & EVENT_A_EVENTS_C) {
3836311c331Sjca 		event_c = dapmic_reg_read(sc, EVENT_C);
3846311c331Sjca 		DPRINTF((", event_c %#02.2hhx", event_c));
3856311c331Sjca 		if (event_c != 0)
3866311c331Sjca 			dapmic_reg_write(sc, EVENT_C, event_c);
3876311c331Sjca 	}
3886311c331Sjca 	if (event_a & EVENT_A_EVENTS_D) {
3896311c331Sjca 		event_d = dapmic_reg_read(sc, EVENT_D);
3906311c331Sjca 		DPRINTF((", event_d %#02.2hhx", event_d));
3916311c331Sjca 		if (event_d != 0)
3926311c331Sjca 			dapmic_reg_write(sc, EVENT_D, event_d);
3936311c331Sjca 	}
3946311c331Sjca 	event_a &= ~(EVENT_A_EVENTS_B|EVENT_A_EVENTS_C|EVENT_A_EVENTS_D);
3956311c331Sjca 	if (event_a != 0)
3966311c331Sjca 		dapmic_reg_write(sc, EVENT_A, event_a);
3976311c331Sjca 
3986311c331Sjca 	DPRINTF(("\n"));
3996311c331Sjca 
4006311c331Sjca 	fault = dapmic_reg_read(sc, FAULT_LOG);
4016311c331Sjca 	if (fault != 0) {
4026311c331Sjca 		static int warned;
4036311c331Sjca 		if (!warned) {
4046311c331Sjca 			warned = 1;
4056311c331Sjca 			printf("%s: FAULT_LOG %#02.2hhx\n", sc->sc_dev.dv_xname,
4066311c331Sjca 			    fault);
4076311c331Sjca 		}
4086311c331Sjca 		/*
4096311c331Sjca 		 * Don't blindly acknowledge the fault log bits, else we may
4106311c331Sjca 		 * prevent legit behavior like a forced poweroff with a long
4116311c331Sjca 		 * power button press.
4126311c331Sjca 		 */
4136311c331Sjca 	}
4146311c331Sjca 
4156311c331Sjca 	if (event_a & EVENT_A_E_nONKEY)
4166311c331Sjca 		task_add(systq, &sc->sc_task);
4176311c331Sjca 
4186311c331Sjca 	if (event_a | event_b | event_c | event_d)
4196311c331Sjca 		return 1;
4206311c331Sjca 
4216311c331Sjca 	return 0;
4226311c331Sjca }
423