1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 #include <sys/types.h> 29 #include <sys/conf.h> 30 #include <sys/devops.h> 31 #include <sys/kmem.h> 32 #include <sys/open.h> 33 #include <sys/file.h> 34 #include <sys/note.h> 35 #include <sys/ddi.h> 36 #include <sys/sunddi.h> 37 38 #include <sys/modctl.h> 39 #include <sys/stat.h> 40 #include <sys/clock.h> 41 #include <sys/reboot.h> 42 #include <sys/machsystm.h> 43 #include <sys/poll.h> 44 #include <sys/pbio.h> 45 #include <sys/sysmacros.h> 46 47 /* Added for prom interface */ 48 #include <sys/promif.h> 49 #include <sys/promimpl.h> 50 51 #include <sys/i2c/misc/i2c_svc.h> 52 #include <sys/todds1307.h> 53 54 #define I2C_DELAY 20000 55 #define DS1307_DEVICE_TYPE "rtc" 56 57 /* 58 * Driver enrty routines 59 */ 60 static int todds1307_attach(dev_info_t *, ddi_attach_cmd_t); 61 static int todds1307_detach(dev_info_t *, ddi_detach_cmd_t); 62 static int todds1307_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **); 63 64 /* 65 * tod_ops entry routines 66 */ 67 static timestruc_t todds1307_get(void); 68 static void todds1307_set(timestruc_t); 69 static uint_t todds1307_set_watchdog_timer(uint_t); 70 static uint_t todds1307_clear_watchdog_timer(void); 71 static void todds1307_set_power_alarm(timestruc_t); 72 static void todds1307_clear_power_alarm(void); 73 static int todds1307_setup_prom(); 74 static void todds1307_rele_prom(); 75 static int todds1307_prom_getdate(struct rtc_t *rtc); 76 static int todds1307_prom_setdate(struct rtc_t *rtc); 77 78 /* 79 * Local functions 80 */ 81 static int todds1307_read_rtc(struct rtc_t *); 82 static int todds1307_write_rtc(struct rtc_t *); 83 84 /* Anchor for soft state structure */ 85 static void *ds1307_statep; 86 static int instance = -1; 87 static int todds1307_attach_done = 0; 88 static kmutex_t todds1307_rd_lock; 89 static ihandle_t todds1307_ihandle = 0; 90 91 /* one second time out */ 92 #define I2c_CYCLIC_TIMEOUT 1000000000 93 uint_t i2c_cyclic_timeout = I2c_CYCLIC_TIMEOUT; 94 static int sync_clock_once = 1; 95 static struct rtc_t soft_rtc; 96 97 /* 98 * For debugging only 99 */ 100 static unsigned char int2bcd(int num); 101 static int bcd2int(unsigned char num); 102 103 /* 104 * cp_ops structure 105 */ 106 static struct cb_ops ds1307_cbops = { 107 nodev, /* open */ 108 nodev, /* close */ 109 nodev, /* strategy */ 110 nodev, /* print */ 111 nodev, /* dump */ 112 nodev, /* read */ 113 nodev, /* write */ 114 nodev, /* ioctl */ 115 nodev, /* devmap */ 116 nodev, /* mmap */ 117 nodev, /* segmap */ 118 NULL, /* poll */ 119 ddi_prop_op, /* cb_prop_op */ 120 NULL, /* streamtab */ 121 D_NEW | D_MP, /* Driver compatibility flag */ 122 CB_REV, /* rev */ 123 nodev, /* int (*cb_aread)() */ 124 nodev /* int (*cb_awrite)() */ 125 }; 126 127 /* 128 * dev_ops structure 129 */ 130 static struct dev_ops ds1307_ops = { 131 DEVO_REV, /* devo_rev */ 132 0, /* refcnt - reference cnt always set to 0 */ 133 todds1307_getinfo, /* getinfo - Maybe requred */ 134 nulldev, /* identify */ 135 nulldev, /* probe */ 136 todds1307_attach, /* attach */ 137 todds1307_detach, /* detach */ 138 nodev, /* reset */ 139 &ds1307_cbops, /* cb_ops - ds1307 does not need this(?) */ 140 NULL 141 }; 142 143 static struct modldrv todds1307_modldrv = { 144 &mod_driverops, /* Type of module. This one is a driver */ 145 "tod driver for DS1307 v%I%", /* Name of the module */ 146 &ds1307_ops, /* Pointer to dev_ops */ 147 }; 148 149 /* 150 * Module linkage structure 151 */ 152 static struct modlinkage todds1307_modlinkage = { 153 MODREV_1, 154 &todds1307_modldrv, 155 0 156 }; 157 158 int 159 _init(void) 160 { 161 int error; 162 163 if (strcmp(tod_module_name, "todds1307") == 0) { 164 if ((error = ddi_soft_state_init(&ds1307_statep, 165 sizeof (ds1307_state_t), 0)) != DDI_SUCCESS) { 166 return (error); 167 } 168 169 tod_ops.tod_get = todds1307_get; 170 tod_ops.tod_set = todds1307_set; 171 tod_ops.tod_set_watchdog_timer = todds1307_set_watchdog_timer; 172 tod_ops.tod_clear_watchdog_timer = 173 todds1307_clear_watchdog_timer; 174 tod_ops.tod_set_power_alarm = todds1307_set_power_alarm; 175 tod_ops.tod_clear_power_alarm = todds1307_clear_power_alarm; 176 } 177 178 (void) todds1307_setup_prom(); 179 180 /* 181 * Install the module 182 */ 183 if ((error = mod_install(&todds1307_modlinkage)) != 0) { 184 ddi_soft_state_fini(&ds1307_statep); 185 return (error); 186 } 187 mutex_init(&todds1307_rd_lock, NULL, MUTEX_DEFAULT, NULL); 188 189 return (0); 190 } 191 192 int 193 _fini(void) 194 { 195 int error = 0; 196 197 if (strcmp(tod_module_name, "todds1307") == 0) { 198 error = EBUSY; 199 } else { 200 if ((error = mod_remove(&todds1307_modlinkage)) == 0) { 201 ddi_soft_state_fini(&ds1307_statep); 202 mutex_destroy(&todds1307_rd_lock); 203 todds1307_rele_prom(); 204 } 205 } 206 207 return (error); 208 } 209 210 int 211 _info(struct modinfo *modinfop) 212 { 213 return (mod_info(&todds1307_modlinkage, modinfop)); 214 } 215 216 /* 217 * cyclical call to get tod. 218 */ 219 static void 220 todds1307_cyclic(void *arg) 221 { 222 223 todds1307_read_rtc((struct rtc_t *)arg); 224 225 } 226 227 /* 228 * register ds1307 client device with i2c services, and 229 * allocate & initialize soft state structure. 230 */ 231 static int 232 todds1307_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 233 { 234 static ds1307_state_t *statep = NULL; 235 i2c_transfer_t *i2c_tp = NULL; 236 uint8_t tempVal = (uint8_t)0; 237 switch (cmd) { 238 239 case DDI_ATTACH: 240 break; 241 case DDI_RESUME: 242 return (DDI_SUCCESS); 243 default: 244 return (DDI_FAILURE); 245 } 246 247 if (instance != -1) { 248 return (DDI_FAILURE); 249 } 250 251 instance = ddi_get_instance(dip); 252 253 /* 254 * Allocate soft state structure 255 */ 256 if (ddi_soft_state_zalloc(ds1307_statep, instance) != DDI_SUCCESS) { 257 return (DDI_FAILURE); 258 } 259 260 statep = ddi_get_soft_state(ds1307_statep, instance); 261 if (statep == NULL) { 262 return (DDI_FAILURE); 263 } 264 265 statep->dip = dip; 266 267 if (i2c_client_register(dip, &statep->ds1307_i2c_hdl) != I2C_SUCCESS) { 268 ddi_soft_state_free(ds1307_statep, instance); 269 delay(drv_usectohz(I2C_DELAY)); 270 return (DDI_FAILURE); 271 } 272 273 /* check and initialize the oscillator */ 274 275 (void) i2c_transfer_alloc(statep->ds1307_i2c_hdl, 276 &i2c_tp, 1, 1, I2C_SLEEP); 277 i2c_tp->i2c_version = I2C_XFER_REV; 278 i2c_tp->i2c_flags = I2C_WR_RD; 279 i2c_tp->i2c_wbuf[0] = (uchar_t)0x00; /* Read 00h */ 280 i2c_tp->i2c_wlen = 1; 281 i2c_tp->i2c_rlen = 1; 282 283 if ((i2c_transfer(statep->ds1307_i2c_hdl, i2c_tp)) != I2C_SUCCESS) { 284 (void) i2c_transfer_free(statep->ds1307_i2c_hdl, i2c_tp); 285 ddi_soft_state_free(ds1307_statep, instance); 286 delay(drv_usectohz(I2C_DELAY)); 287 return (DDI_FAILURE); 288 } 289 290 tempVal = i2c_tp->i2c_rbuf[0]; 291 292 (void) i2c_transfer_free(statep->ds1307_i2c_hdl, i2c_tp); 293 294 if (tempVal & 0x80) { /* check Oscillator */ 295 (void) i2c_transfer_alloc(statep->ds1307_i2c_hdl, &i2c_tp, 296 2, 1, I2C_SLEEP); 297 i2c_tp->i2c_version = I2C_XFER_REV; 298 i2c_tp->i2c_flags = I2C_WR; 299 i2c_tp->i2c_wbuf[0] = 0x00; 300 i2c_tp->i2c_wbuf[1] = 301 (uchar_t)(i2c_tp->i2c_rbuf[0]& 0x7f); 302 i2c_tp->i2c_wlen = 2; 303 /* Enable oscillator */ 304 if ((i2c_transfer(statep->ds1307_i2c_hdl, i2c_tp)) 305 != I2C_SUCCESS) { 306 (void) i2c_transfer_free(statep->ds1307_i2c_hdl, 307 i2c_tp); 308 ddi_soft_state_free(ds1307_statep, instance); 309 return (DDI_FAILURE); 310 } 311 (void) i2c_transfer_free(statep->ds1307_i2c_hdl, i2c_tp); 312 } 313 314 /* 315 * Create a periodical handler to read TOD. 316 */ 317 ASSERT(statep->cycid == NULL); 318 statep->cycid = ddi_periodic_add(todds1307_cyclic, &soft_rtc, 319 i2c_cyclic_timeout, DDI_IPL_1); 320 321 statep->state = TOD_ATTACHED; 322 todds1307_attach_done = 1; 323 ddi_report_dev(dip); 324 325 return (DDI_SUCCESS); 326 } 327 328 /* 329 * Unregister ds1307 client device with i2c services and free 330 * soft state structure. 331 */ 332 /*ARGSUSED*/ 333 static int 334 todds1307_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 335 { 336 switch (cmd) { 337 338 /* 339 * Once attached, do not allow detach because the system constantly 340 * calling todds1307_get() to get the time. If the driver is detached 341 * and the system try to get the time, the system will have memory 342 * problem. 343 * 344 * ds1307_state_t *statep = NULL; 345 * case DDI_DETACH: 346 * if ((statep = ddi_get_soft_state(ds1307_statep, 347 * instance)) == NULL) { 348 * return (ENOMEM); 349 * } 350 * i2c_client_unregister(statep->ds1307_i2c_hdl); 351 * ddi_soft_state_free(ds1307_statep, instance); 352 * return (DDI_SUCCESS); 353 */ 354 case DDI_SUSPEND: 355 return (DDI_SUCCESS); 356 357 default: 358 return (DDI_FAILURE); 359 } 360 } 361 362 /* *********************** tod_ops entry points ******************** */ 363 364 /* 365 * Read the current time from the DS1307 chip and convert to UNIX form. 366 * Should be called with tod_clock held. 367 */ 368 369 static timestruc_t 370 todds1307_get(void) 371 { 372 timestruc_t ts; 373 todinfo_t tod; 374 struct rtc_t rtc; 375 376 ASSERT(MUTEX_HELD(&tod_lock)); 377 378 if (sync_clock_once) { 379 todds1307_read_rtc(&soft_rtc); 380 sync_clock_once = 0; 381 } else { 382 tod_fault_reset(); 383 return (hrestime); 384 } 385 386 bcopy(&soft_rtc, &rtc, sizeof (rtc)); 387 388 /* 389 * 00 - 68 = 2000 thru 2068 390 * 69-99 = 1969 thru 1999 391 */ 392 tod.tod_year = rtc.rtc_year; 393 if (rtc.rtc_year <= 68) 394 tod.tod_year += 100; 395 tod.tod_month = rtc.rtc_mon; 396 tod.tod_day = rtc.rtc_dom; 397 tod.tod_dow = rtc.rtc_dow; 398 tod.tod_hour = rtc.rtc_hrs; 399 tod.tod_min = rtc.rtc_min; 400 tod.tod_sec = rtc.rtc_sec; 401 402 ts.tv_sec = tod_to_utc(tod); 403 ts.tv_nsec = 0; 404 return (ts); 405 } 406 407 /* 408 * Program DS1307 with the specified time. 409 * Must be called with tod_lock held. The TOD 410 * chip supports date from 1969-2068 only. We must 411 * reject requests to set date below 2000. 412 */ 413 static void 414 todds1307_set(timestruc_t ts) 415 { 416 struct rtc_t rtc; 417 todinfo_t tod = utc_to_tod(ts.tv_sec); 418 int year; 419 420 421 ASSERT(MUTEX_HELD(&tod_lock)); 422 423 /* 424 * Year is base 1900, valid year range 1969-2068 425 */ 426 if ((tod.tod_year < 69) || (tod.tod_year > 168)) 427 return; 428 429 year = tod.tod_year; 430 if (year >= 100) 431 year -= 100; 432 433 rtc.rtc_year = int2bcd(year); 434 rtc.rtc_mon = int2bcd(tod.tod_month); 435 rtc.rtc_dom = int2bcd(tod.tod_day); 436 rtc.rtc_dow = int2bcd(tod.tod_dow); 437 rtc.rtc_hrs = int2bcd(tod.tod_hour); 438 rtc.rtc_min = int2bcd(tod.tod_min); 439 rtc.rtc_sec = int2bcd(tod.tod_sec); 440 441 todds1307_write_rtc(&rtc); 442 } 443 444 /* ARGSUSED */ 445 static void 446 todds1307_set_power_alarm(timestruc_t ts) 447 { 448 ASSERT(MUTEX_HELD(&tod_lock)); 449 } 450 451 /* ARGSUSED */ 452 static void 453 todds1307_clear_power_alarm(void) 454 { 455 ASSERT(MUTEX_HELD(&tod_lock)); 456 } 457 458 /* ARGSUSED */ 459 static uint_t 460 todds1307_set_watchdog_timer(uint_t timeoutval) 461 { 462 ASSERT(MUTEX_HELD(&tod_lock)); 463 return (0); 464 } 465 466 /* ARGSUSED */ 467 static uint_t 468 todds1307_clear_watchdog_timer(void) 469 { 470 ASSERT(MUTEX_HELD(&tod_lock)); 471 return (0); 472 } 473 474 /* ********************** Local functions ***************************** */ 475 476 static char tod_read[7] = {-1, -1, -1, -1, -1, -1, -1}; 477 static int 478 todds1307_read_rtc(struct rtc_t *rtc) 479 { 480 static ds1307_state_t *statep = NULL; 481 i2c_transfer_t *i2c_tp = NULL; 482 int i2c_cmd_status = I2C_FAILURE; 483 int counter = 4; 484 485 if (!todds1307_attach_done) { 486 return (todds1307_prom_getdate(rtc)); 487 } 488 489 statep = ddi_get_soft_state(ds1307_statep, instance); 490 if (statep == NULL) { 491 cmn_err(CE_WARN, "todds1307: ddi_get_soft_state failed"); 492 return (DDI_FAILURE); 493 } 494 495 mutex_enter(&todds1307_rd_lock); 496 497 /* 498 * Allocate 1 byte for write buffer and 7 bytes for read buffer to 499 * to accomodate sec, min, hrs, dayOfWeek, dayOfMonth, year 500 */ 501 if ((i2c_transfer_alloc(statep->ds1307_i2c_hdl, &i2c_tp, 1, 502 7, I2C_SLEEP)) != I2C_SUCCESS) { 503 mutex_exit(&todds1307_rd_lock); 504 return (DDI_FAILURE); 505 } 506 507 do { 508 i2c_tp->i2c_version = I2C_XFER_REV; 509 i2c_tp->i2c_flags = I2C_WR_RD; 510 i2c_tp->i2c_wbuf[0] = (uchar_t)0x00; /* Start from reg 0x00 */ 511 i2c_tp->i2c_wlen = 1; /* Write one byte address */ 512 i2c_tp->i2c_rlen = 7; /* Read 7 regs */ 513 514 if ((i2c_cmd_status = i2c_transfer(statep->ds1307_i2c_hdl, 515 i2c_tp)) != I2C_SUCCESS) { 516 drv_usecwait(I2C_DELAY); 517 goto done; 518 } 519 /* for first read, need to get valid data */ 520 while (tod_read[0] == -1 && counter > 0) { 521 /* move data to static buffer */ 522 bcopy(i2c_tp->i2c_rbuf, tod_read, 7); 523 524 /* now read again */ 525 /* Start reading reg from 0x00 */ 526 i2c_tp->i2c_wbuf[0] = (uchar_t)0x00; 527 i2c_tp->i2c_wlen = 1; /* Write one byte address */ 528 i2c_tp->i2c_rlen = 7; /* Read 7 regs */ 529 if ((i2c_cmd_status = i2c_transfer(statep->ds1307_i2c_hdl, 530 i2c_tp)) != I2C_SUCCESS) { 531 drv_usecwait(I2C_DELAY); 532 goto done; 533 } 534 /* if they are not the same, then read again */ 535 if (bcmp(tod_read, i2c_tp->i2c_rbuf, 7) != 0) { 536 tod_read[0] = -1; 537 counter--; 538 } 539 } 540 541 } while (i2c_tp->i2c_rbuf[0] == 0x59 && 542 /* if seconds register is 0x59 (BCD), add data should match */ 543 bcmp(&tod_read[1], &i2c_tp->i2c_rbuf[1], 6) != 0 && 544 counter-- > 0); 545 546 if (counter < 0) 547 cmn_err(CE_WARN, "i2ctod: TOD Chip failed ??"); 548 549 /* move data to static buffer */ 550 bcopy(i2c_tp->i2c_rbuf, tod_read, 7); 551 552 553 rtc->rtc_year = bcd2int(i2c_tp->i2c_rbuf[6]); 554 rtc->rtc_mon = bcd2int(i2c_tp->i2c_rbuf[5]); 555 rtc->rtc_dom = bcd2int(i2c_tp->i2c_rbuf[4]); 556 rtc->rtc_dow = bcd2int(i2c_tp->i2c_rbuf[3]); 557 rtc->rtc_hrs = bcd2int(i2c_tp->i2c_rbuf[2]); 558 rtc->rtc_min = bcd2int(i2c_tp->i2c_rbuf[1]); 559 rtc->rtc_sec = bcd2int(i2c_tp->i2c_rbuf[0]); 560 561 done: 562 (void) i2c_transfer_free(statep->ds1307_i2c_hdl, i2c_tp); 563 564 mutex_exit(&todds1307_rd_lock); 565 return (i2c_cmd_status); 566 } 567 568 569 static int 570 todds1307_write_rtc(struct rtc_t *rtc) 571 { 572 ds1307_state_t *statep = NULL; 573 i2c_transfer_t *i2c_tp = NULL; 574 int i2c_cmd_status = I2C_SUCCESS; 575 576 577 if (!todds1307_attach_done) { 578 return (todds1307_prom_setdate(rtc)); 579 } 580 581 statep = ddi_get_soft_state(ds1307_statep, instance); 582 if (statep == NULL) { 583 return (DDI_FAILURE); 584 } 585 586 if ((i2c_cmd_status = i2c_transfer_alloc(statep->ds1307_i2c_hdl, 587 &i2c_tp, 8, 0, I2C_SLEEP)) != I2C_SUCCESS) { 588 return (i2c_cmd_status); 589 } 590 591 i2c_tp->i2c_version = I2C_XFER_REV; 592 i2c_tp->i2c_flags = I2C_WR; 593 i2c_tp->i2c_wbuf[0] = (uchar_t)0x00; 594 i2c_tp->i2c_wbuf[1] = rtc->rtc_sec; 595 i2c_tp->i2c_wbuf[2] = rtc->rtc_min; 596 i2c_tp->i2c_wbuf[3] = rtc->rtc_hrs; 597 i2c_tp->i2c_wbuf[4] = rtc->rtc_dow; 598 i2c_tp->i2c_wbuf[5] = rtc->rtc_dom; 599 i2c_tp->i2c_wbuf[6] = rtc->rtc_mon; 600 i2c_tp->i2c_wbuf[7] = rtc->rtc_year; 601 i2c_tp->i2c_wlen = 8; 602 603 if ((i2c_cmd_status = i2c_transfer(statep->ds1307_i2c_hdl, 604 i2c_tp)) != I2C_SUCCESS) { 605 (void) i2c_transfer_free(statep->ds1307_i2c_hdl, i2c_tp); 606 /* delay(drv_usectohz(I2C_DELAY)); */ 607 drv_usecwait(I2C_DELAY); 608 return (i2c_cmd_status); 609 } 610 611 tod_read[0] = -1; /* invalidate saved data from read routine */ 612 613 (void) i2c_transfer_free(statep->ds1307_i2c_hdl, i2c_tp); 614 615 return (i2c_cmd_status); 616 } 617 618 619 /*ARGSUSED*/ 620 static int 621 todds1307_getinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, 622 void **result) 623 { 624 ds1307_state_t *softsp; 625 626 if (instance == -1) { 627 return (DDI_FAILURE); 628 } 629 630 switch (infocmd) { 631 case DDI_INFO_DEVT2DEVINFO: 632 if ((softsp = ddi_get_soft_state(ds1307_statep, instance)) 633 == NULL) 634 return (DDI_FAILURE); 635 *result = (void *)softsp->dip; 636 return (DDI_SUCCESS); 637 638 case DDI_INFO_DEVT2INSTANCE: 639 *result = (void *)(uintptr_t)instance; 640 return (DDI_SUCCESS); 641 642 default: 643 return (DDI_FAILURE); 644 } 645 } 646 647 /* 648 * Conversion functions 649 */ 650 static unsigned char 651 int2bcd(int num) { 652 return (((num / 10) << 4) /* tens BCD digit in high four bits */ 653 + (num % 10)); /* units digit goes in low four bits */ 654 } 655 656 static int 657 bcd2int(unsigned char num) { 658 return (((num >> 4) * 10) /* 10 times high-order four bits */ 659 + (num & 0x0f)); /* plus low-order four bits */ 660 } 661 662 /* 663 * Finds the device node with device_type "rtc" and opens it to 664 * execute the get-time method 665 */ 666 static int 667 todds1307_setup_prom() 668 { 669 pnode_t todnode; 670 char tod1307_devpath[MAXNAMELEN]; 671 672 if ((todnode = prom_findnode_bydevtype(prom_rootnode(), 673 DS1307_DEVICE_TYPE)) == OBP_NONODE) 674 return (DDI_FAILURE); 675 676 /* 677 * We now have the phandle of the rtc node, we need to open the 678 * node and get the ihandle 679 */ 680 if (prom_phandle_to_path(todnode, tod1307_devpath, 681 sizeof (tod1307_devpath)) < 0) { 682 cmn_err(CE_WARN, "prom_phandle_to_path failed"); 683 return (DDI_FAILURE); 684 } 685 686 /* 687 * Now open the node and store it's ihandle 688 */ 689 if ((todds1307_ihandle = prom_open(tod1307_devpath)) == NULL) { 690 cmn_err(CE_WARN, "prom_open failed"); 691 return (DDI_FAILURE); 692 } 693 694 return (DDI_SUCCESS); 695 } 696 697 /* 698 * Closes the prom interface 699 */ 700 static void 701 todds1307_rele_prom() 702 { 703 (void) prom_close(todds1307_ihandle); 704 } 705 706 /* 707 * Read the date using "get-time" method in rtc node 708 * PROM returns 1969-1999 when reading 69-99 and 709 * 2000-2068 when reading 00-68 710 */ 711 static int 712 todds1307_prom_getdate(struct rtc_t *rtc) 713 { 714 int year; 715 cell_t ci[12]; 716 717 ci[0] = p1275_ptr2cell("call-method"); /* Service name */ 718 ci[1] = 2; /* # of arguments */ 719 ci[2] = 7; /* # of result cells */ 720 ci[3] = p1275_ptr2cell("get-time"); 721 ci[4] = p1275_ihandle2cell(todds1307_ihandle); 722 723 promif_preprom(); 724 (void) p1275_cif_handler(&ci); 725 promif_postprom(); 726 727 year = p1275_cell2int(ci[6]); 728 rtc->rtc_mon = p1275_cell2int(ci[7]); 729 rtc->rtc_dom = p1275_cell2int(ci[8]); 730 rtc->rtc_dow = 0; 731 rtc->rtc_hrs = p1275_cell2int(ci[9]); 732 rtc->rtc_min = p1275_cell2int(ci[10]); 733 rtc->rtc_sec = p1275_cell2int(ci[11]); 734 if (year >= 2000) 735 year -= 2000; 736 else 737 year -= 1900; 738 rtc->rtc_year = year; 739 740 return (DDI_SUCCESS); 741 } 742 743 /* 744 * Read the date using "set-time" method in rtc node 745 * For values 00 - 68, write 2000-2068, and for 69-99, 746 * write 1969-1999 747 */ 748 static int 749 todds1307_prom_setdate(struct rtc_t *rtc) 750 { 751 int year; 752 cell_t ci[12]; 753 754 year = rtc->rtc_year; 755 756 if ((year < 0) || (year > 99)) 757 return (DDI_FAILURE); 758 759 if (year <= 68) 760 year = rtc->rtc_year + 2000; 761 else 762 year = rtc->rtc_year + 1900; 763 764 ci[0] = p1275_ptr2cell("call-method"); /* Service name */ 765 ci[1] = 8; /* # of arguments */ 766 ci[2] = 0; /* # of result cells */ 767 ci[3] = p1275_ptr2cell("set-time"); 768 ci[4] = p1275_ihandle2cell(todds1307_ihandle); 769 ci[5] = p1275_int2cell(year); 770 ci[6] = p1275_int2cell(rtc->rtc_mon); 771 ci[7] = p1275_int2cell(rtc->rtc_dom); 772 ci[8] = p1275_int2cell(rtc->rtc_hrs); 773 ci[9] = p1275_int2cell(rtc->rtc_min); 774 ci[10] = p1275_int2cell(rtc->rtc_sec); 775 776 promif_preprom(); 777 (void) p1275_cif_handler(&ci); 778 promif_postprom(); 779 780 return (DDI_SUCCESS); 781 } 782