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