1 /* $OpenBSD: dapmic.c,v 1.4 2022/10/12 13:39:50 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 36 extern void (*cpuresetfn)(void); 37 extern 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 87 struct 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 struct task sc_task; 94 95 struct todr_chip_handle sc_todr; 96 }; 97 98 int dapmic_match(struct device *, void *, void *); 99 void dapmic_attach(struct device *, struct device *, void *); 100 101 const struct cfattach dapmic_ca = { 102 sizeof(struct dapmic_softc), dapmic_match, dapmic_attach 103 }; 104 105 struct cfdriver dapmic_cd = { 106 NULL, "dapmic", DV_DULL 107 }; 108 109 uint8_t dapmic_reg_read(struct dapmic_softc *, int); 110 void dapmic_reg_write(struct dapmic_softc *, int, uint8_t); 111 int dapmic_clock_read(struct dapmic_softc *, struct clock_ymdhms *); 112 int dapmic_clock_write(struct dapmic_softc *, struct clock_ymdhms *); 113 int dapmic_gettime(struct todr_chip_handle *, struct timeval *); 114 int dapmic_settime(struct todr_chip_handle *, struct timeval *); 115 void dapmic_reset_irq_mask(struct dapmic_softc *); 116 void dapmic_reset(void); 117 void dapmic_powerdown(void); 118 int dapmic_intr(void *); 119 void dapmic_shutdown_task(void *); 120 121 int 122 dapmic_match(struct device *parent, void *match, void *aux) 123 { 124 struct i2c_attach_args *ia = aux; 125 126 return (strcmp(ia->ia_name, "dlg,da9063") == 0); 127 } 128 129 void 130 dapmic_attach(struct device *parent, struct device *self, void *aux) 131 { 132 struct dapmic_softc *sc = (struct dapmic_softc *)self; 133 struct i2c_attach_args *ia = aux; 134 int node = *(int *)ia->ia_cookie; 135 136 sc->sc_tag = ia->ia_tag; 137 sc->sc_addr = ia->ia_addr; 138 139 sc->sc_todr.cookie = sc; 140 sc->sc_todr.todr_gettime = dapmic_gettime; 141 sc->sc_todr.todr_settime = dapmic_settime; 142 sc->sc_todr.todr_quality = 0; 143 todr_attach(&sc->sc_todr); 144 145 if (cpuresetfn == NULL) 146 cpuresetfn = dapmic_reset; 147 if (powerdownfn == NULL) 148 powerdownfn = dapmic_powerdown; 149 150 task_set(&sc->sc_task, dapmic_shutdown_task, sc); 151 152 /* Mask away events we don't care about */ 153 dapmic_reg_write(sc, IRQ_MASK_A, 154 0xff & ~(IRQ_MASK_A_M_RESERVED | IRQ_MASK_A_M_nONKEY)); 155 dapmic_reg_write(sc, IRQ_MASK_B, 0xff); 156 dapmic_reg_write(sc, IRQ_MASK_C, 0xff); 157 dapmic_reg_write(sc, IRQ_MASK_D, 0xff); 158 159 /* Clear past faults and events. */ 160 dapmic_reg_write(sc, FAULT_LOG, dapmic_reg_read(sc, FAULT_LOG)); 161 dapmic_reg_write(sc, EVENT_A, dapmic_reg_read(sc, EVENT_A)); 162 dapmic_reg_write(sc, EVENT_B, dapmic_reg_read(sc, EVENT_B)); 163 dapmic_reg_write(sc, EVENT_C, dapmic_reg_read(sc, EVENT_C)); 164 dapmic_reg_write(sc, EVENT_D, dapmic_reg_read(sc, EVENT_D)); 165 166 if (node != 0) { 167 sc->sc_ih = fdt_intr_establish_idx(node, 0, IPL_CLOCK, 168 dapmic_intr, sc, sc->sc_dev.dv_xname); 169 if (sc->sc_ih == NULL) 170 printf(", can't establish interrupt"); 171 } 172 173 printf("\n"); 174 } 175 176 uint8_t 177 dapmic_reg_read(struct dapmic_softc *sc, int reg) 178 { 179 uint8_t cmd = reg; 180 uint8_t val; 181 int error; 182 183 iic_acquire_bus(sc->sc_tag, I2C_F_POLL); 184 error = iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, sc->sc_addr, 185 &cmd, sizeof cmd, &val, sizeof val, I2C_F_POLL); 186 iic_release_bus(sc->sc_tag, I2C_F_POLL); 187 188 if (error) { 189 printf("%s: can't read register 0x%02x\n", 190 sc->sc_dev.dv_xname, reg); 191 val = 0xff; 192 } 193 194 return val; 195 } 196 197 void 198 dapmic_reg_write(struct dapmic_softc *sc, int reg, uint8_t val) 199 { 200 uint8_t cmd = reg; 201 int error; 202 203 iic_acquire_bus(sc->sc_tag, I2C_F_POLL); 204 error = iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP, sc->sc_addr, 205 &cmd, sizeof cmd, &val, sizeof val, I2C_F_POLL); 206 iic_release_bus(sc->sc_tag, I2C_F_POLL); 207 208 if (error) { 209 printf("%s: can't write register 0x%02x\n", 210 sc->sc_dev.dv_xname, reg); 211 } 212 } 213 214 int 215 dapmic_clock_read(struct dapmic_softc *sc, struct clock_ymdhms *dt) 216 { 217 uint8_t regs[6]; 218 uint8_t cmd = COUNT_S; 219 int error; 220 221 iic_acquire_bus(sc->sc_tag, I2C_F_POLL); 222 error = iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, sc->sc_addr, 223 &cmd, sizeof(cmd), regs, sizeof(regs), I2C_F_POLL); 224 iic_release_bus(sc->sc_tag, I2C_F_POLL); 225 226 if (error) 227 return error; 228 229 dt->dt_sec = (regs[0] & COUNT_S_COUNT_SEC); 230 dt->dt_min = (regs[1] & COUNT_MI_COUNT_MIN); 231 dt->dt_hour = (regs[2] & COUNT_H_COUNT_HOUR); 232 dt->dt_day = (regs[3] & COUNT_D_COUNT_DAY); 233 dt->dt_mon = (regs[4] & COUNT_MO_COUNT_MONTH); 234 dt->dt_year = (regs[5] & COUNT_Y_COUNT_YEAR) + 2000; 235 236 /* Consider the time to be invalid if the MONITOR bit isn't set. */ 237 if ((regs[5] & COUNT_Y_MONITOR) == 0) 238 return EINVAL; 239 240 return 0; 241 } 242 243 int 244 dapmic_clock_write(struct dapmic_softc *sc, struct clock_ymdhms *dt) 245 { 246 uint8_t regs[6]; 247 uint8_t cmd = COUNT_S; 248 int error; 249 250 regs[0] = dt->dt_sec; 251 regs[1] = dt->dt_min; 252 regs[2] = dt->dt_hour; 253 regs[3] = dt->dt_day; 254 regs[4] = dt->dt_mon; 255 regs[5] = (dt->dt_year - 2000) | COUNT_Y_MONITOR; 256 257 iic_acquire_bus(sc->sc_tag, I2C_F_POLL); 258 error = iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP, sc->sc_addr, 259 &cmd, sizeof(cmd), regs, sizeof(regs), I2C_F_POLL); 260 iic_release_bus(sc->sc_tag, I2C_F_POLL); 261 262 if (error) 263 return error; 264 265 return 0; 266 } 267 268 int 269 dapmic_gettime(struct todr_chip_handle *handle, struct timeval *tv) 270 { 271 struct dapmic_softc *sc = handle->cookie; 272 struct clock_ymdhms dt; 273 int error; 274 275 error = dapmic_clock_read(sc, &dt); 276 if (error) 277 return error; 278 279 if (dt.dt_sec > 59 || dt.dt_min > 59 || dt.dt_hour > 23 || 280 dt.dt_day > 31 || dt.dt_day == 0 || 281 dt.dt_mon > 12 || dt.dt_mon == 0 || 282 dt.dt_year < POSIX_BASE_YEAR) 283 return EINVAL; 284 285 tv->tv_sec = clock_ymdhms_to_secs(&dt); 286 tv->tv_usec = 0; 287 return 0; 288 } 289 290 int 291 dapmic_settime(struct todr_chip_handle *handle, struct timeval *tv) 292 { 293 struct dapmic_softc *sc = handle->cookie; 294 struct clock_ymdhms dt; 295 296 clock_secs_to_ymdhms(tv->tv_sec, &dt); 297 298 return dapmic_clock_write(sc, &dt); 299 } 300 301 void 302 dapmic_reset_irq_mask(struct dapmic_softc *sc) 303 { 304 dapmic_reg_write(sc, IRQ_MASK_A, 0); 305 dapmic_reg_write(sc, IRQ_MASK_B, 0); 306 dapmic_reg_write(sc, IRQ_MASK_C, 0); 307 dapmic_reg_write(sc, IRQ_MASK_D, 0); 308 } 309 310 void 311 dapmic_reset(void) 312 { 313 struct dapmic_softc *sc = dapmic_cd.cd_devs[0]; 314 uint8_t reg; 315 316 /* Re-enable irqs and the associated wake-up events. */ 317 dapmic_reset_irq_mask(sc); 318 319 /* Enable tick alarm wakeup with a one second interval. */ 320 reg = dapmic_reg_read(sc, ALARM_MO); 321 reg &= ~ALARM_MO_TICK_TYPE; 322 reg |= ALARM_MO_TICK_WAKE; 323 dapmic_reg_write(sc, ALARM_MO, reg); 324 325 /* Enable tick function. */ 326 reg = dapmic_reg_read(sc, ALARM_Y); 327 reg |= ALARM_Y_TICK_ON; 328 dapmic_reg_write(sc, ALARM_Y, reg); 329 330 /* Clear events such that we wake up again. */ 331 dapmic_reg_write(sc, EVENT_A, dapmic_reg_read(sc, EVENT_A)); 332 dapmic_reg_write(sc, CONTROL_F, CONTROL_F_SHUTDOWN); 333 } 334 335 void 336 dapmic_powerdown(void) 337 { 338 struct dapmic_softc *sc = dapmic_cd.cd_devs[0]; 339 uint8_t reg; 340 341 /* Re-enable irqs and the associated wake-up events. */ 342 dapmic_reset_irq_mask(sc); 343 344 /* Disable tick function such that it doesn't wake us up. */ 345 reg = dapmic_reg_read(sc, ALARM_Y); 346 reg &= ~ALARM_Y_TICK_ON; 347 dapmic_reg_write(sc, ALARM_Y, reg); 348 349 dapmic_reg_write(sc, CONTROL_F, CONTROL_F_SHUTDOWN); 350 } 351 352 void 353 dapmic_shutdown_task(void *arg) 354 { 355 extern int allowpowerdown; 356 357 if (allowpowerdown == 1) { 358 allowpowerdown = 0; 359 prsignal(initprocess, SIGUSR2); 360 } 361 } 362 363 int 364 dapmic_intr(void *arg) 365 { 366 struct dapmic_softc *sc = arg; 367 uint8_t event_a, event_b, event_c, event_d, fault; 368 369 event_b = event_c = event_d = 0; 370 371 event_a = dapmic_reg_read(sc, EVENT_A); 372 DPRINTF(("%s: %s: event_a %#02.2hhx", sc->sc_dev.dv_xname, __func__, 373 event_a)); 374 375 /* Acknowledge all events. */ 376 if (event_a & EVENT_A_EVENTS_B) { 377 event_b = dapmic_reg_read(sc, EVENT_B); 378 DPRINTF((", event_b %#02.2hhx", event_b)); 379 if (event_b != 0) 380 dapmic_reg_write(sc, EVENT_B, event_b); 381 } 382 if (event_a & EVENT_A_EVENTS_C) { 383 event_c = dapmic_reg_read(sc, EVENT_C); 384 DPRINTF((", event_c %#02.2hhx", event_c)); 385 if (event_c != 0) 386 dapmic_reg_write(sc, EVENT_C, event_c); 387 } 388 if (event_a & EVENT_A_EVENTS_D) { 389 event_d = dapmic_reg_read(sc, EVENT_D); 390 DPRINTF((", event_d %#02.2hhx", event_d)); 391 if (event_d != 0) 392 dapmic_reg_write(sc, EVENT_D, event_d); 393 } 394 event_a &= ~(EVENT_A_EVENTS_B|EVENT_A_EVENTS_C|EVENT_A_EVENTS_D); 395 if (event_a != 0) 396 dapmic_reg_write(sc, EVENT_A, event_a); 397 398 DPRINTF(("\n")); 399 400 fault = dapmic_reg_read(sc, FAULT_LOG); 401 if (fault != 0) { 402 static int warned; 403 if (!warned) { 404 warned = 1; 405 printf("%s: FAULT_LOG %#02.2hhx\n", sc->sc_dev.dv_xname, 406 fault); 407 } 408 /* 409 * Don't blindly acknowledge the fault log bits, else we may 410 * prevent legit behavior like a forced poweroff with a long 411 * power button press. 412 */ 413 } 414 415 if (event_a & EVENT_A_E_nONKEY) 416 task_add(systq, &sc->sc_task); 417 418 if (event_a | event_b | event_c | event_d) 419 return 1; 420 421 return 0; 422 } 423