xref: /minix3/minix/drivers/clock/readclock/arch/earm/omap_rtc.c (revision 433d6423c39e34ec4b79c950597bb2d236f886be)
1*433d6423SLionel Sambuc #include <minix/syslib.h>
2*433d6423SLionel Sambuc #include <minix/drvlib.h>
3*433d6423SLionel Sambuc #include <minix/log.h>
4*433d6423SLionel Sambuc #include <minix/mmio.h>
5*433d6423SLionel Sambuc #include <minix/clkconf.h>
6*433d6423SLionel Sambuc #include <minix/sysutil.h>
7*433d6423SLionel Sambuc #include <minix/board.h>
8*433d6423SLionel Sambuc 
9*433d6423SLionel Sambuc #include <sys/mman.h>
10*433d6423SLionel Sambuc #include <sys/types.h>
11*433d6423SLionel Sambuc 
12*433d6423SLionel Sambuc #include <stdio.h>
13*433d6423SLionel Sambuc #include <stdlib.h>
14*433d6423SLionel Sambuc #include <stdarg.h>
15*433d6423SLionel Sambuc #include <string.h>
16*433d6423SLionel Sambuc #include <errno.h>
17*433d6423SLionel Sambuc #include <assert.h>
18*433d6423SLionel Sambuc #include <time.h>
19*433d6423SLionel Sambuc 
20*433d6423SLionel Sambuc #include "omap_rtc.h"
21*433d6423SLionel Sambuc #include "readclock.h"
22*433d6423SLionel Sambuc 
23*433d6423SLionel Sambuc /* defines the set of register */
24*433d6423SLionel Sambuc 
25*433d6423SLionel Sambuc typedef struct omap_rtc_registers
26*433d6423SLionel Sambuc {
27*433d6423SLionel Sambuc 	vir_bytes RTC_SS_SECONDS_REG;
28*433d6423SLionel Sambuc 	vir_bytes RTC_SS_MINUTES_REG;
29*433d6423SLionel Sambuc 	vir_bytes RTC_SS_HOURS_REG;
30*433d6423SLionel Sambuc 	vir_bytes RTC_SS_DAYS_REG;
31*433d6423SLionel Sambuc 	vir_bytes RTC_SS_MONTHS_REG;
32*433d6423SLionel Sambuc 	vir_bytes RTC_SS_YEARS_REG;
33*433d6423SLionel Sambuc 	vir_bytes RTC_SS_WEEKS_REG;
34*433d6423SLionel Sambuc 	vir_bytes RTC_SS_ALARM_SECONDS_REG;
35*433d6423SLionel Sambuc 	vir_bytes RTC_SS_ALARM_MINUTES_REG;
36*433d6423SLionel Sambuc 	vir_bytes RTC_SS_ALARM_HOURS_REG;
37*433d6423SLionel Sambuc 	vir_bytes RTC_SS_ALARM_DAYS_REG;
38*433d6423SLionel Sambuc 	vir_bytes RTC_SS_ALARM_MONTHS_REG;
39*433d6423SLionel Sambuc 	vir_bytes RTC_SS_ALARM_YEARS_REG;
40*433d6423SLionel Sambuc 	vir_bytes RTC_SS_RTC_CTRL_REG;
41*433d6423SLionel Sambuc 	vir_bytes RTC_SS_RTC_STATUS_REG;
42*433d6423SLionel Sambuc 	vir_bytes RTC_SS_RTC_INTERRUPTS_REG;
43*433d6423SLionel Sambuc 	vir_bytes RTC_SS_RTC_COMP_LSB_REG;
44*433d6423SLionel Sambuc 	vir_bytes RTC_SS_RTC_COMP_MSB_REG;
45*433d6423SLionel Sambuc 	vir_bytes RTC_SS_RTC_OSC_REG;
46*433d6423SLionel Sambuc 	vir_bytes RTC_SS_RTC_SCRATCH0_REG;
47*433d6423SLionel Sambuc 	vir_bytes RTC_SS_RTC_SCRATCH1_REG;
48*433d6423SLionel Sambuc 	vir_bytes RTC_SS_RTC_SCRATCH2_REG;
49*433d6423SLionel Sambuc 	vir_bytes RTC_SS_KICK0R;
50*433d6423SLionel Sambuc 	vir_bytes RTC_SS_KICK1R;
51*433d6423SLionel Sambuc 	vir_bytes RTC_SS_RTC_REVISION;
52*433d6423SLionel Sambuc 	vir_bytes RTC_SS_RTC_SYSCONFIG;
53*433d6423SLionel Sambuc 	vir_bytes RTC_SS_RTC_IRQWAKEEN;
54*433d6423SLionel Sambuc 	vir_bytes RTC_SS_ALARM2_SECONDS_REG;
55*433d6423SLionel Sambuc 	vir_bytes RTC_SS_ALARM2_MINUTES_REG;
56*433d6423SLionel Sambuc 	vir_bytes RTC_SS_ALARM2_HOURS_REG;
57*433d6423SLionel Sambuc 	vir_bytes RTC_SS_ALARM2_DAYS_REG;
58*433d6423SLionel Sambuc 	vir_bytes RTC_SS_ALARM2_MONTHS_REG;
59*433d6423SLionel Sambuc 	vir_bytes RTC_SS_ALARM2_YEARS_REG;
60*433d6423SLionel Sambuc 	vir_bytes RTC_SS_RTC_PMIC;
61*433d6423SLionel Sambuc 	vir_bytes RTC_SS_RTC_DEBOUNCE;
62*433d6423SLionel Sambuc } omap_rtc_registers_t;
63*433d6423SLionel Sambuc 
64*433d6423SLionel Sambuc typedef struct omap_rtc_clock
65*433d6423SLionel Sambuc {
66*433d6423SLionel Sambuc 	enum rtc_clock_type
67*433d6423SLionel Sambuc 	{ am335x } clock_type;
68*433d6423SLionel Sambuc 	phys_bytes mr_base;
69*433d6423SLionel Sambuc 	phys_bytes mr_size;
70*433d6423SLionel Sambuc 	vir_bytes mapped_addr;
71*433d6423SLionel Sambuc 	omap_rtc_registers_t *regs;
72*433d6423SLionel Sambuc } omap_rtc_clock_t;
73*433d6423SLionel Sambuc 
74*433d6423SLionel Sambuc /* Define the registers for each chip */
75*433d6423SLionel Sambuc 
76*433d6423SLionel Sambuc static omap_rtc_registers_t am335x_rtc_regs = {
77*433d6423SLionel Sambuc 	.RTC_SS_SECONDS_REG = AM335X_RTC_SS_SECONDS_REG,
78*433d6423SLionel Sambuc 	.RTC_SS_MINUTES_REG = AM335X_RTC_SS_MINUTES_REG,
79*433d6423SLionel Sambuc 	.RTC_SS_HOURS_REG = AM335X_RTC_SS_HOURS_REG,
80*433d6423SLionel Sambuc 	.RTC_SS_DAYS_REG = AM335X_RTC_SS_DAYS_REG,
81*433d6423SLionel Sambuc 	.RTC_SS_MONTHS_REG = AM335X_RTC_SS_MONTHS_REG,
82*433d6423SLionel Sambuc 	.RTC_SS_YEARS_REG = AM335X_RTC_SS_YEARS_REG,
83*433d6423SLionel Sambuc 	.RTC_SS_WEEKS_REG = AM335X_RTC_SS_WEEKS_REG,
84*433d6423SLionel Sambuc 	.RTC_SS_ALARM_SECONDS_REG = AM335X_RTC_SS_ALARM_SECONDS_REG,
85*433d6423SLionel Sambuc 	.RTC_SS_ALARM_MINUTES_REG = AM335X_RTC_SS_ALARM_MINUTES_REG,
86*433d6423SLionel Sambuc 	.RTC_SS_ALARM_HOURS_REG = AM335X_RTC_SS_ALARM_HOURS_REG,
87*433d6423SLionel Sambuc 	.RTC_SS_ALARM_DAYS_REG = AM335X_RTC_SS_ALARM_DAYS_REG,
88*433d6423SLionel Sambuc 	.RTC_SS_ALARM_MONTHS_REG = AM335X_RTC_SS_ALARM_MONTHS_REG,
89*433d6423SLionel Sambuc 	.RTC_SS_ALARM_YEARS_REG = AM335X_RTC_SS_ALARM_YEARS_REG,
90*433d6423SLionel Sambuc 	.RTC_SS_RTC_CTRL_REG = AM335X_RTC_SS_RTC_CTRL_REG,
91*433d6423SLionel Sambuc 	.RTC_SS_RTC_STATUS_REG = AM335X_RTC_SS_RTC_STATUS_REG,
92*433d6423SLionel Sambuc 	.RTC_SS_RTC_INTERRUPTS_REG = AM335X_RTC_SS_RTC_INTERRUPTS_REG,
93*433d6423SLionel Sambuc 	.RTC_SS_RTC_COMP_LSB_REG = AM335X_RTC_SS_RTC_COMP_LSB_REG,
94*433d6423SLionel Sambuc 	.RTC_SS_RTC_COMP_MSB_REG = AM335X_RTC_SS_RTC_COMP_MSB_REG,
95*433d6423SLionel Sambuc 	.RTC_SS_RTC_OSC_REG = AM335X_RTC_SS_RTC_OSC_REG,
96*433d6423SLionel Sambuc 	.RTC_SS_RTC_SCRATCH0_REG = AM335X_RTC_SS_RTC_SCRATCH0_REG,
97*433d6423SLionel Sambuc 	.RTC_SS_RTC_SCRATCH1_REG = AM335X_RTC_SS_RTC_SCRATCH1_REG,
98*433d6423SLionel Sambuc 	.RTC_SS_RTC_SCRATCH2_REG = AM335X_RTC_SS_RTC_SCRATCH2_REG,
99*433d6423SLionel Sambuc 	.RTC_SS_KICK0R = AM335X_RTC_SS_KICK0R,
100*433d6423SLionel Sambuc 	.RTC_SS_KICK1R = AM335X_RTC_SS_KICK1R,
101*433d6423SLionel Sambuc 	.RTC_SS_RTC_REVISION = AM335X_RTC_SS_RTC_REVISION,
102*433d6423SLionel Sambuc 	.RTC_SS_RTC_SYSCONFIG = AM335X_RTC_SS_RTC_SYSCONFIG,
103*433d6423SLionel Sambuc 	.RTC_SS_RTC_IRQWAKEEN = AM335X_RTC_SS_RTC_IRQWAKEEN,
104*433d6423SLionel Sambuc 	.RTC_SS_ALARM2_SECONDS_REG = AM335X_RTC_SS_ALARM2_SECONDS_REG,
105*433d6423SLionel Sambuc 	.RTC_SS_ALARM2_MINUTES_REG = AM335X_RTC_SS_ALARM2_MINUTES_REG,
106*433d6423SLionel Sambuc 	.RTC_SS_ALARM2_HOURS_REG = AM335X_RTC_SS_ALARM2_HOURS_REG,
107*433d6423SLionel Sambuc 	.RTC_SS_ALARM2_DAYS_REG = AM335X_RTC_SS_ALARM2_DAYS_REG,
108*433d6423SLionel Sambuc 	.RTC_SS_ALARM2_MONTHS_REG = AM335X_RTC_SS_ALARM2_MONTHS_REG,
109*433d6423SLionel Sambuc 	.RTC_SS_ALARM2_YEARS_REG = AM335X_RTC_SS_ALARM2_YEARS_REG,
110*433d6423SLionel Sambuc 	.RTC_SS_RTC_PMIC = AM335X_RTC_SS_RTC_PMIC,
111*433d6423SLionel Sambuc 	.RTC_SS_RTC_DEBOUNCE = AM335X_RTC_SS_RTC_DEBOUNCE
112*433d6423SLionel Sambuc };
113*433d6423SLionel Sambuc 
114*433d6423SLionel Sambuc static omap_rtc_clock_t rtc = {
115*433d6423SLionel Sambuc 	am335x, AM335X_RTC_SS_BASE, AM335X_RTC_SS_SIZE, 0, &am335x_rtc_regs
116*433d6423SLionel Sambuc };
117*433d6423SLionel Sambuc 
118*433d6423SLionel Sambuc /* used for logging */
119*433d6423SLionel Sambuc static struct log log = {
120*433d6423SLionel Sambuc 	.name = "omap_rtc",
121*433d6423SLionel Sambuc 	.log_level = LEVEL_INFO,
122*433d6423SLionel Sambuc 	.log_func = default_log
123*433d6423SLionel Sambuc };
124*433d6423SLionel Sambuc 
125*433d6423SLionel Sambuc static u32_t use_count = 0;
126*433d6423SLionel Sambuc static u32_t pwr_off_in_progress = 0;
127*433d6423SLionel Sambuc 
128*433d6423SLionel Sambuc static void omap_rtc_unlock(void);
129*433d6423SLionel Sambuc static void omap_rtc_lock(void);
130*433d6423SLionel Sambuc static int omap_rtc_clkconf(void);
131*433d6423SLionel Sambuc 
132*433d6423SLionel Sambuc /* Helper Functions for Register Access */
133*433d6423SLionel Sambuc #define reg_read(a) (*(volatile uint32_t *)(rtc.mapped_addr + a))
134*433d6423SLionel Sambuc #define reg_write(a,v) (*(volatile uint32_t *)(rtc.mapped_addr + a) = (v))
135*433d6423SLionel Sambuc #define reg_set_bit(a,v) reg_write((a), reg_read((a)) | (1<<v))
136*433d6423SLionel Sambuc #define reg_clear_bit(a,v) reg_write((a), reg_read((a)) & ~(1<<v))
137*433d6423SLionel Sambuc #define RTC_IS_BUSY (reg_read(rtc.regs->RTC_SS_RTC_STATUS_REG) & (1<<RTC_BUSY_BIT))
138*433d6423SLionel Sambuc 
139*433d6423SLionel Sambuc /* When the RTC is running, writes should not happen when the RTC is busy.
140*433d6423SLionel Sambuc  * This macro waits until the RTC is free before doing the write.
141*433d6423SLionel Sambuc  */
142*433d6423SLionel Sambuc #define safe_reg_write(a,v) do { while (RTC_IS_BUSY) {micro_delay(1);} reg_write((a),(v)); } while (0)
143*433d6423SLionel Sambuc #define safe_reg_set_bit(a,v) safe_reg_write((a), reg_read((a)) | (1<<v))
144*433d6423SLionel Sambuc #define safe_reg_clear_bit(a,v) safe_reg_write((a), reg_read((a)) & ~(1<<v))
145*433d6423SLionel Sambuc 
146*433d6423SLionel Sambuc static void
omap_rtc_unlock(void)147*433d6423SLionel Sambuc omap_rtc_unlock(void)
148*433d6423SLionel Sambuc {
149*433d6423SLionel Sambuc 	/* Specific bit patterns need to be written to specific registers in a
150*433d6423SLionel Sambuc 	 * specific order to enable writing to RTC_SS registers.
151*433d6423SLionel Sambuc 	 */
152*433d6423SLionel Sambuc 	reg_write(rtc.regs->RTC_SS_KICK0R, AM335X_RTC_SS_KICK0R_UNLOCK_MASK);
153*433d6423SLionel Sambuc 	reg_write(rtc.regs->RTC_SS_KICK1R, AM335X_RTC_SS_KICK1R_UNLOCK_MASK);
154*433d6423SLionel Sambuc }
155*433d6423SLionel Sambuc 
156*433d6423SLionel Sambuc static void
omap_rtc_lock(void)157*433d6423SLionel Sambuc omap_rtc_lock(void)
158*433d6423SLionel Sambuc {
159*433d6423SLionel Sambuc 	/* Write garbage to the KICK registers to enable write protect. */
160*433d6423SLionel Sambuc 	reg_write(rtc.regs->RTC_SS_KICK0R, AM335X_RTC_SS_KICK0R_LOCK_MASK);
161*433d6423SLionel Sambuc 	reg_write(rtc.regs->RTC_SS_KICK1R, AM335X_RTC_SS_KICK1R_LOCK_MASK);
162*433d6423SLionel Sambuc }
163*433d6423SLionel Sambuc 
164*433d6423SLionel Sambuc static int
omap_rtc_clkconf(void)165*433d6423SLionel Sambuc omap_rtc_clkconf(void)
166*433d6423SLionel Sambuc {
167*433d6423SLionel Sambuc 	int r;
168*433d6423SLionel Sambuc 
169*433d6423SLionel Sambuc 	/* Configure the clocks need to run the RTC */
170*433d6423SLionel Sambuc 	r = clkconf_init();
171*433d6423SLionel Sambuc 	if (r != OK) {
172*433d6423SLionel Sambuc 		return r;
173*433d6423SLionel Sambuc 	}
174*433d6423SLionel Sambuc 
175*433d6423SLionel Sambuc 	r = clkconf_set(CM_RTC_RTC_CLKCTRL, 0xffffffff,
176*433d6423SLionel Sambuc 	    CM_RTC_RTC_CLKCTRL_MASK);
177*433d6423SLionel Sambuc 	if (r != OK) {
178*433d6423SLionel Sambuc 		return r;
179*433d6423SLionel Sambuc 	}
180*433d6423SLionel Sambuc 
181*433d6423SLionel Sambuc 	r = clkconf_set(CM_RTC_CLKSTCTRL, 0xffffffff, CM_RTC_CLKSTCTRL_MASK);
182*433d6423SLionel Sambuc 	if (r != OK) {
183*433d6423SLionel Sambuc 		return r;
184*433d6423SLionel Sambuc 	}
185*433d6423SLionel Sambuc 
186*433d6423SLionel Sambuc 	r = clkconf_release();
187*433d6423SLionel Sambuc 	if (r != OK) {
188*433d6423SLionel Sambuc 		return r;
189*433d6423SLionel Sambuc 	}
190*433d6423SLionel Sambuc 
191*433d6423SLionel Sambuc 	return OK;
192*433d6423SLionel Sambuc }
193*433d6423SLionel Sambuc 
194*433d6423SLionel Sambuc int
omap_rtc_init(void)195*433d6423SLionel Sambuc omap_rtc_init(void)
196*433d6423SLionel Sambuc {
197*433d6423SLionel Sambuc 	int r;
198*433d6423SLionel Sambuc 	int rtc_rev, major, minor;
199*433d6423SLionel Sambuc 	struct minix_mem_range mr;
200*433d6423SLionel Sambuc 
201*433d6423SLionel Sambuc 	struct machine  machine ;
202*433d6423SLionel Sambuc 	sys_getmachine(&machine);
203*433d6423SLionel Sambuc 
204*433d6423SLionel Sambuc 	if(! BOARD_IS_BB(machine.board_id)){
205*433d6423SLionel Sambuc 		/* Only the am335x (BeagleBone & BeagleBone Black) is supported ATM.
206*433d6423SLionel Sambuc 		 * The dm37xx (BeagleBoard-xM) doesn't have a real time clock
207*433d6423SLionel Sambuc 		 * built-in. Instead, it uses the RTC on the PMIC. A driver for
208*433d6423SLionel Sambuc 		 * the BeagleBoard-xM's PMIC still needs to be developed.
209*433d6423SLionel Sambuc 		 */
210*433d6423SLionel Sambuc 		log_warn(&log, "unsupported processor\n");
211*433d6423SLionel Sambuc 		return ENOSYS;
212*433d6423SLionel Sambuc 	}
213*433d6423SLionel Sambuc 
214*433d6423SLionel Sambuc 	if (pwr_off_in_progress)
215*433d6423SLionel Sambuc 		return EINVAL;
216*433d6423SLionel Sambuc 
217*433d6423SLionel Sambuc 	use_count++;
218*433d6423SLionel Sambuc 	if (rtc.mapped_addr != 0) {
219*433d6423SLionel Sambuc 		/* already intialized */
220*433d6423SLionel Sambuc 		return OK;
221*433d6423SLionel Sambuc 	}
222*433d6423SLionel Sambuc 
223*433d6423SLionel Sambuc 	/* Enable Clocks */
224*433d6423SLionel Sambuc 	r = omap_rtc_clkconf();
225*433d6423SLionel Sambuc 	if (r != OK) {
226*433d6423SLionel Sambuc 		log_warn(&log, "Failed to enable clocks for RTC.\n");
227*433d6423SLionel Sambuc 		return r;
228*433d6423SLionel Sambuc 	}
229*433d6423SLionel Sambuc 
230*433d6423SLionel Sambuc 	/*
231*433d6423SLionel Sambuc 	 * Map RTC_SS Registers
232*433d6423SLionel Sambuc 	 */
233*433d6423SLionel Sambuc 
234*433d6423SLionel Sambuc 	/* Configure memory access */
235*433d6423SLionel Sambuc 	mr.mr_base = rtc.mr_base;	/* start addr */
236*433d6423SLionel Sambuc 	mr.mr_limit = mr.mr_base + rtc.mr_size;	/* end addr */
237*433d6423SLionel Sambuc 
238*433d6423SLionel Sambuc 	/* ask for privileges to access the RTC_SS memory range */
239*433d6423SLionel Sambuc 	if (sys_privctl(SELF, SYS_PRIV_ADD_MEM, &mr) != OK) {
240*433d6423SLionel Sambuc 		log_warn(&log,
241*433d6423SLionel Sambuc 		    "Unable to obtain RTC memory range privileges.");
242*433d6423SLionel Sambuc 		return EPERM;
243*433d6423SLionel Sambuc 	}
244*433d6423SLionel Sambuc 
245*433d6423SLionel Sambuc 	/* map the memory into this process */
246*433d6423SLionel Sambuc 	rtc.mapped_addr = (vir_bytes) vm_map_phys(SELF,
247*433d6423SLionel Sambuc 	    (void *) rtc.mr_base, rtc.mr_size);
248*433d6423SLionel Sambuc 	if (rtc.mapped_addr == (vir_bytes) MAP_FAILED) {
249*433d6423SLionel Sambuc 		log_warn(&log, "Unable to map RTC registers\n");
250*433d6423SLionel Sambuc 		return EPERM;
251*433d6423SLionel Sambuc 	}
252*433d6423SLionel Sambuc 
253*433d6423SLionel Sambuc 	rtc_rev = reg_read(rtc.regs->RTC_SS_RTC_REVISION);
254*433d6423SLionel Sambuc 	major = (rtc_rev & 0x0700) >> 8;
255*433d6423SLionel Sambuc 	minor = (rtc_rev & 0x001f);
256*433d6423SLionel Sambuc 	log_debug(&log, "omap rtc rev %d.%d\n", major, minor);
257*433d6423SLionel Sambuc 
258*433d6423SLionel Sambuc 	/* Disable register write protect */
259*433d6423SLionel Sambuc 	omap_rtc_unlock();
260*433d6423SLionel Sambuc 
261*433d6423SLionel Sambuc 	/* Set NOIDLE */
262*433d6423SLionel Sambuc 	reg_write(rtc.regs->RTC_SS_RTC_SYSCONFIG, (1 << NOIDLE_BIT));
263*433d6423SLionel Sambuc 
264*433d6423SLionel Sambuc 	/* Enable 32kHz clock */
265*433d6423SLionel Sambuc 	reg_set_bit(rtc.regs->RTC_SS_RTC_OSC_REG, EN_32KCLK_BIT);
266*433d6423SLionel Sambuc 
267*433d6423SLionel Sambuc 	/* Setting the stop bit starts the RTC running */
268*433d6423SLionel Sambuc 	reg_set_bit(rtc.regs->RTC_SS_RTC_CTRL_REG, RTC_STOP_BIT);
269*433d6423SLionel Sambuc 
270*433d6423SLionel Sambuc 	/* Re-enable Write Protection */
271*433d6423SLionel Sambuc 	omap_rtc_lock();
272*433d6423SLionel Sambuc 
273*433d6423SLionel Sambuc 	log_debug(&log, "OMAP RTC Initialized\n");
274*433d6423SLionel Sambuc 
275*433d6423SLionel Sambuc 	return OK;
276*433d6423SLionel Sambuc }
277*433d6423SLionel Sambuc 
278*433d6423SLionel Sambuc /*
279*433d6423SLionel Sambuc  * These are the ranges used by the real time clock and struct tm.
280*433d6423SLionel Sambuc  *
281*433d6423SLionel Sambuc  * Field		OMAP RTC		struct tm
282*433d6423SLionel Sambuc  * -----		--------		---------
283*433d6423SLionel Sambuc  * seconds		0 to 59 (Mask 0x7f)	0 to 59 (60 for leap seconds)
284*433d6423SLionel Sambuc  * minutes		0 to 59 (Mask 0x7f)	0 to 59
285*433d6423SLionel Sambuc  * hours		0 to 23	(Mask 0x3f)	0 to 23
286*433d6423SLionel Sambuc  * day			1 to 31	(Mask 0x3f)	1 to 31
287*433d6423SLionel Sambuc  * month		1 to 12	(Mask 0x1f)	0 to 11
288*433d6423SLionel Sambuc  * year			last 2 digits of year	X + 1900
289*433d6423SLionel Sambuc  */
290*433d6423SLionel Sambuc 
291*433d6423SLionel Sambuc int
omap_rtc_get_time(struct tm * t,int flags)292*433d6423SLionel Sambuc omap_rtc_get_time(struct tm *t, int flags)
293*433d6423SLionel Sambuc {
294*433d6423SLionel Sambuc 	int r;
295*433d6423SLionel Sambuc 
296*433d6423SLionel Sambuc 	if (pwr_off_in_progress)
297*433d6423SLionel Sambuc 		return EINVAL;
298*433d6423SLionel Sambuc 
299*433d6423SLionel Sambuc 	memset(t, '\0', sizeof(struct tm));
300*433d6423SLionel Sambuc 
301*433d6423SLionel Sambuc 	/* Read and Convert BCD to binary (default RTC mode). */
302*433d6423SLionel Sambuc 	t->tm_sec = bcd_to_dec(reg_read(rtc.regs->RTC_SS_SECONDS_REG) & 0x7f);
303*433d6423SLionel Sambuc 	t->tm_min = bcd_to_dec(reg_read(rtc.regs->RTC_SS_MINUTES_REG) & 0x7f);
304*433d6423SLionel Sambuc 	t->tm_hour = bcd_to_dec(reg_read(rtc.regs->RTC_SS_HOURS_REG) & 0x3f);
305*433d6423SLionel Sambuc 	t->tm_mday = bcd_to_dec(reg_read(rtc.regs->RTC_SS_DAYS_REG) & 0x3f);
306*433d6423SLionel Sambuc 	t->tm_mon =
307*433d6423SLionel Sambuc 	    bcd_to_dec(reg_read(rtc.regs->RTC_SS_MONTHS_REG) & 0x1f) - 1;
308*433d6423SLionel Sambuc 	t->tm_year =
309*433d6423SLionel Sambuc 	    bcd_to_dec(reg_read(rtc.regs->RTC_SS_YEARS_REG) & 0xff) + 100;
310*433d6423SLionel Sambuc 
311*433d6423SLionel Sambuc 	if (t->tm_year == 100) {
312*433d6423SLionel Sambuc 		/* Cold start - no date/time set - default to 2013-01-01 */
313*433d6423SLionel Sambuc 		t->tm_sec = 0;
314*433d6423SLionel Sambuc 		t->tm_min = 0;
315*433d6423SLionel Sambuc 		t->tm_hour = 0;
316*433d6423SLionel Sambuc 		t->tm_mday = 1;
317*433d6423SLionel Sambuc 		t->tm_mon = 0;
318*433d6423SLionel Sambuc 		t->tm_year = 113;
319*433d6423SLionel Sambuc 
320*433d6423SLionel Sambuc 		omap_rtc_set_time(t, RTCDEV_NOFLAGS);
321*433d6423SLionel Sambuc 	}
322*433d6423SLionel Sambuc 
323*433d6423SLionel Sambuc 	return OK;
324*433d6423SLionel Sambuc }
325*433d6423SLionel Sambuc 
326*433d6423SLionel Sambuc int
omap_rtc_set_time(struct tm * t,int flags)327*433d6423SLionel Sambuc omap_rtc_set_time(struct tm *t, int flags)
328*433d6423SLionel Sambuc {
329*433d6423SLionel Sambuc 	int r;
330*433d6423SLionel Sambuc 
331*433d6423SLionel Sambuc 	if (pwr_off_in_progress)
332*433d6423SLionel Sambuc 		return EINVAL;
333*433d6423SLionel Sambuc 
334*433d6423SLionel Sambuc 	/* Disable Write Protection */
335*433d6423SLionel Sambuc 	omap_rtc_unlock();
336*433d6423SLionel Sambuc 
337*433d6423SLionel Sambuc 	/* Write the date/time to the RTC registers. */
338*433d6423SLionel Sambuc 	safe_reg_write(rtc.regs->RTC_SS_SECONDS_REG,
339*433d6423SLionel Sambuc 	    (dec_to_bcd(t->tm_sec) & 0x7f));
340*433d6423SLionel Sambuc 	safe_reg_write(rtc.regs->RTC_SS_MINUTES_REG,
341*433d6423SLionel Sambuc 	    (dec_to_bcd(t->tm_min) & 0x7f));
342*433d6423SLionel Sambuc 	safe_reg_write(rtc.regs->RTC_SS_HOURS_REG,
343*433d6423SLionel Sambuc 	    (dec_to_bcd(t->tm_hour) & 0x3f));
344*433d6423SLionel Sambuc 	safe_reg_write(rtc.regs->RTC_SS_DAYS_REG,
345*433d6423SLionel Sambuc 	    (dec_to_bcd(t->tm_mday) & 0x3f));
346*433d6423SLionel Sambuc 	safe_reg_write(rtc.regs->RTC_SS_MONTHS_REG,
347*433d6423SLionel Sambuc 	    (dec_to_bcd(t->tm_mon + 1) & 0x1f));
348*433d6423SLionel Sambuc 	safe_reg_write(rtc.regs->RTC_SS_YEARS_REG,
349*433d6423SLionel Sambuc 	    (dec_to_bcd(t->tm_year % 100) & 0xff));
350*433d6423SLionel Sambuc 
351*433d6423SLionel Sambuc 	/* Re-enable Write Protection */
352*433d6423SLionel Sambuc 	omap_rtc_lock();
353*433d6423SLionel Sambuc 
354*433d6423SLionel Sambuc 	return OK;
355*433d6423SLionel Sambuc }
356*433d6423SLionel Sambuc 
357*433d6423SLionel Sambuc int
omap_rtc_pwr_off(void)358*433d6423SLionel Sambuc omap_rtc_pwr_off(void)
359*433d6423SLionel Sambuc {
360*433d6423SLionel Sambuc 	int r;
361*433d6423SLionel Sambuc 	struct tm t;
362*433d6423SLionel Sambuc 
363*433d6423SLionel Sambuc 	if (pwr_off_in_progress)
364*433d6423SLionel Sambuc 		return EINVAL;
365*433d6423SLionel Sambuc 
366*433d6423SLionel Sambuc 	/* wait until 3 seconds can be added without overflowing tm_sec */
367*433d6423SLionel Sambuc 	do {
368*433d6423SLionel Sambuc 		omap_rtc_get_time(&t, RTCDEV_NOFLAGS);
369*433d6423SLionel Sambuc 		micro_delay(250000);
370*433d6423SLionel Sambuc 	} while (t.tm_sec >= 57);
371*433d6423SLionel Sambuc 
372*433d6423SLionel Sambuc 	/* set the alarm for 3 seconds from now */
373*433d6423SLionel Sambuc 	t.tm_sec += 3;
374*433d6423SLionel Sambuc 
375*433d6423SLionel Sambuc 	/* Disable register write protect */
376*433d6423SLionel Sambuc 	omap_rtc_unlock();
377*433d6423SLionel Sambuc 
378*433d6423SLionel Sambuc 	/* enable power-off via ALARM2 by setting the PWR_ENABLE_EN bit. */
379*433d6423SLionel Sambuc 	safe_reg_set_bit(rtc.regs->RTC_SS_RTC_PMIC, PWR_ENABLE_EN_BIT);
380*433d6423SLionel Sambuc 
381*433d6423SLionel Sambuc 	/* Write the date/time to the RTC registers. */
382*433d6423SLionel Sambuc 	safe_reg_write(rtc.regs->RTC_SS_ALARM2_SECONDS_REG,
383*433d6423SLionel Sambuc 	    (dec_to_bcd(t.tm_sec) & 0x7f));
384*433d6423SLionel Sambuc 	safe_reg_write(rtc.regs->RTC_SS_ALARM2_MINUTES_REG,
385*433d6423SLionel Sambuc 	    (dec_to_bcd(t.tm_min) & 0x7f));
386*433d6423SLionel Sambuc 	safe_reg_write(rtc.regs->RTC_SS_ALARM2_HOURS_REG,
387*433d6423SLionel Sambuc 	    (dec_to_bcd(t.tm_hour) & 0x3f));
388*433d6423SLionel Sambuc 	safe_reg_write(rtc.regs->RTC_SS_ALARM2_DAYS_REG,
389*433d6423SLionel Sambuc 	    (dec_to_bcd(t.tm_mday) & 0x3f));
390*433d6423SLionel Sambuc 	safe_reg_write(rtc.regs->RTC_SS_ALARM2_MONTHS_REG,
391*433d6423SLionel Sambuc 	    (dec_to_bcd(t.tm_mon + 1) & 0x1f));
392*433d6423SLionel Sambuc 	safe_reg_write(rtc.regs->RTC_SS_ALARM2_YEARS_REG,
393*433d6423SLionel Sambuc 	    (dec_to_bcd(t.tm_year % 100) & 0xff));
394*433d6423SLionel Sambuc 
395*433d6423SLionel Sambuc 	/* enable interrupt to trigger POWER_EN to go low when alarm2 hits. */
396*433d6423SLionel Sambuc 	safe_reg_set_bit(rtc.regs->RTC_SS_RTC_INTERRUPTS_REG, IT_ALARM2_BIT);
397*433d6423SLionel Sambuc 
398*433d6423SLionel Sambuc 	/* pause the realtime clock. the kernel will enable it when safe. */
399*433d6423SLionel Sambuc 	reg_clear_bit(rtc.regs->RTC_SS_RTC_CTRL_REG, RTC_STOP_BIT);
400*433d6423SLionel Sambuc 
401*433d6423SLionel Sambuc 	/* Set this flag to block all other operations so that the clock isn't
402*433d6423SLionel Sambuc 	 * accidentally re-startered and so write protect isn't re-enabled. */
403*433d6423SLionel Sambuc 	pwr_off_in_progress = 1;
404*433d6423SLionel Sambuc 
405*433d6423SLionel Sambuc 	/* Make the kernel's job easier by not re-enabling write protection */
406*433d6423SLionel Sambuc 
407*433d6423SLionel Sambuc 	return OK;
408*433d6423SLionel Sambuc }
409*433d6423SLionel Sambuc 
410*433d6423SLionel Sambuc void
omap_rtc_exit(void)411*433d6423SLionel Sambuc omap_rtc_exit(void)
412*433d6423SLionel Sambuc {
413*433d6423SLionel Sambuc 	use_count--;
414*433d6423SLionel Sambuc 	if (use_count == 0) {
415*433d6423SLionel Sambuc 		vm_unmap_phys(SELF, (void *) rtc.mapped_addr, rtc.mr_size);
416*433d6423SLionel Sambuc 		rtc.mapped_addr = 0;
417*433d6423SLionel Sambuc 	}
418*433d6423SLionel Sambuc 	log_debug(&log, "Exiting\n");
419*433d6423SLionel Sambuc }
420