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