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/*****************************************************************************/
55static 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/*****************************************************************************/
92static 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/*****************************************************************************/
146t_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/*****************************************************************************/
192t_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/*****************************************************************************/
258t_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/*****************************************************************************/
281t_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/*****************************************************************************/
298t_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/*****************************************************************************/
311t_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/*****************************************************************************/
324t_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/*****************************************************************************/
337t_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/*****************************************************************************/
350t_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/*****************************************************************************/
363t_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/*****************************************************************************/
376t_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/*****************************************************************************/
395t_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/*****************************************************************************/
416t_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/*****************************************************************************/
428t_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/*****************************************************************************/
443t_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/*****************************************************************************/
455t_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/*****************************************************************************/
492t_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/*****************************************************************************/
532t_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/*****************************************************************************/
551t_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/*****************************************************************************/
575t_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/*****************************************************************************/
593t_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/*****************************************************************************/
611t_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/*****************************************************************************/
624t_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/*****************************************************************************/
638t_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/*****************************************************************************/
651t_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/*****************************************************************************/
666t_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/*****************************************************************************/
680t_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