528be9bb1f3bf9c204b9df79db63b4a057316621
[profile/mobile/platform/kernel/u-boot-tm1.git] / arch / arm / cpu / armv7 / sc9630 / rtc-sprd.c
1 /*
2  * An RTC device/driver
3  * Copyright (C) 2011 Spreadtrum Communication Inc 
4  * Author: Mark Yang<markyang@spreadtrum.com>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License version 2 as
8  * published by the Free Software Foundation.
9  */
10
11 #include <common.h>
12 #include "asm/arch/bits.h"
13 #include "asm/arch/rtc_reg_v3.h"
14 #include "asm/arch/adi_hal_internal.h"
15
16 #define CLEAR_RTC_INT(mask) \
17         do{ ANA_REG_SET(ANA_RTC_INT_CLR, mask); \
18                 while(ANA_REG_GET(ANA_RTC_INT_RSTS) & mask); \
19         }while(0)
20
21 void rtc_clean_all_int(void)
22 {
23         CLEAR_RTC_INT(RTC_INT_ALL_MSK);
24 }
25 #define mdelay(_ms) udelay(_ms*1000)
26 #define SPRD_RTC_POWEROFF_ALARM                 (0x1 << 8)
27
28 static inline unsigned get_sec(void)
29 {
30     unsigned sec, sec_bak;
31     sec = ANA_REG_GET(ANA_RTC_SEC_CNT) & RTC_SEC_MASK;
32     do{
33         sec_bak = ANA_REG_GET(ANA_RTC_SEC_CNT) & RTC_SEC_MASK;
34         if(sec_bak == sec)
35           break;
36         else
37           sec = sec_bak;
38     }while(1);
39
40     return sec;
41 }
42 static inline unsigned get_min(void)
43 {
44     unsigned min, min_bak;
45     min = ANA_REG_GET(ANA_RTC_MIN_CNT) & RTC_MIN_MASK;
46     do{
47         min_bak = ANA_REG_GET(ANA_RTC_MIN_CNT) & RTC_MIN_MASK;
48         if(min_bak == min)
49           break;
50         else
51           min = min_bak;
52     }while(1);
53
54     return min;
55 }
56 static inline unsigned get_hour(void)
57 {
58     unsigned hour, hour_bak;
59     hour = ANA_REG_GET(ANA_RTC_HOUR_CNT) & RTC_HOUR_MASK;
60     do{
61         hour_bak = ANA_REG_GET(ANA_RTC_HOUR_CNT) & RTC_HOUR_MASK;
62         if(hour_bak == hour)
63           break;
64         else
65           hour = hour_bak;
66     }while(1);
67
68     return hour;
69 }
70 static inline unsigned get_day(void)
71 {
72     unsigned day, day_bak;
73     day = ANA_REG_GET(ANA_RTC_DAY_CNT) & RTC_DAY_MASK;
74     do{
75         day_bak = ANA_REG_GET(ANA_RTC_DAY_CNT) & RTC_DAY_MASK;
76         if(day == day_bak)
77           break;
78         else
79           day = day_bak;
80     }while(1);
81     
82     return day;
83 }
84
85 unsigned long sprd_rtc_get_sec(void)
86 {
87         unsigned sec, min, hour, day;
88         unsigned first = 0, second = 0;
89
90         do {
91                 sec = get_sec();
92                 min = get_min();
93                 hour = get_hour();
94                 day = get_day();
95
96                 second = ((((day*24) + hour)*60 + min)*60 + sec);
97                 if((second - first) == 0)
98                         break;
99                 first = second;
100         }while(1);
101         return first;
102 }
103 void sprd_rtc_set_alarm_sec(unsigned long secs);
104 void sprd_rtc_set_sec(unsigned long secs)
105 {
106         unsigned sec, min, hour, day;
107     unsigned set_mask = 0, int_rsts;
108         unsigned long temp;
109
110         sec = secs % 60;
111         temp = (secs - sec)/60;
112         min = temp%60;
113         temp = (temp - min)/60;
114         hour = temp%24;
115         temp = (temp - hour)/24;
116         day = temp;
117
118
119     ANA_REG_OR(ANA_RTC_INT_CLR, RTC_UPD_TIME_MASK);
120
121     if(sec != get_sec()){
122         ANA_REG_SET(ANA_RTC_SEC_UPDATE, sec);
123         set_mask |= RTC_SEC_ACK_BIT;
124     }
125     if(min != get_min()){
126         ANA_REG_SET(ANA_RTC_MIN_UPDATE, min);
127         set_mask |= RTC_MIN_ACK_BIT;
128     }
129     if(hour != get_hour()){
130         ANA_REG_SET(ANA_RTC_HOUR_UPDATE, hour);
131         set_mask |= RTC_HOUR_ACK_BIT;
132     }
133     if(day != get_day()){
134         ANA_REG_SET(ANA_RTC_DAY_UPDATE, day);
135         set_mask |= RTC_DAY_ACK_BIT;
136     }
137
138     //wait till all update done
139
140     do{
141         int_rsts = ANA_REG_GET(ANA_RTC_INT_RSTS) & RTC_UPD_TIME_MASK;
142
143         if(set_mask == int_rsts)
144           break;
145     }while(1);
146     ANA_REG_OR(ANA_RTC_INT_CLR, RTC_UPD_TIME_MASK);
147
148         return;
149 }
150
151 unsigned long sprd_rtc_get_alarm_sec(void)
152 {
153         unsigned sec, min, hour, day;
154         day = ANA_REG_GET(ANA_RTC_DAY_ALM) & RTC_DAY_MASK;
155         hour = ANA_REG_GET(ANA_RTC_HOUR_ALM) & RTC_HOUR_MASK;
156         min = ANA_REG_GET(ANA_RTC_MIN_ALM) & RTC_MIN_MASK;
157         sec = ANA_REG_GET(ANA_RTC_SEC_ALM) & RTC_SEC_MASK;
158
159         return ((((day*24) + hour)*60 + min)*60 + sec);
160 }
161 void sprd_rtc_set_alarm_sec(unsigned long secs)
162 {
163         unsigned sec, min, hour, day;
164         unsigned long temp;
165         sec = secs % 60;
166         temp = (secs - sec)/60;
167         min = temp%60;
168         temp = (temp - min)/60;
169         hour = temp%24;
170         temp = (temp - hour)/24;
171         day = temp;
172         ANA_REG_SET(ANA_RTC_SEC_ALM, sec);
173         ANA_REG_SET(ANA_RTC_MIN_ALM, min);
174         ANA_REG_SET(ANA_RTC_HOUR_ALM, hour);
175         ANA_REG_SET(ANA_RTC_DAY_ALM, day);
176
177         return;
178 }
179
180
181 int sprd_clean_rtc(void)
182 {
183         int err;
184         ANA_REG_AND(ANA_RTC_INT_EN, ~(RTC_INT_ALL_MSK)); // disable all interrupt
185
186         ANA_REG_OR(ANA_REG_GLB_ARM_MODULE_EN, BIT_ANA_RTC_EN); //rtc enable
187         ANA_REG_OR(ANA_REG_GLB_RTC_CLK_EN,    BIT_RTC_RTC_EN); //rtc rtc clock enable
188
189         CLEAR_RTC_INT(RTC_INT_ALL_MSK);
190         sprd_rtc_set_sec(0);
191         sprd_rtc_set_alarm_sec(0);
192         printf("now time sec %lu\n", sprd_rtc_get_sec());
193         printf("now alarm sec %lu\n", sprd_rtc_get_alarm_sec());
194         return 0;
195 }
196 void sprd_rtc_init(void)
197 {
198         ANA_REG_OR(ANA_REG_GLB_ARM_MODULE_EN, BIT_ANA_RTC_EN); //rtc enable
199         ANA_REG_OR(ANA_REG_GLB_RTC_CLK_EN,    BIT_RTC_RTC_EN); //rtc rtc clock enable
200 }
201
202 int sprd_is_poweroff_alarm(void)
203 {
204         int poweroff_alarm;
205
206         poweroff_alarm = ANA_REG_GET(ANA_RTC_SPG_VALUE);
207         if (poweroff_alarm & SPRD_RTC_POWEROFF_ALARM) {
208                 ANA_REG_SET(ANA_RTC_SPG_UPD,
209                         poweroff_alarm & (~SPRD_RTC_POWEROFF_ALARM));
210                 return 1;
211         } else {
212                 return 0;
213         }
214 }