1 /*
2 * Copyright 2008-2012 Freescale Semiconductor Inc.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
6 * * Redistributions of source code must retain the above copyright
7 * notice, this list of conditions and the following disclaimer.
8 * * Redistributions in binary form must reproduce the above copyright
9 * notice, this list of conditions and the following disclaimer in the
10 * documentation and/or other materials provided with the distribution.
11 * * Neither the name of Freescale Semiconductor nor the
12 * names of its contributors may be used to endorse or promote products
13 * derived from this software without specific prior written permission.
14 *
15 *
16 * ALTERNATIVELY, this software may be distributed under the terms of the
17 * GNU General Public License ("GPL") as published by the Free Software
18 * Foundation, either version 2 of that License or (at your option) any
19 * later version.
20 *
21 * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
22 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
23 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
24 * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
25 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
26 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
28 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
30 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 */
32
33
34 /******************************************************************************
35 @File fm_rtc.c
36
37 @Description FM RTC driver implementation.
38
39 @Cautions None
40 *//***************************************************************************/
41 #include <linux/math64.h>
42 #include "error_ext.h"
43 #include "debug_ext.h"
44 #include "string_ext.h"
45 #include "part_ext.h"
46 #include "xx_ext.h"
47 #include "ncsw_ext.h"
48
49 #include "fm_rtc.h"
50 #include "fm_common.h"
51
52
53
54 /*****************************************************************************/
CheckInitParameters(t_FmRtc * p_Rtc)55 static t_Error CheckInitParameters(t_FmRtc *p_Rtc)
56 {
57 struct rtc_cfg *p_RtcDriverParam = p_Rtc->p_RtcDriverParam;
58 int i;
59
60 if ((p_RtcDriverParam->src_clk != E_FMAN_RTC_SOURCE_CLOCK_EXTERNAL) &&
61 (p_RtcDriverParam->src_clk != E_FMAN_RTC_SOURCE_CLOCK_SYSTEM) &&
62 (p_RtcDriverParam->src_clk != E_FMAN_RTC_SOURCE_CLOCK_OSCILATOR))
63 RETURN_ERROR(MAJOR, E_INVALID_CLOCK, ("Source clock undefined"));
64
65 if (p_Rtc->outputClockDivisor == 0)
66 {
67 RETURN_ERROR(MAJOR, E_INVALID_VALUE,
68 ("Divisor for output clock (should be positive)"));
69 }
70
71 for (i=0; i < FM_RTC_NUM_OF_ALARMS; i++)
72 {
73 if ((p_RtcDriverParam->alarm_polarity[i] != E_FMAN_RTC_ALARM_POLARITY_ACTIVE_LOW) &&
74 (p_RtcDriverParam->alarm_polarity[i] != E_FMAN_RTC_ALARM_POLARITY_ACTIVE_HIGH))
75 {
76 RETURN_ERROR(MAJOR, E_INVALID_SELECTION, ("Alarm %d signal polarity", i));
77 }
78 }
79 for (i=0; i < FM_RTC_NUM_OF_EXT_TRIGGERS; i++)
80 {
81 if ((p_RtcDriverParam->trigger_polarity[i] != E_FMAN_RTC_TRIGGER_ON_FALLING_EDGE) &&
82 (p_RtcDriverParam->trigger_polarity[i] != E_FMAN_RTC_TRIGGER_ON_RISING_EDGE))
83 {
84 RETURN_ERROR(MAJOR, E_INVALID_SELECTION, ("Trigger %d signal polarity", i));
85 }
86 }
87
88 return E_OK;
89 }
90
91 /*****************************************************************************/
RtcExceptions(t_Handle h_FmRtc)92 static void RtcExceptions(t_Handle h_FmRtc)
93 {
94 t_FmRtc *p_Rtc = (t_FmRtc *)h_FmRtc;
95 struct rtc_regs *p_MemMap;
96 register uint32_t events;
97
98 ASSERT_COND(p_Rtc);
99 p_MemMap = p_Rtc->p_MemMap;
100
101 events = fman_rtc_check_and_clear_event(p_MemMap);
102 if (events & FMAN_RTC_TMR_TEVENT_ALM1)
103 {
104 if (p_Rtc->alarmParams[0].clearOnExpiration)
105 {
106 fman_rtc_set_timer_alarm_l(p_MemMap, 0, 0);
107 fman_rtc_disable_interupt(p_MemMap, FMAN_RTC_TMR_TEVENT_ALM1);
108 }
109 ASSERT_COND(p_Rtc->alarmParams[0].f_AlarmCallback);
110 p_Rtc->alarmParams[0].f_AlarmCallback(p_Rtc->h_App, 0);
111 }
112 if (events & FMAN_RTC_TMR_TEVENT_ALM2)
113 {
114 if (p_Rtc->alarmParams[1].clearOnExpiration)
115 {
116 fman_rtc_set_timer_alarm_l(p_MemMap, 1, 0);
117 fman_rtc_disable_interupt(p_MemMap, FMAN_RTC_TMR_TEVENT_ALM2);
118 }
119 ASSERT_COND(p_Rtc->alarmParams[1].f_AlarmCallback);
120 p_Rtc->alarmParams[1].f_AlarmCallback(p_Rtc->h_App, 1);
121 }
122 if (events & FMAN_RTC_TMR_TEVENT_PP1)
123 {
124 ASSERT_COND(p_Rtc->periodicPulseParams[0].f_PeriodicPulseCallback);
125 p_Rtc->periodicPulseParams[0].f_PeriodicPulseCallback(p_Rtc->h_App, 0);
126 }
127 if (events & FMAN_RTC_TMR_TEVENT_PP2)
128 {
129 ASSERT_COND(p_Rtc->periodicPulseParams[1].f_PeriodicPulseCallback);
130 p_Rtc->periodicPulseParams[1].f_PeriodicPulseCallback(p_Rtc->h_App, 1);
131 }
132 if (events & FMAN_RTC_TMR_TEVENT_ETS1)
133 {
134 ASSERT_COND(p_Rtc->externalTriggerParams[0].f_ExternalTriggerCallback);
135 p_Rtc->externalTriggerParams[0].f_ExternalTriggerCallback(p_Rtc->h_App, 0);
136 }
137 if (events & FMAN_RTC_TMR_TEVENT_ETS2)
138 {
139 ASSERT_COND(p_Rtc->externalTriggerParams[1].f_ExternalTriggerCallback);
140 p_Rtc->externalTriggerParams[1].f_ExternalTriggerCallback(p_Rtc->h_App, 1);
141 }
142 }
143
144
145 /*****************************************************************************/
FM_RTC_Config(t_FmRtcParams * p_FmRtcParam)146 t_Handle FM_RTC_Config(t_FmRtcParams *p_FmRtcParam)
147 {
148 t_FmRtc *p_Rtc;
149
150 SANITY_CHECK_RETURN_VALUE(p_FmRtcParam, E_NULL_POINTER, NULL);
151
152 /* Allocate memory for the FM RTC driver parameters */
153 p_Rtc = (t_FmRtc *)XX_Malloc(sizeof(t_FmRtc));
154 if (!p_Rtc)
155 {
156 REPORT_ERROR(MAJOR, E_NO_MEMORY, ("FM RTC driver structure"));
157 return NULL;
158 }
159
160 memset(p_Rtc, 0, sizeof(t_FmRtc));
161
162 /* Allocate memory for the FM RTC driver parameters */
163 p_Rtc->p_RtcDriverParam = (struct rtc_cfg *)XX_Malloc(sizeof(struct rtc_cfg));
164 if (!p_Rtc->p_RtcDriverParam)
165 {
166 REPORT_ERROR(MAJOR, E_NO_MEMORY, ("FM RTC driver parameters"));
167 XX_Free(p_Rtc);
168 return NULL;
169 }
170
171 memset(p_Rtc->p_RtcDriverParam, 0, sizeof(struct rtc_cfg));
172
173 /* Store RTC configuration parameters */
174 p_Rtc->h_Fm = p_FmRtcParam->h_Fm;
175
176 /* Set default RTC configuration parameters */
177 fman_rtc_defconfig(p_Rtc->p_RtcDriverParam);
178
179 p_Rtc->outputClockDivisor = DEFAULT_OUTPUT_CLOCK_DIVISOR;
180 p_Rtc->p_RtcDriverParam->bypass = DEFAULT_BYPASS;
181 p_Rtc->clockPeriodNanoSec = DEFAULT_CLOCK_PERIOD; /* 1 usec */
182
183
184 /* Store RTC parameters in the RTC control structure */
185 p_Rtc->p_MemMap = (struct rtc_regs *)UINT_TO_PTR(p_FmRtcParam->baseAddress);
186 p_Rtc->h_App = p_FmRtcParam->h_App;
187
188 return p_Rtc;
189 }
190
191 /*****************************************************************************/
FM_RTC_Init(t_Handle h_FmRtc)192 t_Error FM_RTC_Init(t_Handle h_FmRtc)
193 {
194 t_FmRtc *p_Rtc = (t_FmRtc *)h_FmRtc;
195 struct rtc_cfg *p_RtcDriverParam;
196 struct rtc_regs *p_MemMap;
197 uint32_t freqCompensation = 0;
198 uint64_t tmpDouble;
199 bool init_freq_comp = FALSE;
200
201 p_RtcDriverParam = p_Rtc->p_RtcDriverParam;
202 p_MemMap = p_Rtc->p_MemMap;
203
204 if (CheckInitParameters(p_Rtc)!=E_OK)
205 RETURN_ERROR(MAJOR, E_CONFLICT,
206 ("Init Parameters are not Valid"));
207
208 /* TODO check that no timestamping MACs are working in this stage. */
209
210 /* find source clock frequency in Mhz */
211 if (p_Rtc->p_RtcDriverParam->src_clk != E_FMAN_RTC_SOURCE_CLOCK_SYSTEM)
212 p_Rtc->srcClkFreqMhz = p_Rtc->p_RtcDriverParam->ext_src_clk_freq;
213 else
214 p_Rtc->srcClkFreqMhz = (uint32_t)(FmGetMacClockFreq(p_Rtc->h_Fm));
215
216 /* if timer in Master mode Initialize TMR_CTRL */
217 /* We want the counter (TMR_CNT) to count in nano-seconds */
218 if (!p_RtcDriverParam->timer_slave_mode && p_Rtc->p_RtcDriverParam->bypass)
219 p_Rtc->clockPeriodNanoSec = (1000 / p_Rtc->srcClkFreqMhz);
220 else
221 {
222 /* Initialize TMR_ADD with the initial frequency compensation value:
223 freqCompensation = (2^32 / frequency ratio) */
224 /* frequency ratio = sorce clock/rtc clock =
225 * (p_Rtc->srcClkFreqMhz*1000000))/ 1/(p_Rtc->clockPeriodNanoSec * 1000000000) */
226 init_freq_comp = TRUE;
227 freqCompensation = (uint32_t)DIV_CEIL(ACCUMULATOR_OVERFLOW * 1000,
228 p_Rtc->clockPeriodNanoSec * p_Rtc->srcClkFreqMhz);
229 }
230
231 /* check the legality of the relation between source and destination clocks */
232 /* should be larger than 1.0001 */
233 tmpDouble = 10000 * (uint64_t)p_Rtc->clockPeriodNanoSec * (uint64_t)p_Rtc->srcClkFreqMhz;
234 if ((tmpDouble) <= 10001)
235 RETURN_ERROR(MAJOR, E_CONFLICT,
236 ("Invalid relation between source and destination clocks. Should be larger than 1.0001"));
237
238 fman_rtc_init(p_RtcDriverParam,
239 p_MemMap,
240 FM_RTC_NUM_OF_ALARMS,
241 FM_RTC_NUM_OF_PERIODIC_PULSES,
242 FM_RTC_NUM_OF_EXT_TRIGGERS,
243 init_freq_comp,
244 freqCompensation,
245 p_Rtc->outputClockDivisor);
246
247 /* Register the FM RTC interrupt */
248 FmRegisterIntr(p_Rtc->h_Fm, e_FM_MOD_TMR, 0, e_FM_INTR_TYPE_NORMAL, RtcExceptions , p_Rtc);
249
250 /* Free parameters structures */
251 XX_Free(p_Rtc->p_RtcDriverParam);
252 p_Rtc->p_RtcDriverParam = NULL;
253
254 return E_OK;
255 }
256
257 /*****************************************************************************/
FM_RTC_Free(t_Handle h_FmRtc)258 t_Error FM_RTC_Free(t_Handle h_FmRtc)
259 {
260 t_FmRtc *p_Rtc = (t_FmRtc *)h_FmRtc;
261
262 SANITY_CHECK_RETURN_ERROR(p_Rtc, E_INVALID_HANDLE);
263
264 if (p_Rtc->p_RtcDriverParam)
265 {
266 XX_Free(p_Rtc->p_RtcDriverParam);
267 }
268 else
269 {
270 FM_RTC_Disable(h_FmRtc);
271 }
272
273 /* Unregister FM RTC interrupt */
274 FmUnregisterIntr(p_Rtc->h_Fm, e_FM_MOD_TMR, 0, e_FM_INTR_TYPE_NORMAL);
275 XX_Free(p_Rtc);
276
277 return E_OK;
278 }
279
280 /*****************************************************************************/
FM_RTC_ConfigSourceClock(t_Handle h_FmRtc,e_FmSrcClk srcClk,uint32_t freqInMhz)281 t_Error FM_RTC_ConfigSourceClock(t_Handle h_FmRtc,
282 e_FmSrcClk srcClk,
283 uint32_t freqInMhz)
284 {
285 t_FmRtc *p_Rtc = (t_FmRtc *)h_FmRtc;
286
287 SANITY_CHECK_RETURN_ERROR(p_Rtc, E_INVALID_HANDLE);
288 SANITY_CHECK_RETURN_ERROR(p_Rtc->p_RtcDriverParam, E_INVALID_STATE);
289
290 p_Rtc->p_RtcDriverParam->src_clk = (enum fman_src_clock)srcClk;
291 if (srcClk != e_FM_RTC_SOURCE_CLOCK_SYSTEM)
292 p_Rtc->p_RtcDriverParam->ext_src_clk_freq = freqInMhz;
293
294 return E_OK;
295 }
296
297 /*****************************************************************************/
FM_RTC_ConfigPeriod(t_Handle h_FmRtc,uint32_t period)298 t_Error FM_RTC_ConfigPeriod(t_Handle h_FmRtc, uint32_t period)
299 {
300 t_FmRtc *p_Rtc = (t_FmRtc *)h_FmRtc;
301
302 SANITY_CHECK_RETURN_ERROR(p_Rtc, E_INVALID_HANDLE);
303 SANITY_CHECK_RETURN_ERROR(p_Rtc->p_RtcDriverParam, E_INVALID_STATE);
304
305 p_Rtc->clockPeriodNanoSec = period;
306
307 return E_OK;
308 }
309
310 /*****************************************************************************/
FM_RTC_ConfigFrequencyBypass(t_Handle h_FmRtc,bool enabled)311 t_Error FM_RTC_ConfigFrequencyBypass(t_Handle h_FmRtc, bool enabled)
312 {
313 t_FmRtc *p_Rtc = (t_FmRtc *)h_FmRtc;
314
315 SANITY_CHECK_RETURN_ERROR(p_Rtc, E_INVALID_HANDLE);
316 SANITY_CHECK_RETURN_ERROR(p_Rtc->p_RtcDriverParam, E_INVALID_STATE);
317
318 p_Rtc->p_RtcDriverParam->bypass = enabled;
319
320 return E_OK;
321 }
322
323 /*****************************************************************************/
FM_RTC_ConfigInvertedInputClockPhase(t_Handle h_FmRtc,bool inverted)324 t_Error FM_RTC_ConfigInvertedInputClockPhase(t_Handle h_FmRtc, bool inverted)
325 {
326 t_FmRtc *p_Rtc = (t_FmRtc *)h_FmRtc;
327
328 SANITY_CHECK_RETURN_ERROR(p_Rtc, E_INVALID_HANDLE);
329 SANITY_CHECK_RETURN_ERROR(p_Rtc->p_RtcDriverParam, E_INVALID_STATE);
330
331 p_Rtc->p_RtcDriverParam->invert_input_clk_phase = inverted;
332
333 return E_OK;
334 }
335
336 /*****************************************************************************/
FM_RTC_ConfigInvertedOutputClockPhase(t_Handle h_FmRtc,bool inverted)337 t_Error FM_RTC_ConfigInvertedOutputClockPhase(t_Handle h_FmRtc, bool inverted)
338 {
339 t_FmRtc *p_Rtc = (t_FmRtc *)h_FmRtc;
340
341 SANITY_CHECK_RETURN_ERROR(p_Rtc, E_INVALID_HANDLE);
342 SANITY_CHECK_RETURN_ERROR(p_Rtc->p_RtcDriverParam, E_INVALID_STATE);
343
344 p_Rtc->p_RtcDriverParam->invert_output_clk_phase = inverted;
345
346 return E_OK;
347 }
348
349 /*****************************************************************************/
FM_RTC_ConfigOutputClockDivisor(t_Handle h_FmRtc,uint16_t divisor)350 t_Error FM_RTC_ConfigOutputClockDivisor(t_Handle h_FmRtc, uint16_t divisor)
351 {
352 t_FmRtc *p_Rtc = (t_FmRtc *)h_FmRtc;
353
354 SANITY_CHECK_RETURN_ERROR(p_Rtc, E_INVALID_HANDLE);
355 SANITY_CHECK_RETURN_ERROR(p_Rtc->p_RtcDriverParam, E_INVALID_STATE);
356
357 p_Rtc->outputClockDivisor = divisor;
358
359 return E_OK;
360 }
361
362 /*****************************************************************************/
FM_RTC_ConfigPulseRealignment(t_Handle h_FmRtc,bool enable)363 t_Error FM_RTC_ConfigPulseRealignment(t_Handle h_FmRtc, bool enable)
364 {
365 t_FmRtc *p_Rtc = (t_FmRtc *)h_FmRtc;
366
367 SANITY_CHECK_RETURN_ERROR(p_Rtc, E_INVALID_HANDLE);
368 SANITY_CHECK_RETURN_ERROR(p_Rtc->p_RtcDriverParam, E_INVALID_STATE);
369
370 p_Rtc->p_RtcDriverParam->pulse_realign = enable;
371
372 return E_OK;
373 }
374
375 /*****************************************************************************/
FM_RTC_ConfigAlarmPolarity(t_Handle h_FmRtc,uint8_t alarmId,e_FmRtcAlarmPolarity alarmPolarity)376 t_Error FM_RTC_ConfigAlarmPolarity(t_Handle h_FmRtc,
377 uint8_t alarmId,
378 e_FmRtcAlarmPolarity alarmPolarity)
379 {
380 t_FmRtc *p_Rtc = (t_FmRtc *)h_FmRtc;
381
382 SANITY_CHECK_RETURN_ERROR(p_Rtc, E_INVALID_HANDLE);
383 SANITY_CHECK_RETURN_ERROR(p_Rtc->p_RtcDriverParam, E_INVALID_STATE);
384
385 if (alarmId >= FM_RTC_NUM_OF_ALARMS)
386 RETURN_ERROR(MAJOR, E_INVALID_SELECTION, ("Alarm ID"));
387
388 p_Rtc->p_RtcDriverParam->alarm_polarity[alarmId] =
389 (enum fman_rtc_alarm_polarity)alarmPolarity;
390
391 return E_OK;
392 }
393
394 /*****************************************************************************/
FM_RTC_ConfigExternalTriggerPolarity(t_Handle h_FmRtc,uint8_t triggerId,e_FmRtcTriggerPolarity triggerPolarity)395 t_Error FM_RTC_ConfigExternalTriggerPolarity(t_Handle h_FmRtc,
396 uint8_t triggerId,
397 e_FmRtcTriggerPolarity triggerPolarity)
398 {
399 t_FmRtc *p_Rtc = (t_FmRtc *)h_FmRtc;
400
401 SANITY_CHECK_RETURN_ERROR(p_Rtc, E_INVALID_HANDLE);
402 SANITY_CHECK_RETURN_ERROR(p_Rtc->p_RtcDriverParam, E_INVALID_STATE);
403
404 if (triggerId >= FM_RTC_NUM_OF_EXT_TRIGGERS)
405 {
406 RETURN_ERROR(MAJOR, E_INVALID_SELECTION, ("External trigger ID"));
407 }
408
409 p_Rtc->p_RtcDriverParam->trigger_polarity[triggerId] =
410 (enum fman_rtc_trigger_polarity)triggerPolarity;
411
412 return E_OK;
413 }
414
415 /*****************************************************************************/
FM_RTC_Enable(t_Handle h_FmRtc,bool resetClock)416 t_Error FM_RTC_Enable(t_Handle h_FmRtc, bool resetClock)
417 {
418 t_FmRtc *p_Rtc = (t_FmRtc *)h_FmRtc;
419
420 SANITY_CHECK_RETURN_ERROR(p_Rtc, E_INVALID_HANDLE);
421 SANITY_CHECK_RETURN_ERROR(!p_Rtc->p_RtcDriverParam, E_INVALID_STATE);
422
423 fman_rtc_enable(p_Rtc->p_MemMap, resetClock);
424 return E_OK;
425 }
426
427 /*****************************************************************************/
FM_RTC_Disable(t_Handle h_FmRtc)428 t_Error FM_RTC_Disable(t_Handle h_FmRtc)
429 {
430 t_FmRtc *p_Rtc = (t_FmRtc *)h_FmRtc;
431
432 SANITY_CHECK_RETURN_ERROR(p_Rtc, E_INVALID_HANDLE);
433 SANITY_CHECK_RETURN_ERROR(!p_Rtc->p_RtcDriverParam, E_INVALID_STATE);
434
435 /* TODO A check must be added here, that no timestamping MAC's
436 * are working in this stage. */
437 fman_rtc_disable(p_Rtc->p_MemMap);
438
439 return E_OK;
440 }
441
442 /*****************************************************************************/
FM_RTC_SetClockOffset(t_Handle h_FmRtc,int64_t offset)443 t_Error FM_RTC_SetClockOffset(t_Handle h_FmRtc, int64_t offset)
444 {
445 t_FmRtc *p_Rtc = (t_FmRtc *)h_FmRtc;
446
447 SANITY_CHECK_RETURN_ERROR(p_Rtc, E_INVALID_HANDLE);
448 SANITY_CHECK_RETURN_ERROR(!p_Rtc->p_RtcDriverParam, E_INVALID_STATE);
449
450 fman_rtc_set_timer_offset(p_Rtc->p_MemMap, offset);
451 return E_OK;
452 }
453
454 /*****************************************************************************/
FM_RTC_SetAlarm(t_Handle h_FmRtc,t_FmRtcAlarmParams * p_FmRtcAlarmParams)455 t_Error FM_RTC_SetAlarm(t_Handle h_FmRtc, t_FmRtcAlarmParams *p_FmRtcAlarmParams)
456 {
457 t_FmRtc *p_Rtc = (t_FmRtc *)h_FmRtc;
458 uint64_t tmpAlarm;
459 bool enable = FALSE;
460
461 SANITY_CHECK_RETURN_ERROR(p_Rtc, E_INVALID_HANDLE);
462 SANITY_CHECK_RETURN_ERROR(!p_Rtc->p_RtcDriverParam, E_INVALID_STATE);
463
464 if (p_FmRtcAlarmParams->alarmId >= FM_RTC_NUM_OF_ALARMS)
465 {
466 RETURN_ERROR(MAJOR, E_INVALID_SELECTION, ("Alarm ID"));
467 }
468
469 if (p_FmRtcAlarmParams->alarmTime < p_Rtc->clockPeriodNanoSec)
470 RETURN_ERROR(MAJOR, E_INVALID_SELECTION,
471 ("Alarm time must be equal or larger than RTC period - %d nanoseconds",
472 p_Rtc->clockPeriodNanoSec));
473 tmpAlarm = p_FmRtcAlarmParams->alarmTime;
474 if (do_div(tmpAlarm, p_Rtc->clockPeriodNanoSec))
475 RETURN_ERROR(MAJOR, E_INVALID_SELECTION,
476 ("Alarm time must be a multiple of RTC period - %d nanoseconds",
477 p_Rtc->clockPeriodNanoSec));
478
479 if (p_FmRtcAlarmParams->f_AlarmCallback)
480 {
481 p_Rtc->alarmParams[p_FmRtcAlarmParams->alarmId].f_AlarmCallback = p_FmRtcAlarmParams->f_AlarmCallback;
482 p_Rtc->alarmParams[p_FmRtcAlarmParams->alarmId].clearOnExpiration = p_FmRtcAlarmParams->clearOnExpiration;
483 enable = TRUE;
484 }
485
486 fman_rtc_set_alarm(p_Rtc->p_MemMap, p_FmRtcAlarmParams->alarmId, (unsigned long)tmpAlarm, enable);
487
488 return E_OK;
489 }
490
491 /*****************************************************************************/
FM_RTC_SetPeriodicPulse(t_Handle h_FmRtc,t_FmRtcPeriodicPulseParams * p_FmRtcPeriodicPulseParams)492 t_Error FM_RTC_SetPeriodicPulse(t_Handle h_FmRtc, t_FmRtcPeriodicPulseParams *p_FmRtcPeriodicPulseParams)
493 {
494 t_FmRtc *p_Rtc = (t_FmRtc *)h_FmRtc;
495 bool enable = FALSE;
496 uint64_t tmpFiper;
497
498 SANITY_CHECK_RETURN_ERROR(p_Rtc, E_INVALID_HANDLE);
499 SANITY_CHECK_RETURN_ERROR(!p_Rtc->p_RtcDriverParam, E_INVALID_STATE);
500
501 if (p_FmRtcPeriodicPulseParams->periodicPulseId >= FM_RTC_NUM_OF_PERIODIC_PULSES)
502 {
503 RETURN_ERROR(MAJOR, E_INVALID_SELECTION, ("Periodic pulse ID"));
504 }
505 if (fman_rtc_is_enabled(p_Rtc->p_MemMap))
506 RETURN_ERROR(MAJOR, E_INVALID_SELECTION, ("Can't set Periodic pulse when RTC is enabled."));
507 if (p_FmRtcPeriodicPulseParams->periodicPulsePeriod < p_Rtc->clockPeriodNanoSec)
508 RETURN_ERROR(MAJOR, E_INVALID_SELECTION,
509 ("Periodic pulse must be equal or larger than RTC period - %d nanoseconds",
510 p_Rtc->clockPeriodNanoSec));
511 tmpFiper = p_FmRtcPeriodicPulseParams->periodicPulsePeriod;
512 if (do_div(tmpFiper, p_Rtc->clockPeriodNanoSec))
513 RETURN_ERROR(MAJOR, E_INVALID_SELECTION,
514 ("Periodic pulse must be a multiple of RTC period - %d nanoseconds",
515 p_Rtc->clockPeriodNanoSec));
516 if (tmpFiper & 0xffffffff00000000LL)
517 RETURN_ERROR(MAJOR, E_INVALID_SELECTION,
518 ("Periodic pulse/RTC Period must be smaller than 4294967296",
519 p_Rtc->clockPeriodNanoSec));
520
521 if (p_FmRtcPeriodicPulseParams->f_PeriodicPulseCallback)
522 {
523 p_Rtc->periodicPulseParams[p_FmRtcPeriodicPulseParams->periodicPulseId].f_PeriodicPulseCallback =
524 p_FmRtcPeriodicPulseParams->f_PeriodicPulseCallback;
525 enable = TRUE;
526 }
527 fman_rtc_set_periodic_pulse(p_Rtc->p_MemMap, p_FmRtcPeriodicPulseParams->periodicPulseId, (uint32_t)tmpFiper, enable);
528 return E_OK;
529 }
530
531 /*****************************************************************************/
FM_RTC_ClearPeriodicPulse(t_Handle h_FmRtc,uint8_t periodicPulseId)532 t_Error FM_RTC_ClearPeriodicPulse(t_Handle h_FmRtc, uint8_t periodicPulseId)
533 {
534 t_FmRtc *p_Rtc = (t_FmRtc *)h_FmRtc;
535
536 SANITY_CHECK_RETURN_ERROR(p_Rtc, E_INVALID_HANDLE);
537 SANITY_CHECK_RETURN_ERROR(!p_Rtc->p_RtcDriverParam, E_INVALID_STATE);
538
539 if (periodicPulseId >= FM_RTC_NUM_OF_PERIODIC_PULSES)
540 {
541 RETURN_ERROR(MAJOR, E_INVALID_SELECTION, ("Periodic pulse ID"));
542 }
543
544 p_Rtc->periodicPulseParams[periodicPulseId].f_PeriodicPulseCallback = NULL;
545 fman_rtc_clear_periodic_pulse(p_Rtc->p_MemMap, periodicPulseId);
546
547 return E_OK;
548 }
549
550 /*****************************************************************************/
FM_RTC_SetExternalTrigger(t_Handle h_FmRtc,t_FmRtcExternalTriggerParams * p_FmRtcExternalTriggerParams)551 t_Error FM_RTC_SetExternalTrigger(t_Handle h_FmRtc, t_FmRtcExternalTriggerParams *p_FmRtcExternalTriggerParams)
552 {
553 t_FmRtc *p_Rtc = (t_FmRtc *)h_FmRtc;
554 bool enable = FALSE;
555
556 SANITY_CHECK_RETURN_ERROR(p_Rtc, E_INVALID_HANDLE);
557 SANITY_CHECK_RETURN_ERROR(!p_Rtc->p_RtcDriverParam, E_INVALID_STATE);
558
559 if (p_FmRtcExternalTriggerParams->externalTriggerId >= FM_RTC_NUM_OF_EXT_TRIGGERS)
560 {
561 RETURN_ERROR(MAJOR, E_INVALID_SELECTION, ("External Trigger ID"));
562 }
563
564 if (p_FmRtcExternalTriggerParams->f_ExternalTriggerCallback)
565 {
566 p_Rtc->externalTriggerParams[p_FmRtcExternalTriggerParams->externalTriggerId].f_ExternalTriggerCallback = p_FmRtcExternalTriggerParams->f_ExternalTriggerCallback;
567 enable = TRUE;
568 }
569
570 fman_rtc_set_ext_trigger(p_Rtc->p_MemMap, p_FmRtcExternalTriggerParams->externalTriggerId, enable, p_FmRtcExternalTriggerParams->usePulseAsInput);
571 return E_OK;
572 }
573
574 /*****************************************************************************/
FM_RTC_ClearExternalTrigger(t_Handle h_FmRtc,uint8_t externalTriggerId)575 t_Error FM_RTC_ClearExternalTrigger(t_Handle h_FmRtc, uint8_t externalTriggerId)
576 {
577 t_FmRtc *p_Rtc = (t_FmRtc *)h_FmRtc;
578
579 SANITY_CHECK_RETURN_ERROR(p_Rtc, E_INVALID_HANDLE);
580 SANITY_CHECK_RETURN_ERROR(!p_Rtc->p_RtcDriverParam, E_INVALID_STATE);
581
582 if (externalTriggerId >= FM_RTC_NUM_OF_EXT_TRIGGERS)
583 RETURN_ERROR(MAJOR, E_INVALID_SELECTION, ("External Trigger ID"));
584
585 p_Rtc->externalTriggerParams[externalTriggerId].f_ExternalTriggerCallback = NULL;
586
587 fman_rtc_clear_external_trigger(p_Rtc->p_MemMap, externalTriggerId);
588
589 return E_OK;
590 }
591
592 /*****************************************************************************/
FM_RTC_GetExternalTriggerTimeStamp(t_Handle h_FmRtc,uint8_t triggerId,uint64_t * p_TimeStamp)593 t_Error FM_RTC_GetExternalTriggerTimeStamp(t_Handle h_FmRtc,
594 uint8_t triggerId,
595 uint64_t *p_TimeStamp)
596 {
597 t_FmRtc *p_Rtc = (t_FmRtc *)h_FmRtc;
598
599 SANITY_CHECK_RETURN_ERROR(p_Rtc, E_INVALID_HANDLE);
600 SANITY_CHECK_RETURN_ERROR(!p_Rtc->p_RtcDriverParam, E_INVALID_STATE);
601
602 if (triggerId >= FM_RTC_NUM_OF_EXT_TRIGGERS)
603 RETURN_ERROR(MAJOR, E_INVALID_SELECTION, ("External trigger ID"));
604
605 *p_TimeStamp = fman_rtc_get_trigger_stamp(p_Rtc->p_MemMap, triggerId)*p_Rtc->clockPeriodNanoSec;
606
607 return E_OK;
608 }
609
610 /*****************************************************************************/
FM_RTC_GetCurrentTime(t_Handle h_FmRtc,uint64_t * p_Ts)611 t_Error FM_RTC_GetCurrentTime(t_Handle h_FmRtc, uint64_t *p_Ts)
612 {
613 t_FmRtc *p_Rtc = (t_FmRtc *)h_FmRtc;
614
615 SANITY_CHECK_RETURN_ERROR(p_Rtc, E_INVALID_HANDLE);
616 SANITY_CHECK_RETURN_ERROR(!p_Rtc->p_RtcDriverParam, E_INVALID_STATE);
617
618 *p_Ts = fman_rtc_get_timer(p_Rtc->p_MemMap)*p_Rtc->clockPeriodNanoSec;
619
620 return E_OK;
621 }
622
623 /*****************************************************************************/
FM_RTC_SetCurrentTime(t_Handle h_FmRtc,uint64_t ts)624 t_Error FM_RTC_SetCurrentTime(t_Handle h_FmRtc, uint64_t ts)
625 {
626 t_FmRtc *p_Rtc = (t_FmRtc *)h_FmRtc;
627
628 SANITY_CHECK_RETURN_ERROR(p_Rtc, E_INVALID_HANDLE);
629 SANITY_CHECK_RETURN_ERROR(!p_Rtc->p_RtcDriverParam, E_INVALID_STATE);
630
631 do_div(ts, p_Rtc->clockPeriodNanoSec);
632 fman_rtc_set_timer(p_Rtc->p_MemMap, (int64_t)ts);
633
634 return E_OK;
635 }
636
637 /*****************************************************************************/
FM_RTC_GetFreqCompensation(t_Handle h_FmRtc,uint32_t * p_Compensation)638 t_Error FM_RTC_GetFreqCompensation(t_Handle h_FmRtc, uint32_t *p_Compensation)
639 {
640 t_FmRtc *p_Rtc = (t_FmRtc *)h_FmRtc;
641
642 SANITY_CHECK_RETURN_ERROR(p_Rtc, E_INVALID_HANDLE);
643 SANITY_CHECK_RETURN_ERROR(!p_Rtc->p_RtcDriverParam, E_INVALID_STATE);
644
645 *p_Compensation = fman_rtc_get_frequency_compensation(p_Rtc->p_MemMap);
646
647 return E_OK;
648 }
649
650 /*****************************************************************************/
FM_RTC_SetFreqCompensation(t_Handle h_FmRtc,uint32_t freqCompensation)651 t_Error FM_RTC_SetFreqCompensation(t_Handle h_FmRtc, uint32_t freqCompensation)
652 {
653 t_FmRtc *p_Rtc = (t_FmRtc *)h_FmRtc;
654
655 SANITY_CHECK_RETURN_ERROR(p_Rtc, E_INVALID_HANDLE);
656 SANITY_CHECK_RETURN_ERROR(!p_Rtc->p_RtcDriverParam, E_INVALID_STATE);
657
658 /* set the new freqCompensation */
659 fman_rtc_set_frequency_compensation(p_Rtc->p_MemMap, freqCompensation);
660
661 return E_OK;
662 }
663
664 #ifdef CONFIG_PTP_1588_CLOCK_DPAA
665 /*****************************************************************************/
FM_RTC_EnableInterrupt(t_Handle h_FmRtc,uint32_t events)666 t_Error FM_RTC_EnableInterrupt(t_Handle h_FmRtc, uint32_t events)
667 {
668 t_FmRtc *p_Rtc = (t_FmRtc *)h_FmRtc;
669
670 SANITY_CHECK_RETURN_ERROR(p_Rtc, E_INVALID_HANDLE);
671 SANITY_CHECK_RETURN_ERROR(!p_Rtc->p_RtcDriverParam, E_INVALID_STATE);
672
673 /* enable interrupt */
674 fman_rtc_enable_interupt(p_Rtc->p_MemMap, events);
675
676 return E_OK;
677 }
678
679 /*****************************************************************************/
FM_RTC_DisableInterrupt(t_Handle h_FmRtc,uint32_t events)680 t_Error FM_RTC_DisableInterrupt(t_Handle h_FmRtc, uint32_t events)
681 {
682 t_FmRtc *p_Rtc = (t_FmRtc *)h_FmRtc;
683
684 SANITY_CHECK_RETURN_ERROR(p_Rtc, E_INVALID_HANDLE);
685 SANITY_CHECK_RETURN_ERROR(!p_Rtc->p_RtcDriverParam, E_INVALID_STATE);
686
687 /* disable interrupt */
688 fman_rtc_disable_interupt(p_Rtc->p_MemMap, events);
689
690 return E_OK;
691 }
692 #endif
693