xref: /freebsd/sys/contrib/ncsw/Peripherals/FM/Rtc/fm_rtc.c (revision 3fc36ee018bb836bd1796067cf4ef8683f166ebc)
1 /* Copyright (c) 2008-2011 Freescale Semiconductor, Inc.
2  * All rights reserved.
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  @File          fm_rtc.c
35 
36  @Description   FM RTC driver implementation.
37 
38  @Cautions      None
39 *//***************************************************************************/
40 
41 #include "error_ext.h"
42 #include "debug_ext.h"
43 #include "string_ext.h"
44 #include "part_ext.h"
45 #include "xx_ext.h"
46 #include "ncsw_ext.h"
47 
48 #include "fm_rtc.h"
49 #include "fm_common.h"
50 
51 
52 /*****************************************************************************/
53 static void SetDefaultParam(t_FmRtc *p_Rtc)
54 {
55     t_FmRtcDriverParam  *p_RtcDriverParam = p_Rtc->p_RtcDriverParam;
56     int                 i;
57 
58     p_Rtc->outputClockDivisor = DEFAULT_outputClockDivisor;
59     p_Rtc->p_RtcDriverParam->bypass = DEFAULT_bypass;
60     p_RtcDriverParam->srcClk = DEFAULT_srcClock;
61     p_RtcDriverParam->invertInputClkPhase = DEFAULT_invertInputClkPhase;
62     p_RtcDriverParam->invertOutputClkPhase = DEFAULT_invertOutputClkPhase;
63     p_RtcDriverParam->pulseRealign = DEFAULT_pulseRealign;
64     for (i=0; i < FM_RTC_NUM_OF_ALARMS; i++)
65     {
66         p_RtcDriverParam->alarmPolarity[i] = DEFAULT_alarmPolarity;
67     }
68     for (i=0; i < FM_RTC_NUM_OF_EXT_TRIGGERS; i++)
69     {
70         p_RtcDriverParam->triggerPolarity[i] = DEFAULT_triggerPolarity;
71     }
72     p_Rtc->clockPeriodNanoSec = DEFAULT_clockPeriod; /* 1 usec */
73 }
74 
75 /*****************************************************************************/
76 static t_Error CheckInitParameters(t_FmRtc *p_Rtc)
77 {
78     t_FmRtcDriverParam  *p_RtcDriverParam = p_Rtc->p_RtcDriverParam;
79     int                 i;
80 
81     if ((p_RtcDriverParam->srcClk != e_FM_RTC_SOURCE_CLOCK_EXTERNAL) &&
82         (p_RtcDriverParam->srcClk != e_FM_RTC_SOURCE_CLOCK_SYSTEM) &&
83         (p_RtcDriverParam->srcClk != e_FM_RTC_SOURCE_CLOCK_OSCILATOR))
84         RETURN_ERROR(MAJOR, E_INVALID_CLOCK, ("Source clock undefined"));
85 
86     if (p_Rtc->outputClockDivisor == 0)
87     {
88         RETURN_ERROR(MAJOR, E_INVALID_VALUE,
89                      ("Divisor for output clock (should be positive)"));
90     }
91 
92     for (i=0; i < FM_RTC_NUM_OF_ALARMS; i++)
93     {
94         if ((p_RtcDriverParam->alarmPolarity[i] != e_FM_RTC_ALARM_POLARITY_ACTIVE_LOW) &&
95             (p_RtcDriverParam->alarmPolarity[i] != e_FM_RTC_ALARM_POLARITY_ACTIVE_HIGH))
96         {
97             RETURN_ERROR(MAJOR, E_INVALID_SELECTION, ("Alarm %d signal polarity", i));
98         }
99     }
100     for (i=0; i < FM_RTC_NUM_OF_EXT_TRIGGERS; i++)
101     {
102         if ((p_RtcDriverParam->triggerPolarity[i] != e_FM_RTC_TRIGGER_ON_FALLING_EDGE) &&
103             (p_RtcDriverParam->triggerPolarity[i] != e_FM_RTC_TRIGGER_ON_RISING_EDGE))
104         {
105             RETURN_ERROR(MAJOR, E_INVALID_SELECTION, ("Trigger %d signal polarity", i));
106         }
107     }
108 
109 #ifdef FM_1588_SRC_CLK_ERRATA_FMAN1
110     {
111         t_FmRevisionInfo revInfo;
112         FM_GetRevision(p_Rtc->h_Fm, &revInfo);
113         if ((revInfo.majorRev == 1) && (revInfo.minorRev == 0)&&
114            ((p_RtcDriverParam->srcClk==e_FM_RTC_SOURCE_CLOCK_SYSTEM) && p_RtcDriverParam->invertInputClkPhase))
115             RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("Can not use invertInputClkPhase when source clock is e_FM_RTC_SOURCE_CLOCK_SYSTEM"));
116     }
117 #endif /* FM_1588_SRC_CLK_ERRATA_FMAN1 */
118 
119     return E_OK;
120 }
121 
122 /*****************************************************************************/
123 static void RtcExceptions(t_Handle h_FmRtc)
124 {
125     t_FmRtc             *p_Rtc = (t_FmRtc *)h_FmRtc;
126     t_FmRtcMemMap       *p_MemMap;
127     register uint32_t   events;
128 
129     ASSERT_COND(p_Rtc);
130     p_MemMap = p_Rtc->p_MemMap;
131 
132     /* Get valid events */
133     events =  GET_UINT32(p_MemMap->tmr_tevent);
134     events &= GET_UINT32(p_MemMap->tmr_temask);
135 
136     /* Clear event bits */
137     WRITE_UINT32(p_MemMap->tmr_tevent, events);
138 
139     if (events & TMR_TEVENT_ALM1)
140     {
141         if(p_Rtc->alarmParams[0].clearOnExpiration)
142         {
143             WRITE_UINT32(p_MemMap->tmr_alarm[0].tmr_alarm_l, 0);
144             WRITE_UINT32(p_MemMap->tmr_temask, GET_UINT32(p_MemMap->tmr_temask) & ~TMR_TEVENT_ALM1);
145         }
146         ASSERT_COND(p_Rtc->alarmParams[0].f_AlarmCallback);
147         p_Rtc->alarmParams[0].f_AlarmCallback(p_Rtc->h_App, 0);
148     }
149     if (events & TMR_TEVENT_ALM2)
150     {
151         if(p_Rtc->alarmParams[1].clearOnExpiration)
152         {
153             WRITE_UINT32(p_MemMap->tmr_alarm[1].tmr_alarm_l, 0);
154             WRITE_UINT32(p_MemMap->tmr_temask, GET_UINT32(p_MemMap->tmr_temask) & ~TMR_TEVENT_ALM2);
155         }
156         ASSERT_COND(p_Rtc->alarmParams[1].f_AlarmCallback);
157         p_Rtc->alarmParams[1].f_AlarmCallback(p_Rtc->h_App, 1);
158     }
159     if (events & TMR_TEVENT_PP1)
160     {
161         ASSERT_COND(p_Rtc->periodicPulseParams[0].f_PeriodicPulseCallback);
162         p_Rtc->periodicPulseParams[0].f_PeriodicPulseCallback(p_Rtc->h_App, 0);
163     }
164     if (events & TMR_TEVENT_PP2)
165     {
166         ASSERT_COND(p_Rtc->periodicPulseParams[1].f_PeriodicPulseCallback);
167         p_Rtc->periodicPulseParams[1].f_PeriodicPulseCallback(p_Rtc->h_App, 1);
168     }
169     if (events & TMR_TEVENT_ETS1)
170     {
171         ASSERT_COND(p_Rtc->externalTriggerParams[0].f_ExternalTriggerCallback);
172         p_Rtc->externalTriggerParams[0].f_ExternalTriggerCallback(p_Rtc->h_App, 0);
173     }
174     if (events & TMR_TEVENT_ETS2)
175     {
176         ASSERT_COND(p_Rtc->externalTriggerParams[1].f_ExternalTriggerCallback);
177         p_Rtc->externalTriggerParams[1].f_ExternalTriggerCallback(p_Rtc->h_App, 1);
178     }
179 }
180 
181 
182 /*****************************************************************************/
183 t_Handle FM_RTC_Config(t_FmRtcParams *p_FmRtcParam)
184 {
185     t_FmRtc *p_Rtc;
186 
187     SANITY_CHECK_RETURN_VALUE(p_FmRtcParam, E_NULL_POINTER, NULL);
188 
189     /* Allocate memory for the FM RTC driver parameters */
190     p_Rtc = (t_FmRtc *)XX_Malloc(sizeof(t_FmRtc));
191     if (!p_Rtc)
192     {
193         REPORT_ERROR(MAJOR, E_NO_MEMORY, ("FM RTC driver structure"));
194         return NULL;
195     }
196 
197     memset(p_Rtc, 0, sizeof(t_FmRtc));
198 
199     /* Allocate memory for the FM RTC driver parameters */
200     p_Rtc->p_RtcDriverParam = (t_FmRtcDriverParam *)XX_Malloc(sizeof(t_FmRtcDriverParam));
201     if (!p_Rtc->p_RtcDriverParam)
202     {
203         REPORT_ERROR(MAJOR, E_NO_MEMORY, ("FM RTC driver parameters"));
204         XX_Free(p_Rtc);
205         return NULL;
206     }
207 
208     memset(p_Rtc->p_RtcDriverParam, 0, sizeof(t_FmRtcDriverParam));
209 
210     /* Store RTC configuration parameters */
211     p_Rtc->h_Fm = p_FmRtcParam->h_Fm;
212 
213     /* Set default RTC configuration parameters */
214     SetDefaultParam(p_Rtc);
215 
216     /* Store RTC parameters in the RTC control structure */
217     p_Rtc->p_MemMap = (t_FmRtcMemMap *)UINT_TO_PTR(p_FmRtcParam->baseAddress);
218     p_Rtc->h_App    = p_FmRtcParam->h_App;
219 
220     return p_Rtc;
221 }
222 
223 /*****************************************************************************/
224 t_Error FM_RTC_Init(t_Handle h_FmRtc)
225 {
226     t_FmRtc             *p_Rtc = (t_FmRtc *)h_FmRtc;
227     t_FmRtcDriverParam  *p_RtcDriverParam;
228     t_FmRtcMemMap       *p_MemMap;
229     uint32_t            freqCompensation;
230     uint32_t            tmrCtrl;
231     int                 i;
232     uint64_t            tmpDouble;
233 
234     p_RtcDriverParam = p_Rtc->p_RtcDriverParam;
235     p_MemMap = p_Rtc->p_MemMap;
236 
237     if(CheckInitParameters(p_Rtc)!=E_OK)
238         RETURN_ERROR(MAJOR, E_CONFLICT,
239                      ("Init Parameters are not Valid"));
240 
241     /* TODO A check must be added here, that no timestamping MAC's
242      * are working in this stage. */
243     WRITE_UINT32(p_MemMap->tmr_ctrl, TMR_CTRL_TMSR);
244     XX_UDelay(10);
245     WRITE_UINT32(p_MemMap->tmr_ctrl, 0);
246 
247     /* Set the source clock */
248     switch (p_RtcDriverParam->srcClk)
249     {
250         case e_FM_RTC_SOURCE_CLOCK_SYSTEM:
251             tmrCtrl = TMR_CTRL_CKSEL_MAC_CLK;
252             break;
253         case e_FM_RTC_SOURCE_CLOCK_OSCILATOR:
254             tmrCtrl = TMR_CTRL_CKSEL_OSC_CLK;
255             break;
256         default:
257             /* Use a clock from the External TMR reference clock.*/
258             tmrCtrl = TMR_CTRL_CKSEL_EXT_CLK;
259             break;
260     }
261 
262     /* whatever period the user picked, the timestamp will advance in '1' every time
263      * the period passed. */
264     tmrCtrl |= ((1 << TMR_CTRL_TCLK_PERIOD_SHIFT) & TMR_CTRL_TCLK_PERIOD_MASK);
265 
266     if (p_RtcDriverParam->invertInputClkPhase)
267         tmrCtrl |= TMR_CTRL_CIPH;
268     if (p_RtcDriverParam->invertOutputClkPhase)
269         tmrCtrl |= TMR_CTRL_COPH;
270 
271     for (i=0; i < FM_RTC_NUM_OF_ALARMS; i++)
272     {
273         if (p_RtcDriverParam->alarmPolarity[i] == e_FM_RTC_ALARM_POLARITY_ACTIVE_LOW)
274             tmrCtrl |= (TMR_CTRL_ALMP1 >> i);
275     }
276 
277     for (i=0; i < FM_RTC_NUM_OF_EXT_TRIGGERS; i++)
278         if (p_RtcDriverParam->triggerPolarity[i] == e_FM_RTC_TRIGGER_ON_FALLING_EDGE)
279             tmrCtrl |= (TMR_CTRL_ETEP1 << i);
280 
281     if (!p_RtcDriverParam->timerSlaveMode && p_Rtc->p_RtcDriverParam->bypass)
282         tmrCtrl |= TMR_CTRL_BYP;
283 
284     WRITE_UINT32(p_MemMap->tmr_ctrl, tmrCtrl);
285 
286      for (i=0; i < FM_RTC_NUM_OF_ALARMS; i++)
287     {
288         /* Clear TMR_ALARM registers */
289         WRITE_UINT32(p_MemMap->tmr_alarm[i].tmr_alarm_l, 0xFFFFFFFF);
290         WRITE_UINT32(p_MemMap->tmr_alarm[i].tmr_alarm_h, 0xFFFFFFFF);
291     }
292 
293     /* Clear TMR_TEVENT */
294     WRITE_UINT32(p_MemMap->tmr_tevent, TMR_TEVENT_ALL);
295 
296     /* Initialize TMR_TEMASK */
297     WRITE_UINT32(p_MemMap->tmr_temask, 0);
298 
299 
300     /* find source clock frequency in Mhz */
301     if (p_Rtc->p_RtcDriverParam->srcClk != e_FM_RTC_SOURCE_CLOCK_SYSTEM)
302          p_Rtc->srcClkFreqMhz = p_Rtc->p_RtcDriverParam->extSrcClkFreq;
303     else
304         p_Rtc->srcClkFreqMhz = (uint32_t)(FmGetClockFreq(p_Rtc->h_Fm)/2);
305 
306     /* if timer in Master mode Initialize TMR_CTRL */
307     /* We want the counter (TMR_CNT) to count in nano-seconds */
308     if (!p_RtcDriverParam->timerSlaveMode && p_Rtc->p_RtcDriverParam->bypass)
309     {
310         p_Rtc->clockPeriodNanoSec = (1000 / p_Rtc->srcClkFreqMhz);
311     }
312     else
313     {
314         /* Initialize TMR_ADD with the initial frequency compensation value:
315            freqCompensation = (2^32 / frequency ratio) */
316         /* frequency ratio = sorce clock/rtc clock =
317          * (p_Rtc->srcClkFreqMhz*1000000))/ 1/(p_Rtc->clockPeriodNanoSec * 1000000000) */
318         freqCompensation = (uint32_t)DIV_CEIL(ACCUMULATOR_OVERFLOW * 1000,
319                                     p_Rtc->clockPeriodNanoSec * p_Rtc->srcClkFreqMhz);
320         WRITE_UINT32(p_MemMap->tmr_add, freqCompensation);
321     }
322     /* check the legality of the relation between source and destination clocks */
323     /* should be larger than 1.0001 */
324     tmpDouble = 10000 * (uint64_t)p_Rtc->clockPeriodNanoSec * (uint64_t)p_Rtc->srcClkFreqMhz;
325     if((tmpDouble) <= 10001)
326         RETURN_ERROR(MAJOR, E_CONFLICT,
327               ("Invalid relation between source and destination clocks. Should be larger than 1.0001"));
328 
329 
330     for (i=0; i < 2; i++)
331         /* Clear TMR_FIPER registers */
332         WRITE_UINT32(p_MemMap->tmr_fiper[i], 0xFFFFFFFF);
333 
334     /* Initialize TMR_PRSC */
335     WRITE_UINT32(p_MemMap->tmr_prsc, p_Rtc->outputClockDivisor);
336 
337     /* Clear TMR_OFF */
338     WRITE_UINT32(p_MemMap->tmr_off_l, 0);
339     WRITE_UINT32(p_MemMap->tmr_off_h, 0);
340 
341     /* Register the FM RTC interrupt */
342     FmRegisterIntr(p_Rtc->h_Fm, e_FM_MOD_TMR, 0, e_FM_INTR_TYPE_NORMAL, RtcExceptions , p_Rtc);
343 
344     /* Free parameters structures */
345     XX_Free(p_Rtc->p_RtcDriverParam);
346     p_Rtc->p_RtcDriverParam = NULL;
347 
348     return E_OK;
349 }
350 
351 /*****************************************************************************/
352 t_Error FM_RTC_Free(t_Handle h_FmRtc)
353 {
354     t_FmRtc *p_Rtc = (t_FmRtc *)h_FmRtc;
355 
356     SANITY_CHECK_RETURN_ERROR(p_Rtc, E_INVALID_HANDLE);
357 
358     if (p_Rtc->p_RtcDriverParam)
359     {
360         XX_Free(p_Rtc->p_RtcDriverParam);
361     }
362     else
363     {
364         FM_RTC_Disable(h_FmRtc);
365     }
366 
367     /* Unregister FM RTC interrupt */
368     FmUnregisterIntr(p_Rtc->h_Fm, e_FM_MOD_TMR, 0, e_FM_INTR_TYPE_NORMAL);
369     XX_Free(p_Rtc);
370 
371     return E_OK;
372 }
373 
374 /*****************************************************************************/
375 t_Error FM_RTC_ConfigSourceClock(t_Handle         h_FmRtc,
376                                     e_FmSrcClk    srcClk,
377                                     uint32_t      freqInMhz)
378 {
379     t_FmRtc *p_Rtc = (t_FmRtc *)h_FmRtc;
380 
381     SANITY_CHECK_RETURN_ERROR(p_Rtc, E_INVALID_HANDLE);
382     SANITY_CHECK_RETURN_ERROR(p_Rtc->p_RtcDriverParam, E_INVALID_STATE);
383 
384     p_Rtc->p_RtcDriverParam->srcClk = srcClk;
385     if(srcClk != e_FM_RTC_SOURCE_CLOCK_SYSTEM)
386         p_Rtc->p_RtcDriverParam->extSrcClkFreq = freqInMhz;
387 
388     return E_OK;
389 }
390 
391 /*****************************************************************************/
392 t_Error FM_RTC_ConfigPeriod(t_Handle h_FmRtc, uint32_t period)
393 {
394     t_FmRtc *p_Rtc = (t_FmRtc *)h_FmRtc;
395 
396     SANITY_CHECK_RETURN_ERROR(p_Rtc, E_INVALID_HANDLE);
397     SANITY_CHECK_RETURN_ERROR(p_Rtc->p_RtcDriverParam, E_INVALID_STATE);
398 
399     p_Rtc->clockPeriodNanoSec = period;
400 
401     return E_OK;
402 }
403 
404 /*****************************************************************************/
405 t_Error FM_RTC_ConfigFrequencyBypass(t_Handle h_FmRtc, bool enabled)
406 {
407     t_FmRtc *p_Rtc = (t_FmRtc *)h_FmRtc;
408 
409     SANITY_CHECK_RETURN_ERROR(p_Rtc, E_INVALID_HANDLE);
410     SANITY_CHECK_RETURN_ERROR(p_Rtc->p_RtcDriverParam, E_INVALID_STATE);
411 
412     p_Rtc->p_RtcDriverParam->bypass = enabled;
413 
414     return E_OK;
415 }
416 
417 /*****************************************************************************/
418 t_Error FM_RTC_ConfigInvertedInputClockPhase(t_Handle h_FmRtc, bool inverted)
419 {
420     t_FmRtc *p_Rtc = (t_FmRtc *)h_FmRtc;
421 
422     SANITY_CHECK_RETURN_ERROR(p_Rtc, E_INVALID_HANDLE);
423     SANITY_CHECK_RETURN_ERROR(p_Rtc->p_RtcDriverParam, E_INVALID_STATE);
424 
425     p_Rtc->p_RtcDriverParam->invertInputClkPhase = inverted;
426 
427     return E_OK;
428 }
429 
430 /*****************************************************************************/
431 t_Error FM_RTC_ConfigInvertedOutputClockPhase(t_Handle h_FmRtc, bool inverted)
432 {
433     t_FmRtc *p_Rtc = (t_FmRtc *)h_FmRtc;
434 
435     SANITY_CHECK_RETURN_ERROR(p_Rtc, E_INVALID_HANDLE);
436     SANITY_CHECK_RETURN_ERROR(p_Rtc->p_RtcDriverParam, E_INVALID_STATE);
437 
438     p_Rtc->p_RtcDriverParam->invertOutputClkPhase = inverted;
439 
440     return E_OK;
441 }
442 
443 /*****************************************************************************/
444 t_Error FM_RTC_ConfigOutputClockDivisor(t_Handle h_FmRtc, uint16_t divisor)
445 {
446     t_FmRtc *p_Rtc = (t_FmRtc *)h_FmRtc;
447 
448     SANITY_CHECK_RETURN_ERROR(p_Rtc, E_INVALID_HANDLE);
449     SANITY_CHECK_RETURN_ERROR(p_Rtc->p_RtcDriverParam, E_INVALID_STATE);
450 
451     p_Rtc->outputClockDivisor = divisor;
452 
453     return E_OK;
454 }
455 
456 /*****************************************************************************/
457 t_Error FM_RTC_ConfigPulseRealignment(t_Handle h_FmRtc, bool enable)
458 {
459     t_FmRtc *p_Rtc = (t_FmRtc *)h_FmRtc;
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     p_Rtc->p_RtcDriverParam->pulseRealign = enable;
465 
466     return E_OK;
467 }
468 
469 /*****************************************************************************/
470 t_Error FM_RTC_ConfigAlarmPolarity(t_Handle             h_FmRtc,
471                                    uint8_t              alarmId,
472                                    e_FmRtcAlarmPolarity alarmPolarity)
473 {
474     t_FmRtc *p_Rtc = (t_FmRtc *)h_FmRtc;
475 
476     SANITY_CHECK_RETURN_ERROR(p_Rtc, E_INVALID_HANDLE);
477     SANITY_CHECK_RETURN_ERROR(p_Rtc->p_RtcDriverParam, E_INVALID_STATE);
478 
479     if (alarmId >= FM_RTC_NUM_OF_ALARMS)
480     {
481         RETURN_ERROR(MAJOR, E_INVALID_SELECTION, ("Alarm ID"));
482     }
483 
484     p_Rtc->p_RtcDriverParam->alarmPolarity[alarmId] = alarmPolarity;
485 
486     return E_OK;
487 }
488 
489 /*****************************************************************************/
490 t_Error FM_RTC_ConfigExternalTriggerPolarity(t_Handle               h_FmRtc,
491                                              uint8_t                triggerId,
492                                              e_FmRtcTriggerPolarity triggerPolarity)
493 {
494     t_FmRtc *p_Rtc = (t_FmRtc *)h_FmRtc;
495 
496     SANITY_CHECK_RETURN_ERROR(p_Rtc, E_INVALID_HANDLE);
497     SANITY_CHECK_RETURN_ERROR(p_Rtc->p_RtcDriverParam, E_INVALID_STATE);
498 
499     if (triggerId >= FM_RTC_NUM_OF_EXT_TRIGGERS)
500     {
501         RETURN_ERROR(MAJOR, E_INVALID_SELECTION, ("External trigger ID"));
502     }
503 
504     p_Rtc->p_RtcDriverParam->triggerPolarity[triggerId] = triggerPolarity;
505 
506     return E_OK;
507 }
508 
509 /*****************************************************************************/
510 t_Error FM_RTC_Enable(t_Handle h_FmRtc, bool resetClock)
511 {
512     t_FmRtc         *p_Rtc = (t_FmRtc *)h_FmRtc;
513     uint32_t        tmrCtrl;
514 
515     SANITY_CHECK_RETURN_ERROR(p_Rtc, E_INVALID_HANDLE);
516     SANITY_CHECK_RETURN_ERROR(!p_Rtc->p_RtcDriverParam, E_INVALID_STATE);
517 
518     tmrCtrl = GET_UINT32(p_Rtc->p_MemMap->tmr_ctrl);
519 
520     /* TODO A check must be added here, that no timestamping MAC's
521      * are working in this stage. */
522     if (resetClock)
523     {
524         WRITE_UINT32(p_Rtc->p_MemMap->tmr_ctrl, (tmrCtrl | TMR_CTRL_TMSR));
525 
526         XX_UDelay(10);
527         /* Clear TMR_OFF */
528         WRITE_UINT32(p_Rtc->p_MemMap->tmr_off_l, 0);
529         WRITE_UINT32(p_Rtc->p_MemMap->tmr_off_h, 0);
530     }
531 
532     WRITE_UINT32(p_Rtc->p_MemMap->tmr_ctrl, (tmrCtrl | TMR_CTRL_TE));
533 
534     return E_OK;
535 }
536 
537 /*****************************************************************************/
538 t_Error FM_RTC_Disable(t_Handle h_FmRtc)
539 {
540     t_FmRtc         *p_Rtc = (t_FmRtc *)h_FmRtc;
541     uint32_t        tmrCtrl;
542 
543     SANITY_CHECK_RETURN_ERROR(p_Rtc, E_INVALID_HANDLE);
544     SANITY_CHECK_RETURN_ERROR(!p_Rtc->p_RtcDriverParam, E_INVALID_STATE);
545 
546     /* TODO A check must be added here, that no timestamping MAC's
547      * are working in this stage. */
548     tmrCtrl = GET_UINT32(p_Rtc->p_MemMap->tmr_ctrl);
549     WRITE_UINT32(p_Rtc->p_MemMap->tmr_ctrl, (tmrCtrl & ~(TMR_CTRL_TE)));
550 
551     return E_OK;
552 }
553 
554 /*****************************************************************************/
555 t_Error FM_RTC_SetClockOffset(t_Handle h_FmRtc, int64_t offset)
556 {
557     t_FmRtc *p_Rtc = (t_FmRtc *)h_FmRtc;
558 
559     SANITY_CHECK_RETURN_ERROR(p_Rtc, E_INVALID_HANDLE);
560     SANITY_CHECK_RETURN_ERROR(!p_Rtc->p_RtcDriverParam, E_INVALID_STATE);
561 
562     /* TMR_OFF_L must be written first */
563     WRITE_UINT32(p_Rtc->p_MemMap->tmr_off_l, (uint32_t)offset);
564     WRITE_UINT32(p_Rtc->p_MemMap->tmr_off_h, (uint32_t)(offset >> 32));
565 
566     return E_OK;
567 }
568 
569 /*****************************************************************************/
570 t_Error FM_RTC_SetAlarm(t_Handle h_FmRtc, t_FmRtcAlarmParams *p_FmRtcAlarmParams)
571 {
572     t_FmRtc         *p_Rtc = (t_FmRtc *)h_FmRtc;
573     t_FmRtcMemMap   *p_MemMap;
574     uint32_t        tmpReg;
575     uint64_t        tmpAlarm;
576 
577     SANITY_CHECK_RETURN_ERROR(p_Rtc, E_INVALID_HANDLE);
578     SANITY_CHECK_RETURN_ERROR(!p_Rtc->p_RtcDriverParam, E_INVALID_STATE);
579 
580     p_MemMap = p_Rtc->p_MemMap;
581 
582     if (p_FmRtcAlarmParams->alarmId >= FM_RTC_NUM_OF_ALARMS)
583     {
584         RETURN_ERROR(MAJOR, E_INVALID_SELECTION, ("Alarm ID"));
585     }
586 
587     if(p_FmRtcAlarmParams->alarmTime < p_Rtc->clockPeriodNanoSec)
588         RETURN_ERROR(MAJOR, E_INVALID_SELECTION, ("Alarm time must be equal or larger than RTC period - %d nanoseconds", p_Rtc->clockPeriodNanoSec));
589     if(p_FmRtcAlarmParams->alarmTime % (uint64_t)p_Rtc->clockPeriodNanoSec)
590         RETURN_ERROR(MAJOR, E_INVALID_SELECTION, ("Alarm time must be a multiple of RTC period - %d nanoseconds", p_Rtc->clockPeriodNanoSec));
591     tmpAlarm = p_FmRtcAlarmParams->alarmTime/(uint64_t)p_Rtc->clockPeriodNanoSec;
592 
593     /* TMR_ALARM_L must be written first */
594     WRITE_UINT32(p_MemMap->tmr_alarm[p_FmRtcAlarmParams->alarmId].tmr_alarm_l, (uint32_t)tmpAlarm);
595     WRITE_UINT32(p_MemMap->tmr_alarm[p_FmRtcAlarmParams->alarmId].tmr_alarm_h,
596                  (uint32_t)(tmpAlarm >> 32));
597 
598     if (p_FmRtcAlarmParams->f_AlarmCallback)
599     {
600         p_Rtc->alarmParams[p_FmRtcAlarmParams->alarmId].f_AlarmCallback = p_FmRtcAlarmParams->f_AlarmCallback;
601         p_Rtc->alarmParams[p_FmRtcAlarmParams->alarmId].clearOnExpiration = p_FmRtcAlarmParams->clearOnExpiration;
602 
603         if(p_FmRtcAlarmParams->alarmId == 0)
604             tmpReg = TMR_TEVENT_ALM1;
605         else
606             tmpReg = TMR_TEVENT_ALM2;
607         WRITE_UINT32(p_MemMap->tmr_temask, GET_UINT32(p_MemMap->tmr_temask) | tmpReg);
608     }
609 
610     return E_OK;
611 }
612 
613 /*****************************************************************************/
614 t_Error FM_RTC_SetPeriodicPulse(t_Handle h_FmRtc, t_FmRtcPeriodicPulseParams *p_FmRtcPeriodicPulseParams)
615 {
616     t_FmRtc         *p_Rtc = (t_FmRtc *)h_FmRtc;
617     t_FmRtcMemMap   *p_MemMap;
618     uint32_t        tmpReg;
619     uint64_t        tmpFiper;
620 
621     SANITY_CHECK_RETURN_ERROR(p_Rtc, E_INVALID_HANDLE);
622     SANITY_CHECK_RETURN_ERROR(!p_Rtc->p_RtcDriverParam, E_INVALID_STATE);
623 
624     p_MemMap = p_Rtc->p_MemMap;
625 
626     if (p_FmRtcPeriodicPulseParams->periodicPulseId >= FM_RTC_NUM_OF_PERIODIC_PULSES)
627     {
628         RETURN_ERROR(MAJOR, E_INVALID_SELECTION, ("Periodic pulse ID"));
629     }
630     if(GET_UINT32(p_MemMap->tmr_ctrl) & TMR_CTRL_TE)
631         RETURN_ERROR(MAJOR, E_INVALID_SELECTION, ("Can't set Periodic pulse when RTC is enabled."));
632     if(p_FmRtcPeriodicPulseParams->periodicPulsePeriod < p_Rtc->clockPeriodNanoSec)
633         RETURN_ERROR(MAJOR, E_INVALID_SELECTION, ("Periodic pulse must be equal or larger than RTC period - %d nanoseconds", p_Rtc->clockPeriodNanoSec));
634     if(p_FmRtcPeriodicPulseParams->periodicPulsePeriod % (uint64_t)p_Rtc->clockPeriodNanoSec)
635         RETURN_ERROR(MAJOR, E_INVALID_SELECTION, ("Periodic pulse must be a multiple of RTC period - %d nanoseconds", p_Rtc->clockPeriodNanoSec));
636     tmpFiper = p_FmRtcPeriodicPulseParams->periodicPulsePeriod/(uint64_t)p_Rtc->clockPeriodNanoSec;
637     if(tmpFiper & 0xffffffff00000000LL)
638         RETURN_ERROR(MAJOR, E_INVALID_SELECTION, ("Periodic pulse/RTC Period must be smaller than 4294967296", p_Rtc->clockPeriodNanoSec));
639 
640     WRITE_UINT32(p_MemMap->tmr_fiper[p_FmRtcPeriodicPulseParams->periodicPulseId], (uint32_t)tmpFiper);
641 
642     if (p_FmRtcPeriodicPulseParams->f_PeriodicPulseCallback)
643     {
644         p_Rtc->periodicPulseParams[p_FmRtcPeriodicPulseParams->periodicPulseId].f_PeriodicPulseCallback =
645                                                            p_FmRtcPeriodicPulseParams->f_PeriodicPulseCallback;
646 
647         if(p_FmRtcPeriodicPulseParams->periodicPulseId == 0)
648             tmpReg = TMR_TEVENT_PP1;
649         else
650             tmpReg = TMR_TEVENT_PP2;
651         WRITE_UINT32(p_MemMap->tmr_temask, GET_UINT32(p_MemMap->tmr_temask) | tmpReg);
652     }
653 
654     return E_OK;
655 }
656 
657 /*****************************************************************************/
658 t_Error FM_RTC_ClearPeriodicPulse(t_Handle h_FmRtc, uint8_t periodicPulseId)
659 {
660     t_FmRtc     *p_Rtc = (t_FmRtc *)h_FmRtc;
661     uint32_t    tmpReg;
662 
663     SANITY_CHECK_RETURN_ERROR(p_Rtc, E_INVALID_HANDLE);
664     SANITY_CHECK_RETURN_ERROR(!p_Rtc->p_RtcDriverParam, E_INVALID_STATE);
665 
666     if (periodicPulseId >= FM_RTC_NUM_OF_PERIODIC_PULSES)
667     {
668         RETURN_ERROR(MAJOR, E_INVALID_SELECTION, ("Periodic pulse ID"));
669     }
670 
671     p_Rtc->periodicPulseParams[periodicPulseId].f_PeriodicPulseCallback = NULL;
672 
673     if(periodicPulseId == 0)
674         tmpReg = TMR_TEVENT_PP1;
675     else
676         tmpReg = TMR_TEVENT_PP2;
677     WRITE_UINT32(p_Rtc->p_MemMap->tmr_temask, GET_UINT32(p_Rtc->p_MemMap->tmr_temask) & ~tmpReg);
678 
679     if (GET_UINT32(p_Rtc->p_MemMap->tmr_ctrl) & TMR_CTRL_FS)
680         WRITE_UINT32(p_Rtc->p_MemMap->tmr_ctrl, GET_UINT32(p_Rtc->p_MemMap->tmr_ctrl) & ~TMR_CTRL_FS);
681 
682     WRITE_UINT32(p_Rtc->p_MemMap->tmr_fiper[periodicPulseId], 0xFFFFFFFF);
683 
684     return E_OK;
685 }
686 
687 /*****************************************************************************/
688 t_Error FM_RTC_SetExternalTrigger(t_Handle h_FmRtc, t_FmRtcExternalTriggerParams *p_FmRtcExternalTriggerParams)
689 {
690     t_FmRtc     *p_Rtc = (t_FmRtc *)h_FmRtc;
691     uint32_t    tmpReg;
692 
693     SANITY_CHECK_RETURN_ERROR(p_Rtc, E_INVALID_HANDLE);
694     SANITY_CHECK_RETURN_ERROR(!p_Rtc->p_RtcDriverParam, E_INVALID_STATE);
695 
696     if (p_FmRtcExternalTriggerParams->externalTriggerId >= FM_RTC_NUM_OF_EXT_TRIGGERS)
697     {
698         RETURN_ERROR(MAJOR, E_INVALID_SELECTION, ("External Trigger ID"));
699     }
700 
701     if (p_FmRtcExternalTriggerParams->f_ExternalTriggerCallback)
702     {
703         p_Rtc->externalTriggerParams[p_FmRtcExternalTriggerParams->externalTriggerId].f_ExternalTriggerCallback = p_FmRtcExternalTriggerParams->f_ExternalTriggerCallback;
704         if(p_FmRtcExternalTriggerParams->externalTriggerId == 0)
705             tmpReg = TMR_TEVENT_ETS1;
706         else
707             tmpReg = TMR_TEVENT_ETS2;
708         WRITE_UINT32(p_Rtc->p_MemMap->tmr_temask, GET_UINT32(p_Rtc->p_MemMap->tmr_temask) | tmpReg);
709     }
710 
711     if(p_FmRtcExternalTriggerParams->usePulseAsInput)
712     {
713         if(p_FmRtcExternalTriggerParams->externalTriggerId == 0)
714             tmpReg = TMR_CTRL_PP1L;
715         else
716             tmpReg = TMR_CTRL_PP2L;
717         WRITE_UINT32(p_Rtc->p_MemMap->tmr_ctrl, GET_UINT32(p_Rtc->p_MemMap->tmr_ctrl) | tmpReg);
718     }
719 
720     return E_OK;
721 }
722 
723 /*****************************************************************************/
724 t_Error FM_RTC_ClearExternalTrigger(t_Handle h_FmRtc, uint8_t externalTriggerId)
725 {
726     t_FmRtc     *p_Rtc = (t_FmRtc *)h_FmRtc;
727     uint32_t    tmpReg;
728 
729     SANITY_CHECK_RETURN_ERROR(p_Rtc, E_INVALID_HANDLE);
730     SANITY_CHECK_RETURN_ERROR(!p_Rtc->p_RtcDriverParam, E_INVALID_STATE);
731 
732     if (externalTriggerId >= FM_RTC_NUM_OF_EXT_TRIGGERS)
733         RETURN_ERROR(MAJOR, E_INVALID_SELECTION, ("External Trigger ID"));
734 
735     p_Rtc->externalTriggerParams[externalTriggerId].f_ExternalTriggerCallback = NULL;
736 
737     if(externalTriggerId == 0)
738         tmpReg = TMR_TEVENT_ETS1;
739     else
740         tmpReg = TMR_TEVENT_ETS2;
741     WRITE_UINT32(p_Rtc->p_MemMap->tmr_temask, GET_UINT32(p_Rtc->p_MemMap->tmr_temask) & ~tmpReg);
742 
743     if(externalTriggerId == 0)
744         tmpReg = TMR_CTRL_PP1L;
745     else
746         tmpReg = TMR_CTRL_PP2L;
747 
748     if (GET_UINT32(p_Rtc->p_MemMap->tmr_ctrl) & tmpReg)
749         WRITE_UINT32(p_Rtc->p_MemMap->tmr_ctrl, GET_UINT32(p_Rtc->p_MemMap->tmr_ctrl) & ~tmpReg);
750 
751     return E_OK;
752 }
753 
754 /*****************************************************************************/
755 t_Error FM_RTC_GetExternalTriggerTimeStamp(t_Handle             h_FmRtc,
756                                               uint8_t           triggerId,
757                                               uint64_t          *p_TimeStamp)
758 {
759     t_FmRtc     *p_Rtc = (t_FmRtc *)h_FmRtc;
760     uint64_t    timeStamp;
761 
762     SANITY_CHECK_RETURN_ERROR(p_Rtc, E_INVALID_HANDLE);
763     SANITY_CHECK_RETURN_ERROR(!p_Rtc->p_RtcDriverParam, E_INVALID_STATE);
764 
765     if (triggerId >= FM_RTC_NUM_OF_EXT_TRIGGERS)
766     {
767         RETURN_ERROR(MAJOR, E_INVALID_SELECTION, ("External trigger ID"));
768     }
769 
770     timeStamp = (uint64_t)GET_UINT32(p_Rtc->p_MemMap->tmr_etts[triggerId].tmr_etts_l);
771     timeStamp |= ((uint64_t)GET_UINT32(p_Rtc->p_MemMap->tmr_etts[triggerId].tmr_etts_h) << 32);
772 
773     timeStamp = timeStamp*p_Rtc->clockPeriodNanoSec;
774     *p_TimeStamp = timeStamp;
775 
776     return E_OK;
777 }
778 
779 /*****************************************************************************/
780 t_Error FM_RTC_GetCurrentTime(t_Handle h_FmRtc, uint64_t *p_Ts)
781 {
782     t_FmRtc     *p_Rtc = (t_FmRtc *)h_FmRtc;
783     uint64_t    time;
784 
785     SANITY_CHECK_RETURN_ERROR(p_Rtc, E_INVALID_HANDLE);
786     SANITY_CHECK_RETURN_ERROR(!p_Rtc->p_RtcDriverParam, E_INVALID_STATE);
787 
788     /* TMR_CNT_L must be read first to get an accurate value */
789     time = (uint64_t)GET_UINT32(p_Rtc->p_MemMap->tmr_cnt_l);
790     time |= ((uint64_t)GET_UINT32(p_Rtc->p_MemMap->tmr_cnt_h) << 32);
791 
792     time = time*p_Rtc->clockPeriodNanoSec;
793 
794     *p_Ts = time;
795 
796     return E_OK;
797 }
798 
799 /*****************************************************************************/
800 t_Error FM_RTC_SetCurrentTime(t_Handle h_FmRtc, uint64_t ts)
801 {
802     t_FmRtc     *p_Rtc = (t_FmRtc *)h_FmRtc;
803 
804     SANITY_CHECK_RETURN_ERROR(p_Rtc, E_INVALID_HANDLE);
805     SANITY_CHECK_RETURN_ERROR(!p_Rtc->p_RtcDriverParam, E_INVALID_STATE);
806 
807     ts = ts/p_Rtc->clockPeriodNanoSec;
808     /* TMR_CNT_L must be written first to get an accurate value */
809     WRITE_UINT32(p_Rtc->p_MemMap->tmr_cnt_l, (uint32_t)ts);
810     WRITE_UINT32(p_Rtc->p_MemMap->tmr_cnt_h, (uint32_t)(ts >> 32));
811 
812     return E_OK;
813 }
814 
815 /*****************************************************************************/
816 t_Error FM_RTC_GetFreqCompensation(t_Handle h_FmRtc, uint32_t *p_Compensation)
817 {
818     t_FmRtc     *p_Rtc = (t_FmRtc *)h_FmRtc;
819 
820     SANITY_CHECK_RETURN_ERROR(p_Rtc, E_INVALID_HANDLE);
821     SANITY_CHECK_RETURN_ERROR(!p_Rtc->p_RtcDriverParam, E_INVALID_STATE);
822 
823     *p_Compensation = (uint32_t)
824         DIV_CEIL(ACCUMULATOR_OVERFLOW * 1000,
825                  p_Rtc->clockPeriodNanoSec * p_Rtc->srcClkFreqMhz);
826 
827     return E_OK;
828 }
829 
830 /*****************************************************************************/
831 t_Error FM_RTC_SetFreqCompensation(t_Handle h_FmRtc, uint32_t freqCompensation)
832 {
833     t_FmRtc *p_Rtc = (t_FmRtc *)h_FmRtc;
834 
835     SANITY_CHECK_RETURN_ERROR(p_Rtc, E_INVALID_HANDLE);
836     SANITY_CHECK_RETURN_ERROR(!p_Rtc->p_RtcDriverParam, E_INVALID_STATE);
837 
838     /* set the new freqCompensation */
839     WRITE_UINT32(p_Rtc->p_MemMap->tmr_add, freqCompensation);
840 
841     return E_OK;
842 }
843 
844 /*****************************************************************************/
845 #if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0))
846 t_Error FM_RTC_DumpRegs(t_Handle h_FmRtc)
847 {
848     t_FmRtc         *p_Rtc = (t_FmRtc *)h_FmRtc;
849     t_FmRtcMemMap   *p_MemMap = p_Rtc->p_MemMap;
850     int             i = 0;
851 
852     DECLARE_DUMP;
853 
854     if (p_MemMap)
855     {
856 
857         DUMP_TITLE(p_MemMap, ("RTC:"));
858         DUMP_VAR(p_MemMap, tmr_id);
859         DUMP_VAR(p_MemMap, tmr_id2);
860         DUMP_VAR(p_MemMap, tmr_ctrl);
861         DUMP_VAR(p_MemMap, tmr_tevent);
862         DUMP_VAR(p_MemMap, tmr_temask);
863         DUMP_VAR(p_MemMap, tmr_cnt_h);
864         DUMP_VAR(p_MemMap, tmr_cnt_l);
865         DUMP_VAR(p_MemMap, tmr_ctrl);
866         DUMP_VAR(p_MemMap, tmr_add);
867         DUMP_VAR(p_MemMap, tmr_acc);
868         DUMP_VAR(p_MemMap, tmr_prsc);
869         DUMP_VAR(p_MemMap, tmr_off_h);
870         DUMP_VAR(p_MemMap, tmr_off_l);
871 
872         DUMP_SUBSTRUCT_ARRAY(i, 2)
873         {
874             DUMP_VAR(p_MemMap, tmr_alarm[i].tmr_alarm_h);
875             DUMP_VAR(p_MemMap, tmr_alarm[i].tmr_alarm_l);
876         }
877         DUMP_SUBSTRUCT_ARRAY(i, 2)
878         {
879             DUMP_VAR(p_MemMap, tmr_fiper[i]);
880             DUMP_VAR(p_MemMap, tmr_fiper[i]);
881         }
882         DUMP_SUBSTRUCT_ARRAY(i, 2)
883         {
884             DUMP_VAR(p_MemMap, tmr_etts[i].tmr_etts_l);
885             DUMP_VAR(p_MemMap, tmr_etts[i].tmr_etts_l);
886         }
887     }
888 
889     return E_OK;
890 }
891 #endif /* (defined(DEBUG_ERRORS) && ... */
892