jcs's openbsd hax
openbsd
at jcs 407 lines 11 kB view raw
1/* $OpenBSD: dapmic.c,v 1.5 2025/06/16 20:21:33 kettenis Exp $ */ 2/* 3 * Copyright (c) 2021 Mark Kettenis <kettenis@openbsd.org> 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18#include <sys/param.h> 19#include <sys/systm.h> 20#include <sys/device.h> 21#include <sys/malloc.h> 22#include <sys/task.h> 23#include <sys/proc.h> 24#include <sys/signalvar.h> 25 26#include <dev/ofw/openfirm.h> 27#include <dev/ofw/ofw_regulator.h> 28#include <dev/ofw/fdt.h> 29 30#include <dev/i2c/i2cvar.h> 31 32#include <dev/clock_subr.h> 33 34#include <machine/fdt.h> 35 36extern void (*cpuresetfn)(void); 37extern void (*powerdownfn)(void); 38 39/* Registers */ 40#define FAULT_LOG 0x05 41#define EVENT_A 0x06 42#define EVENT_A_EVENTS_D (1 << 7) 43#define EVENT_A_EVENTS_C (1 << 6) 44#define EVENT_A_EVENTS_B (1 << 5) 45#define EVENT_A_E_nONKEY (1 << 0) 46#define EVENT_B 0x07 47#define EVENT_C 0x08 48#define EVENT_D 0x09 49#define IRQ_MASK_A 0x0a 50#define IRQ_MASK_A_M_RESERVED ((1 << 7) | (1 << 6) | (1 << 5)) 51#define IRQ_MASK_A_M_SEQ_RDY (1 << 4) 52#define IRQ_MASK_A_M_ADC_RDY (1 << 3) 53#define IRQ_MASK_A_M_TICK (1 << 2) 54#define IRQ_MASK_A_M_ALARM (1 << 1) 55#define IRQ_MASK_A_M_nONKEY (1 << 0) 56#define IRQ_MASK_B 0x0b 57#define IRQ_MASK_C 0x0c 58#define IRQ_MASK_D 0x0d 59#define CONTROL_F 0x13 60#define CONTROL_F_WAKE_UP (1 << 2) 61#define CONTROL_F_SHUTDOWN (1 << 1) 62#define COUNT_S 0x40 63#define COUNT_S_COUNT_SEC 0x3f 64#define COUNT_MI 0x41 65#define COUNT_MI_COUNT_MIN 0x3f 66#define COUNT_H 0x42 67#define COUNT_H_COUNT_HOUR 0x1f 68#define COUNT_D 0x43 69#define COUNT_D_COUNT_DAY 0x1f 70#define COUNT_MO 0x44 71#define COUNT_MO_COUNT_MONTH 0x0f 72#define COUNT_Y 0x45 73#define COUNT_Y_MONITOR (1 << 6) 74#define COUNT_Y_COUNT_YEAR 0x3f 75#define ALARM_MO 0x4a 76#define ALARM_MO_TICK_WAKE (1 << 5) 77#define ALARM_MO_TICK_TYPE (1 << 4) 78#define ALARM_Y 0x4b 79#define ALARM_Y_TICK_ON (1 << 7) 80 81#ifdef DAPMIC_DEBUG 82# define DPRINTF(args) do { printf args; } while (0) 83#else 84# define DPRINTF(args) do {} while (0) 85#endif 86 87struct dapmic_softc { 88 struct device sc_dev; 89 i2c_tag_t sc_tag; 90 i2c_addr_t sc_addr; 91 92 int (*sc_ih)(void *); 93 94 struct todr_chip_handle sc_todr; 95}; 96 97int dapmic_match(struct device *, void *, void *); 98void dapmic_attach(struct device *, struct device *, void *); 99 100const struct cfattach dapmic_ca = { 101 sizeof(struct dapmic_softc), dapmic_match, dapmic_attach 102}; 103 104struct cfdriver dapmic_cd = { 105 NULL, "dapmic", DV_DULL 106}; 107 108uint8_t dapmic_reg_read(struct dapmic_softc *, int); 109void dapmic_reg_write(struct dapmic_softc *, int, uint8_t); 110int dapmic_clock_read(struct dapmic_softc *, struct clock_ymdhms *); 111int dapmic_clock_write(struct dapmic_softc *, struct clock_ymdhms *); 112int dapmic_gettime(struct todr_chip_handle *, struct timeval *); 113int dapmic_settime(struct todr_chip_handle *, struct timeval *); 114void dapmic_reset_irq_mask(struct dapmic_softc *); 115void dapmic_reset(void); 116void dapmic_powerdown(void); 117int dapmic_intr(void *); 118 119int 120dapmic_match(struct device *parent, void *match, void *aux) 121{ 122 struct i2c_attach_args *ia = aux; 123 124 return (strcmp(ia->ia_name, "dlg,da9063") == 0); 125} 126 127void 128dapmic_attach(struct device *parent, struct device *self, void *aux) 129{ 130 struct dapmic_softc *sc = (struct dapmic_softc *)self; 131 struct i2c_attach_args *ia = aux; 132 int node = *(int *)ia->ia_cookie; 133 134 sc->sc_tag = ia->ia_tag; 135 sc->sc_addr = ia->ia_addr; 136 137 sc->sc_todr.cookie = sc; 138 sc->sc_todr.todr_gettime = dapmic_gettime; 139 sc->sc_todr.todr_settime = dapmic_settime; 140 sc->sc_todr.todr_quality = 0; 141 todr_attach(&sc->sc_todr); 142 143 if (cpuresetfn == NULL) 144 cpuresetfn = dapmic_reset; 145 if (powerdownfn == NULL) 146 powerdownfn = dapmic_powerdown; 147 148 /* Mask away events we don't care about */ 149 dapmic_reg_write(sc, IRQ_MASK_A, 150 0xff & ~(IRQ_MASK_A_M_RESERVED | IRQ_MASK_A_M_nONKEY)); 151 dapmic_reg_write(sc, IRQ_MASK_B, 0xff); 152 dapmic_reg_write(sc, IRQ_MASK_C, 0xff); 153 dapmic_reg_write(sc, IRQ_MASK_D, 0xff); 154 155 /* Clear past faults and events. */ 156 dapmic_reg_write(sc, FAULT_LOG, dapmic_reg_read(sc, FAULT_LOG)); 157 dapmic_reg_write(sc, EVENT_A, dapmic_reg_read(sc, EVENT_A)); 158 dapmic_reg_write(sc, EVENT_B, dapmic_reg_read(sc, EVENT_B)); 159 dapmic_reg_write(sc, EVENT_C, dapmic_reg_read(sc, EVENT_C)); 160 dapmic_reg_write(sc, EVENT_D, dapmic_reg_read(sc, EVENT_D)); 161 162 if (node != 0) { 163 sc->sc_ih = fdt_intr_establish_idx(node, 0, IPL_CLOCK, 164 dapmic_intr, sc, sc->sc_dev.dv_xname); 165 if (sc->sc_ih == NULL) 166 printf(", can't establish interrupt"); 167 } 168 169 printf("\n"); 170} 171 172uint8_t 173dapmic_reg_read(struct dapmic_softc *sc, int reg) 174{ 175 uint8_t cmd = reg; 176 uint8_t val; 177 int error; 178 179 iic_acquire_bus(sc->sc_tag, I2C_F_POLL); 180 error = iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, sc->sc_addr, 181 &cmd, sizeof cmd, &val, sizeof val, I2C_F_POLL); 182 iic_release_bus(sc->sc_tag, I2C_F_POLL); 183 184 if (error) { 185 printf("%s: can't read register 0x%02x\n", 186 sc->sc_dev.dv_xname, reg); 187 val = 0xff; 188 } 189 190 return val; 191} 192 193void 194dapmic_reg_write(struct dapmic_softc *sc, int reg, uint8_t val) 195{ 196 uint8_t cmd = reg; 197 int error; 198 199 iic_acquire_bus(sc->sc_tag, I2C_F_POLL); 200 error = iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP, sc->sc_addr, 201 &cmd, sizeof cmd, &val, sizeof val, I2C_F_POLL); 202 iic_release_bus(sc->sc_tag, I2C_F_POLL); 203 204 if (error) { 205 printf("%s: can't write register 0x%02x\n", 206 sc->sc_dev.dv_xname, reg); 207 } 208} 209 210int 211dapmic_clock_read(struct dapmic_softc *sc, struct clock_ymdhms *dt) 212{ 213 uint8_t regs[6]; 214 uint8_t cmd = COUNT_S; 215 int error; 216 217 iic_acquire_bus(sc->sc_tag, I2C_F_POLL); 218 error = iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, sc->sc_addr, 219 &cmd, sizeof(cmd), regs, sizeof(regs), I2C_F_POLL); 220 iic_release_bus(sc->sc_tag, I2C_F_POLL); 221 222 if (error) 223 return error; 224 225 dt->dt_sec = (regs[0] & COUNT_S_COUNT_SEC); 226 dt->dt_min = (regs[1] & COUNT_MI_COUNT_MIN); 227 dt->dt_hour = (regs[2] & COUNT_H_COUNT_HOUR); 228 dt->dt_day = (regs[3] & COUNT_D_COUNT_DAY); 229 dt->dt_mon = (regs[4] & COUNT_MO_COUNT_MONTH); 230 dt->dt_year = (regs[5] & COUNT_Y_COUNT_YEAR) + 2000; 231 232 /* Consider the time to be invalid if the MONITOR bit isn't set. */ 233 if ((regs[5] & COUNT_Y_MONITOR) == 0) 234 return EINVAL; 235 236 return 0; 237} 238 239int 240dapmic_clock_write(struct dapmic_softc *sc, struct clock_ymdhms *dt) 241{ 242 uint8_t regs[6]; 243 uint8_t cmd = COUNT_S; 244 int error; 245 246 regs[0] = dt->dt_sec; 247 regs[1] = dt->dt_min; 248 regs[2] = dt->dt_hour; 249 regs[3] = dt->dt_day; 250 regs[4] = dt->dt_mon; 251 regs[5] = (dt->dt_year - 2000) | COUNT_Y_MONITOR; 252 253 iic_acquire_bus(sc->sc_tag, I2C_F_POLL); 254 error = iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP, sc->sc_addr, 255 &cmd, sizeof(cmd), regs, sizeof(regs), I2C_F_POLL); 256 iic_release_bus(sc->sc_tag, I2C_F_POLL); 257 258 if (error) 259 return error; 260 261 return 0; 262} 263 264int 265dapmic_gettime(struct todr_chip_handle *handle, struct timeval *tv) 266{ 267 struct dapmic_softc *sc = handle->cookie; 268 struct clock_ymdhms dt; 269 int error; 270 271 error = dapmic_clock_read(sc, &dt); 272 if (error) 273 return error; 274 275 if (dt.dt_sec > 59 || dt.dt_min > 59 || dt.dt_hour > 23 || 276 dt.dt_day > 31 || dt.dt_day == 0 || 277 dt.dt_mon > 12 || dt.dt_mon == 0 || 278 dt.dt_year < POSIX_BASE_YEAR) 279 return EINVAL; 280 281 tv->tv_sec = clock_ymdhms_to_secs(&dt); 282 tv->tv_usec = 0; 283 return 0; 284} 285 286int 287dapmic_settime(struct todr_chip_handle *handle, struct timeval *tv) 288{ 289 struct dapmic_softc *sc = handle->cookie; 290 struct clock_ymdhms dt; 291 292 clock_secs_to_ymdhms(tv->tv_sec, &dt); 293 294 return dapmic_clock_write(sc, &dt); 295} 296 297void 298dapmic_reset_irq_mask(struct dapmic_softc *sc) 299{ 300 dapmic_reg_write(sc, IRQ_MASK_A, 0); 301 dapmic_reg_write(sc, IRQ_MASK_B, 0); 302 dapmic_reg_write(sc, IRQ_MASK_C, 0); 303 dapmic_reg_write(sc, IRQ_MASK_D, 0); 304} 305 306void 307dapmic_reset(void) 308{ 309 struct dapmic_softc *sc = dapmic_cd.cd_devs[0]; 310 uint8_t reg; 311 312 /* Re-enable irqs and the associated wake-up events. */ 313 dapmic_reset_irq_mask(sc); 314 315 /* Enable tick alarm wakeup with a one second interval. */ 316 reg = dapmic_reg_read(sc, ALARM_MO); 317 reg &= ~ALARM_MO_TICK_TYPE; 318 reg |= ALARM_MO_TICK_WAKE; 319 dapmic_reg_write(sc, ALARM_MO, reg); 320 321 /* Enable tick function. */ 322 reg = dapmic_reg_read(sc, ALARM_Y); 323 reg |= ALARM_Y_TICK_ON; 324 dapmic_reg_write(sc, ALARM_Y, reg); 325 326 /* Clear events such that we wake up again. */ 327 dapmic_reg_write(sc, EVENT_A, dapmic_reg_read(sc, EVENT_A)); 328 dapmic_reg_write(sc, CONTROL_F, CONTROL_F_SHUTDOWN); 329} 330 331void 332dapmic_powerdown(void) 333{ 334 struct dapmic_softc *sc = dapmic_cd.cd_devs[0]; 335 uint8_t reg; 336 337 /* Re-enable irqs and the associated wake-up events. */ 338 dapmic_reset_irq_mask(sc); 339 340 /* Disable tick function such that it doesn't wake us up. */ 341 reg = dapmic_reg_read(sc, ALARM_Y); 342 reg &= ~ALARM_Y_TICK_ON; 343 dapmic_reg_write(sc, ALARM_Y, reg); 344 345 dapmic_reg_write(sc, CONTROL_F, CONTROL_F_SHUTDOWN); 346} 347 348int 349dapmic_intr(void *arg) 350{ 351 struct dapmic_softc *sc = arg; 352 uint8_t event_a, event_b, event_c, event_d, fault; 353 354 event_b = event_c = event_d = 0; 355 356 event_a = dapmic_reg_read(sc, EVENT_A); 357 DPRINTF(("%s: %s: event_a %#02.2hhx", sc->sc_dev.dv_xname, __func__, 358 event_a)); 359 360 /* Acknowledge all events. */ 361 if (event_a & EVENT_A_EVENTS_B) { 362 event_b = dapmic_reg_read(sc, EVENT_B); 363 DPRINTF((", event_b %#02.2hhx", event_b)); 364 if (event_b != 0) 365 dapmic_reg_write(sc, EVENT_B, event_b); 366 } 367 if (event_a & EVENT_A_EVENTS_C) { 368 event_c = dapmic_reg_read(sc, EVENT_C); 369 DPRINTF((", event_c %#02.2hhx", event_c)); 370 if (event_c != 0) 371 dapmic_reg_write(sc, EVENT_C, event_c); 372 } 373 if (event_a & EVENT_A_EVENTS_D) { 374 event_d = dapmic_reg_read(sc, EVENT_D); 375 DPRINTF((", event_d %#02.2hhx", event_d)); 376 if (event_d != 0) 377 dapmic_reg_write(sc, EVENT_D, event_d); 378 } 379 event_a &= ~(EVENT_A_EVENTS_B|EVENT_A_EVENTS_C|EVENT_A_EVENTS_D); 380 if (event_a != 0) 381 dapmic_reg_write(sc, EVENT_A, event_a); 382 383 DPRINTF(("\n")); 384 385 fault = dapmic_reg_read(sc, FAULT_LOG); 386 if (fault != 0) { 387 static int warned; 388 if (!warned) { 389 warned = 1; 390 printf("%s: FAULT_LOG %#02.2hhx\n", sc->sc_dev.dv_xname, 391 fault); 392 } 393 /* 394 * Don't blindly acknowledge the fault log bits, else we may 395 * prevent legit behavior like a forced poweroff with a long 396 * power button press. 397 */ 398 } 399 400 if (event_a & EVENT_A_E_nONKEY) 401 powerbutton_event(); 402 403 if (event_a | event_b | event_c | event_d) 404 return 1; 405 406 return 0; 407}