1 /* *****************************************************************************
2  * Copyright (C) 2016 Maxim Integrated Products, Inc., All Rights Reserved.
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included
12  * in all copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17  * IN NO EVENT SHALL MAXIM INTEGRATED BE LIABLE FOR ANY CLAIM, DAMAGES
18  * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20  * OTHER DEALINGS IN THE SOFTWARE.
21  *
22  * Except as contained in this notice, the name of Maxim Integrated
23  * Products, Inc. shall not be used except as stated in the Maxim Integrated
24  * Products, Inc. Branding Policy.
25  *
26  * The mere transfer of this software does not imply any licenses
27  * of trade secrets, proprietary technology, copyrights, patents,
28  * trademarks, maskwork rights, or any other form of intellectual
29  * property whatsoever. Maxim Integrated Products, Inc. retains all
30  * ownership rights.
31  *
32  * $Date: 2019-09-11 14:32:22 -0500 (Wed, 11 Sep 2019) $
33  * $Revision: 46047 $
34  *
35  **************************************************************************** */
36 
37 /* **** Includes **** */
38 #include "mxc_config.h"
39 #include "mxc_assert.h"
40 #include "mxc_sys.h"
41 #include "tmr.h"
42 
43 /* **** Definitions **** */
44 
45 /* **** Globals **** */
46 
47 /* **** Functions **** */
48 
49 /* ************************************************************************** */
TMR_Init(mxc_tmr_regs_t * tmr,tmr_pres_t pres,const sys_cfg_tmr_t * sys_cfg)50 int TMR_Init(mxc_tmr_regs_t *tmr, tmr_pres_t pres, const sys_cfg_tmr_t* sys_cfg)
51 {
52     MXC_ASSERT(tmr);
53 
54     int err;
55     // System settigns
56     if((err=SYS_TMR_Init(tmr, sys_cfg)) !=E_NO_ERROR)
57     {
58         return err;
59     }
60 
61     // Disable timer and clear settings
62     tmr->cn = 0;
63 
64     // Clear interrupt flag
65     tmr->intr = MXC_F_TMR_INTR_IRQ_CLR;
66 
67     // Set the prescaler
68     tmr->cn = pres;
69 
70     return err;
71 }
72 
TMR_Shutdown(mxc_tmr_regs_t * tmr)73 int TMR_Shutdown(mxc_tmr_regs_t *tmr)
74 {
75     MXC_ASSERT(tmr);
76 
77     int err;
78     // System settigns
79     if((err=SYS_TMR_Shutdown(tmr)) !=E_NO_ERROR)
80     {
81         return err;
82     }
83 
84     // Disable timer and clear settings
85     tmr->cn = 0;
86 
87     return err;
88 }
89 
90 /* ************************************************************************** */
TMR_Enable(mxc_tmr_regs_t * tmr)91 void TMR_Enable(mxc_tmr_regs_t* tmr)
92 {
93     MXC_ASSERT(tmr);
94 
95     tmr->cn |= MXC_F_TMR_CN_TEN;
96 }
97 
98 /* ************************************************************************** */
TMR_Disable(mxc_tmr_regs_t * tmr)99 void TMR_Disable(mxc_tmr_regs_t* tmr)
100 {
101     MXC_ASSERT(tmr);
102 
103     tmr->cn &= ~(MXC_F_TMR_CN_TEN);
104 }
105 
106 /* ************************************************************************** */
TMR_Config(mxc_tmr_regs_t * tmr,const tmr_cfg_t * cfg)107 int TMR_Config(mxc_tmr_regs_t *tmr, const tmr_cfg_t *cfg)
108 {
109     MXC_ASSERT(tmr);
110 
111     // Configure the timer
112     tmr->cn = (tmr->cn & ~(MXC_F_TMR_CN_TMODE | MXC_F_TMR_CN_TPOL)) |
113               ((cfg->mode << MXC_F_TMR_CN_TMODE_POS) & MXC_F_TMR_CN_TMODE) |
114               ((cfg->pol << MXC_F_TMR_CN_TPOL_POS) & MXC_F_TMR_CN_TPOL);
115 
116     tmr->cnt = 0x1;
117     tmr->cmp = cfg->cmp_cnt;
118 
119     return E_NO_ERROR;
120 }
121 
122 /* ************************************************************************** */
TMR_PWMConfig(mxc_tmr_regs_t * tmr,const tmr_pwm_cfg_t * cfg)123 int TMR_PWMConfig(mxc_tmr_regs_t *tmr, const tmr_pwm_cfg_t *cfg)
124 {
125     if (cfg->duty_cnt > cfg->per_cnt) {
126         return E_BAD_PARAM;
127     }
128 
129     // Configure the timer
130     tmr->cn = (tmr->cn & ~(MXC_F_TMR_CN_TMODE | MXC_F_TMR_CN_TPOL)) |
131               MXC_S_TMR_CN_TMODE_PWM | ((cfg->pol << MXC_F_TMR_CN_TPOL_POS) & MXC_F_TMR_CN_TPOL);
132 
133     tmr->cnt = 0x1;
134     tmr->cmp = cfg->per_cnt;
135     tmr->pwm = cfg->duty_cnt;
136 
137     return E_NO_ERROR;
138 }
139 
140 /* ************************************************************************** */
TMR_PWMSetDuty(mxc_tmr_regs_t * tmr,uint32_t duty)141 int TMR_PWMSetDuty(mxc_tmr_regs_t *tmr, uint32_t duty)
142 {
143     uint32_t cnt;
144 
145     // Make sure the new Duty count is less than the period count
146     if (duty > tmr->cmp) {
147         return E_BAD_PARAM;
148     }
149 
150     cnt = tmr->cnt; // make sure order of volatile access is known.
151     // Avoid glitching the output
152     if (duty >= tmr->pwm) {
153         // Wait for the count to be in the range of 1 to tmr->pwm
154         while (cnt > tmr->pwm) {
155             cnt = tmr->cnt; // update the volatile access variable
156         }
157     } else {
158         // Wait for the count to pass tmr->pwm
159         while (cnt < tmr->pwm) {
160             cnt = tmr->cnt; // update the volatile access variable
161         }
162     }
163     tmr->pwm = duty;
164 
165     return E_NO_ERROR;
166 }
167 
168 /* ************************************************************************** */
TMR_PWMSetPeriod(mxc_tmr_regs_t * tmr,uint32_t per)169 int TMR_PWMSetPeriod(mxc_tmr_regs_t *tmr, uint32_t per)
170 {
171     // Make sure the new Duty count is less than the period count
172     if (tmr->pwm > per) {
173         return E_BAD_PARAM;
174     }
175 
176     // Wait for the count to be less than the new dut_cnt
177     while (tmr->cnt >= per) {}
178     tmr->cmp = per;
179 
180     return E_NO_ERROR;
181 }
182 
183 
184 /* ************************************************************************** */
TMR_GetCompare(mxc_tmr_regs_t * tmr)185 uint32_t TMR_GetCompare(mxc_tmr_regs_t* tmr)
186 {
187     return tmr->cmp;
188 }
189 
190 /* ************************************************************************** */
TMR_GetCapture(mxc_tmr_regs_t * tmr)191 uint32_t TMR_GetCapture(mxc_tmr_regs_t* tmr)
192 {
193     return tmr->pwm;
194 }
195 
196 /* ************************************************************************* */
TMR_GetCount(mxc_tmr_regs_t * tmr)197 uint32_t TMR_GetCount(mxc_tmr_regs_t* tmr)
198 {
199     return tmr->cnt;
200 }
201 
202 /* ************************************************************************* */
TMR_IntClear(mxc_tmr_regs_t * tmr)203 void TMR_IntClear(mxc_tmr_regs_t* tmr)
204 {
205     tmr->intr = MXC_F_TMR_INTR_IRQ_CLR;
206 }
207 
208 /* ************************************************************************* */
TMR_IntStatus(mxc_tmr_regs_t * tmr)209 uint32_t TMR_IntStatus(mxc_tmr_regs_t* tmr)
210 {
211     return tmr->intr;
212 }
213 
214 /* ************************************************************************* */
TMR_SetCompare(mxc_tmr_regs_t * tmr,uint32_t cmp_cnt)215 void TMR_SetCompare(mxc_tmr_regs_t *tmr, uint32_t cmp_cnt)
216 {
217     tmr->cmp = cmp_cnt;
218 }
219 
220 /* ************************************************************************* */
TMR_SetCount(mxc_tmr_regs_t * tmr,uint32_t cnt)221 void TMR_SetCount(mxc_tmr_regs_t *tmr, uint32_t cnt)
222 {
223     tmr->cnt = cnt;
224 }
225 
226 /* ************************************************************************* */
TMR_GetTicks(mxc_tmr_regs_t * tmr,uint32_t time,tmr_unit_t units,uint32_t * ticks)227 int TMR_GetTicks(mxc_tmr_regs_t *tmr, uint32_t time, tmr_unit_t units, uint32_t *ticks)
228 {
229     uint32_t unit_div0, unit_div1;
230     uint32_t timerClock;
231     uint32_t prescale;
232     uint64_t temp_ticks;
233 
234     timerClock = SYS_TMR_GetFreq(tmr);
235     prescale = ((tmr->cn & MXC_F_TMR_CN_PRES) >> MXC_F_TMR_CN_PRES_POS)
236         | (((tmr->cn & MXC_F_TMR_CN_PRES3) >> (MXC_F_TMR_CN_PRES3_POS))<<3);
237 
238     switch (units) {
239         case TMR_UNIT_NANOSEC:
240             unit_div0 = 1000000;
241             unit_div1 = 1000;
242             break;
243         case TMR_UNIT_MICROSEC:
244             unit_div0 = 1000;
245             unit_div1 = 1000;
246             break;
247         case TMR_UNIT_MILLISEC:
248             unit_div0 = 1;
249             unit_div1 = 1000;
250             break;
251         case TMR_UNIT_SEC:
252             unit_div0 = 1;
253             unit_div1 = 1;
254             break;
255         default:
256             return E_BAD_PARAM;
257     }
258 
259     temp_ticks = (uint64_t)time * (timerClock / unit_div0) / (unit_div1 * (1 << (prescale & 0xF)));
260 
261     //make sure ticks is within a 32 bit value
262     if (!(temp_ticks & 0xffffffff00000000)  && (temp_ticks & 0xffffffff)) {
263         *ticks = temp_ticks;
264         return E_NO_ERROR;
265     }
266 
267     return E_INVALID;
268 }
269 
270 /* ************************************************************************* */
TMR_GetTime(mxc_tmr_regs_t * tmr,uint32_t ticks,uint32_t * time,tmr_unit_t * units)271 int TMR_GetTime(mxc_tmr_regs_t *tmr, uint32_t ticks, uint32_t *time, tmr_unit_t *units)
272 {
273     uint64_t temp_time = 0;
274     uint32_t timerClock = SYS_TMR_GetFreq(tmr);
275     uint32_t prescale = ((tmr->cn & MXC_F_TMR_CN_PRES) >> MXC_F_TMR_CN_PRES_POS)
276         | (((tmr->cn & MXC_F_TMR_CN_PRES3) >> (MXC_F_TMR_CN_PRES3_POS))<<3);
277 
278     temp_time = (uint64_t)ticks * 1000 * (1 << (prescale & 0xF)) / (timerClock / 1000000);
279     if (!(temp_time & 0xffffffff00000000)) {
280         *time = temp_time;
281         *units = TMR_UNIT_NANOSEC;
282         return E_NO_ERROR;
283     }
284 
285     temp_time = (uint64_t)ticks * 1000 * (1 << (prescale & 0xF)) / (timerClock / 1000);
286     if (!(temp_time & 0xffffffff00000000)) {
287         *time = temp_time;
288         *units = TMR_UNIT_MICROSEC;
289         return E_NO_ERROR;
290     }
291 
292     temp_time = (uint64_t)ticks * 1000 * (1 << (prescale & 0xF)) / timerClock;
293     if (!(temp_time & 0xffffffff00000000)) {
294         *time = temp_time;
295         *units = TMR_UNIT_MILLISEC;
296         return E_NO_ERROR;
297     }
298 
299     temp_time = (uint64_t)ticks * (1 << (prescale & 0xF)) / timerClock;
300     if (!(temp_time & 0xffffffff00000000)) {
301         *time = temp_time;
302         *units = TMR_UNIT_SEC;
303         return E_NO_ERROR;
304     }
305 
306     return E_INVALID;
307 }
308