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 */
57static int todds1337_attach(dev_info_t *, ddi_attach_cmd_t);
58static int todds1337_detach(dev_info_t *, ddi_detach_cmd_t);
59static int todds1337_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **);
60
61/*
62 * tod_ops entry routines
63 */
64static timestruc_t	todds1337_get(void);
65static void		todds1337_set(timestruc_t);
66static uint_t		todds1337_set_watchdog_timer(uint_t);
67static uint_t		todds1337_clear_watchdog_timer(void);
68static void		todds1337_set_power_alarm(timestruc_t);
69static void		todds1337_clear_power_alarm(void);
70static int		todds1337_setup_prom(void);
71static void		todds1337_rele_prom(void);
72static int		todds1337_prom_getdate(struct rtc_t *rtc);
73static int		todds1337_prom_setdate(struct rtc_t *rtc);
74
75/*
76 * Local functions
77 */
78static int		todds1337_read_rtc(struct rtc_t *);
79static int		todds1337_write_rtc(struct rtc_t *);
80
81/* Anchor for soft state structure */
82static void	*ds1337_statep;
83static int	instance = -1;
84static int	todds1337_attach_done = 0;
85static kmutex_t	todds1337_rd_lock;
86static kmutex_t	todds1337_alarm_lock;
87static ihandle_t todds1337_ihandle = 0;
88
89/* one second time out */
90#define	I2C_CYCLIC_TIMEOUT	1000000000
91uint_t i2c_cyclic_timeout = I2C_CYCLIC_TIMEOUT;
92static int sync_clock_once = 1;
93static struct	rtc_t	 soft_rtc;
94
95/*
96 * cp_ops structure
97 */
98static 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 */
122static 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
137static 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 */
146static struct modlinkage todds1337_modlinkage = {
147	MODREV_1,
148	&todds1337_modldrv,
149	0
150};
151
152int
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
190int
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
208int
209_info(struct modinfo *modinfop)
210{
211	return (mod_info(&todds1337_modlinkage, modinfop));
212}
213
214/*
215 * cyclical call to get tod.
216 */
217static void
218todds1337_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 */
229static int
230todds1337_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*/
367static int
368todds1337_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
392static timestruc_t
393todds1337_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 */
439static void
440todds1337_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 */
475static void
476todds1337_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 */
600static void
601todds1337_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 */
714static uint_t
715todds1337_set_watchdog_timer(uint_t timeoutval)
716{
717	ASSERT(MUTEX_HELD(&tod_lock));
718	return (0);
719}
720
721/* ARGSUSED */
722static uint_t
723todds1337_clear_watchdog_timer(void)
724{
725	ASSERT(MUTEX_HELD(&tod_lock));
726	return (0);
727}
728
729/* ********************** Local functions ***************************** */
730
731static char tod_read[7] = {-1, -1, -1, -1, -1, -1, -1};
732static int
733todds1337_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
814done:
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
822static int
823todds1337_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*/
871static int
872todds1337_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 */
900static int
901todds1337_setup_prom(void)
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)) == 0) {
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 */
934static void
935todds1337_rele_prom(void)
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 */
945static int
946todds1337_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 */
982static int
983todds1337_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