1 /* $OpenBSD: rkpmic.c,v 1.13 2023/04/10 04:21:20 jsg Exp $ */ 2 /* 3 * Copyright (c) 2017 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 23 #include <dev/ofw/openfirm.h> 24 #include <dev/ofw/ofw_regulator.h> 25 #include <dev/ofw/fdt.h> 26 27 #include <dev/i2c/i2cvar.h> 28 29 #include <dev/clock_subr.h> 30 31 #define RK80X_SECONDS 0x00 32 #define RK80X_MINUTES 0x01 33 #define RK80X_HOURS 0x02 34 #define RK80X_DAYS 0x03 35 #define RK80X_MONTHS 0x04 36 #define RK80X_YEARS 0x05 37 #define RK80X_WEEKS 0x06 38 #define RK80X_NRTC_REGS 7 39 40 #define RK805_RTC_CTRL 0x10 41 #define RK808_RTC_CTRL 0x10 42 #define RK809_RTC_CTRL 0x0d 43 #define RK80X_RTC_CTRL_STOP_RTC 0x01 44 45 #define RK805_RTC_STATUS 0x11 46 #define RK808_RTC_STATUS 0x11 47 #define RK809_RTC_STATUS 0x0e 48 #define RK80X_RTC_STATUS_POWER_UP 0x80 49 50 struct rkpmic_vsel_range { 51 uint32_t base, delta; 52 uint8_t vsel_min, vsel_max; 53 }; 54 55 struct rkpmic_regdata { 56 const char *name; 57 uint8_t reg, mask; 58 const struct rkpmic_vsel_range *vsel_range; 59 }; 60 61 /* 62 * Used by RK805 for BUCK1, BUCK2 63 * 0-59: 0.7125V-1.45V, step=12.5mV 64 * 60-62: 1.8V-2.2V, step=200mV 65 * 63: 2.3V 66 */ 67 const struct rkpmic_vsel_range rk805_vsel_range1[] = { 68 { 712500, 12500, 0, 59 }, 69 { 1800000, 200000, 60, 62 }, 70 { 2300000, 0, 63, 63 }, 71 {} 72 }; 73 74 /* 75 * Used by RK805 for BUCK4 76 * 0-27: 0.8V-3.5V, step=100mV 77 */ 78 const struct rkpmic_vsel_range rk805_vsel_range2[] = { 79 { 800000, 100000, 0, 27 }, 80 {} 81 }; 82 83 /* 84 * Used by RK805 for LDO1-3 85 * 0-26: 0.8V-3.4V, step=100mV 86 */ 87 const struct rkpmic_vsel_range rk805_vsel_range3[] = { 88 { 800000, 100000, 0, 26 }, 89 {} 90 }; 91 92 const struct rkpmic_regdata rk805_regdata[] = { 93 { "DCDC_REG1", 0x2f, 0x3f, rk805_vsel_range1 }, 94 { "DCDC_REG2", 0x33, 0x3f, rk805_vsel_range1 }, 95 { "DCDC_REG4", 0x38, 0x1f, rk805_vsel_range2 }, 96 { "LDO_REG1", 0x3b, 0x1f, rk805_vsel_range3 }, 97 { "LDO_REG2", 0x3d, 0x1f, rk805_vsel_range3 }, 98 { "LDO_REG3", 0x3f, 0x1f, rk805_vsel_range3 }, 99 { } 100 }; 101 102 /* 103 * Used by RK808 for BUCK1 & BUCK2 104 * 0-63: 0.7125V-1.5V, step=12.5mV 105 */ 106 const struct rkpmic_vsel_range rk808_vsel_range1[] = { 107 { 712500, 12500, 0, 63 }, 108 {} 109 }; 110 111 /* 112 * Used by RK808 for BUCK4 113 * 0-15: 1.8V-3.3V,step=100mV 114 */ 115 const struct rkpmic_vsel_range rk808_vsel_range2[] = { 116 { 1800000, 100000, 0, 15 }, 117 {} 118 }; 119 120 /* 121 * Used by RK808 for LDO1-2, 4-5, 8 122 * 0-16: 1.8V-3.4V, step=100mV 123 */ 124 const struct rkpmic_vsel_range rk808_vsel_range3[] = { 125 { 1800000, 100000, 0, 16 }, 126 {} 127 }; 128 129 /* 130 * Used by RK808 for LDO3 131 * 0-12: 0.8V~2.0V, step=100mV 132 * 13: 2.2V 133 * 15: 2.5V 134 */ 135 const struct rkpmic_vsel_range rk808_vsel_range4[] = { 136 { 800000, 100000, 0, 12 }, 137 { 2200000, 0, 13, 13 }, 138 { 2500000, 0, 15, 15 }, 139 {} 140 }; 141 142 /* 143 * Used by RK808 for LDO6-7 144 * 0-17: 0.8V-2.5V,step=100mV 145 */ 146 const struct rkpmic_vsel_range rk808_vsel_range5[] = { 147 { 800000, 100000, 0, 17 }, 148 {} 149 }; 150 151 const struct rkpmic_regdata rk808_regdata[] = { 152 { "DCDC_REG1", 0x2f, 0x3f, rk808_vsel_range1 }, 153 { "DCDC_REG2", 0x33, 0x3f, rk808_vsel_range1 }, 154 { "DCDC_REG4", 0x38, 0x0f, rk808_vsel_range2 }, 155 { "LDO_REG1", 0x3b, 0x1f, rk808_vsel_range3 }, 156 { "LDO_REG2", 0x3d, 0x1f, rk808_vsel_range3 }, 157 { "LDO_REG3", 0x3f, 0x0f, rk808_vsel_range4 }, 158 { "LDO_REG4", 0x41, 0x1f, rk808_vsel_range3 }, 159 { "LDO_REG5", 0x43, 0x1f, rk808_vsel_range3 }, 160 { "LDO_REG6", 0x45, 0x1f, rk808_vsel_range5 }, 161 { "LDO_REG7", 0x47, 0x1f, rk808_vsel_range5 }, 162 { "LDO_REG8", 0x49, 0x1f, rk808_vsel_range3 }, 163 { } 164 }; 165 166 /* 167 * Used by RK809 for BUCK1-3 168 * 0-80: 0.5V-1.5V,step=12.5mV 169 * 81-89: 1.6V-2.4V,step=100mV 170 */ 171 const struct rkpmic_vsel_range rk809_vsel_range1[] = { 172 { 500000, 12500, 0, 80 }, 173 { 1600000, 100000, 81, 89 }, 174 {} 175 }; 176 177 /* 178 * Used by RK809 for BUCK4 179 * 0-80: 0.5V-1.5V,step=12.5mV 180 * 81-99: 1.6V-3.4V,step=100mV 181 */ 182 const struct rkpmic_vsel_range rk809_vsel_range2[] = { 183 { 500000, 12500, 0, 80 }, 184 { 1600000, 100000, 81, 99 }, 185 {} 186 }; 187 188 /* 189 * Used by RK809 for BUCK5 190 * 0: 1.5V 191 * 1-3: 1.8V-2.2V,step=200mV 192 * 4-5: 2.8V-3.0V,step=200mV 193 * 6-7: 3.3V-3.6V,step=300mV 194 */ 195 const struct rkpmic_vsel_range rk809_vsel_range3[] = { 196 { 1500000, 0, 0, 0 }, 197 { 1800000, 200000, 1, 3 }, 198 { 2800000, 200000, 4, 5 }, 199 { 3300000, 300000, 6, 7 }, 200 {} 201 }; 202 203 /* 204 * Used by RK809 for LDO1-7 205 * 0-112: 0.6V-3.4V,step=25mV 206 */ 207 const struct rkpmic_vsel_range rk809_vsel_range4[] = { 208 { 600000, 25000, 0, 112 }, 209 {} 210 }; 211 212 const struct rkpmic_regdata rk809_regdata[] = { 213 { "DCDC_REG1", 0xbb, 0x7f, rk809_vsel_range1 }, 214 { "DCDC_REG2", 0xbe, 0x7f, rk809_vsel_range1 }, 215 { "DCDC_REG3", 0xc1, 0x7f, rk809_vsel_range1 }, 216 { "DCDC_REG4", 0xc4, 0x7f, rk809_vsel_range2 }, 217 { "DCDC_REG5", 0xde, 0x0f, rk809_vsel_range3}, 218 { "LDO_REG1", 0xcc, 0x7f, rk809_vsel_range4 }, 219 { "LDO_REG2", 0xce, 0x7f, rk809_vsel_range4 }, 220 { "LDO_REG3", 0xd0, 0x7f, rk809_vsel_range4 }, 221 { "LDO_REG4", 0xd2, 0x7f, rk809_vsel_range4 }, 222 { "LDO_REG5", 0xd4, 0x7f, rk809_vsel_range4 }, 223 { "LDO_REG6", 0xd6, 0x7f, rk809_vsel_range4 }, 224 { "LDO_REG7", 0xd8, 0x7f, rk809_vsel_range4 }, 225 { "LDO_REG8", 0xda, 0x7f, rk809_vsel_range4 }, 226 { "LDO_REG9", 0xdc, 0x7f, rk809_vsel_range4 }, 227 { } 228 }; 229 230 /* 231 * Used by RK817 for BOOST 232 * 0-7: 4.7V-5.4V,step=100mV 233 */ 234 const struct rkpmic_vsel_range rk817_boost_range[] = { 235 { 4700000, 100000, 0, 7 }, 236 {} 237 }; 238 239 const struct rkpmic_regdata rk817_regdata[] = { 240 { "DCDC_REG1", 0xbb, 0x7f, rk809_vsel_range1 }, 241 { "DCDC_REG2", 0xbe, 0x7f, rk809_vsel_range1 }, 242 { "DCDC_REG3", 0xc1, 0x7f, rk809_vsel_range1 }, 243 { "DCDC_REG4", 0xc4, 0x7f, rk809_vsel_range2 }, 244 { "LDO_REG1", 0xcc, 0x7f, rk809_vsel_range4 }, 245 { "LDO_REG2", 0xce, 0x7f, rk809_vsel_range4 }, 246 { "LDO_REG3", 0xd0, 0x7f, rk809_vsel_range4 }, 247 { "LDO_REG4", 0xd2, 0x7f, rk809_vsel_range4 }, 248 { "LDO_REG5", 0xd4, 0x7f, rk809_vsel_range4 }, 249 { "LDO_REG6", 0xd6, 0x7f, rk809_vsel_range4 }, 250 { "LDO_REG7", 0xd8, 0x7f, rk809_vsel_range4 }, 251 { "LDO_REG8", 0xda, 0x7f, rk809_vsel_range4 }, 252 { "LDO_REG9", 0xdc, 0x7f, rk809_vsel_range4 }, 253 { "BOOST", 0xde, 0x07, rk817_boost_range }, 254 { } 255 }; 256 257 struct rkpmic_softc { 258 struct device sc_dev; 259 i2c_tag_t sc_tag; 260 i2c_addr_t sc_addr; 261 262 int sc_rtc_ctrl_reg, sc_rtc_status_reg; 263 struct todr_chip_handle sc_todr; 264 const struct rkpmic_regdata *sc_regdata; 265 }; 266 267 int rkpmic_match(struct device *, void *, void *); 268 void rkpmic_attach(struct device *, struct device *, void *); 269 270 const struct cfattach rkpmic_ca = { 271 sizeof(struct rkpmic_softc), rkpmic_match, rkpmic_attach 272 }; 273 274 struct cfdriver rkpmic_cd = { 275 NULL, "rkpmic", DV_DULL 276 }; 277 278 void rkpmic_attach_regulator(struct rkpmic_softc *, int); 279 uint8_t rkpmic_reg_read(struct rkpmic_softc *, int); 280 void rkpmic_reg_write(struct rkpmic_softc *, int, uint8_t); 281 int rkpmic_clock_read(struct rkpmic_softc *, struct clock_ymdhms *); 282 int rkpmic_clock_write(struct rkpmic_softc *, struct clock_ymdhms *); 283 int rkpmic_gettime(struct todr_chip_handle *, struct timeval *); 284 int rkpmic_settime(struct todr_chip_handle *, struct timeval *); 285 286 int 287 rkpmic_match(struct device *parent, void *match, void *aux) 288 { 289 struct i2c_attach_args *ia = aux; 290 291 return (strcmp(ia->ia_name, "rockchip,rk805") == 0 || 292 strcmp(ia->ia_name, "rockchip,rk808") == 0 || 293 strcmp(ia->ia_name, "rockchip,rk809") == 0 || 294 strcmp(ia->ia_name, "rockchip,rk817") == 0); 295 } 296 297 void 298 rkpmic_attach(struct device *parent, struct device *self, void *aux) 299 { 300 struct rkpmic_softc *sc = (struct rkpmic_softc *)self; 301 struct i2c_attach_args *ia = aux; 302 int node = *(int *)ia->ia_cookie; 303 const char *chip; 304 305 sc->sc_tag = ia->ia_tag; 306 sc->sc_addr = ia->ia_addr; 307 308 sc->sc_todr.cookie = sc; 309 sc->sc_todr.todr_gettime = rkpmic_gettime; 310 sc->sc_todr.todr_settime = rkpmic_settime; 311 sc->sc_todr.todr_quality = 0; 312 todr_attach(&sc->sc_todr); 313 314 if (OF_is_compatible(node, "rockchip,rk805")) { 315 chip = "RK805"; 316 sc->sc_rtc_ctrl_reg = RK805_RTC_CTRL; 317 sc->sc_rtc_status_reg = RK805_RTC_STATUS; 318 sc->sc_regdata = rk805_regdata; 319 } else if (OF_is_compatible(node, "rockchip,rk808")) { 320 chip = "RK808"; 321 sc->sc_rtc_ctrl_reg = RK808_RTC_CTRL; 322 sc->sc_rtc_status_reg = RK808_RTC_STATUS; 323 sc->sc_regdata = rk808_regdata; 324 } else if (OF_is_compatible(node, "rockchip,rk809")) { 325 chip = "RK809"; 326 sc->sc_rtc_ctrl_reg = RK809_RTC_CTRL; 327 sc->sc_rtc_status_reg = RK809_RTC_STATUS; 328 sc->sc_regdata = rk809_regdata; 329 } else { 330 chip = "RK817"; 331 sc->sc_rtc_ctrl_reg = RK809_RTC_CTRL; 332 sc->sc_rtc_status_reg = RK809_RTC_STATUS; 333 sc->sc_regdata = rk817_regdata; 334 } 335 printf(": %s\n", chip); 336 337 node = OF_getnodebyname(node, "regulators"); 338 if (node == 0) 339 return; 340 for (node = OF_child(node); node; node = OF_peer(node)) 341 rkpmic_attach_regulator(sc, node); 342 } 343 344 struct rkpmic_regulator { 345 struct rkpmic_softc *rr_sc; 346 347 uint8_t rr_reg, rr_mask; 348 const struct rkpmic_vsel_range *rr_vsel_range; 349 350 struct regulator_device rr_rd; 351 }; 352 353 uint32_t rkpmic_get_voltage(void *); 354 int rkpmic_set_voltage(void *, uint32_t); 355 356 void 357 rkpmic_attach_regulator(struct rkpmic_softc *sc, int node) 358 { 359 struct rkpmic_regulator *rr; 360 char name[32]; 361 int i; 362 363 name[0] = 0; 364 OF_getprop(node, "name", name, sizeof(name)); 365 name[sizeof(name) - 1] = 0; 366 for (i = 0; sc->sc_regdata[i].name; i++) { 367 if (strcmp(sc->sc_regdata[i].name, name) == 0) 368 break; 369 } 370 if (sc->sc_regdata[i].name == NULL) 371 return; 372 373 rr = malloc(sizeof(*rr), M_DEVBUF, M_WAITOK | M_ZERO); 374 rr->rr_sc = sc; 375 376 rr->rr_reg = sc->sc_regdata[i].reg; 377 rr->rr_mask = sc->sc_regdata[i].mask; 378 rr->rr_vsel_range = sc->sc_regdata[i].vsel_range; 379 380 rr->rr_rd.rd_node = node; 381 rr->rr_rd.rd_cookie = rr; 382 rr->rr_rd.rd_get_voltage = rkpmic_get_voltage; 383 rr->rr_rd.rd_set_voltage = rkpmic_set_voltage; 384 regulator_register(&rr->rr_rd); 385 } 386 387 uint32_t 388 rkpmic_get_voltage(void *cookie) 389 { 390 struct rkpmic_regulator *rr = cookie; 391 const struct rkpmic_vsel_range *vsel_range = rr->rr_vsel_range; 392 uint8_t vsel; 393 uint32_t ret = 0; 394 395 vsel = rkpmic_reg_read(rr->rr_sc, rr->rr_reg) & rr->rr_mask; 396 397 while (vsel_range->base) { 398 ret = vsel_range->base; 399 if (vsel >= vsel_range->vsel_min && 400 vsel <= vsel_range->vsel_max) { 401 ret += (vsel - vsel_range->vsel_min) * 402 vsel_range->delta; 403 break; 404 } else 405 ret += (vsel_range->vsel_max - vsel_range->vsel_min) * 406 vsel_range->delta; 407 vsel_range++; 408 409 } 410 411 return ret; 412 } 413 414 int 415 rkpmic_set_voltage(void *cookie, uint32_t voltage) 416 { 417 struct rkpmic_regulator *rr = cookie; 418 const struct rkpmic_vsel_range *vsel_range = rr->rr_vsel_range; 419 uint32_t vmin, vmax, volt; 420 uint8_t reg, vsel; 421 422 while (vsel_range->base) { 423 vmin = vsel_range->base; 424 vmax = vmin + (vsel_range->vsel_max - vsel_range->vsel_min) * 425 vsel_range->delta; 426 if (voltage < vmin) 427 return EINVAL; 428 if (voltage <= vmax) { 429 vsel = vsel_range->vsel_min; 430 volt = vsel_range->base; 431 while (vsel <= vsel_range->vsel_max) { 432 if (volt == voltage) 433 break; 434 else { 435 vsel++; 436 volt += vsel_range->delta; 437 } 438 } 439 if (volt != voltage) 440 return EINVAL; 441 break; 442 } 443 vsel_range++; 444 } 445 446 if (vsel_range->base == 0) 447 return EINVAL; 448 449 reg = rkpmic_reg_read(rr->rr_sc, rr->rr_reg); 450 reg &= ~rr->rr_mask; 451 reg |= vsel; 452 rkpmic_reg_write(rr->rr_sc, rr->rr_reg, reg); 453 454 return 0; 455 } 456 457 int 458 rkpmic_gettime(struct todr_chip_handle *handle, struct timeval *tv) 459 { 460 struct rkpmic_softc *sc = handle->cookie; 461 struct clock_ymdhms dt; 462 time_t secs; 463 int error; 464 465 error = rkpmic_clock_read(sc, &dt); 466 if (error) 467 return error; 468 469 if (dt.dt_sec > 59 || dt.dt_min > 59 || dt.dt_hour > 23 || 470 dt.dt_day > 31 || dt.dt_day == 0 || 471 dt.dt_mon > 12 || dt.dt_mon == 0 || 472 dt.dt_year < POSIX_BASE_YEAR) 473 return EINVAL; 474 475 /* 476 * The RTC thinks November has 31 days. Match what Linux does 477 * and undo the damage by considering the calendars to be in 478 * sync on January 1st 2016. 479 */ 480 secs = clock_ymdhms_to_secs(&dt); 481 secs += (dt.dt_year - 2016 + (dt.dt_mon == 12 ? 1 : 0)) * 86400; 482 483 tv->tv_sec = secs; 484 tv->tv_usec = 0; 485 return 0; 486 } 487 488 int 489 rkpmic_settime(struct todr_chip_handle *handle, struct timeval *tv) 490 { 491 struct rkpmic_softc *sc = handle->cookie; 492 struct clock_ymdhms dt; 493 time_t secs; 494 495 /* 496 * Take care of the November 31st braindamage here as well. 497 * Don't try to be clever, just do the conversion in two 498 * steps, first taking care of November 31 in previous years, 499 * and then taking care of days in December of the current 500 * year. December 1st turns into November 31st! 501 */ 502 secs = tv->tv_sec; 503 clock_secs_to_ymdhms(secs, &dt); 504 secs -= (dt.dt_year - 2016) * 86400; 505 clock_secs_to_ymdhms(secs, &dt); 506 if (dt.dt_mon == 12) { 507 dt.dt_day--; 508 if (dt.dt_day == 0) { 509 dt.dt_mon = 11; 510 dt.dt_day = 31; 511 } 512 } 513 514 return rkpmic_clock_write(sc, &dt); 515 } 516 517 uint8_t 518 rkpmic_reg_read(struct rkpmic_softc *sc, int reg) 519 { 520 uint8_t cmd = reg; 521 uint8_t val; 522 int error; 523 524 iic_acquire_bus(sc->sc_tag, I2C_F_POLL); 525 error = iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, sc->sc_addr, 526 &cmd, sizeof cmd, &val, sizeof val, I2C_F_POLL); 527 iic_release_bus(sc->sc_tag, I2C_F_POLL); 528 529 if (error) { 530 printf("%s: can't read register 0x%02x\n", 531 sc->sc_dev.dv_xname, reg); 532 val = 0xff; 533 } 534 535 return val; 536 } 537 538 void 539 rkpmic_reg_write(struct rkpmic_softc *sc, int reg, uint8_t val) 540 { 541 uint8_t cmd = reg; 542 int error; 543 544 iic_acquire_bus(sc->sc_tag, I2C_F_POLL); 545 error = iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP, sc->sc_addr, 546 &cmd, sizeof cmd, &val, sizeof val, I2C_F_POLL); 547 iic_release_bus(sc->sc_tag, I2C_F_POLL); 548 549 if (error) { 550 printf("%s: can't write register 0x%02x\n", 551 sc->sc_dev.dv_xname, reg); 552 } 553 } 554 555 int 556 rkpmic_clock_read(struct rkpmic_softc *sc, struct clock_ymdhms *dt) 557 { 558 uint8_t regs[RK80X_NRTC_REGS]; 559 uint8_t cmd = RK80X_SECONDS; 560 uint8_t status; 561 int error; 562 563 iic_acquire_bus(sc->sc_tag, I2C_F_POLL); 564 error = iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, sc->sc_addr, 565 &cmd, sizeof(cmd), regs, RK80X_NRTC_REGS, I2C_F_POLL); 566 iic_release_bus(sc->sc_tag, I2C_F_POLL); 567 568 if (error) { 569 printf("%s: can't read RTC\n", sc->sc_dev.dv_xname); 570 return error; 571 } 572 573 /* 574 * Convert the RK80x's register values into something useable. 575 */ 576 dt->dt_sec = FROMBCD(regs[0]); 577 dt->dt_min = FROMBCD(regs[1]); 578 dt->dt_hour = FROMBCD(regs[2]); 579 dt->dt_day = FROMBCD(regs[3]); 580 dt->dt_mon = FROMBCD(regs[4]); 581 dt->dt_year = FROMBCD(regs[5]) + 2000; 582 583 /* Consider the time to be invalid if the POWER_UP bit is set. */ 584 status = rkpmic_reg_read(sc, sc->sc_rtc_status_reg); 585 if (status & RK80X_RTC_STATUS_POWER_UP) 586 return EINVAL; 587 588 return 0; 589 } 590 591 int 592 rkpmic_clock_write(struct rkpmic_softc *sc, struct clock_ymdhms *dt) 593 { 594 uint8_t regs[RK80X_NRTC_REGS]; 595 uint8_t cmd = RK80X_SECONDS; 596 int error; 597 598 /* 599 * Convert our time representation into something the RK80x 600 * can understand. 601 */ 602 regs[0] = TOBCD(dt->dt_sec); 603 regs[1] = TOBCD(dt->dt_min); 604 regs[2] = TOBCD(dt->dt_hour); 605 regs[3] = TOBCD(dt->dt_day); 606 regs[4] = TOBCD(dt->dt_mon); 607 regs[5] = TOBCD(dt->dt_year - 2000); 608 regs[6] = TOBCD(dt->dt_wday); 609 610 /* Stop RTC such that we can write to it. */ 611 rkpmic_reg_write(sc, sc->sc_rtc_ctrl_reg, RK80X_RTC_CTRL_STOP_RTC); 612 613 iic_acquire_bus(sc->sc_tag, I2C_F_POLL); 614 error = iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP, sc->sc_addr, 615 &cmd, sizeof(cmd), regs, RK80X_NRTC_REGS, I2C_F_POLL); 616 iic_release_bus(sc->sc_tag, I2C_F_POLL); 617 618 /* Restart RTC. */ 619 rkpmic_reg_write(sc, sc->sc_rtc_ctrl_reg, 0); 620 621 if (error) { 622 printf("%s: can't write RTC\n", sc->sc_dev.dv_xname); 623 return error; 624 } 625 626 /* Clear POWER_UP bit to indicate the time is now valid. */ 627 rkpmic_reg_write(sc, sc->sc_rtc_status_reg, RK80X_RTC_STATUS_POWER_UP); 628 629 return 0; 630 } 631