xref: /titanic_44/usr/src/uts/sun4u/io/todds1337.c (revision 8fc99e42676a23421c75e76660640f9765d693b1)
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 2010 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
_init(void)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
_fini(void)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
_info(struct modinfo * modinfop)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
todds1337_cyclic(void * arg)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
todds1337_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)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
todds1337_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)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_lock held.
390  */
391 
392 static timestruc_t
todds1337_get(void)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_status_set(TOD_GET_FAILED);
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 	/* read was successful so ensure failure flag is clear */
426 	tod_status_clear(TOD_GET_FAILED);
427 
428 	ts.tv_sec = tod_to_utc(tod);
429 	ts.tv_nsec = 0;
430 	return (ts);
431 }
432 
433 /*
434  * Program DS1337 with the specified time.
435  * Must be called with tod_lock held. The TOD
436  * chip supports date from 1969-2068 only. We must
437  * reject requests to set date below 1969.
438  */
439 static void
todds1337_set(timestruc_t ts)440 todds1337_set(timestruc_t ts)
441 {
442 	struct rtc_t	rtc;
443 	todinfo_t	tod = utc_to_tod(ts.tv_sec);
444 	int		year;
445 
446 
447 	ASSERT(MUTEX_HELD(&tod_lock));
448 
449 	/*
450 	 * Year is base 1900, valid year range 1969-2068
451 	 */
452 	if ((tod.tod_year < 69) || (tod.tod_year > 168))
453 		return;
454 
455 	year = tod.tod_year;
456 	if (year >= 100)
457 		year -= 100;
458 
459 	rtc.rtc_year	= (uint8_t)year;
460 	rtc.rtc_mon	= (uint8_t)tod.tod_month;
461 	rtc.rtc_dom	= (uint8_t)tod.tod_day;
462 	rtc.rtc_dow	= (uint8_t)tod.tod_dow;
463 	rtc.rtc_hrs	= (uint8_t)tod.tod_hour;
464 	rtc.rtc_min	= (uint8_t)tod.tod_min;
465 	rtc.rtc_sec	= (uint8_t)tod.tod_sec;
466 
467 	(void) todds1337_write_rtc(&rtc);
468 }
469 
470 /*
471  * Program ds1337 registers for alarm to go off at the specified time.
472  * Alarm #1 is used (Alarm #2 stays idle)
473  */
474 /* ARGSUSED */
475 static void
todds1337_set_power_alarm(timestruc_t ts)476 todds1337_set_power_alarm(timestruc_t ts)
477 {
478 	todinfo_t	tod;
479 	ds1337_state_t	*statep = NULL;
480 	i2c_transfer_t	*i2c_tp = NULL;
481 	uint8_t tmpval;
482 
483 	ASSERT(MUTEX_HELD(&tod_lock));
484 
485 	if (!todds1337_attach_done) {
486 		cmn_err(CE_WARN, "todds1337: driver not attached");
487 		return;
488 	}
489 
490 	statep = ddi_get_soft_state(ds1337_statep, instance);
491 	if (statep == NULL) {
492 		cmn_err(CE_WARN, "todds1337: ddi_get_soft_state failed");
493 		return;
494 	}
495 
496 	tod = utc_to_tod(ts.tv_sec);
497 
498 	/*
499 	 * i2c_transfe() may block; to avoid locking clock() which
500 	 * is running in interrupt context at PIL10 we temporarely exit
501 	 * the tod_mutex and enter alarm lock. Time/date and alarm hardware
502 	 * have non-interlsecting registers, it is safe to use different locks.
503 	 */
504 	mutex_exit(&tod_lock);
505 	mutex_enter(&todds1337_alarm_lock);
506 
507 	/*
508 	 * Disable Power Alarm (A1IE)
509 	 */
510 	(void) i2c_transfer_alloc(statep->ds1337_i2c_hdl,
511 	    &i2c_tp, 1, 1, I2C_SLEEP);
512 	i2c_tp->i2c_version = I2C_XFER_REV;
513 	i2c_tp->i2c_flags = I2C_WR_RD;
514 	i2c_tp->i2c_wbuf[0] = (uchar_t)RTC_CTL; /* Read Control register */
515 
516 	if ((i2c_transfer(statep->ds1337_i2c_hdl, i2c_tp)) != I2C_SUCCESS) {
517 		(void) i2c_transfer_free(statep->ds1337_i2c_hdl, i2c_tp);
518 		cmn_err(CE_WARN, "todds1337_set_power_alarm: failed to read "
519 		    "DS1337 control register");
520 		mutex_exit(&todds1337_alarm_lock);
521 		mutex_enter(&tod_lock);
522 		return;
523 	}
524 
525 	tmpval = i2c_tp->i2c_rbuf[0];
526 
527 	(void) i2c_transfer_free(statep->ds1337_i2c_hdl, i2c_tp);
528 
529 	(void) i2c_transfer_alloc(statep->ds1337_i2c_hdl,
530 	    &i2c_tp, 2, 0, I2C_SLEEP);
531 	i2c_tp->i2c_version = I2C_XFER_REV;
532 	i2c_tp->i2c_flags = I2C_WR;
533 	i2c_tp->i2c_wbuf[0] = (uchar_t)RTC_CTL; /* Write Control register */
534 	i2c_tp->i2c_wbuf[1] = tmpval & ~RTC_CTL_A1IE;
535 
536 	if ((i2c_transfer(statep->ds1337_i2c_hdl, i2c_tp)) != I2C_SUCCESS) {
537 		(void) i2c_transfer_free(statep->ds1337_i2c_hdl, i2c_tp);
538 		cmn_err(CE_WARN, "todds1337_set_power_alarm: failed to write "
539 		    "DS1337control register");
540 		mutex_exit(&todds1337_alarm_lock);
541 		mutex_enter(&tod_lock);
542 		return;
543 	}
544 
545 	(void) i2c_transfer_free(statep->ds1337_i2c_hdl, i2c_tp);
546 
547 
548 	/*
549 	 * Write Alarm #1 registers
550 	 */
551 
552 	(void) i2c_transfer_alloc(statep->ds1337_i2c_hdl,
553 	    &i2c_tp, 5, 0, I2C_SLEEP);
554 	i2c_tp->i2c_version = I2C_XFER_REV;
555 	i2c_tp->i2c_flags = I2C_WR;
556 	i2c_tp->i2c_wbuf[0] = (uchar_t)RTC_ALARM_SEC; /* Alarm #1 Seconds */
557 	i2c_tp->i2c_wbuf[1] = BYTE_TO_BCD(tod.tod_sec);
558 	i2c_tp->i2c_wbuf[2] = BYTE_TO_BCD(tod.tod_min);
559 	i2c_tp->i2c_wbuf[3] = BYTE_TO_BCD(tod.tod_hour);
560 	i2c_tp->i2c_wbuf[4] = BYTE_TO_BCD(tod.tod_day);
561 
562 	if ((i2c_transfer(statep->ds1337_i2c_hdl, i2c_tp)) != I2C_SUCCESS) {
563 		(void) i2c_transfer_free(statep->ds1337_i2c_hdl, i2c_tp);
564 		cmn_err(CE_WARN, "todds1337_set_power_alarm: failed to write "
565 		    "DS1337 alarm registers");
566 		mutex_exit(&todds1337_alarm_lock);
567 		mutex_enter(&tod_lock);
568 		return;
569 	}
570 
571 	(void) i2c_transfer_free(statep->ds1337_i2c_hdl, i2c_tp);
572 
573 
574 	/*
575 	 * Enable Power Alarm
576 	 */
577 	(void) i2c_transfer_alloc(statep->ds1337_i2c_hdl,
578 	    &i2c_tp, 2, 0, I2C_SLEEP);
579 	i2c_tp->i2c_version = I2C_XFER_REV;
580 	i2c_tp->i2c_flags = I2C_WR;
581 	i2c_tp->i2c_wbuf[0] = (uchar_t)RTC_CTL; /* Write Control register */
582 	i2c_tp->i2c_wbuf[1] = tmpval | RTC_CTL_A1IE;
583 
584 	if ((i2c_transfer(statep->ds1337_i2c_hdl, i2c_tp)) != I2C_SUCCESS) {
585 		(void) i2c_transfer_free(statep->ds1337_i2c_hdl, i2c_tp);
586 		cmn_err(CE_WARN, "todds1337_set_power_alarm: failed to enable "
587 		    "DS1337 alarm");
588 		mutex_exit(&todds1337_alarm_lock);
589 		mutex_enter(&tod_lock);
590 		return;
591 	}
592 
593 	(void) i2c_transfer_free(statep->ds1337_i2c_hdl, i2c_tp);
594 
595 	mutex_exit(&todds1337_alarm_lock);
596 	mutex_enter(&tod_lock);
597 }
598 
599 /* ARGSUSED */
600 static void
todds1337_clear_power_alarm(void)601 todds1337_clear_power_alarm(void)
602 {
603 	ds1337_state_t	*statep = NULL;
604 	i2c_transfer_t	*i2c_tp = NULL;
605 	uint8_t tmpval;
606 
607 	ASSERT(MUTEX_HELD(&tod_lock));
608 
609 	if (!todds1337_attach_done) {
610 		cmn_err(CE_WARN, "todds1337: driver was not attached");
611 		return;
612 	}
613 
614 	statep = ddi_get_soft_state(ds1337_statep, instance);
615 	if (statep == NULL) {
616 		cmn_err(CE_WARN, "todds1337: ddi_get_soft_state has failed");
617 		return;
618 	}
619 
620 	/*
621 	 * i2c_transfe() may block; to avoid locking clock() which
622 	 * is running in interrupt context at PIL10 we temporarely exit
623 	 * the tod_mutex and enter alarm lock. Time/date and alarm hardware
624 	 * have non-interlsecting registers, it is safe to use different locks.
625 	 */
626 	mutex_exit(&tod_lock);
627 	mutex_enter(&todds1337_alarm_lock);
628 
629 	/*
630 	 * Disable Alarm #1 Interrupt
631 	 */
632 	(void) i2c_transfer_alloc(statep->ds1337_i2c_hdl,
633 	    &i2c_tp, 1, 1, I2C_SLEEP);
634 	i2c_tp->i2c_version = I2C_XFER_REV;
635 	i2c_tp->i2c_flags = I2C_WR_RD;
636 	i2c_tp->i2c_wbuf[0] = (uchar_t)RTC_CTL; /* Read Control register */
637 
638 	if ((i2c_transfer(statep->ds1337_i2c_hdl, i2c_tp)) != I2C_SUCCESS) {
639 		(void) i2c_transfer_free(statep->ds1337_i2c_hdl, i2c_tp);
640 		cmn_err(CE_WARN, "todds1337_clear_power_alarm: failed to read "
641 		    "DS1337 control register");
642 		mutex_exit(&todds1337_alarm_lock);
643 		mutex_enter(&tod_lock);
644 		return;
645 	}
646 
647 	tmpval = i2c_tp->i2c_rbuf[0];
648 
649 	(void) i2c_transfer_free(statep->ds1337_i2c_hdl, i2c_tp);
650 
651 	(void) i2c_transfer_alloc(statep->ds1337_i2c_hdl,
652 	    &i2c_tp, 2, 0, I2C_SLEEP);
653 	i2c_tp->i2c_version = I2C_XFER_REV;
654 	i2c_tp->i2c_flags = I2C_WR;
655 	i2c_tp->i2c_wbuf[0] = (uchar_t)RTC_CTL; /* Write Control register */
656 	i2c_tp->i2c_wbuf[1] = tmpval & ~RTC_CTL_A1IE;
657 
658 	if ((i2c_transfer(statep->ds1337_i2c_hdl, i2c_tp)) != I2C_SUCCESS) {
659 		(void) i2c_transfer_free(statep->ds1337_i2c_hdl, i2c_tp);
660 		cmn_err(CE_WARN, "todds1337_clear_power_alarm: failed to write "
661 		    "DS1337 control register");
662 		mutex_exit(&todds1337_alarm_lock);
663 		mutex_enter(&tod_lock);
664 		return;
665 	}
666 
667 	(void) i2c_transfer_free(statep->ds1337_i2c_hdl, i2c_tp);
668 
669 	/*
670 	 * Reset Alarm #1 Flag
671 	 */
672 	(void) i2c_transfer_alloc(statep->ds1337_i2c_hdl,
673 	    &i2c_tp, 1, 1, I2C_SLEEP);
674 	i2c_tp->i2c_version = I2C_XFER_REV;
675 	i2c_tp->i2c_flags = I2C_WR_RD;
676 	i2c_tp->i2c_wbuf[0] = (uchar_t)RTC_STATUS; /* Read Status register */
677 
678 	if ((i2c_transfer(statep->ds1337_i2c_hdl, i2c_tp)) != I2C_SUCCESS) {
679 		(void) i2c_transfer_free(statep->ds1337_i2c_hdl, i2c_tp);
680 		cmn_err(CE_WARN, "todds1337_clear_power_alarm: failed to read "
681 		    "DS1337 status register");
682 		mutex_exit(&todds1337_alarm_lock);
683 		mutex_enter(&tod_lock);
684 		return;
685 	}
686 
687 	tmpval = i2c_tp->i2c_rbuf[0];
688 
689 	(void) i2c_transfer_free(statep->ds1337_i2c_hdl, i2c_tp);
690 
691 	(void) i2c_transfer_alloc(statep->ds1337_i2c_hdl,
692 	    &i2c_tp, 2, 0, I2C_SLEEP);
693 	i2c_tp->i2c_version = I2C_XFER_REV;
694 	i2c_tp->i2c_flags = I2C_WR;
695 	i2c_tp->i2c_wbuf[0] = (uchar_t)RTC_STATUS; /* Write Status register */
696 	i2c_tp->i2c_wbuf[1] = tmpval & ~RTC_STATUS_A1F;
697 
698 	if ((i2c_transfer(statep->ds1337_i2c_hdl, i2c_tp)) != I2C_SUCCESS) {
699 		(void) i2c_transfer_free(statep->ds1337_i2c_hdl, i2c_tp);
700 		cmn_err(CE_WARN, "todds1337_clear_power_alarm: failed to write "
701 		    "DS1337 status register");
702 		mutex_exit(&todds1337_alarm_lock);
703 		mutex_enter(&tod_lock);
704 		return;
705 	}
706 
707 	(void) i2c_transfer_free(statep->ds1337_i2c_hdl, i2c_tp);
708 
709 	mutex_exit(&todds1337_alarm_lock);
710 	mutex_enter(&tod_lock);
711 }
712 
713 /* ARGSUSED */
714 static uint_t
todds1337_set_watchdog_timer(uint_t timeoutval)715 todds1337_set_watchdog_timer(uint_t timeoutval)
716 {
717 	ASSERT(MUTEX_HELD(&tod_lock));
718 	return (0);
719 }
720 
721 /* ARGSUSED */
722 static uint_t
todds1337_clear_watchdog_timer(void)723 todds1337_clear_watchdog_timer(void)
724 {
725 	ASSERT(MUTEX_HELD(&tod_lock));
726 	return (0);
727 }
728 
729 /* ********************** Local functions ***************************** */
730 
731 static char tod_read[7] = {-1, -1, -1, -1, -1, -1, -1};
732 static int
todds1337_read_rtc(struct rtc_t * rtc)733 todds1337_read_rtc(struct rtc_t *rtc)
734 {
735 	static	ds1337_state_t	*statep = NULL;
736 	i2c_transfer_t	*i2c_tp = NULL;
737 	int i2c_cmd_status = I2C_FAILURE;
738 	int counter = 4;
739 
740 	if (!todds1337_attach_done) {
741 		return (todds1337_prom_getdate(rtc));
742 	}
743 
744 	statep = ddi_get_soft_state(ds1337_statep, instance);
745 	if (statep == NULL) {
746 		cmn_err(CE_WARN, "todds1337: ddi_get_soft_state failing");
747 		return (DDI_FAILURE);
748 	}
749 
750 	mutex_enter(&todds1337_rd_lock);
751 
752 	/*
753 	 * Allocate 1 byte for write buffer and 7 bytes for read buffer to
754 	 * to accomodate sec, min, hrs, dayOfWeek, dayOfMonth, year
755 	 */
756 	if ((i2c_transfer_alloc(statep->ds1337_i2c_hdl, &i2c_tp, 1,
757 	    7, I2C_SLEEP)) != I2C_SUCCESS) {
758 		mutex_exit(&todds1337_rd_lock);
759 		return (DDI_FAILURE);
760 	}
761 
762 	do {
763 		i2c_tp->i2c_version = I2C_XFER_REV;
764 		i2c_tp->i2c_flags = I2C_WR_RD;
765 		i2c_tp->i2c_wbuf[0] = (uchar_t)RTC_SEC; /* Start from 0x00 */
766 		i2c_tp->i2c_wlen = 1;	/* Write one byte address */
767 		i2c_tp->i2c_rlen = 7;	/* Read 7 regs */
768 
769 		if ((i2c_cmd_status = i2c_transfer(statep->ds1337_i2c_hdl,
770 		    i2c_tp)) != I2C_SUCCESS) {
771 			goto done;
772 		}
773 		/* for first read, need to get valid data */
774 		while (tod_read[0] == -1 && counter > 0) {
775 		/* move data to static buffer */
776 		bcopy(i2c_tp->i2c_rbuf, tod_read, 7);
777 
778 		/* now read again */
779 		/* Start reading reg from 0x00 */
780 		i2c_tp->i2c_wbuf[0] = (uchar_t)0x00;
781 		i2c_tp->i2c_wlen = 1;	/* Write one byte address */
782 		i2c_tp->i2c_rlen = 7;	/* Read 7 regs */
783 		if ((i2c_cmd_status = i2c_transfer(statep->ds1337_i2c_hdl,
784 		    i2c_tp)) != I2C_SUCCESS) {
785 			goto done;
786 		}
787 		/* if they are not the same, then read again */
788 		if (bcmp(tod_read, i2c_tp->i2c_rbuf, 7) != 0) {
789 			tod_read[0] = -1;
790 			counter--;
791 		}
792 	}
793 
794 	} while (i2c_tp->i2c_rbuf[0] == 0x59 &&
795 	    /* if seconds register is 0x59 (BCD), add data should match */
796 	    bcmp(&tod_read[1], &i2c_tp->i2c_rbuf[1], 6) != 0 &&
797 	    counter-- > 0);
798 
799 	if (counter < 0)
800 		cmn_err(CE_WARN, "i2ctod: TOD Chip failed ??");
801 
802 	/* move data to static buffer */
803 	bcopy(i2c_tp->i2c_rbuf, tod_read, 7);
804 
805 
806 	rtc->rtc_year	= BCD_TO_BYTE(i2c_tp->i2c_rbuf[6]);
807 	rtc->rtc_mon	= BCD_TO_BYTE(i2c_tp->i2c_rbuf[5]);
808 	rtc->rtc_dom	= BCD_TO_BYTE(i2c_tp->i2c_rbuf[4]);
809 	rtc->rtc_dow	= BCD_TO_BYTE(i2c_tp->i2c_rbuf[3]);
810 	rtc->rtc_hrs	= BCD_TO_BYTE(i2c_tp->i2c_rbuf[2]);
811 	rtc->rtc_min	= BCD_TO_BYTE(i2c_tp->i2c_rbuf[1]);
812 	rtc->rtc_sec	= BCD_TO_BYTE(i2c_tp->i2c_rbuf[0]);
813 
814 done:
815 	(void) i2c_transfer_free(statep->ds1337_i2c_hdl, i2c_tp);
816 
817 	mutex_exit(&todds1337_rd_lock);
818 	return (i2c_cmd_status);
819 }
820 
821 
822 static int
todds1337_write_rtc(struct rtc_t * rtc)823 todds1337_write_rtc(struct rtc_t *rtc)
824 {
825 	ds1337_state_t	*statep = NULL;
826 	i2c_transfer_t	*i2c_tp = NULL;
827 	int i2c_cmd_status = I2C_SUCCESS;
828 
829 
830 	if (!todds1337_attach_done) {
831 		return (todds1337_prom_setdate(rtc));
832 	}
833 
834 	statep = ddi_get_soft_state(ds1337_statep, instance);
835 	if (statep == NULL) {
836 		return (DDI_FAILURE);
837 	}
838 
839 	if ((i2c_cmd_status = i2c_transfer_alloc(statep->ds1337_i2c_hdl,
840 	    &i2c_tp, 8, 0, I2C_SLEEP)) != I2C_SUCCESS) {
841 		return (i2c_cmd_status);
842 	}
843 
844 	i2c_tp->i2c_version = I2C_XFER_REV;
845 	i2c_tp->i2c_flags = I2C_WR;
846 	i2c_tp->i2c_wbuf[0] = (uchar_t)RTC_SEC;
847 	i2c_tp->i2c_wbuf[1] = BYTE_TO_BCD(rtc->rtc_sec);
848 	i2c_tp->i2c_wbuf[2] = BYTE_TO_BCD(rtc->rtc_min);
849 	i2c_tp->i2c_wbuf[3] = BYTE_TO_BCD(rtc->rtc_hrs);
850 	i2c_tp->i2c_wbuf[4] = BYTE_TO_BCD(rtc->rtc_dow);
851 	i2c_tp->i2c_wbuf[5] = BYTE_TO_BCD(rtc->rtc_dom);
852 	i2c_tp->i2c_wbuf[6] = BYTE_TO_BCD(rtc->rtc_mon);
853 	i2c_tp->i2c_wbuf[7] = BYTE_TO_BCD(rtc->rtc_year);
854 	i2c_tp->i2c_wlen = 8;
855 
856 	if ((i2c_cmd_status = i2c_transfer(statep->ds1337_i2c_hdl,
857 	    i2c_tp)) != I2C_SUCCESS) {
858 		(void) i2c_transfer_free(statep->ds1337_i2c_hdl, i2c_tp);
859 		return (i2c_cmd_status);
860 	}
861 
862 	tod_read[0] = -1;  /* invalidate saved data from read routine */
863 
864 	(void) i2c_transfer_free(statep->ds1337_i2c_hdl, i2c_tp);
865 
866 	return (i2c_cmd_status);
867 }
868 
869 
870 /*ARGSUSED*/
871 static int
todds1337_getinfo(dev_info_t * dip,ddi_info_cmd_t infocmd,void * arg,void ** result)872 todds1337_getinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg,
873     void **result)
874 {
875 	ds1337_state_t *softsp;
876 
877 	if (instance == -1) {
878 		return (DDI_FAILURE);
879 	}
880 
881 	switch (infocmd) {
882 	case DDI_INFO_DEVT2DEVINFO:
883 		if ((softsp = ddi_get_soft_state(ds1337_statep, instance)) ==
884 		    NULL)
885 			return (DDI_FAILURE);
886 		*result = (void *)softsp->dip;
887 		return (DDI_SUCCESS);
888 	case DDI_INFO_DEVT2INSTANCE:
889 		*result = (void *)(uintptr_t)instance;
890 		return (DDI_SUCCESS);
891 	default:
892 		return (DDI_FAILURE);
893 	}
894 }
895 
896 /*
897  * Finds the device node with device_type "rtc" and opens it to
898  * execute the get-time method
899  */
900 static int
todds1337_setup_prom()901 todds1337_setup_prom()
902 {
903 	pnode_t todnode;
904 	char tod1337_devpath[MAXNAMELEN];
905 
906 	if ((todnode = prom_findnode_bydevtype(prom_rootnode(),
907 	    DS1337_DEVICE_TYPE)) == OBP_NONODE)
908 		return (DDI_FAILURE);
909 
910 	/*
911 	 * We now have the phandle of the rtc node, we need to open the
912 	 * node and get the ihandle
913 	 */
914 	if (prom_phandle_to_path(todnode, tod1337_devpath,
915 	    sizeof (tod1337_devpath)) < 0) {
916 		cmn_err(CE_WARN, "prom_phandle_to_path failed");
917 		return (DDI_FAILURE);
918 	}
919 
920 	/*
921 	 * Now open the node and store it's ihandle
922 	 */
923 	if ((todds1337_ihandle = prom_open(tod1337_devpath)) == NULL) {
924 		cmn_err(CE_WARN, "prom_open failed");
925 		return (DDI_FAILURE);
926 	}
927 
928 	return (DDI_SUCCESS);
929 }
930 
931 /*
932  * Closes the prom interface
933  */
934 static void
todds1337_rele_prom()935 todds1337_rele_prom()
936 {
937 	(void) prom_close(todds1337_ihandle);
938 }
939 
940 /*
941  * Read the date using "get-time" method in rtc node
942  * PROM returns 1969-1999 when reading 69-99 and
943  * 2000-2068 when reading 00-68
944  */
945 static int
todds1337_prom_getdate(struct rtc_t * rtc)946 todds1337_prom_getdate(struct rtc_t *rtc)
947 {
948 	int year;
949 	cell_t ci[12];
950 
951 	ci[0] = p1275_ptr2cell("call-method");  /* Service name */
952 	ci[1] = 2; /* # of arguments */
953 	ci[2] = 7; /* # of result cells */
954 	ci[3] = p1275_ptr2cell("get-time");
955 	ci[4] = p1275_ihandle2cell(todds1337_ihandle);
956 
957 	promif_preprom();
958 	(void) p1275_cif_handler(&ci);
959 	promif_postprom();
960 
961 	year 		= p1275_cell2int(ci[6]);
962 	rtc->rtc_mon	= p1275_cell2int(ci[7]);
963 	rtc->rtc_dom	= p1275_cell2int(ci[8]);
964 	rtc->rtc_dow	= 0;
965 	rtc->rtc_hrs	= p1275_cell2int(ci[9]);
966 	rtc->rtc_min	= p1275_cell2int(ci[10]);
967 	rtc->rtc_sec	= p1275_cell2int(ci[11]);
968 	if (year >= 2000)
969 		year -= 2000;
970 	else
971 		year -= 1900;
972 	rtc->rtc_year	= year;
973 
974 	return (DDI_SUCCESS);
975 }
976 
977 /*
978  * Read the date using "set-time" method in rtc node
979  * For values 00 - 68, write 2000-2068, and for 69-99,
980  * write 1969-1999
981  */
982 static int
todds1337_prom_setdate(struct rtc_t * rtc)983 todds1337_prom_setdate(struct rtc_t *rtc)
984 {
985 	int year;
986 	cell_t ci[12];
987 
988 	year = rtc->rtc_year;
989 
990 	if ((year < 0) || (year > 99))
991 		return (DDI_FAILURE);
992 
993 	if (year <= 68)
994 		year = rtc->rtc_year + 2000;
995 	else
996 		year = rtc->rtc_year + 1900;
997 
998 	ci[0] = p1275_ptr2cell("call-method");  /* Service name */
999 	ci[1] = 8; /* # of arguments */
1000 	ci[2] = 0; /* # of result cells */
1001 	ci[3] = p1275_ptr2cell("set-time");
1002 	ci[4] = p1275_ihandle2cell(todds1337_ihandle);
1003 	ci[5] = p1275_int2cell(year);
1004 	ci[6] = p1275_int2cell(rtc->rtc_mon);
1005 	ci[7] = p1275_int2cell(rtc->rtc_dom);
1006 	ci[8] = p1275_int2cell(rtc->rtc_hrs);
1007 	ci[9] = p1275_int2cell(rtc->rtc_min);
1008 	ci[10] = p1275_int2cell(rtc->rtc_sec);
1009 
1010 	promif_preprom();
1011 	(void) p1275_cif_handler(&ci);
1012 	promif_postprom();
1013 
1014 	return (DDI_SUCCESS);
1015 }
1016