1*7c478bd9Sstevel@tonic-gate /* 2*7c478bd9Sstevel@tonic-gate * CDDL HEADER START 3*7c478bd9Sstevel@tonic-gate * 4*7c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*7c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*7c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*7c478bd9Sstevel@tonic-gate * with the License. 8*7c478bd9Sstevel@tonic-gate * 9*7c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*7c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*7c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 12*7c478bd9Sstevel@tonic-gate * and limitations under the License. 13*7c478bd9Sstevel@tonic-gate * 14*7c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*7c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*7c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*7c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*7c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*7c478bd9Sstevel@tonic-gate * 20*7c478bd9Sstevel@tonic-gate * CDDL HEADER END 21*7c478bd9Sstevel@tonic-gate */ 22*7c478bd9Sstevel@tonic-gate /* 23*7c478bd9Sstevel@tonic-gate * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24*7c478bd9Sstevel@tonic-gate * Use is subject to license terms. 25*7c478bd9Sstevel@tonic-gate */ 26*7c478bd9Sstevel@tonic-gate 27*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*7c478bd9Sstevel@tonic-gate 29*7c478bd9Sstevel@tonic-gate #include <sys/types.h> 30*7c478bd9Sstevel@tonic-gate #include <sys/conf.h> 31*7c478bd9Sstevel@tonic-gate #include <sys/devops.h> 32*7c478bd9Sstevel@tonic-gate #include <sys/kmem.h> 33*7c478bd9Sstevel@tonic-gate #include <sys/open.h> 34*7c478bd9Sstevel@tonic-gate #include <sys/file.h> 35*7c478bd9Sstevel@tonic-gate #include <sys/note.h> 36*7c478bd9Sstevel@tonic-gate #include <sys/ddi.h> 37*7c478bd9Sstevel@tonic-gate #include <sys/sunddi.h> 38*7c478bd9Sstevel@tonic-gate 39*7c478bd9Sstevel@tonic-gate #include <sys/modctl.h> 40*7c478bd9Sstevel@tonic-gate #include <sys/stat.h> 41*7c478bd9Sstevel@tonic-gate #include <sys/clock.h> 42*7c478bd9Sstevel@tonic-gate #include <sys/reboot.h> 43*7c478bd9Sstevel@tonic-gate #include <sys/machsystm.h> 44*7c478bd9Sstevel@tonic-gate #include <sys/poll.h> 45*7c478bd9Sstevel@tonic-gate #include <sys/pbio.h> 46*7c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h> 47*7c478bd9Sstevel@tonic-gate #include <sys/cyclic.h> 48*7c478bd9Sstevel@tonic-gate 49*7c478bd9Sstevel@tonic-gate /* Added for prom interface */ 50*7c478bd9Sstevel@tonic-gate #include <sys/promif.h> 51*7c478bd9Sstevel@tonic-gate #include <sys/promimpl.h> 52*7c478bd9Sstevel@tonic-gate 53*7c478bd9Sstevel@tonic-gate #include <sys/i2c/misc/i2c_svc.h> 54*7c478bd9Sstevel@tonic-gate #include <sys/todds1337.h> 55*7c478bd9Sstevel@tonic-gate 56*7c478bd9Sstevel@tonic-gate #define DS1337_DEVICE_TYPE "rtc" 57*7c478bd9Sstevel@tonic-gate 58*7c478bd9Sstevel@tonic-gate /* 59*7c478bd9Sstevel@tonic-gate * Driver entry routines 60*7c478bd9Sstevel@tonic-gate */ 61*7c478bd9Sstevel@tonic-gate static int todds1337_attach(dev_info_t *, ddi_attach_cmd_t); 62*7c478bd9Sstevel@tonic-gate static int todds1337_detach(dev_info_t *, ddi_detach_cmd_t); 63*7c478bd9Sstevel@tonic-gate static int todds1337_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **); 64*7c478bd9Sstevel@tonic-gate 65*7c478bd9Sstevel@tonic-gate /* 66*7c478bd9Sstevel@tonic-gate * tod_ops entry routines 67*7c478bd9Sstevel@tonic-gate */ 68*7c478bd9Sstevel@tonic-gate static timestruc_t todds1337_get(void); 69*7c478bd9Sstevel@tonic-gate static void todds1337_set(timestruc_t); 70*7c478bd9Sstevel@tonic-gate static uint_t todds1337_set_watchdog_timer(uint_t); 71*7c478bd9Sstevel@tonic-gate static uint_t todds1337_clear_watchdog_timer(void); 72*7c478bd9Sstevel@tonic-gate static void todds1337_set_power_alarm(timestruc_t); 73*7c478bd9Sstevel@tonic-gate static void todds1337_clear_power_alarm(void); 74*7c478bd9Sstevel@tonic-gate static int todds1337_setup_prom(); 75*7c478bd9Sstevel@tonic-gate static void todds1337_rele_prom(); 76*7c478bd9Sstevel@tonic-gate static int todds1337_prom_getdate(struct rtc_t *rtc); 77*7c478bd9Sstevel@tonic-gate static int todds1337_prom_setdate(struct rtc_t *rtc); 78*7c478bd9Sstevel@tonic-gate 79*7c478bd9Sstevel@tonic-gate /* 80*7c478bd9Sstevel@tonic-gate * Local functions 81*7c478bd9Sstevel@tonic-gate */ 82*7c478bd9Sstevel@tonic-gate static int todds1337_read_rtc(struct rtc_t *); 83*7c478bd9Sstevel@tonic-gate static int todds1337_write_rtc(struct rtc_t *); 84*7c478bd9Sstevel@tonic-gate 85*7c478bd9Sstevel@tonic-gate /* Anchor for soft state structure */ 86*7c478bd9Sstevel@tonic-gate static void *ds1337_statep; 87*7c478bd9Sstevel@tonic-gate static int instance = -1; 88*7c478bd9Sstevel@tonic-gate static int todds1337_attach_done = 0; 89*7c478bd9Sstevel@tonic-gate static kmutex_t todds1337_rd_lock; 90*7c478bd9Sstevel@tonic-gate static kmutex_t todds1337_alarm_lock; 91*7c478bd9Sstevel@tonic-gate static ihandle_t todds1337_ihandle = 0; 92*7c478bd9Sstevel@tonic-gate 93*7c478bd9Sstevel@tonic-gate /* one second time out */ 94*7c478bd9Sstevel@tonic-gate #define I2C_CYCLIC_TIMEOUT 1000000000 95*7c478bd9Sstevel@tonic-gate uint_t i2c_cyclic_timeout = I2C_CYCLIC_TIMEOUT; 96*7c478bd9Sstevel@tonic-gate static int sync_clock_once = 1; 97*7c478bd9Sstevel@tonic-gate static struct rtc_t soft_rtc; 98*7c478bd9Sstevel@tonic-gate 99*7c478bd9Sstevel@tonic-gate /* 100*7c478bd9Sstevel@tonic-gate * cp_ops structure 101*7c478bd9Sstevel@tonic-gate */ 102*7c478bd9Sstevel@tonic-gate static struct cb_ops ds1337_cbops = { 103*7c478bd9Sstevel@tonic-gate nodev, /* open */ 104*7c478bd9Sstevel@tonic-gate nodev, /* close */ 105*7c478bd9Sstevel@tonic-gate nodev, /* strategy */ 106*7c478bd9Sstevel@tonic-gate nodev, /* print */ 107*7c478bd9Sstevel@tonic-gate nodev, /* dump */ 108*7c478bd9Sstevel@tonic-gate nodev, /* read */ 109*7c478bd9Sstevel@tonic-gate nodev, /* write */ 110*7c478bd9Sstevel@tonic-gate nodev, /* ioctl */ 111*7c478bd9Sstevel@tonic-gate nodev, /* devmap */ 112*7c478bd9Sstevel@tonic-gate nodev, /* mmap */ 113*7c478bd9Sstevel@tonic-gate nodev, /* segmap */ 114*7c478bd9Sstevel@tonic-gate NULL, /* poll */ 115*7c478bd9Sstevel@tonic-gate ddi_prop_op, /* cb_prop_op */ 116*7c478bd9Sstevel@tonic-gate NULL, /* streamtab */ 117*7c478bd9Sstevel@tonic-gate D_NEW | D_MP, /* Driver compatibility flag */ 118*7c478bd9Sstevel@tonic-gate CB_REV, /* rev */ 119*7c478bd9Sstevel@tonic-gate nodev, /* int (*cb_aread)() */ 120*7c478bd9Sstevel@tonic-gate nodev /* int (*cb_awrite)() */ 121*7c478bd9Sstevel@tonic-gate }; 122*7c478bd9Sstevel@tonic-gate 123*7c478bd9Sstevel@tonic-gate /* 124*7c478bd9Sstevel@tonic-gate * dev_ops structure 125*7c478bd9Sstevel@tonic-gate */ 126*7c478bd9Sstevel@tonic-gate static struct dev_ops ds1337_ops = { 127*7c478bd9Sstevel@tonic-gate DEVO_REV, /* devo_rev */ 128*7c478bd9Sstevel@tonic-gate 0, /* refcnt - reference cnt always set to 0 */ 129*7c478bd9Sstevel@tonic-gate todds1337_getinfo, /* getinfo - Maybe requred */ 130*7c478bd9Sstevel@tonic-gate nulldev, /* identify */ 131*7c478bd9Sstevel@tonic-gate nulldev, /* probe */ 132*7c478bd9Sstevel@tonic-gate todds1337_attach, /* attach */ 133*7c478bd9Sstevel@tonic-gate todds1337_detach, /* detach */ 134*7c478bd9Sstevel@tonic-gate nodev, /* reset */ 135*7c478bd9Sstevel@tonic-gate &ds1337_cbops, /* cb_ops - ds1337 does not need this(?) */ 136*7c478bd9Sstevel@tonic-gate NULL 137*7c478bd9Sstevel@tonic-gate }; 138*7c478bd9Sstevel@tonic-gate 139*7c478bd9Sstevel@tonic-gate static struct modldrv todds1337_modldrv = { 140*7c478bd9Sstevel@tonic-gate &mod_driverops, /* Type of module. This one is a driver */ 141*7c478bd9Sstevel@tonic-gate "tod driver for DS1337 %I%", /* Name of the module. */ 142*7c478bd9Sstevel@tonic-gate &ds1337_ops, /* Pointer to dev_ops */ 143*7c478bd9Sstevel@tonic-gate }; 144*7c478bd9Sstevel@tonic-gate 145*7c478bd9Sstevel@tonic-gate /* 146*7c478bd9Sstevel@tonic-gate * Module linkage structure 147*7c478bd9Sstevel@tonic-gate */ 148*7c478bd9Sstevel@tonic-gate static struct modlinkage todds1337_modlinkage = { 149*7c478bd9Sstevel@tonic-gate MODREV_1, 150*7c478bd9Sstevel@tonic-gate &todds1337_modldrv, 151*7c478bd9Sstevel@tonic-gate 0 152*7c478bd9Sstevel@tonic-gate }; 153*7c478bd9Sstevel@tonic-gate 154*7c478bd9Sstevel@tonic-gate int 155*7c478bd9Sstevel@tonic-gate _init(void) 156*7c478bd9Sstevel@tonic-gate { 157*7c478bd9Sstevel@tonic-gate int error; 158*7c478bd9Sstevel@tonic-gate 159*7c478bd9Sstevel@tonic-gate if (strcmp(tod_module_name, "todds1337") == 0) { 160*7c478bd9Sstevel@tonic-gate if ((error = ddi_soft_state_init(&ds1337_statep, 161*7c478bd9Sstevel@tonic-gate sizeof (ds1337_state_t), 0)) != DDI_SUCCESS) { 162*7c478bd9Sstevel@tonic-gate return (error); 163*7c478bd9Sstevel@tonic-gate } 164*7c478bd9Sstevel@tonic-gate 165*7c478bd9Sstevel@tonic-gate tod_ops.tod_get = todds1337_get; 166*7c478bd9Sstevel@tonic-gate tod_ops.tod_set = todds1337_set; 167*7c478bd9Sstevel@tonic-gate tod_ops.tod_set_watchdog_timer = todds1337_set_watchdog_timer; 168*7c478bd9Sstevel@tonic-gate tod_ops.tod_clear_watchdog_timer = 169*7c478bd9Sstevel@tonic-gate todds1337_clear_watchdog_timer; 170*7c478bd9Sstevel@tonic-gate tod_ops.tod_set_power_alarm = todds1337_set_power_alarm; 171*7c478bd9Sstevel@tonic-gate tod_ops.tod_clear_power_alarm = todds1337_clear_power_alarm; 172*7c478bd9Sstevel@tonic-gate } 173*7c478bd9Sstevel@tonic-gate 174*7c478bd9Sstevel@tonic-gate (void) todds1337_setup_prom(); 175*7c478bd9Sstevel@tonic-gate 176*7c478bd9Sstevel@tonic-gate /* 177*7c478bd9Sstevel@tonic-gate * Install the module 178*7c478bd9Sstevel@tonic-gate */ 179*7c478bd9Sstevel@tonic-gate if ((error = mod_install(&todds1337_modlinkage)) != 0) { 180*7c478bd9Sstevel@tonic-gate ddi_soft_state_fini(&ds1337_statep); 181*7c478bd9Sstevel@tonic-gate return (error); 182*7c478bd9Sstevel@tonic-gate } 183*7c478bd9Sstevel@tonic-gate mutex_init(&todds1337_rd_lock, NULL, MUTEX_DEFAULT, NULL); 184*7c478bd9Sstevel@tonic-gate mutex_init(&todds1337_alarm_lock, NULL, MUTEX_DEFAULT, NULL); 185*7c478bd9Sstevel@tonic-gate 186*7c478bd9Sstevel@tonic-gate return (0); 187*7c478bd9Sstevel@tonic-gate } 188*7c478bd9Sstevel@tonic-gate 189*7c478bd9Sstevel@tonic-gate int 190*7c478bd9Sstevel@tonic-gate _fini(void) 191*7c478bd9Sstevel@tonic-gate { 192*7c478bd9Sstevel@tonic-gate int error = 0; 193*7c478bd9Sstevel@tonic-gate 194*7c478bd9Sstevel@tonic-gate if (strcmp(tod_module_name, "todds1337") == 0) { 195*7c478bd9Sstevel@tonic-gate error = EBUSY; 196*7c478bd9Sstevel@tonic-gate } else { 197*7c478bd9Sstevel@tonic-gate if ((error = mod_remove(&todds1337_modlinkage)) == 0) { 198*7c478bd9Sstevel@tonic-gate ddi_soft_state_fini(&ds1337_statep); 199*7c478bd9Sstevel@tonic-gate mutex_destroy(&todds1337_rd_lock); 200*7c478bd9Sstevel@tonic-gate mutex_destroy(&todds1337_alarm_lock); 201*7c478bd9Sstevel@tonic-gate todds1337_rele_prom(); 202*7c478bd9Sstevel@tonic-gate } 203*7c478bd9Sstevel@tonic-gate } 204*7c478bd9Sstevel@tonic-gate 205*7c478bd9Sstevel@tonic-gate return (error); 206*7c478bd9Sstevel@tonic-gate } 207*7c478bd9Sstevel@tonic-gate 208*7c478bd9Sstevel@tonic-gate int 209*7c478bd9Sstevel@tonic-gate _info(struct modinfo *modinfop) 210*7c478bd9Sstevel@tonic-gate { 211*7c478bd9Sstevel@tonic-gate return (mod_info(&todds1337_modlinkage, modinfop)); 212*7c478bd9Sstevel@tonic-gate } 213*7c478bd9Sstevel@tonic-gate 214*7c478bd9Sstevel@tonic-gate /* 215*7c478bd9Sstevel@tonic-gate * cyclical call to get tod. 216*7c478bd9Sstevel@tonic-gate */ 217*7c478bd9Sstevel@tonic-gate static void 218*7c478bd9Sstevel@tonic-gate todds1337_cyclic(void *arg) 219*7c478bd9Sstevel@tonic-gate { 220*7c478bd9Sstevel@tonic-gate 221*7c478bd9Sstevel@tonic-gate (void) todds1337_read_rtc((struct rtc_t *)arg); 222*7c478bd9Sstevel@tonic-gate 223*7c478bd9Sstevel@tonic-gate } 224*7c478bd9Sstevel@tonic-gate 225*7c478bd9Sstevel@tonic-gate /* 226*7c478bd9Sstevel@tonic-gate * register ds1337 client device with i2c services, and 227*7c478bd9Sstevel@tonic-gate * allocate & initialize soft state structure. 228*7c478bd9Sstevel@tonic-gate */ 229*7c478bd9Sstevel@tonic-gate static int 230*7c478bd9Sstevel@tonic-gate todds1337_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 231*7c478bd9Sstevel@tonic-gate { 232*7c478bd9Sstevel@tonic-gate static ds1337_state_t *statep = NULL; 233*7c478bd9Sstevel@tonic-gate i2c_transfer_t *i2c_tp = NULL; 234*7c478bd9Sstevel@tonic-gate uint8_t tempVal = (uint8_t)0; 235*7c478bd9Sstevel@tonic-gate cyc_handler_t cychand; 236*7c478bd9Sstevel@tonic-gate cyc_time_t cyctime; 237*7c478bd9Sstevel@tonic-gate 238*7c478bd9Sstevel@tonic-gate switch (cmd) { 239*7c478bd9Sstevel@tonic-gate case DDI_ATTACH: 240*7c478bd9Sstevel@tonic-gate break; 241*7c478bd9Sstevel@tonic-gate case DDI_RESUME: 242*7c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 243*7c478bd9Sstevel@tonic-gate default: 244*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 245*7c478bd9Sstevel@tonic-gate } 246*7c478bd9Sstevel@tonic-gate 247*7c478bd9Sstevel@tonic-gate if (instance != -1) { 248*7c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "todds1337_attach: wrong instance"); 249*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 250*7c478bd9Sstevel@tonic-gate } 251*7c478bd9Sstevel@tonic-gate 252*7c478bd9Sstevel@tonic-gate instance = ddi_get_instance(dip); 253*7c478bd9Sstevel@tonic-gate 254*7c478bd9Sstevel@tonic-gate /* 255*7c478bd9Sstevel@tonic-gate * Allocate soft state structure 256*7c478bd9Sstevel@tonic-gate */ 257*7c478bd9Sstevel@tonic-gate if (ddi_soft_state_zalloc(ds1337_statep, instance) != DDI_SUCCESS) { 258*7c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "todds1337_attach: cannot allocate soft " 259*7c478bd9Sstevel@tonic-gate "state"); 260*7c478bd9Sstevel@tonic-gate instance = -1; 261*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 262*7c478bd9Sstevel@tonic-gate } 263*7c478bd9Sstevel@tonic-gate 264*7c478bd9Sstevel@tonic-gate statep = ddi_get_soft_state(ds1337_statep, instance); 265*7c478bd9Sstevel@tonic-gate if (statep == NULL) { 266*7c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "todds1337_attach: cannot acquire soft " 267*7c478bd9Sstevel@tonic-gate "state"); 268*7c478bd9Sstevel@tonic-gate instance = -1; 269*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 270*7c478bd9Sstevel@tonic-gate } 271*7c478bd9Sstevel@tonic-gate 272*7c478bd9Sstevel@tonic-gate statep->dip = dip; 273*7c478bd9Sstevel@tonic-gate 274*7c478bd9Sstevel@tonic-gate if (i2c_client_register(dip, &statep->ds1337_i2c_hdl) != I2C_SUCCESS) { 275*7c478bd9Sstevel@tonic-gate ddi_soft_state_free(ds1337_statep, instance); 276*7c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "todds1337_attach: cannot register i2c " 277*7c478bd9Sstevel@tonic-gate "client"); 278*7c478bd9Sstevel@tonic-gate instance = -1; 279*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 280*7c478bd9Sstevel@tonic-gate } 281*7c478bd9Sstevel@tonic-gate 282*7c478bd9Sstevel@tonic-gate /* check and initialize the oscillator */ 283*7c478bd9Sstevel@tonic-gate 284*7c478bd9Sstevel@tonic-gate (void) i2c_transfer_alloc(statep->ds1337_i2c_hdl, 285*7c478bd9Sstevel@tonic-gate &i2c_tp, 1, 1, I2C_SLEEP); 286*7c478bd9Sstevel@tonic-gate i2c_tp->i2c_version = I2C_XFER_REV; 287*7c478bd9Sstevel@tonic-gate i2c_tp->i2c_flags = I2C_WR_RD; 288*7c478bd9Sstevel@tonic-gate i2c_tp->i2c_wbuf[0] = (uchar_t)RTC_STATUS; /* Read Status register */ 289*7c478bd9Sstevel@tonic-gate i2c_tp->i2c_wlen = 1; 290*7c478bd9Sstevel@tonic-gate i2c_tp->i2c_rlen = 1; 291*7c478bd9Sstevel@tonic-gate 292*7c478bd9Sstevel@tonic-gate if ((i2c_transfer(statep->ds1337_i2c_hdl, i2c_tp)) != I2C_SUCCESS) { 293*7c478bd9Sstevel@tonic-gate (void) i2c_transfer_free(statep->ds1337_i2c_hdl, i2c_tp); 294*7c478bd9Sstevel@tonic-gate i2c_client_unregister(statep->ds1337_i2c_hdl); 295*7c478bd9Sstevel@tonic-gate ddi_soft_state_free(ds1337_statep, instance); 296*7c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "todds1337_attach: failed to read DS1337 " 297*7c478bd9Sstevel@tonic-gate "status register"); 298*7c478bd9Sstevel@tonic-gate instance = -1; 299*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 300*7c478bd9Sstevel@tonic-gate } 301*7c478bd9Sstevel@tonic-gate 302*7c478bd9Sstevel@tonic-gate tempVal = i2c_tp->i2c_rbuf[0]; 303*7c478bd9Sstevel@tonic-gate 304*7c478bd9Sstevel@tonic-gate (void) i2c_transfer_free(statep->ds1337_i2c_hdl, i2c_tp); 305*7c478bd9Sstevel@tonic-gate 306*7c478bd9Sstevel@tonic-gate /* 307*7c478bd9Sstevel@tonic-gate * Check Oscillator and initialize chip if OBP failed to do it 308*7c478bd9Sstevel@tonic-gate */ 309*7c478bd9Sstevel@tonic-gate 310*7c478bd9Sstevel@tonic-gate if (tempVal & RTC_CTL_EOSC) { 311*7c478bd9Sstevel@tonic-gate (void) i2c_transfer_alloc(statep->ds1337_i2c_hdl, &i2c_tp, 312*7c478bd9Sstevel@tonic-gate 2, 0, I2C_SLEEP); 313*7c478bd9Sstevel@tonic-gate i2c_tp->i2c_version = I2C_XFER_REV; 314*7c478bd9Sstevel@tonic-gate i2c_tp->i2c_flags = I2C_WR; 315*7c478bd9Sstevel@tonic-gate i2c_tp->i2c_wbuf[0] = RTC_CTL; /* Write Control register */ 316*7c478bd9Sstevel@tonic-gate i2c_tp->i2c_wbuf[1] = (uchar_t)(RTC_CTL_RS2 | RTC_CTL_RS1 | 317*7c478bd9Sstevel@tonic-gate RTC_CTL_INTCN); 318*7c478bd9Sstevel@tonic-gate if ((i2c_transfer(statep->ds1337_i2c_hdl, i2c_tp)) 319*7c478bd9Sstevel@tonic-gate != I2C_SUCCESS) { 320*7c478bd9Sstevel@tonic-gate (void) i2c_transfer_free(statep->ds1337_i2c_hdl, 321*7c478bd9Sstevel@tonic-gate i2c_tp); 322*7c478bd9Sstevel@tonic-gate i2c_client_unregister(statep->ds1337_i2c_hdl); 323*7c478bd9Sstevel@tonic-gate ddi_soft_state_free(ds1337_statep, instance); 324*7c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "todds1337_attach: failed to write " 325*7c478bd9Sstevel@tonic-gate "DS1337 control register"); 326*7c478bd9Sstevel@tonic-gate instance = -1; 327*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 328*7c478bd9Sstevel@tonic-gate } 329*7c478bd9Sstevel@tonic-gate 330*7c478bd9Sstevel@tonic-gate (void) i2c_transfer_free(statep->ds1337_i2c_hdl, i2c_tp); 331*7c478bd9Sstevel@tonic-gate 332*7c478bd9Sstevel@tonic-gate /* 333*7c478bd9Sstevel@tonic-gate * Now reset the OSF flag in the Status register 334*7c478bd9Sstevel@tonic-gate */ 335*7c478bd9Sstevel@tonic-gate (void) i2c_transfer_alloc(statep->ds1337_i2c_hdl, &i2c_tp, 336*7c478bd9Sstevel@tonic-gate 2, 0, I2C_SLEEP); 337*7c478bd9Sstevel@tonic-gate i2c_tp->i2c_version = I2C_XFER_REV; 338*7c478bd9Sstevel@tonic-gate i2c_tp->i2c_flags = I2C_WR; 339*7c478bd9Sstevel@tonic-gate i2c_tp->i2c_wbuf[0] = RTC_STATUS; 340*7c478bd9Sstevel@tonic-gate i2c_tp->i2c_wbuf[1] = (uchar_t)0; 341*7c478bd9Sstevel@tonic-gate if ((i2c_transfer(statep->ds1337_i2c_hdl, i2c_tp)) 342*7c478bd9Sstevel@tonic-gate != I2C_SUCCESS) { 343*7c478bd9Sstevel@tonic-gate (void) i2c_transfer_free(statep->ds1337_i2c_hdl, 344*7c478bd9Sstevel@tonic-gate i2c_tp); 345*7c478bd9Sstevel@tonic-gate i2c_client_unregister(statep->ds1337_i2c_hdl); 346*7c478bd9Sstevel@tonic-gate ddi_soft_state_free(ds1337_statep, instance); 347*7c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "todds1337_attach: failed to write " 348*7c478bd9Sstevel@tonic-gate "DS1337 status register"); 349*7c478bd9Sstevel@tonic-gate instance = -1; 350*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 351*7c478bd9Sstevel@tonic-gate } 352*7c478bd9Sstevel@tonic-gate 353*7c478bd9Sstevel@tonic-gate (void) i2c_transfer_free(statep->ds1337_i2c_hdl, i2c_tp); 354*7c478bd9Sstevel@tonic-gate } 355*7c478bd9Sstevel@tonic-gate 356*7c478bd9Sstevel@tonic-gate /* Create a cyclic handler to read TOD */ 357*7c478bd9Sstevel@tonic-gate cychand.cyh_func = todds1337_cyclic; 358*7c478bd9Sstevel@tonic-gate cychand.cyh_arg = &soft_rtc; 359*7c478bd9Sstevel@tonic-gate cychand.cyh_level = CY_LOW_LEVEL; 360*7c478bd9Sstevel@tonic-gate cyctime.cyt_when = 0; 361*7c478bd9Sstevel@tonic-gate cyctime.cyt_interval = i2c_cyclic_timeout; 362*7c478bd9Sstevel@tonic-gate ASSERT(statep->cycid == CYCLIC_NONE); 363*7c478bd9Sstevel@tonic-gate mutex_enter(&cpu_lock); 364*7c478bd9Sstevel@tonic-gate statep->cycid = cyclic_add(&cychand, &cyctime); 365*7c478bd9Sstevel@tonic-gate mutex_exit(&cpu_lock); 366*7c478bd9Sstevel@tonic-gate ASSERT(statep->cycid != CYCLIC_NONE); 367*7c478bd9Sstevel@tonic-gate 368*7c478bd9Sstevel@tonic-gate statep->state = TOD_ATTACHED; 369*7c478bd9Sstevel@tonic-gate todds1337_attach_done = 1; 370*7c478bd9Sstevel@tonic-gate ddi_report_dev(dip); 371*7c478bd9Sstevel@tonic-gate 372*7c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 373*7c478bd9Sstevel@tonic-gate } 374*7c478bd9Sstevel@tonic-gate 375*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 376*7c478bd9Sstevel@tonic-gate static int 377*7c478bd9Sstevel@tonic-gate todds1337_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 378*7c478bd9Sstevel@tonic-gate { 379*7c478bd9Sstevel@tonic-gate /* 380*7c478bd9Sstevel@tonic-gate * Once attached, do not allow detach because the system constantly 381*7c478bd9Sstevel@tonic-gate * calling todds1337_get() to get the time. If the driver is detached 382*7c478bd9Sstevel@tonic-gate * and the system try to get the time, the system will have memory 383*7c478bd9Sstevel@tonic-gate * problem. 384*7c478bd9Sstevel@tonic-gate * 385*7c478bd9Sstevel@tonic-gate */ 386*7c478bd9Sstevel@tonic-gate switch (cmd) { 387*7c478bd9Sstevel@tonic-gate case DDI_SUSPEND: 388*7c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 389*7c478bd9Sstevel@tonic-gate default: 390*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 391*7c478bd9Sstevel@tonic-gate } 392*7c478bd9Sstevel@tonic-gate } 393*7c478bd9Sstevel@tonic-gate 394*7c478bd9Sstevel@tonic-gate /* *********************** tod_ops entry points ******************** */ 395*7c478bd9Sstevel@tonic-gate 396*7c478bd9Sstevel@tonic-gate /* 397*7c478bd9Sstevel@tonic-gate * Read the current time from the DS1337 chip and convert to UNIX form. 398*7c478bd9Sstevel@tonic-gate * Should be called with tod_clock held. 399*7c478bd9Sstevel@tonic-gate */ 400*7c478bd9Sstevel@tonic-gate 401*7c478bd9Sstevel@tonic-gate static timestruc_t 402*7c478bd9Sstevel@tonic-gate todds1337_get(void) 403*7c478bd9Sstevel@tonic-gate { 404*7c478bd9Sstevel@tonic-gate timestruc_t ts; 405*7c478bd9Sstevel@tonic-gate todinfo_t tod; 406*7c478bd9Sstevel@tonic-gate struct rtc_t rtc; 407*7c478bd9Sstevel@tonic-gate 408*7c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&tod_lock)); 409*7c478bd9Sstevel@tonic-gate 410*7c478bd9Sstevel@tonic-gate if (sync_clock_once) { 411*7c478bd9Sstevel@tonic-gate (void) todds1337_read_rtc(&soft_rtc); 412*7c478bd9Sstevel@tonic-gate sync_clock_once = 0; 413*7c478bd9Sstevel@tonic-gate } else { 414*7c478bd9Sstevel@tonic-gate tod_fault_reset(); 415*7c478bd9Sstevel@tonic-gate return (hrestime); 416*7c478bd9Sstevel@tonic-gate } 417*7c478bd9Sstevel@tonic-gate 418*7c478bd9Sstevel@tonic-gate bcopy(&soft_rtc, &rtc, sizeof (rtc)); 419*7c478bd9Sstevel@tonic-gate 420*7c478bd9Sstevel@tonic-gate /* 421*7c478bd9Sstevel@tonic-gate * 00 - 68 = 2000 thru 2068 422*7c478bd9Sstevel@tonic-gate * 69-99 = 1969 thru 1999 423*7c478bd9Sstevel@tonic-gate */ 424*7c478bd9Sstevel@tonic-gate tod.tod_year = rtc.rtc_year; 425*7c478bd9Sstevel@tonic-gate if (rtc.rtc_year <= 68) 426*7c478bd9Sstevel@tonic-gate tod.tod_year += 100; 427*7c478bd9Sstevel@tonic-gate tod.tod_month = rtc.rtc_mon; 428*7c478bd9Sstevel@tonic-gate tod.tod_day = rtc.rtc_dom; 429*7c478bd9Sstevel@tonic-gate tod.tod_dow = rtc.rtc_dow; 430*7c478bd9Sstevel@tonic-gate tod.tod_hour = rtc.rtc_hrs; 431*7c478bd9Sstevel@tonic-gate tod.tod_min = rtc.rtc_min; 432*7c478bd9Sstevel@tonic-gate tod.tod_sec = rtc.rtc_sec; 433*7c478bd9Sstevel@tonic-gate 434*7c478bd9Sstevel@tonic-gate ts.tv_sec = tod_to_utc(tod); 435*7c478bd9Sstevel@tonic-gate ts.tv_nsec = 0; 436*7c478bd9Sstevel@tonic-gate return (ts); 437*7c478bd9Sstevel@tonic-gate } 438*7c478bd9Sstevel@tonic-gate 439*7c478bd9Sstevel@tonic-gate /* 440*7c478bd9Sstevel@tonic-gate * Program DS1337 with the specified time. 441*7c478bd9Sstevel@tonic-gate * Must be called with tod_lock held. The TOD 442*7c478bd9Sstevel@tonic-gate * chip supports date from 1969-2068 only. We must 443*7c478bd9Sstevel@tonic-gate * reject requests to set date below 1969. 444*7c478bd9Sstevel@tonic-gate */ 445*7c478bd9Sstevel@tonic-gate static void 446*7c478bd9Sstevel@tonic-gate todds1337_set(timestruc_t ts) 447*7c478bd9Sstevel@tonic-gate { 448*7c478bd9Sstevel@tonic-gate struct rtc_t rtc; 449*7c478bd9Sstevel@tonic-gate todinfo_t tod = utc_to_tod(ts.tv_sec); 450*7c478bd9Sstevel@tonic-gate int year; 451*7c478bd9Sstevel@tonic-gate 452*7c478bd9Sstevel@tonic-gate 453*7c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&tod_lock)); 454*7c478bd9Sstevel@tonic-gate 455*7c478bd9Sstevel@tonic-gate /* 456*7c478bd9Sstevel@tonic-gate * Year is base 1900, valid year range 1969-2068 457*7c478bd9Sstevel@tonic-gate */ 458*7c478bd9Sstevel@tonic-gate if ((tod.tod_year < 69) || (tod.tod_year > 168)) 459*7c478bd9Sstevel@tonic-gate return; 460*7c478bd9Sstevel@tonic-gate 461*7c478bd9Sstevel@tonic-gate year = tod.tod_year; 462*7c478bd9Sstevel@tonic-gate if (year >= 100) 463*7c478bd9Sstevel@tonic-gate year -= 100; 464*7c478bd9Sstevel@tonic-gate 465*7c478bd9Sstevel@tonic-gate rtc.rtc_year = (uint8_t)year; 466*7c478bd9Sstevel@tonic-gate rtc.rtc_mon = (uint8_t)tod.tod_month; 467*7c478bd9Sstevel@tonic-gate rtc.rtc_dom = (uint8_t)tod.tod_day; 468*7c478bd9Sstevel@tonic-gate rtc.rtc_dow = (uint8_t)tod.tod_dow; 469*7c478bd9Sstevel@tonic-gate rtc.rtc_hrs = (uint8_t)tod.tod_hour; 470*7c478bd9Sstevel@tonic-gate rtc.rtc_min = (uint8_t)tod.tod_min; 471*7c478bd9Sstevel@tonic-gate rtc.rtc_sec = (uint8_t)tod.tod_sec; 472*7c478bd9Sstevel@tonic-gate 473*7c478bd9Sstevel@tonic-gate (void) todds1337_write_rtc(&rtc); 474*7c478bd9Sstevel@tonic-gate } 475*7c478bd9Sstevel@tonic-gate 476*7c478bd9Sstevel@tonic-gate /* 477*7c478bd9Sstevel@tonic-gate * Program ds1337 registers for alarm to go off at the specified time. 478*7c478bd9Sstevel@tonic-gate * Alarm #1 is used (Alarm #2 stays idle) 479*7c478bd9Sstevel@tonic-gate */ 480*7c478bd9Sstevel@tonic-gate /* ARGSUSED */ 481*7c478bd9Sstevel@tonic-gate static void 482*7c478bd9Sstevel@tonic-gate todds1337_set_power_alarm(timestruc_t ts) 483*7c478bd9Sstevel@tonic-gate { 484*7c478bd9Sstevel@tonic-gate todinfo_t tod; 485*7c478bd9Sstevel@tonic-gate ds1337_state_t *statep = NULL; 486*7c478bd9Sstevel@tonic-gate i2c_transfer_t *i2c_tp = NULL; 487*7c478bd9Sstevel@tonic-gate uint8_t tmpval; 488*7c478bd9Sstevel@tonic-gate 489*7c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&tod_lock)); 490*7c478bd9Sstevel@tonic-gate 491*7c478bd9Sstevel@tonic-gate if (!todds1337_attach_done) { 492*7c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "todds1337: driver not attached"); 493*7c478bd9Sstevel@tonic-gate return; 494*7c478bd9Sstevel@tonic-gate } 495*7c478bd9Sstevel@tonic-gate 496*7c478bd9Sstevel@tonic-gate statep = ddi_get_soft_state(ds1337_statep, instance); 497*7c478bd9Sstevel@tonic-gate if (statep == NULL) { 498*7c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "todds1337: ddi_get_soft_state failed"); 499*7c478bd9Sstevel@tonic-gate return; 500*7c478bd9Sstevel@tonic-gate } 501*7c478bd9Sstevel@tonic-gate 502*7c478bd9Sstevel@tonic-gate tod = utc_to_tod(ts.tv_sec); 503*7c478bd9Sstevel@tonic-gate 504*7c478bd9Sstevel@tonic-gate /* 505*7c478bd9Sstevel@tonic-gate * i2c_transfe() may block; to avoid locking clock() which 506*7c478bd9Sstevel@tonic-gate * is running in interrupt context at PIL10 we temporarely exit 507*7c478bd9Sstevel@tonic-gate * the tod_mutex and enter alarm lock. Time/date and alarm hardware 508*7c478bd9Sstevel@tonic-gate * have non-interlsecting registers, it is safe to use different locks. 509*7c478bd9Sstevel@tonic-gate */ 510*7c478bd9Sstevel@tonic-gate mutex_exit(&tod_lock); 511*7c478bd9Sstevel@tonic-gate mutex_enter(&todds1337_alarm_lock); 512*7c478bd9Sstevel@tonic-gate 513*7c478bd9Sstevel@tonic-gate /* 514*7c478bd9Sstevel@tonic-gate * Disable Power Alarm (A1IE) 515*7c478bd9Sstevel@tonic-gate */ 516*7c478bd9Sstevel@tonic-gate (void) i2c_transfer_alloc(statep->ds1337_i2c_hdl, 517*7c478bd9Sstevel@tonic-gate &i2c_tp, 1, 1, I2C_SLEEP); 518*7c478bd9Sstevel@tonic-gate i2c_tp->i2c_version = I2C_XFER_REV; 519*7c478bd9Sstevel@tonic-gate i2c_tp->i2c_flags = I2C_WR_RD; 520*7c478bd9Sstevel@tonic-gate i2c_tp->i2c_wbuf[0] = (uchar_t)RTC_CTL; /* Read Control register */ 521*7c478bd9Sstevel@tonic-gate 522*7c478bd9Sstevel@tonic-gate if ((i2c_transfer(statep->ds1337_i2c_hdl, i2c_tp)) != I2C_SUCCESS) { 523*7c478bd9Sstevel@tonic-gate (void) i2c_transfer_free(statep->ds1337_i2c_hdl, i2c_tp); 524*7c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "todds1337_set_power_alarm: failed to read " 525*7c478bd9Sstevel@tonic-gate "DS1337 control register"); 526*7c478bd9Sstevel@tonic-gate mutex_exit(&todds1337_alarm_lock); 527*7c478bd9Sstevel@tonic-gate mutex_enter(&tod_lock); 528*7c478bd9Sstevel@tonic-gate return; 529*7c478bd9Sstevel@tonic-gate } 530*7c478bd9Sstevel@tonic-gate 531*7c478bd9Sstevel@tonic-gate tmpval = i2c_tp->i2c_rbuf[0]; 532*7c478bd9Sstevel@tonic-gate 533*7c478bd9Sstevel@tonic-gate (void) i2c_transfer_free(statep->ds1337_i2c_hdl, i2c_tp); 534*7c478bd9Sstevel@tonic-gate 535*7c478bd9Sstevel@tonic-gate (void) i2c_transfer_alloc(statep->ds1337_i2c_hdl, 536*7c478bd9Sstevel@tonic-gate &i2c_tp, 2, 0, I2C_SLEEP); 537*7c478bd9Sstevel@tonic-gate i2c_tp->i2c_version = I2C_XFER_REV; 538*7c478bd9Sstevel@tonic-gate i2c_tp->i2c_flags = I2C_WR; 539*7c478bd9Sstevel@tonic-gate i2c_tp->i2c_wbuf[0] = (uchar_t)RTC_CTL; /* Write Control register */ 540*7c478bd9Sstevel@tonic-gate i2c_tp->i2c_wbuf[1] = tmpval & ~RTC_CTL_A1IE; 541*7c478bd9Sstevel@tonic-gate 542*7c478bd9Sstevel@tonic-gate if ((i2c_transfer(statep->ds1337_i2c_hdl, i2c_tp)) != I2C_SUCCESS) { 543*7c478bd9Sstevel@tonic-gate (void) i2c_transfer_free(statep->ds1337_i2c_hdl, i2c_tp); 544*7c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "todds1337_set_power_alarm: failed to write " 545*7c478bd9Sstevel@tonic-gate "DS1337control register"); 546*7c478bd9Sstevel@tonic-gate mutex_exit(&todds1337_alarm_lock); 547*7c478bd9Sstevel@tonic-gate mutex_enter(&tod_lock); 548*7c478bd9Sstevel@tonic-gate return; 549*7c478bd9Sstevel@tonic-gate } 550*7c478bd9Sstevel@tonic-gate 551*7c478bd9Sstevel@tonic-gate (void) i2c_transfer_free(statep->ds1337_i2c_hdl, i2c_tp); 552*7c478bd9Sstevel@tonic-gate 553*7c478bd9Sstevel@tonic-gate 554*7c478bd9Sstevel@tonic-gate /* 555*7c478bd9Sstevel@tonic-gate * Write Alarm #1 registers 556*7c478bd9Sstevel@tonic-gate */ 557*7c478bd9Sstevel@tonic-gate 558*7c478bd9Sstevel@tonic-gate (void) i2c_transfer_alloc(statep->ds1337_i2c_hdl, 559*7c478bd9Sstevel@tonic-gate &i2c_tp, 5, 0, I2C_SLEEP); 560*7c478bd9Sstevel@tonic-gate i2c_tp->i2c_version = I2C_XFER_REV; 561*7c478bd9Sstevel@tonic-gate i2c_tp->i2c_flags = I2C_WR; 562*7c478bd9Sstevel@tonic-gate i2c_tp->i2c_wbuf[0] = (uchar_t)RTC_ALARM_SEC; /* Alarm #1 Seconds */ 563*7c478bd9Sstevel@tonic-gate i2c_tp->i2c_wbuf[1] = BYTE_TO_BCD(tod.tod_sec); 564*7c478bd9Sstevel@tonic-gate i2c_tp->i2c_wbuf[2] = BYTE_TO_BCD(tod.tod_min); 565*7c478bd9Sstevel@tonic-gate i2c_tp->i2c_wbuf[3] = BYTE_TO_BCD(tod.tod_hour); 566*7c478bd9Sstevel@tonic-gate i2c_tp->i2c_wbuf[4] = BYTE_TO_BCD(tod.tod_day); 567*7c478bd9Sstevel@tonic-gate 568*7c478bd9Sstevel@tonic-gate if ((i2c_transfer(statep->ds1337_i2c_hdl, i2c_tp)) != I2C_SUCCESS) { 569*7c478bd9Sstevel@tonic-gate (void) i2c_transfer_free(statep->ds1337_i2c_hdl, i2c_tp); 570*7c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "todds1337_set_power_alarm: failed to write " 571*7c478bd9Sstevel@tonic-gate "DS1337 alarm registers"); 572*7c478bd9Sstevel@tonic-gate mutex_exit(&todds1337_alarm_lock); 573*7c478bd9Sstevel@tonic-gate mutex_enter(&tod_lock); 574*7c478bd9Sstevel@tonic-gate return; 575*7c478bd9Sstevel@tonic-gate } 576*7c478bd9Sstevel@tonic-gate 577*7c478bd9Sstevel@tonic-gate (void) i2c_transfer_free(statep->ds1337_i2c_hdl, i2c_tp); 578*7c478bd9Sstevel@tonic-gate 579*7c478bd9Sstevel@tonic-gate 580*7c478bd9Sstevel@tonic-gate /* 581*7c478bd9Sstevel@tonic-gate * Enable Power Alarm 582*7c478bd9Sstevel@tonic-gate */ 583*7c478bd9Sstevel@tonic-gate (void) i2c_transfer_alloc(statep->ds1337_i2c_hdl, 584*7c478bd9Sstevel@tonic-gate &i2c_tp, 2, 0, I2C_SLEEP); 585*7c478bd9Sstevel@tonic-gate i2c_tp->i2c_version = I2C_XFER_REV; 586*7c478bd9Sstevel@tonic-gate i2c_tp->i2c_flags = I2C_WR; 587*7c478bd9Sstevel@tonic-gate i2c_tp->i2c_wbuf[0] = (uchar_t)RTC_CTL; /* Write Control register */ 588*7c478bd9Sstevel@tonic-gate i2c_tp->i2c_wbuf[1] = tmpval | RTC_CTL_A1IE; 589*7c478bd9Sstevel@tonic-gate 590*7c478bd9Sstevel@tonic-gate if ((i2c_transfer(statep->ds1337_i2c_hdl, i2c_tp)) != I2C_SUCCESS) { 591*7c478bd9Sstevel@tonic-gate (void) i2c_transfer_free(statep->ds1337_i2c_hdl, i2c_tp); 592*7c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "todds1337_set_power_alarm: failed to enable " 593*7c478bd9Sstevel@tonic-gate "DS1337 alarm"); 594*7c478bd9Sstevel@tonic-gate mutex_exit(&todds1337_alarm_lock); 595*7c478bd9Sstevel@tonic-gate mutex_enter(&tod_lock); 596*7c478bd9Sstevel@tonic-gate return; 597*7c478bd9Sstevel@tonic-gate } 598*7c478bd9Sstevel@tonic-gate 599*7c478bd9Sstevel@tonic-gate (void) i2c_transfer_free(statep->ds1337_i2c_hdl, i2c_tp); 600*7c478bd9Sstevel@tonic-gate 601*7c478bd9Sstevel@tonic-gate mutex_exit(&todds1337_alarm_lock); 602*7c478bd9Sstevel@tonic-gate mutex_enter(&tod_lock); 603*7c478bd9Sstevel@tonic-gate } 604*7c478bd9Sstevel@tonic-gate 605*7c478bd9Sstevel@tonic-gate /* ARGSUSED */ 606*7c478bd9Sstevel@tonic-gate static void 607*7c478bd9Sstevel@tonic-gate todds1337_clear_power_alarm(void) 608*7c478bd9Sstevel@tonic-gate { 609*7c478bd9Sstevel@tonic-gate ds1337_state_t *statep = NULL; 610*7c478bd9Sstevel@tonic-gate i2c_transfer_t *i2c_tp = NULL; 611*7c478bd9Sstevel@tonic-gate uint8_t tmpval; 612*7c478bd9Sstevel@tonic-gate 613*7c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&tod_lock)); 614*7c478bd9Sstevel@tonic-gate 615*7c478bd9Sstevel@tonic-gate if (!todds1337_attach_done) { 616*7c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "todds1337: driver was not attached"); 617*7c478bd9Sstevel@tonic-gate return; 618*7c478bd9Sstevel@tonic-gate } 619*7c478bd9Sstevel@tonic-gate 620*7c478bd9Sstevel@tonic-gate statep = ddi_get_soft_state(ds1337_statep, instance); 621*7c478bd9Sstevel@tonic-gate if (statep == NULL) { 622*7c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "todds1337: ddi_get_soft_state has failed"); 623*7c478bd9Sstevel@tonic-gate return; 624*7c478bd9Sstevel@tonic-gate } 625*7c478bd9Sstevel@tonic-gate 626*7c478bd9Sstevel@tonic-gate /* 627*7c478bd9Sstevel@tonic-gate * i2c_transfe() may block; to avoid locking clock() which 628*7c478bd9Sstevel@tonic-gate * is running in interrupt context at PIL10 we temporarely exit 629*7c478bd9Sstevel@tonic-gate * the tod_mutex and enter alarm lock. Time/date and alarm hardware 630*7c478bd9Sstevel@tonic-gate * have non-interlsecting registers, it is safe to use different locks. 631*7c478bd9Sstevel@tonic-gate */ 632*7c478bd9Sstevel@tonic-gate mutex_exit(&tod_lock); 633*7c478bd9Sstevel@tonic-gate mutex_enter(&todds1337_alarm_lock); 634*7c478bd9Sstevel@tonic-gate 635*7c478bd9Sstevel@tonic-gate /* 636*7c478bd9Sstevel@tonic-gate * Disable Alarm #1 Interrupt 637*7c478bd9Sstevel@tonic-gate */ 638*7c478bd9Sstevel@tonic-gate (void) i2c_transfer_alloc(statep->ds1337_i2c_hdl, 639*7c478bd9Sstevel@tonic-gate &i2c_tp, 1, 1, I2C_SLEEP); 640*7c478bd9Sstevel@tonic-gate i2c_tp->i2c_version = I2C_XFER_REV; 641*7c478bd9Sstevel@tonic-gate i2c_tp->i2c_flags = I2C_WR_RD; 642*7c478bd9Sstevel@tonic-gate i2c_tp->i2c_wbuf[0] = (uchar_t)RTC_CTL; /* Read Control register */ 643*7c478bd9Sstevel@tonic-gate 644*7c478bd9Sstevel@tonic-gate if ((i2c_transfer(statep->ds1337_i2c_hdl, i2c_tp)) != I2C_SUCCESS) { 645*7c478bd9Sstevel@tonic-gate (void) i2c_transfer_free(statep->ds1337_i2c_hdl, i2c_tp); 646*7c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "todds1337_clear_power_alarm: failed to read " 647*7c478bd9Sstevel@tonic-gate "DS1337 control register"); 648*7c478bd9Sstevel@tonic-gate mutex_exit(&todds1337_alarm_lock); 649*7c478bd9Sstevel@tonic-gate mutex_enter(&tod_lock); 650*7c478bd9Sstevel@tonic-gate return; 651*7c478bd9Sstevel@tonic-gate } 652*7c478bd9Sstevel@tonic-gate 653*7c478bd9Sstevel@tonic-gate tmpval = i2c_tp->i2c_rbuf[0]; 654*7c478bd9Sstevel@tonic-gate 655*7c478bd9Sstevel@tonic-gate (void) i2c_transfer_free(statep->ds1337_i2c_hdl, i2c_tp); 656*7c478bd9Sstevel@tonic-gate 657*7c478bd9Sstevel@tonic-gate (void) i2c_transfer_alloc(statep->ds1337_i2c_hdl, 658*7c478bd9Sstevel@tonic-gate &i2c_tp, 2, 0, I2C_SLEEP); 659*7c478bd9Sstevel@tonic-gate i2c_tp->i2c_version = I2C_XFER_REV; 660*7c478bd9Sstevel@tonic-gate i2c_tp->i2c_flags = I2C_WR; 661*7c478bd9Sstevel@tonic-gate i2c_tp->i2c_wbuf[0] = (uchar_t)RTC_CTL; /* Write Control register */ 662*7c478bd9Sstevel@tonic-gate i2c_tp->i2c_wbuf[1] = tmpval & ~RTC_CTL_A1IE; 663*7c478bd9Sstevel@tonic-gate 664*7c478bd9Sstevel@tonic-gate if ((i2c_transfer(statep->ds1337_i2c_hdl, i2c_tp)) != I2C_SUCCESS) { 665*7c478bd9Sstevel@tonic-gate (void) i2c_transfer_free(statep->ds1337_i2c_hdl, i2c_tp); 666*7c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "todds1337_clear_power_alarm: failed to write " 667*7c478bd9Sstevel@tonic-gate "DS1337 control register"); 668*7c478bd9Sstevel@tonic-gate mutex_exit(&todds1337_alarm_lock); 669*7c478bd9Sstevel@tonic-gate mutex_enter(&tod_lock); 670*7c478bd9Sstevel@tonic-gate return; 671*7c478bd9Sstevel@tonic-gate } 672*7c478bd9Sstevel@tonic-gate 673*7c478bd9Sstevel@tonic-gate (void) i2c_transfer_free(statep->ds1337_i2c_hdl, i2c_tp); 674*7c478bd9Sstevel@tonic-gate 675*7c478bd9Sstevel@tonic-gate /* 676*7c478bd9Sstevel@tonic-gate * Reset Alarm #1 Flag 677*7c478bd9Sstevel@tonic-gate */ 678*7c478bd9Sstevel@tonic-gate (void) i2c_transfer_alloc(statep->ds1337_i2c_hdl, 679*7c478bd9Sstevel@tonic-gate &i2c_tp, 1, 1, I2C_SLEEP); 680*7c478bd9Sstevel@tonic-gate i2c_tp->i2c_version = I2C_XFER_REV; 681*7c478bd9Sstevel@tonic-gate i2c_tp->i2c_flags = I2C_WR_RD; 682*7c478bd9Sstevel@tonic-gate i2c_tp->i2c_wbuf[0] = (uchar_t)RTC_STATUS; /* Read Status register */ 683*7c478bd9Sstevel@tonic-gate 684*7c478bd9Sstevel@tonic-gate if ((i2c_transfer(statep->ds1337_i2c_hdl, i2c_tp)) != I2C_SUCCESS) { 685*7c478bd9Sstevel@tonic-gate (void) i2c_transfer_free(statep->ds1337_i2c_hdl, i2c_tp); 686*7c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "todds1337_clear_power_alarm: failed to read " 687*7c478bd9Sstevel@tonic-gate "DS1337 status register"); 688*7c478bd9Sstevel@tonic-gate mutex_exit(&todds1337_alarm_lock); 689*7c478bd9Sstevel@tonic-gate mutex_enter(&tod_lock); 690*7c478bd9Sstevel@tonic-gate return; 691*7c478bd9Sstevel@tonic-gate } 692*7c478bd9Sstevel@tonic-gate 693*7c478bd9Sstevel@tonic-gate tmpval = i2c_tp->i2c_rbuf[0]; 694*7c478bd9Sstevel@tonic-gate 695*7c478bd9Sstevel@tonic-gate (void) i2c_transfer_free(statep->ds1337_i2c_hdl, i2c_tp); 696*7c478bd9Sstevel@tonic-gate 697*7c478bd9Sstevel@tonic-gate (void) i2c_transfer_alloc(statep->ds1337_i2c_hdl, 698*7c478bd9Sstevel@tonic-gate &i2c_tp, 2, 0, I2C_SLEEP); 699*7c478bd9Sstevel@tonic-gate i2c_tp->i2c_version = I2C_XFER_REV; 700*7c478bd9Sstevel@tonic-gate i2c_tp->i2c_flags = I2C_WR; 701*7c478bd9Sstevel@tonic-gate i2c_tp->i2c_wbuf[0] = (uchar_t)RTC_STATUS; /* Write Status register */ 702*7c478bd9Sstevel@tonic-gate i2c_tp->i2c_wbuf[1] = tmpval & ~RTC_STATUS_A1F; 703*7c478bd9Sstevel@tonic-gate 704*7c478bd9Sstevel@tonic-gate if ((i2c_transfer(statep->ds1337_i2c_hdl, i2c_tp)) != I2C_SUCCESS) { 705*7c478bd9Sstevel@tonic-gate (void) i2c_transfer_free(statep->ds1337_i2c_hdl, i2c_tp); 706*7c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "todds1337_clear_power_alarm: failed to write " 707*7c478bd9Sstevel@tonic-gate "DS1337 status register"); 708*7c478bd9Sstevel@tonic-gate mutex_exit(&todds1337_alarm_lock); 709*7c478bd9Sstevel@tonic-gate mutex_enter(&tod_lock); 710*7c478bd9Sstevel@tonic-gate return; 711*7c478bd9Sstevel@tonic-gate } 712*7c478bd9Sstevel@tonic-gate 713*7c478bd9Sstevel@tonic-gate (void) i2c_transfer_free(statep->ds1337_i2c_hdl, i2c_tp); 714*7c478bd9Sstevel@tonic-gate 715*7c478bd9Sstevel@tonic-gate mutex_exit(&todds1337_alarm_lock); 716*7c478bd9Sstevel@tonic-gate mutex_enter(&tod_lock); 717*7c478bd9Sstevel@tonic-gate } 718*7c478bd9Sstevel@tonic-gate 719*7c478bd9Sstevel@tonic-gate /* ARGSUSED */ 720*7c478bd9Sstevel@tonic-gate static uint_t 721*7c478bd9Sstevel@tonic-gate todds1337_set_watchdog_timer(uint_t timeoutval) 722*7c478bd9Sstevel@tonic-gate { 723*7c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&tod_lock)); 724*7c478bd9Sstevel@tonic-gate return (0); 725*7c478bd9Sstevel@tonic-gate } 726*7c478bd9Sstevel@tonic-gate 727*7c478bd9Sstevel@tonic-gate /* ARGSUSED */ 728*7c478bd9Sstevel@tonic-gate static uint_t 729*7c478bd9Sstevel@tonic-gate todds1337_clear_watchdog_timer(void) 730*7c478bd9Sstevel@tonic-gate { 731*7c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&tod_lock)); 732*7c478bd9Sstevel@tonic-gate return (0); 733*7c478bd9Sstevel@tonic-gate } 734*7c478bd9Sstevel@tonic-gate 735*7c478bd9Sstevel@tonic-gate /* ********************** Local functions ***************************** */ 736*7c478bd9Sstevel@tonic-gate 737*7c478bd9Sstevel@tonic-gate static char tod_read[7] = {-1, -1, -1, -1, -1, -1, -1}; 738*7c478bd9Sstevel@tonic-gate static int 739*7c478bd9Sstevel@tonic-gate todds1337_read_rtc(struct rtc_t *rtc) 740*7c478bd9Sstevel@tonic-gate { 741*7c478bd9Sstevel@tonic-gate static ds1337_state_t *statep = NULL; 742*7c478bd9Sstevel@tonic-gate i2c_transfer_t *i2c_tp = NULL; 743*7c478bd9Sstevel@tonic-gate int i2c_cmd_status = I2C_FAILURE; 744*7c478bd9Sstevel@tonic-gate int counter = 4; 745*7c478bd9Sstevel@tonic-gate 746*7c478bd9Sstevel@tonic-gate if (!todds1337_attach_done) { 747*7c478bd9Sstevel@tonic-gate return (todds1337_prom_getdate(rtc)); 748*7c478bd9Sstevel@tonic-gate } 749*7c478bd9Sstevel@tonic-gate 750*7c478bd9Sstevel@tonic-gate statep = ddi_get_soft_state(ds1337_statep, instance); 751*7c478bd9Sstevel@tonic-gate if (statep == NULL) { 752*7c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "todds1337: ddi_get_soft_state failing"); 753*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 754*7c478bd9Sstevel@tonic-gate } 755*7c478bd9Sstevel@tonic-gate 756*7c478bd9Sstevel@tonic-gate mutex_enter(&todds1337_rd_lock); 757*7c478bd9Sstevel@tonic-gate 758*7c478bd9Sstevel@tonic-gate /* 759*7c478bd9Sstevel@tonic-gate * Allocate 1 byte for write buffer and 7 bytes for read buffer to 760*7c478bd9Sstevel@tonic-gate * to accomodate sec, min, hrs, dayOfWeek, dayOfMonth, year 761*7c478bd9Sstevel@tonic-gate */ 762*7c478bd9Sstevel@tonic-gate if ((i2c_transfer_alloc(statep->ds1337_i2c_hdl, &i2c_tp, 1, 763*7c478bd9Sstevel@tonic-gate 7, I2C_SLEEP)) != I2C_SUCCESS) { 764*7c478bd9Sstevel@tonic-gate mutex_exit(&todds1337_rd_lock); 765*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 766*7c478bd9Sstevel@tonic-gate } 767*7c478bd9Sstevel@tonic-gate 768*7c478bd9Sstevel@tonic-gate do { 769*7c478bd9Sstevel@tonic-gate i2c_tp->i2c_version = I2C_XFER_REV; 770*7c478bd9Sstevel@tonic-gate i2c_tp->i2c_flags = I2C_WR_RD; 771*7c478bd9Sstevel@tonic-gate i2c_tp->i2c_wbuf[0] = (uchar_t)RTC_SEC; /* Start from 0x00 */ 772*7c478bd9Sstevel@tonic-gate i2c_tp->i2c_wlen = 1; /* Write one byte address */ 773*7c478bd9Sstevel@tonic-gate i2c_tp->i2c_rlen = 7; /* Read 7 regs */ 774*7c478bd9Sstevel@tonic-gate 775*7c478bd9Sstevel@tonic-gate if ((i2c_cmd_status = i2c_transfer(statep->ds1337_i2c_hdl, 776*7c478bd9Sstevel@tonic-gate i2c_tp)) != I2C_SUCCESS) { 777*7c478bd9Sstevel@tonic-gate goto done; 778*7c478bd9Sstevel@tonic-gate } 779*7c478bd9Sstevel@tonic-gate /* for first read, need to get valid data */ 780*7c478bd9Sstevel@tonic-gate while (tod_read[0] == -1 && counter > 0) { 781*7c478bd9Sstevel@tonic-gate /* move data to static buffer */ 782*7c478bd9Sstevel@tonic-gate bcopy(i2c_tp->i2c_rbuf, tod_read, 7); 783*7c478bd9Sstevel@tonic-gate 784*7c478bd9Sstevel@tonic-gate /* now read again */ 785*7c478bd9Sstevel@tonic-gate /* Start reading reg from 0x00 */ 786*7c478bd9Sstevel@tonic-gate i2c_tp->i2c_wbuf[0] = (uchar_t)0x00; 787*7c478bd9Sstevel@tonic-gate i2c_tp->i2c_wlen = 1; /* Write one byte address */ 788*7c478bd9Sstevel@tonic-gate i2c_tp->i2c_rlen = 7; /* Read 7 regs */ 789*7c478bd9Sstevel@tonic-gate if ((i2c_cmd_status = i2c_transfer(statep->ds1337_i2c_hdl, 790*7c478bd9Sstevel@tonic-gate i2c_tp)) != I2C_SUCCESS) { 791*7c478bd9Sstevel@tonic-gate goto done; 792*7c478bd9Sstevel@tonic-gate } 793*7c478bd9Sstevel@tonic-gate /* if they are not the same, then read again */ 794*7c478bd9Sstevel@tonic-gate if (bcmp(tod_read, i2c_tp->i2c_rbuf, 7) != 0) { 795*7c478bd9Sstevel@tonic-gate tod_read[0] = -1; 796*7c478bd9Sstevel@tonic-gate counter--; 797*7c478bd9Sstevel@tonic-gate } 798*7c478bd9Sstevel@tonic-gate } 799*7c478bd9Sstevel@tonic-gate 800*7c478bd9Sstevel@tonic-gate } while (i2c_tp->i2c_rbuf[0] == 0x59 && 801*7c478bd9Sstevel@tonic-gate /* if seconds register is 0x59 (BCD), add data should match */ 802*7c478bd9Sstevel@tonic-gate bcmp(&tod_read[1], &i2c_tp->i2c_rbuf[1], 6) != 0 && 803*7c478bd9Sstevel@tonic-gate counter-- > 0); 804*7c478bd9Sstevel@tonic-gate 805*7c478bd9Sstevel@tonic-gate if (counter < 0) 806*7c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "i2ctod: TOD Chip failed ??"); 807*7c478bd9Sstevel@tonic-gate 808*7c478bd9Sstevel@tonic-gate /* move data to static buffer */ 809*7c478bd9Sstevel@tonic-gate bcopy(i2c_tp->i2c_rbuf, tod_read, 7); 810*7c478bd9Sstevel@tonic-gate 811*7c478bd9Sstevel@tonic-gate 812*7c478bd9Sstevel@tonic-gate rtc->rtc_year = BCD_TO_BYTE(i2c_tp->i2c_rbuf[6]); 813*7c478bd9Sstevel@tonic-gate rtc->rtc_mon = BCD_TO_BYTE(i2c_tp->i2c_rbuf[5]); 814*7c478bd9Sstevel@tonic-gate rtc->rtc_dom = BCD_TO_BYTE(i2c_tp->i2c_rbuf[4]); 815*7c478bd9Sstevel@tonic-gate rtc->rtc_dow = BCD_TO_BYTE(i2c_tp->i2c_rbuf[3]); 816*7c478bd9Sstevel@tonic-gate rtc->rtc_hrs = BCD_TO_BYTE(i2c_tp->i2c_rbuf[2]); 817*7c478bd9Sstevel@tonic-gate rtc->rtc_min = BCD_TO_BYTE(i2c_tp->i2c_rbuf[1]); 818*7c478bd9Sstevel@tonic-gate rtc->rtc_sec = BCD_TO_BYTE(i2c_tp->i2c_rbuf[0]); 819*7c478bd9Sstevel@tonic-gate 820*7c478bd9Sstevel@tonic-gate done: 821*7c478bd9Sstevel@tonic-gate (void) i2c_transfer_free(statep->ds1337_i2c_hdl, i2c_tp); 822*7c478bd9Sstevel@tonic-gate 823*7c478bd9Sstevel@tonic-gate mutex_exit(&todds1337_rd_lock); 824*7c478bd9Sstevel@tonic-gate return (i2c_cmd_status); 825*7c478bd9Sstevel@tonic-gate } 826*7c478bd9Sstevel@tonic-gate 827*7c478bd9Sstevel@tonic-gate 828*7c478bd9Sstevel@tonic-gate static int 829*7c478bd9Sstevel@tonic-gate todds1337_write_rtc(struct rtc_t *rtc) 830*7c478bd9Sstevel@tonic-gate { 831*7c478bd9Sstevel@tonic-gate ds1337_state_t *statep = NULL; 832*7c478bd9Sstevel@tonic-gate i2c_transfer_t *i2c_tp = NULL; 833*7c478bd9Sstevel@tonic-gate int i2c_cmd_status = I2C_SUCCESS; 834*7c478bd9Sstevel@tonic-gate 835*7c478bd9Sstevel@tonic-gate 836*7c478bd9Sstevel@tonic-gate if (!todds1337_attach_done) { 837*7c478bd9Sstevel@tonic-gate return (todds1337_prom_setdate(rtc)); 838*7c478bd9Sstevel@tonic-gate } 839*7c478bd9Sstevel@tonic-gate 840*7c478bd9Sstevel@tonic-gate statep = ddi_get_soft_state(ds1337_statep, instance); 841*7c478bd9Sstevel@tonic-gate if (statep == NULL) { 842*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 843*7c478bd9Sstevel@tonic-gate } 844*7c478bd9Sstevel@tonic-gate 845*7c478bd9Sstevel@tonic-gate if ((i2c_cmd_status = i2c_transfer_alloc(statep->ds1337_i2c_hdl, 846*7c478bd9Sstevel@tonic-gate &i2c_tp, 8, 0, I2C_SLEEP)) != I2C_SUCCESS) { 847*7c478bd9Sstevel@tonic-gate return (i2c_cmd_status); 848*7c478bd9Sstevel@tonic-gate } 849*7c478bd9Sstevel@tonic-gate 850*7c478bd9Sstevel@tonic-gate i2c_tp->i2c_version = I2C_XFER_REV; 851*7c478bd9Sstevel@tonic-gate i2c_tp->i2c_flags = I2C_WR; 852*7c478bd9Sstevel@tonic-gate i2c_tp->i2c_wbuf[0] = (uchar_t)RTC_SEC; 853*7c478bd9Sstevel@tonic-gate i2c_tp->i2c_wbuf[1] = BYTE_TO_BCD(rtc->rtc_sec); 854*7c478bd9Sstevel@tonic-gate i2c_tp->i2c_wbuf[2] = BYTE_TO_BCD(rtc->rtc_min); 855*7c478bd9Sstevel@tonic-gate i2c_tp->i2c_wbuf[3] = BYTE_TO_BCD(rtc->rtc_hrs); 856*7c478bd9Sstevel@tonic-gate i2c_tp->i2c_wbuf[4] = BYTE_TO_BCD(rtc->rtc_dow); 857*7c478bd9Sstevel@tonic-gate i2c_tp->i2c_wbuf[5] = BYTE_TO_BCD(rtc->rtc_dom); 858*7c478bd9Sstevel@tonic-gate i2c_tp->i2c_wbuf[6] = BYTE_TO_BCD(rtc->rtc_mon); 859*7c478bd9Sstevel@tonic-gate i2c_tp->i2c_wbuf[7] = BYTE_TO_BCD(rtc->rtc_year); 860*7c478bd9Sstevel@tonic-gate i2c_tp->i2c_wlen = 8; 861*7c478bd9Sstevel@tonic-gate 862*7c478bd9Sstevel@tonic-gate if ((i2c_cmd_status = i2c_transfer(statep->ds1337_i2c_hdl, 863*7c478bd9Sstevel@tonic-gate i2c_tp)) != I2C_SUCCESS) { 864*7c478bd9Sstevel@tonic-gate (void) i2c_transfer_free(statep->ds1337_i2c_hdl, i2c_tp); 865*7c478bd9Sstevel@tonic-gate return (i2c_cmd_status); 866*7c478bd9Sstevel@tonic-gate } 867*7c478bd9Sstevel@tonic-gate 868*7c478bd9Sstevel@tonic-gate tod_read[0] = -1; /* invalidate saved data from read routine */ 869*7c478bd9Sstevel@tonic-gate 870*7c478bd9Sstevel@tonic-gate (void) i2c_transfer_free(statep->ds1337_i2c_hdl, i2c_tp); 871*7c478bd9Sstevel@tonic-gate 872*7c478bd9Sstevel@tonic-gate return (i2c_cmd_status); 873*7c478bd9Sstevel@tonic-gate } 874*7c478bd9Sstevel@tonic-gate 875*7c478bd9Sstevel@tonic-gate 876*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 877*7c478bd9Sstevel@tonic-gate static int 878*7c478bd9Sstevel@tonic-gate todds1337_getinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, 879*7c478bd9Sstevel@tonic-gate void **result) 880*7c478bd9Sstevel@tonic-gate { 881*7c478bd9Sstevel@tonic-gate ds1337_state_t *softsp; 882*7c478bd9Sstevel@tonic-gate 883*7c478bd9Sstevel@tonic-gate if (instance == -1) { 884*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 885*7c478bd9Sstevel@tonic-gate } 886*7c478bd9Sstevel@tonic-gate 887*7c478bd9Sstevel@tonic-gate switch (infocmd) { 888*7c478bd9Sstevel@tonic-gate case DDI_INFO_DEVT2DEVINFO: 889*7c478bd9Sstevel@tonic-gate if ((softsp = ddi_get_soft_state(ds1337_statep, instance)) == 890*7c478bd9Sstevel@tonic-gate NULL) 891*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 892*7c478bd9Sstevel@tonic-gate *result = (void *)softsp->dip; 893*7c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 894*7c478bd9Sstevel@tonic-gate case DDI_INFO_DEVT2INSTANCE: 895*7c478bd9Sstevel@tonic-gate *result = (void *)instance; 896*7c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 897*7c478bd9Sstevel@tonic-gate default: 898*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 899*7c478bd9Sstevel@tonic-gate } 900*7c478bd9Sstevel@tonic-gate } 901*7c478bd9Sstevel@tonic-gate 902*7c478bd9Sstevel@tonic-gate /* 903*7c478bd9Sstevel@tonic-gate * Finds the device node with device_type "rtc" and opens it to 904*7c478bd9Sstevel@tonic-gate * execute the get-time method 905*7c478bd9Sstevel@tonic-gate */ 906*7c478bd9Sstevel@tonic-gate static int 907*7c478bd9Sstevel@tonic-gate todds1337_setup_prom() 908*7c478bd9Sstevel@tonic-gate { 909*7c478bd9Sstevel@tonic-gate dnode_t todnode; 910*7c478bd9Sstevel@tonic-gate char tod1337_devpath[MAXNAMELEN]; 911*7c478bd9Sstevel@tonic-gate 912*7c478bd9Sstevel@tonic-gate if ((todnode = prom_findnode_bydevtype(prom_rootnode(), 913*7c478bd9Sstevel@tonic-gate DS1337_DEVICE_TYPE)) == OBP_NONODE) 914*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 915*7c478bd9Sstevel@tonic-gate 916*7c478bd9Sstevel@tonic-gate /* 917*7c478bd9Sstevel@tonic-gate * We now have the phandle of the rtc node, we need to open the 918*7c478bd9Sstevel@tonic-gate * node and get the ihandle 919*7c478bd9Sstevel@tonic-gate */ 920*7c478bd9Sstevel@tonic-gate if (prom_phandle_to_path(todnode, tod1337_devpath, 921*7c478bd9Sstevel@tonic-gate sizeof (tod1337_devpath)) < 0) { 922*7c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "prom_phandle_to_path failed"); 923*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 924*7c478bd9Sstevel@tonic-gate } 925*7c478bd9Sstevel@tonic-gate 926*7c478bd9Sstevel@tonic-gate /* 927*7c478bd9Sstevel@tonic-gate * Now open the node and store it's ihandle 928*7c478bd9Sstevel@tonic-gate */ 929*7c478bd9Sstevel@tonic-gate if ((todds1337_ihandle = prom_open(tod1337_devpath)) == NULL) { 930*7c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "prom_open failed"); 931*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 932*7c478bd9Sstevel@tonic-gate } 933*7c478bd9Sstevel@tonic-gate 934*7c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 935*7c478bd9Sstevel@tonic-gate } 936*7c478bd9Sstevel@tonic-gate 937*7c478bd9Sstevel@tonic-gate /* 938*7c478bd9Sstevel@tonic-gate * Closes the prom interface 939*7c478bd9Sstevel@tonic-gate */ 940*7c478bd9Sstevel@tonic-gate static void 941*7c478bd9Sstevel@tonic-gate todds1337_rele_prom() 942*7c478bd9Sstevel@tonic-gate { 943*7c478bd9Sstevel@tonic-gate (void) prom_close(todds1337_ihandle); 944*7c478bd9Sstevel@tonic-gate } 945*7c478bd9Sstevel@tonic-gate 946*7c478bd9Sstevel@tonic-gate /* 947*7c478bd9Sstevel@tonic-gate * Read the date using "get-time" method in rtc node 948*7c478bd9Sstevel@tonic-gate * PROM returns 1969-1999 when reading 69-99 and 949*7c478bd9Sstevel@tonic-gate * 2000-2068 when reading 00-68 950*7c478bd9Sstevel@tonic-gate */ 951*7c478bd9Sstevel@tonic-gate static int 952*7c478bd9Sstevel@tonic-gate todds1337_prom_getdate(struct rtc_t *rtc) 953*7c478bd9Sstevel@tonic-gate { 954*7c478bd9Sstevel@tonic-gate int year; 955*7c478bd9Sstevel@tonic-gate cell_t ci[12]; 956*7c478bd9Sstevel@tonic-gate 957*7c478bd9Sstevel@tonic-gate ci[0] = p1275_ptr2cell("call-method"); /* Service name */ 958*7c478bd9Sstevel@tonic-gate ci[1] = 2; /* # of arguments */ 959*7c478bd9Sstevel@tonic-gate ci[2] = 7; /* # of result cells */ 960*7c478bd9Sstevel@tonic-gate ci[3] = p1275_ptr2cell("get-time"); 961*7c478bd9Sstevel@tonic-gate ci[4] = p1275_ihandle2cell(todds1337_ihandle); 962*7c478bd9Sstevel@tonic-gate 963*7c478bd9Sstevel@tonic-gate promif_preprom(); 964*7c478bd9Sstevel@tonic-gate (void) p1275_cif_handler(&ci); 965*7c478bd9Sstevel@tonic-gate promif_postprom(); 966*7c478bd9Sstevel@tonic-gate 967*7c478bd9Sstevel@tonic-gate year = p1275_cell2int(ci[6]); 968*7c478bd9Sstevel@tonic-gate rtc->rtc_mon = p1275_cell2int(ci[7]); 969*7c478bd9Sstevel@tonic-gate rtc->rtc_dom = p1275_cell2int(ci[8]); 970*7c478bd9Sstevel@tonic-gate rtc->rtc_dow = 0; 971*7c478bd9Sstevel@tonic-gate rtc->rtc_hrs = p1275_cell2int(ci[9]); 972*7c478bd9Sstevel@tonic-gate rtc->rtc_min = p1275_cell2int(ci[10]); 973*7c478bd9Sstevel@tonic-gate rtc->rtc_sec = p1275_cell2int(ci[11]); 974*7c478bd9Sstevel@tonic-gate if (year >= 2000) 975*7c478bd9Sstevel@tonic-gate year -= 2000; 976*7c478bd9Sstevel@tonic-gate else 977*7c478bd9Sstevel@tonic-gate year -= 1900; 978*7c478bd9Sstevel@tonic-gate rtc->rtc_year = year; 979*7c478bd9Sstevel@tonic-gate 980*7c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 981*7c478bd9Sstevel@tonic-gate } 982*7c478bd9Sstevel@tonic-gate 983*7c478bd9Sstevel@tonic-gate /* 984*7c478bd9Sstevel@tonic-gate * Read the date using "set-time" method in rtc node 985*7c478bd9Sstevel@tonic-gate * For values 00 - 68, write 2000-2068, and for 69-99, 986*7c478bd9Sstevel@tonic-gate * write 1969-1999 987*7c478bd9Sstevel@tonic-gate */ 988*7c478bd9Sstevel@tonic-gate static int 989*7c478bd9Sstevel@tonic-gate todds1337_prom_setdate(struct rtc_t *rtc) 990*7c478bd9Sstevel@tonic-gate { 991*7c478bd9Sstevel@tonic-gate int year; 992*7c478bd9Sstevel@tonic-gate cell_t ci[12]; 993*7c478bd9Sstevel@tonic-gate 994*7c478bd9Sstevel@tonic-gate year = rtc->rtc_year; 995*7c478bd9Sstevel@tonic-gate 996*7c478bd9Sstevel@tonic-gate if ((year < 0) || (year > 99)) 997*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 998*7c478bd9Sstevel@tonic-gate 999*7c478bd9Sstevel@tonic-gate if (year <= 68) 1000*7c478bd9Sstevel@tonic-gate year = rtc->rtc_year + 2000; 1001*7c478bd9Sstevel@tonic-gate else 1002*7c478bd9Sstevel@tonic-gate year = rtc->rtc_year + 1900; 1003*7c478bd9Sstevel@tonic-gate 1004*7c478bd9Sstevel@tonic-gate ci[0] = p1275_ptr2cell("call-method"); /* Service name */ 1005*7c478bd9Sstevel@tonic-gate ci[1] = 8; /* # of arguments */ 1006*7c478bd9Sstevel@tonic-gate ci[2] = 0; /* # of result cells */ 1007*7c478bd9Sstevel@tonic-gate ci[3] = p1275_ptr2cell("set-time"); 1008*7c478bd9Sstevel@tonic-gate ci[4] = p1275_ihandle2cell(todds1337_ihandle); 1009*7c478bd9Sstevel@tonic-gate ci[5] = p1275_int2cell(year); 1010*7c478bd9Sstevel@tonic-gate ci[6] = p1275_int2cell(rtc->rtc_mon); 1011*7c478bd9Sstevel@tonic-gate ci[7] = p1275_int2cell(rtc->rtc_dom); 1012*7c478bd9Sstevel@tonic-gate ci[8] = p1275_int2cell(rtc->rtc_hrs); 1013*7c478bd9Sstevel@tonic-gate ci[9] = p1275_int2cell(rtc->rtc_min); 1014*7c478bd9Sstevel@tonic-gate ci[10] = p1275_int2cell(rtc->rtc_sec); 1015*7c478bd9Sstevel@tonic-gate 1016*7c478bd9Sstevel@tonic-gate promif_preprom(); 1017*7c478bd9Sstevel@tonic-gate (void) p1275_cif_handler(&ci); 1018*7c478bd9Sstevel@tonic-gate promif_postprom(); 1019*7c478bd9Sstevel@tonic-gate 1020*7c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 1021*7c478bd9Sstevel@tonic-gate } 1022