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