1/*
2 * Machine dependent access functions for RTC registers.
3 */
4#ifndef _ASM_MC146818RTC_H
5#define _ASM_MC146818RTC_H
6
7#include <asm/rtc.h>
8
9#define RTC_ALWAYS_BCD	1
10
11#undef  RTC_IRQ
12#define RTC_IRQ		0
13
14#if defined(__sh3__)
15#define RTC_PORT(n)		(R64CNT+(n)*2)
16#define CMOS_READ(addr)		__CMOS_READ(addr,b)
17#define CMOS_WRITE(val,addr)	__CMOS_WRITE(val,addr,b)
18
19#elif defined(__SH4__)
20#define RTC_PORT(n)		(R64CNT+(n)*4)
21#define CMOS_READ(addr)		__CMOS_READ(addr,w)
22#define CMOS_WRITE(val,addr)	__CMOS_WRITE(val,addr,w)
23#endif
24
25#define __CMOS_READ(addr, s) ({						\
26	unsigned char val=0, rcr1, rcr2, r64cnt, retry;			\
27	switch(addr) {							\
28		case RTC_SECONDS:					\
29			val = ctrl_inb(RSECCNT);			\
30			break;						\
31		case RTC_SECONDS_ALARM:					\
32			val = ctrl_inb(RSECAR);				\
33			break;						\
34		case RTC_MINUTES:					\
35			val = ctrl_inb(RMINCNT);			\
36			break;						\
37		case RTC_MINUTES_ALARM:					\
38			val = ctrl_inb(RMINAR);				\
39			break;						\
40		case RTC_HOURS:						\
41			val = ctrl_inb(RHRCNT);				\
42			break;						\
43		case RTC_HOURS_ALARM:					\
44			val = ctrl_inb(RHRAR);				\
45			break;						\
46		case RTC_DAY_OF_WEEK:					\
47			val = ctrl_inb(RWKCNT);				\
48			break;						\
49		case RTC_DAY_OF_MONTH:					\
50			val = ctrl_inb(RDAYCNT);			\
51			break;						\
52		case RTC_MONTH:						\
53			val = ctrl_inb(RMONCNT);			\
54			break;						\
55		case RTC_YEAR:						\
56			val = ctrl_in##s(RYRCNT);			\
57			break;						\
58		case RTC_REG_A: /* RTC_FREQ_SELECT */			\
59			rcr2 = ctrl_inb(RCR2);				\
60			val = (rcr2 & RCR2_PESMASK) >> 4;		\
61			rcr1 = ctrl_inb(RCR1);				\
62			rcr1 = (rcr1 & (RCR1_CIE | RCR1_AIE)) | RCR1_AF;\
63			retry = 0;					\
64			do {						\
65				ctrl_outb(rcr1, RCR1); /* clear CF */	\
66				r64cnt = ctrl_inb(R64CNT);		\
67			} while((ctrl_inb(RCR1) & RCR1_CF) && retry++ < 1000);\
68			r64cnt ^= RTC_BIT_INVERTED;			\
69			if(r64cnt == 0x7f || r64cnt == 0)		\
70				val |= RTC_UIP;				\
71			break;						\
72		case RTC_REG_B:	/* RTC_CONTROL */			\
73			rcr1 = ctrl_inb(RCR1);				\
74			rcr2 = ctrl_inb(RCR2);				\
75			if(rcr1 & RCR1_CIE)	val |= RTC_UIE;		\
76			if(rcr1 & RCR1_AIE)	val |= RTC_AIE;		\
77			if(rcr2 & RCR2_PESMASK)	val |= RTC_PIE;		\
78			if(!(rcr2 & RCR2_START))val |= RTC_SET;		\
79			val |= RTC_24H;					\
80			break;						\
81		case RTC_REG_C:	/* RTC_INTR_FLAGS */			\
82			rcr1 = ctrl_inb(RCR1);				\
83			rcr1 &= ~(RCR1_CF | RCR1_AF);			\
84			ctrl_outb(rcr1, RCR1);				\
85			rcr2 = ctrl_inb(RCR2);				\
86			rcr2 &= ~RCR2_PEF;				\
87			ctrl_outb(rcr2, RCR2);				\
88			break;						\
89		case RTC_REG_D:	/* RTC_VALID */				\
90			/* Always valid ... */				\
91			val = RTC_VRT;					\
92			break;						\
93		default:						\
94			break;						\
95	}								\
96	val;								\
97})
98
99#define __CMOS_WRITE(val, addr, s) ({					\
100	unsigned char rcr1,rcr2;					\
101	switch(addr) {							\
102		case RTC_SECONDS:					\
103			ctrl_outb(val, RSECCNT);			\
104			break;						\
105		case RTC_SECONDS_ALARM:					\
106			ctrl_outb(val, RSECAR);				\
107			break;						\
108		case RTC_MINUTES:					\
109			ctrl_outb(val, RMINCNT);			\
110			break;						\
111		case RTC_MINUTES_ALARM:					\
112			ctrl_outb(val, RMINAR);				\
113			break;						\
114		case RTC_HOURS:						\
115			ctrl_outb(val, RHRCNT);				\
116			break;						\
117		case RTC_HOURS_ALARM:					\
118			ctrl_outb(val, RHRAR);				\
119			break;						\
120		case RTC_DAY_OF_WEEK:					\
121			ctrl_outb(val, RWKCNT);				\
122			break;						\
123		case RTC_DAY_OF_MONTH:					\
124			ctrl_outb(val, RDAYCNT);			\
125			break;						\
126		case RTC_MONTH:						\
127			ctrl_outb(val, RMONCNT);			\
128			break;						\
129		case RTC_YEAR:						\
130			ctrl_out##s((ctrl_in##s(RYRCNT) & 0xff00) | (val & 0xff), RYRCNT);\
131			break;						\
132		case RTC_REG_A: /* RTC_FREQ_SELECT */			\
133			rcr2 = ctrl_inb(RCR2);				\
134			if((val & RTC_DIV_CTL) == RTC_DIV_RESET2)	\
135				rcr2 |= RCR2_RESET;			\
136			ctrl_outb(rcr2, RCR2);				\
137			break;						\
138		case RTC_REG_B:	/* RTC_CONTROL */			\
139			rcr1 = (ctrl_inb(RCR1) & 0x99) | RCR1_AF;	\
140			if(val & RTC_AIE) rcr1 |= RCR1_AIE;		\
141			else              rcr1 &= ~RCR1_AIE;		\
142			if(val & RTC_UIE) rcr1 |= RCR1_CIE;		\
143			else              rcr1 &= ~RCR1_CIE;		\
144			ctrl_outb(rcr1, RCR1);				\
145			rcr2 = ctrl_inb(RCR2);				\
146			if(val & RTC_SET) rcr2 &= ~RCR2_START;		\
147			else              rcr2 |= RCR2_START;		\
148			ctrl_outb(rcr2, RCR2);				\
149			break;						\
150		case RTC_REG_C:	/* RTC_INTR_FLAGS */			\
151			break;						\
152		case RTC_REG_D:	/* RTC_VALID */				\
153			break;						\
154		default:						\
155			break;						\
156	}								\
157})
158#endif /* _ASM_MC146818RTC_H */
159