summaryrefslogtreecommitdiffstats
path: root/drivers/rtc/mpc5xxx.c
blob: ec0b0ef68f0aa83b1858dba46132b8a3bf903c1a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
/*
 * (C) Copyright 2004
 * Reinhard Meyer, EMK Elektronik GmbH
 * r.meyer@emk-elektronik.de
 * www.emk-elektronik.de
 *
 * See file CREDITS for list of people who contributed to this
 * project.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 2 of
 * the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 * MA 02111-1307 USA
 */

/*****************************************************************************
 * Date & Time support for internal RTC of MPC52xx
 *****************************************************************************/
/*#define	DEBUG*/

#include <common.h>
#include <command.h>
#include <rtc.h>

#if defined(CONFIG_CMD_DATE)

/*****************************************************************************
 * this structure should be defined in mpc5200.h ...
 *****************************************************************************/
typedef struct rtc5200 {
	volatile ulong	tsr;	/* MBAR+0x800: time set register */
	volatile ulong	dsr;	/* MBAR+0x804: data set register */
	volatile ulong	nysr;	/* MBAR+0x808: new year and stopwatch register */
	volatile ulong	aier;	/* MBAR+0x80C: alarm and interrupt enable register */
	volatile ulong	ctr;	/* MBAR+0x810: current time register */
	volatile ulong	cdr;	/* MBAR+0x814: current data register */
	volatile ulong	asir;	/* MBAR+0x818: alarm and stopwatch interupt register */
	volatile ulong	piber;	/* MBAR+0x81C: periodic interrupt and bus error register */
	volatile ulong	trdr;	/* MBAR+0x820: test register/divides register */
} RTC5200;

#define	RTC_SET		0x02000000
#define	RTC_PAUSE	0x01000000

/*****************************************************************************
 * get time
 *****************************************************************************/
int rtc_get (struct rtc_time *tmp)
{
	RTC5200	*rtc = (RTC5200 *) (CONFIG_SYS_MBAR+0x800);
	ulong time, date, time2;

	/* read twice to avoid getting a funny time when the second is just changing */
	do {
		time = rtc->ctr;
		date = rtc->cdr;
		time2 = rtc->ctr;
	} while (time != time2);

	tmp->tm_year	= date & 0xfff;
	tmp->tm_mon		= (date >> 24) & 0xf;
	tmp->tm_mday	= (date >> 16) & 0x1f;
	tmp->tm_wday	= (date >> 21) & 7;
	/* sunday is 7 in 5200 but 0 in rtc_time */
	if (tmp->tm_wday == 7)
		tmp->tm_wday = 0;
	tmp->tm_hour	= (time >> 16) & 0x1f;
	tmp->tm_min		= (time >> 8) & 0x3f;
	tmp->tm_sec		= time & 0x3f;

	debug ( "Get DATE: %4d-%02d-%02d (wday=%d)  TIME: %2d:%02d:%02d\n",
		tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday,
		tmp->tm_hour, tmp->tm_min, tmp->tm_sec);

	return 0;
}

/*****************************************************************************
 * set time
 *****************************************************************************/
int rtc_set (struct rtc_time *tmp)
{
	RTC5200	*rtc = (RTC5200 *) (CONFIG_SYS_MBAR+0x800);
	ulong time, date, year;

	debug ( "Set DATE: %4d-%02d-%02d (wday=%d)  TIME: %2d:%02d:%02d\n",
		tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday,
		tmp->tm_hour, tmp->tm_min, tmp->tm_sec);

	time = (tmp->tm_hour << 16) | (tmp->tm_min << 8) | tmp->tm_sec;
	date = (tmp->tm_mon << 16) | tmp->tm_mday;
	if (tmp->tm_wday == 0)
		date |= (7 << 8);
	else
		date |= (tmp->tm_wday << 8);
	year = tmp->tm_year;

	/* mask unwanted bits that might show up when rtc_time is corrupt */
	time &= 0x001f3f3f;
	date &= 0x001f071f;
	year &= 0x00000fff;

	/* pause and set the RTC */
	rtc->nysr = year;
	rtc->dsr = date | RTC_PAUSE;
	udelay (1000);
	rtc->dsr = date | RTC_PAUSE | RTC_SET;
	udelay (1000);
	rtc->dsr = date | RTC_PAUSE;
	udelay (1000);
	rtc->dsr = date;
	udelay (1000);

	rtc->tsr = time | RTC_PAUSE;
	udelay (1000);
	rtc->tsr = time | RTC_PAUSE | RTC_SET;
	udelay (1000);
	rtc->tsr = time | RTC_PAUSE;
	udelay (1000);
	rtc->tsr = time;
	udelay (1000);

	return 0;
}

/*****************************************************************************
 * reset rtc circuit
 *****************************************************************************/
void rtc_reset (void)
{
	return;	/* nothing to do */
}

#endif