6
6
*
7
7
*/
8
8
9
+ #include <linux/clk.h>
9
10
#include <linux/delay.h>
10
11
#include <linux/init.h>
11
12
#include <linux/io.h>
40
41
#define RTC_CALIB_MASK 0x1FFFFF
41
42
#define RTC_ALRM_MASK BIT(1)
42
43
#define RTC_MSEC 1000
44
+ #define RTC_FR_MASK 0xF0000
45
+ #define RTC_FR_MAX_TICKS 16
46
+ #define RTC_PPB 1000000000LL
47
+ #define RTC_MIN_OFFSET -32768000
48
+ #define RTC_MAX_OFFSET 32767000
43
49
44
50
struct xlnx_rtc_dev {
45
51
struct rtc_device * rtc ;
46
52
void __iomem * reg_base ;
47
53
int alarm_irq ;
48
54
int sec_irq ;
49
- unsigned int calibval ;
55
+ struct clk * rtc_clk ;
56
+ unsigned int freq ;
50
57
};
51
58
52
59
static int xlnx_rtc_set_time (struct device * dev , struct rtc_time * tm )
@@ -61,13 +68,6 @@ static int xlnx_rtc_set_time(struct device *dev, struct rtc_time *tm)
61
68
*/
62
69
new_time = rtc_tm_to_time64 (tm ) + 1 ;
63
70
64
- /*
65
- * Writing into calibration register will clear the Tick Counter and
66
- * force the next second to be signaled exactly in 1 second period
67
- */
68
- xrtcdev -> calibval &= RTC_CALIB_MASK ;
69
- writel (xrtcdev -> calibval , (xrtcdev -> reg_base + RTC_CALIB_WR ));
70
-
71
71
writel (new_time , xrtcdev -> reg_base + RTC_SET_TM_WR );
72
72
73
73
/*
@@ -173,15 +173,76 @@ static void xlnx_init_rtc(struct xlnx_rtc_dev *xrtcdev)
173
173
rtc_ctrl = readl (xrtcdev -> reg_base + RTC_CTRL );
174
174
rtc_ctrl |= RTC_BATT_EN ;
175
175
writel (rtc_ctrl , xrtcdev -> reg_base + RTC_CTRL );
176
+ }
176
177
177
- /*
178
- * Based on crystal freq of 33.330 KHz
179
- * set the seconds counter and enable, set fractions counter
180
- * to default value suggested as per design spec
181
- * to correct RTC delay in frequency over period of time.
178
+ static int xlnx_rtc_read_offset (struct device * dev , long * offset )
179
+ {
180
+ struct xlnx_rtc_dev * xrtcdev = dev_get_drvdata (dev );
181
+ unsigned long long rtc_ppb = RTC_PPB ;
182
+ unsigned int tick_mult = do_div (rtc_ppb , xrtcdev -> freq );
183
+ unsigned int calibval ;
184
+ long offset_val ;
185
+
186
+ calibval = readl (xrtcdev -> reg_base + RTC_CALIB_RD );
187
+ /* Offset with seconds ticks */
188
+ offset_val = calibval & RTC_TICK_MASK ;
189
+ offset_val = offset_val - RTC_CALIB_DEF ;
190
+ offset_val = offset_val * tick_mult ;
191
+
192
+ /* Offset with fractional ticks */
193
+ if (calibval & RTC_FR_EN )
194
+ offset_val += ((calibval & RTC_FR_MASK ) >> RTC_FR_DATSHIFT )
195
+ * (tick_mult / RTC_FR_MAX_TICKS );
196
+ * offset = offset_val ;
197
+
198
+ return 0 ;
199
+ }
200
+
201
+ static int xlnx_rtc_set_offset (struct device * dev , long offset )
202
+ {
203
+ struct xlnx_rtc_dev * xrtcdev = dev_get_drvdata (dev );
204
+ unsigned long long rtc_ppb = RTC_PPB ;
205
+ unsigned int tick_mult = do_div (rtc_ppb , xrtcdev -> freq );
206
+ unsigned char fract_tick ;
207
+ unsigned int calibval ;
208
+ short int max_tick ;
209
+ int fract_offset ;
210
+
211
+ if (offset < RTC_MIN_OFFSET || offset > RTC_MAX_OFFSET )
212
+ return - ERANGE ;
213
+
214
+ /* Number ticks for given offset */
215
+ max_tick = div_s64_rem (offset , tick_mult , & fract_offset );
216
+
217
+ /* Number fractional ticks for given offset */
218
+ if (fract_offset ) {
219
+ if (fract_offset < 0 ) {
220
+ fract_offset = fract_offset + tick_mult ;
221
+ max_tick -- ;
222
+ }
223
+ if (fract_offset > (tick_mult / RTC_FR_MAX_TICKS )) {
224
+ for (fract_tick = 1 ; fract_tick < 16 ; fract_tick ++ ) {
225
+ if (fract_offset <=
226
+ (fract_tick *
227
+ (tick_mult / RTC_FR_MAX_TICKS )))
228
+ break ;
229
+ }
230
+ }
231
+ }
232
+
233
+ /* Zynqmp RTC uses second and fractional tick
234
+ * counters for compensation
182
235
*/
183
- xrtcdev -> calibval &= RTC_CALIB_MASK ;
184
- writel (xrtcdev -> calibval , (xrtcdev -> reg_base + RTC_CALIB_WR ));
236
+ calibval = max_tick + RTC_CALIB_DEF ;
237
+
238
+ if (fract_tick )
239
+ calibval |= RTC_FR_EN ;
240
+
241
+ calibval |= (fract_tick << RTC_FR_DATSHIFT );
242
+
243
+ writel (calibval , (xrtcdev -> reg_base + RTC_CALIB_WR ));
244
+
245
+ return 0 ;
185
246
}
186
247
187
248
static const struct rtc_class_ops xlnx_rtc_ops = {
@@ -190,6 +251,8 @@ static const struct rtc_class_ops xlnx_rtc_ops = {
190
251
.read_alarm = xlnx_rtc_read_alarm ,
191
252
.set_alarm = xlnx_rtc_set_alarm ,
192
253
.alarm_irq_enable = xlnx_rtc_alarm_irq_enable ,
254
+ .read_offset = xlnx_rtc_read_offset ,
255
+ .set_offset = xlnx_rtc_set_offset ,
193
256
};
194
257
195
258
static irqreturn_t xlnx_rtc_interrupt (int irq , void * id )
@@ -255,10 +318,22 @@ static int xlnx_rtc_probe(struct platform_device *pdev)
255
318
return ret ;
256
319
}
257
320
258
- ret = of_property_read_u32 (pdev -> dev .of_node , "calibration" ,
259
- & xrtcdev -> calibval );
260
- if (ret )
261
- xrtcdev -> calibval = RTC_CALIB_DEF ;
321
+ /* Getting the rtc_clk info */
322
+ xrtcdev -> rtc_clk = devm_clk_get_optional (& pdev -> dev , "rtc_clk" );
323
+ if (IS_ERR (xrtcdev -> rtc_clk )) {
324
+ if (PTR_ERR (xrtcdev -> rtc_clk ) != - EPROBE_DEFER )
325
+ dev_warn (& pdev -> dev , "Device clock not found.\n" );
326
+ }
327
+ xrtcdev -> freq = clk_get_rate (xrtcdev -> rtc_clk );
328
+ if (!xrtcdev -> freq ) {
329
+ ret = of_property_read_u32 (pdev -> dev .of_node , "calibration" ,
330
+ & xrtcdev -> freq );
331
+ if (ret )
332
+ xrtcdev -> freq = RTC_CALIB_DEF ;
333
+ }
334
+ ret = readl (xrtcdev -> reg_base + RTC_CALIB_RD );
335
+ if (!ret )
336
+ writel (xrtcdev -> freq , (xrtcdev -> reg_base + RTC_CALIB_WR ));
262
337
263
338
xlnx_init_rtc (xrtcdev );
264
339
0 commit comments