1 /**
2  * \file
3  *
4  * \brief SAM DUALTIMER Driver for SAMB11
5  *
6  * Copyright (C) 2015-2016 Atmel Corporation. All rights reserved.
7  *
8  * \asf_license_start
9  *
10  * \page License
11  *
12  * Redistribution and use in source and binary forms, with or without
13  * modification, are permitted provided that the following conditions are met:
14  *
15  * 1. Redistributions of source code must retain the above copyright notice,
16  *    this list of conditions and the following disclaimer.
17  *
18  * 2. Redistributions in binary form must reproduce the above copyright notice,
19  *    this list of conditions and the following disclaimer in the documentation
20  *    and/or other materials provided with the distribution.
21  *
22  * 3. The name of Atmel may not be used to endorse or promote products derived
23  *    from this software without specific prior written permission.
24  *
25  * 4. This software may only be redistributed and used in connection with an
26  *    Atmel microcontroller product.
27  *
28  * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
29  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
30  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
31  * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
32  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
33  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
34  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
35  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
36  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
37  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
38  * POSSIBILITY OF SUCH DAMAGE.
39  *
40  * \asf_license_stop
41  *
42  */
43 /*
44  * Support and FAQ: visit <a href="http://www.atmel.com/design-support/">Atmel Support</a>
45  */
46 #include "dualtimer.h"
47 
48 static dualtimer_callback_t dualtimer_callback_timer1 = NULL;
49 static dualtimer_callback_t dualtimer_callback_timer2 = NULL;
50 /**
51  * \brief Initializes config with predefined default values.
52  *
53  * This function will initialize a given Dualtimer configuration structure to
54  * a set of known default values. This function should be called on
55  * any new instance of the configuration structures before being
56  * modified by the user application.
57  *
58  * \param[out]  config  Pointer to a DUALTIMER module configuration structure to set
59  */
dualtimer_get_config_defaults(struct dualtimer_config * config)60 void dualtimer_get_config_defaults(struct dualtimer_config *config)
61 {
62 	config->timer1.timer_enable = true;
63 	config->timer2.timer_enable = true;
64 
65 	config->timer1.counter_mode = DUALTIMER_PERIODIC_MODE;
66 	config->timer2.counter_mode = DUALTIMER_PERIODIC_MODE;
67 
68 	config->timer1.counter_size = DUALTIMER_COUNTER_SIZE_32BIT;
69 	config->timer2.counter_size = DUALTIMER_COUNTER_SIZE_32BIT;
70 
71 	config->timer1.clock_prescaler = DUALTIMER_CLOCK_PRESCALER_DIV1;
72 	config->timer2.clock_prescaler = DUALTIMER_CLOCK_PRESCALER_DIV1;
73 
74 	config->timer1.interrup_enable = true;
75 	config->timer2.interrup_enable = true;
76 
77 	config->timer1.load_value = 0;
78 	config->timer2.load_value = 0;
79 
80 	config->clock_source = DUALTIMER_CLK_INPUT_0;
81 }
82 
83 
84 /**
85  * \brief Get Dualtimer module timer1/timer2 current value.
86  *
87  * \param[in]     timer        Timer1/Timer2
88  *
89  * \retval Timer1/Timer2 current value
90  */
dualtimer_get_value(enum dualtimer_timer timer)91 uint32_t dualtimer_get_value(enum dualtimer_timer timer)
92 {
93 	if (timer == DUALTIMER_TIMER1) {
94 		return DUALTIMER0->TIMER1VALUE.reg;
95 	} else {
96 		return DUALTIMER0->TIMER2VALUE.reg;
97 	}
98 }
99 
100 /**
101  * \brief Set Dualtimer module timer1/timer2 load value.
102  *
103  * \param[in]     timer        Timer1/Timer2
104  * \param[in]     cur_bg       Current/Background
105  * \param[in]     value        Load value
106  */
dualtimer_set_counter(enum dualtimer_timer timer,enum dualtimer_set_register cur_bg,uint32_t value)107 void dualtimer_set_counter(enum dualtimer_timer timer,
108 		enum dualtimer_set_register cur_bg, uint32_t value)
109 {
110 	if (timer == DUALTIMER_TIMER1) {
111 		if (cur_bg == DUALTIMER_SET_CURRUNT_REG) {
112 			DUALTIMER0->TIMER1LOAD.reg = value;
113 		} else {
114 			DUALTIMER0->TIMER1BGLOAD.reg = value;
115 		}
116 	} else {
117 		if (cur_bg == DUALTIMER_SET_CURRUNT_REG) {
118 			DUALTIMER0->TIMER2LOAD.reg = value;
119 			} else {
120 			DUALTIMER0->TIMER2BGLOAD.reg = value;
121 		}
122 	}
123 }
124 
125 /**
126  * \brief Get Dualtimer module timer1/timer2 raw interrupt status
127  *
128  * \param[in]     timer        Timer1/Timer2
129  *
130  * \retval The raw interrupt status of timer1/timer2
131  */
dualtimer_get_status(enum dualtimer_timer timer)132 uint8_t dualtimer_get_status(enum dualtimer_timer timer)
133 {
134 	if (timer == DUALTIMER_TIMER1) {
135 		return DUALTIMER0->TIMER1RIS.reg;
136 	} else {
137 		return DUALTIMER0->TIMER2RIS.reg;
138 	}
139 }
140 
141 /**
142  * \brief Get Dualtimer module timer1/timer2 interrupt status
143  *
144  * \param[in]     timer        Timer1/Timer2
145  *
146  * \retval The interrupt status of timer1/timer2
147  */
dualtimer_get_interrupt_status(enum dualtimer_timer timer)148 uint8_t dualtimer_get_interrupt_status(enum dualtimer_timer timer)
149 {
150 	if (timer == DUALTIMER_TIMER1) {
151 		return DUALTIMER0->TIMER1MIS.reg;
152 	} else {
153 		return DUALTIMER0->TIMER2MIS.reg;
154 	}
155 }
156 
157 /**
158  * \brief Clear Dualtimer module timer1/timer2 interrupt status
159  *
160  * Clear the Dualtimer module timer1/timer2 interrupt status
161  *
162  * \param[in]     timer        Timer1/Timer2
163  */
dualtimer_clear_interrupt_status(enum dualtimer_timer timer)164 void dualtimer_clear_interrupt_status(enum dualtimer_timer timer)
165 {
166 	if (timer == DUALTIMER_TIMER1) {
167 		DUALTIMER0->TIMER1INTCLR.reg = 1;
168 	} else {
169 		DUALTIMER0->TIMER2INTCLR.reg = 1;
170 	}
171 }
172 
173 /**
174  * \brief Set Dualtimer module timer1/timer2 enable
175  *
176  * Enable the Dualtimer module timer1/timer2
177  *
178  * \param[in]     timer        Timer1/Timer2
179  */
dualtimer_enable(enum dualtimer_timer timer)180 void dualtimer_enable(enum dualtimer_timer timer)
181 {
182 	if (timer == DUALTIMER_TIMER1) {
183 		DUALTIMER0->TIMER1CONTROL.reg |= DUALTIMER_TIMER1CONTROL_TIMER_ENABLE;
184 	} else {
185 		DUALTIMER0->TIMER2CONTROL.reg |= DUALTIMER_TIMER2CONTROL_TIMER_ENABLE;
186 	}
187 }
188 
189 /**
190  * \brief Set Dualtimer module timer1/timer2 disable
191  *
192  * Disable the Dualtimer module timer1/timer2
193  *
194  * \param[in]     timer        Timer1/Timer2
195  */
dualtimer_disable(enum dualtimer_timer timer)196 void dualtimer_disable(enum dualtimer_timer timer)
197 {
198 	if (timer == DUALTIMER_TIMER1) {
199 		DUALTIMER0->TIMER1CONTROL.reg &= ~DUALTIMER_TIMER1CONTROL_TIMER_ENABLE;
200 	} else {
201 		DUALTIMER0->TIMER2CONTROL.reg &= ~DUALTIMER_TIMER2CONTROL_TIMER_ENABLE;
202 	}
203 }
204 
205 /**
206  * \brief Dualtimer ISR handler.
207  *
208  * Dualtimer ISR handler.
209  *
210  */
dualtimer_isr_handler(void)211 static void dualtimer_isr_handler(void)
212 {
213 	if (dualtimer_get_interrupt_status(DUALTIMER_TIMER1)) {
214 		dualtimer_clear_interrupt_status(DUALTIMER_TIMER1);
215 		if (dualtimer_callback_timer1)
216 			dualtimer_callback_timer1();
217 	}
218 	if (dualtimer_get_interrupt_status(DUALTIMER_TIMER2)) {
219 		dualtimer_clear_interrupt_status(DUALTIMER_TIMER2);
220 		if (dualtimer_callback_timer2)
221 			dualtimer_callback_timer2();
222 	}
223 }
224 
225 /**
226  * \brief Initializes Dualtimer module instance.
227  *
228  * Initializes the Dualtimer module, based on the given
229  * configuration values.
230  *
231  * \param[in]     config       Pointer to the Dualtimer configuration options struct
232  *
233  * \return Status of the initialization procedure.
234  */
dualtimer_init(const struct dualtimer_config * config)235 void dualtimer_init(const struct dualtimer_config *config)
236 {
237 	uint8_t regval = 0;
238 
239 	/* Global reset */
240 	system_peripheral_reset(PERIPHERAL_DUALT_TIMER);
241 
242 	/* Common config */
243 	if (config->timer1.timer_enable || config->timer2.timer_enable) {
244 		LPMCU_MISC_REGS0->LPMCU_CLOCK_ENABLES_0.reg |=
245 		LPMCU_MISC_REGS_LPMCU_CLOCK_ENABLES_0_DUALTIMER0_CLK_EN;
246 		LPMCU_MISC_REGS0->LPMCU_CTRL.bit.DUALTIMER0_CLK_SEL = config->clock_source;
247 	}
248 
249 	/* Timer1 config */
250 	if (config->timer1.timer_enable) {
251 		if (config->timer1.counter_mode == DUALTIMER_ONE_SHOT_MODE) {
252 			regval = DUALTIMER_TIMER1CONTROL_ONE_SHOT_COUNT_1;
253 		} else if (config->timer1.counter_mode == DUALTIMER_FREE_RUNNING_MODE) {
254 			regval = DUALTIMER_TIMER1CONTROL_TIMER_MODE_0;
255 		} else if (config->timer1.counter_mode == DUALTIMER_PERIODIC_MODE) {
256 			regval = DUALTIMER_TIMER1CONTROL_TIMER_MODE_1;
257 		}
258 		regval |= (DUALTIMER_TIMER1CONTROL_TIMER_SIZE &
259 				((config->timer1.counter_size) << DUALTIMER_TIMER1CONTROL_TIMER_SIZE_Pos)) |
260 				DUALTIMER_TIMER1CONTROL_TIMERPRE(config->timer1.clock_prescaler);
261 		if (config->timer1.interrup_enable) {
262 			regval |= DUALTIMER_TIMER1CONTROL_INTERRUPT_ENABLE;
263 		}
264 		DUALTIMER0->TIMER1LOAD.reg = config->timer1.load_value;
265 		DUALTIMER0->TIMER1CONTROL.reg = regval;
266 		LPMCU_MISC_REGS0->DUALTIMER0_CTRL.reg |= LPMCU_MISC_REGS_DUALTIMER0_CTRL_CNTR_1_ENABLE;
267 		dualtimer_enable(DUALTIMER_TIMER1);
268 	}
269 
270 	/* Timer2 config */
271 	if (config->timer2.timer_enable) {
272 		if (config->timer2.counter_mode == DUALTIMER_ONE_SHOT_MODE) {
273 			regval = DUALTIMER_TIMER2CONTROL_ONE_SHOT_COUNT_1;
274 		} else if (config->timer2.counter_mode == DUALTIMER_FREE_RUNNING_MODE) {
275 			regval = DUALTIMER_TIMER2CONTROL_TIMER_MODE_0;
276 		} else if (config->timer2.counter_mode == DUALTIMER_PERIODIC_MODE) {
277 			regval = DUALTIMER_TIMER2CONTROL_TIMER_MODE_1;
278 		}
279 		regval |= (DUALTIMER_TIMER2CONTROL_TIMER_SIZE &
280 				((config->timer2.counter_size) << DUALTIMER_TIMER2CONTROL_TIMER_SIZE_Pos)) |
281 				DUALTIMER_TIMER2CONTROL_TIMERPRE(config->timer2.clock_prescaler);
282 		if (config->timer2.interrup_enable) {
283 			regval |= DUALTIMER_TIMER2CONTROL_INTERRUPT_ENABLE;
284 		}
285 		DUALTIMER0->TIMER2LOAD.reg = config->timer2.load_value;
286 		DUALTIMER0->TIMER2CONTROL.reg = regval;
287 		LPMCU_MISC_REGS0->DUALTIMER0_CTRL.reg |= LPMCU_MISC_REGS_DUALTIMER0_CTRL_CNTR_2_ENABLE;
288 		dualtimer_enable(DUALTIMER_TIMER2);
289 	}
290 
291 	system_register_isr(RAM_ISR_TABLE_DUALTIMER_INDEX, (uint32_t)dualtimer_isr_handler);
292 }
293 
294 /**
295  * \brief Registers a callback.
296  *
297  * Registers and enable a callback function which is implemented by the user.
298  *
299  * \param[in]     callback_func Pointer to callback function
300  */
dualtimer_register_callback(enum dualtimer_timer timer,dualtimer_callback_t fun)301 void dualtimer_register_callback(enum dualtimer_timer timer, dualtimer_callback_t fun)
302 {
303 	if (timer == DUALTIMER_TIMER1) {
304 		dualtimer_callback_timer1 = fun;
305 	} else {
306 		dualtimer_callback_timer2 = fun;
307 	}
308 }
309 
310 /**
311  * \brief Unregisters a callback.
312  *
313  * Unregisters and disable a callback function implemented by the user.
314  *
315  */
dualtimer_unregister_callback(enum dualtimer_timer timer)316 void dualtimer_unregister_callback(enum dualtimer_timer timer)
317 {
318 	if (timer == DUALTIMER_TIMER1) {
319 		dualtimer_callback_timer1 = NULL;
320 	} else {
321 		dualtimer_callback_timer2 = NULL;
322 	}
323 }