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 /*****************************************************************************/
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 /*****************************************************************************/
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 /*****************************************************************************/
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 /*****************************************************************************/
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 /*****************************************************************************/
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 /*****************************************************************************/
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 /*****************************************************************************/
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 /*****************************************************************************/
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 /*****************************************************************************/
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 /*****************************************************************************/
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 /*****************************************************************************/
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 /*****************************************************************************/
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 /*****************************************************************************/
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 /*****************************************************************************/
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 /*****************************************************************************/
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 /*****************************************************************************/
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 /*****************************************************************************/
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 /*****************************************************************************/
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 /*****************************************************************************/
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 /*****************************************************************************/
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 /*****************************************************************************/
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 /*****************************************************************************/
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 /*****************************************************************************/
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 /*****************************************************************************/
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 /*****************************************************************************/
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 /*****************************************************************************/
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 /*****************************************************************************/
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 /*****************************************************************************/
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 /*****************************************************************************/
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