1 /**
2 * \file
3 *
4 * \brief SAM Watchdog Driver for SAMB
5 *
6 * Copyright (C) 2015 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 "wdt_sam_b.h"
47
48 struct wdt_module *_wdt_instances[WDT_INST_NUM];
49
wdt_isr_handler(void)50 static void wdt_isr_handler(void)
51 {
52 struct wdt_module *module = NULL;
53
54 if (WDT0->WDOGMIS.reg) {
55 module = _wdt_instances[0];
56 if (!(module->hw->WDOGCONTROL.reg & WDT_WDOGCONTROL_RESEN)) {
57 module->hw->WDOGINTCLR.reg = 0x01;
58 }
59 if ((module->callback_enable_mask & (1 << WDT_CALLBACK_EARLY_WARNING)) &&
60 (module->callback_reg_mask & (1 << WDT_CALLBACK_EARLY_WARNING))) {
61 (module->callback[WDT_CALLBACK_EARLY_WARNING])();
62 }
63 }
64 if (WDT1->WDOGMIS.reg) {
65 module = _wdt_instances[1];
66 if (!(module->hw->WDOGCONTROL.reg & WDT_WDOGCONTROL_RESEN)) {
67 module->hw->WDOGINTCLR.reg = 0x01;
68 }
69 if ((module->callback_enable_mask & (1 << WDT_CALLBACK_EARLY_WARNING)) &&
70 (module->callback_reg_mask & (1 << WDT_CALLBACK_EARLY_WARNING))) {
71 (module->callback[WDT_CALLBACK_EARLY_WARNING])();
72 }
73 }
74 }
75
76 /**
77 * \brief Initializes a Watchdog Timer configuration structure to defaults.
78 *
79 * Initializes a given Watchdog Timer configuration structure to a set of
80 * known default values. This function should be called on all new
81 * instances of these configuration structures before being modified by the
82 * user application.
83 *
84 * The default configuration is as follows:
85 * \li Load register value
86 * \li Enable reset output
87 * \li Open write access
88 *
89 * \param[out] config Configuration structure to initialize to default values
90 */
wdt_get_config_defaults(struct wdt_config * const config)91 void wdt_get_config_defaults(struct wdt_config *const config)
92 {
93 /* Sanity check arguments */
94 Assert(config);
95
96 config->load_value = 0xFFFFFFFF;
97 config->enable_reset = true;
98 config->write_access = true;
99 }
100
101 /**
102 * \brief Sets up the WDT hardware module based on the configuration.
103 *
104 * Writes a given configuration of a WDT configuration to the
105 * hardware module, and initializes the internal device struct.
106 *
107 * \param[in] module Pointer to the software instance struct
108 * \param[in] hw Pointer to WDT hardware instance
109 * \param[in] config Pointer to configuration struct
110 *
111 * \return Status of the initialization.
112 *
113 * \retval STATUS_OK The initialization was successful
114 * \retval STATUS_ERR_BAD_DATA If the value isn't available
115 */
wdt_set_config(struct wdt_module * const module,Wdt * const hw,const struct wdt_config * const config)116 enum status_code wdt_set_config(struct wdt_module *const module, Wdt * const hw,
117 const struct wdt_config *const config)
118 {
119 /* Sanity check arguments */
120 Assert(module);
121 Assert(hw);
122 Assert(config);
123
124 /* Assign module pointer to software instance struct */
125 module->hw = hw;
126
127 if (config->load_value == 0) {
128 return STATUS_ERR_BAD_DATA;
129 }
130
131 if (module->hw == WDT0) {
132 system_clock_peripheral_disable(PERIPHERAL_WDT0);
133 } else if (module->hw ==WDT1) {
134 system_clock_peripheral_disable(PERIPHERAL_WDT1);
135 }
136
137 /* Unlock register */
138 module->hw->WDOGLOCK.reg = WDT_WRITE_ACCESS_KEY;
139
140 module->hw->WDOGLOAD.reg = config->load_value;
141
142 if (config->enable_reset) {
143 module->hw->WDOGCONTROL.reg |= WDT_WDOGCONTROL_RESEN;
144 }
145 module->hw->WDOGCONTROL.reg |= WDT_WDOGCONTROL_INTEN;
146
147 /* Lock register */
148 if (config->write_access == false) {
149 module->hw->WDOGLOCK.reg = WDT_WDOGLOCK_ENABLE_STATUS;
150 }
151
152 system_register_isr(RAM_ISR_TABLE_NMI_INDEX, (uint32_t)wdt_isr_handler);
153
154 /* Enable WDT clock */
155 if (module->hw == WDT0) {
156 _wdt_instances[0] = module;
157 system_clock_peripheral_enable(PERIPHERAL_WDT0);
158 } else if (module->hw == WDT1) {
159 _wdt_instances[1] = module;
160 system_clock_peripheral_enable(PERIPHERAL_WDT1);
161 }
162
163 return STATUS_OK;
164 }
165
166 /**
167 * \brief Reset WDT module.
168 *
169 * Reset WDT module.
170 *
171 * \param[in] module Pointer to the software instance struct
172 */
wdt_reset(struct wdt_module * const module)173 void wdt_reset(struct wdt_module *const module)
174 {
175 if (module->hw == WDT0) {
176 system_peripheral_reset(PERIPHERAL_WDT0);
177 } else if (module->hw == WDT1) {
178 system_peripheral_reset(PERIPHERAL_WDT1);
179 }
180 }
181
182 /**
183 * \brief Get WDT interrupt status.
184 *
185 * Get WDT interrupt status.
186 *
187 * \param[in] module Pointer to the software instance struct
188 */
wdt_get_interrupt_status(struct wdt_module * const module)189 uint8_t wdt_get_interrupt_status(struct wdt_module *const module)
190 {
191 return module->hw->WDOGMIS.reg;
192 }
193
194 /**
195 * \brief Get WDT raw interrupt status.
196 *
197 * Get WDT raw interrupt status.
198 *
199 * \param[in] module Pointer to the software instance struct
200 */
wdt_get_status(struct wdt_module * const module)201 uint8_t wdt_get_status(struct wdt_module *const module)
202 {
203 return module->hw->WDOGRIS.reg;
204 }
205
206 /**
207 * \brief Clear WDT interrupt status.
208 *
209 * Clear WDT interrupt status.
210 *
211 * \param[in] module Pointer to the software instance struct
212 */
wdt_clear_status(struct wdt_module * const module)213 void wdt_clear_status(struct wdt_module *const module)
214 {
215 module->hw->WDOGINTCLR.reg = 0x01;
216 }
217
218 /**
219 * \brief Reload the count of the running Watchdog Timer.
220 *
221 * Reload the value of WDT Load register. When this register is written to,
222 * the count is immediately restarted from the new value.
223 *
224 * \param[in] module Pointer to the software instance struct
225 * \param[in] load_value Reload value
226 *
227 * \return Status of the operation.
228 * \retval STATUS_OK If the operation was completed
229 * \retval STATUS_ERR_BAD_DATA If the value isn't available
230 */
wdt_set_reload_count(struct wdt_module * const module,uint32_t load_value)231 enum status_code wdt_set_reload_count(struct wdt_module *const module, uint32_t load_value)
232 {
233 if (load_value == 0) {
234 return STATUS_ERR_BAD_DATA;
235 } else {
236 if (module->hw->WDOGLOCK.bit.ENABLE_STATUS) {
237 module->hw->WDOGLOCK.reg = WDT_WRITE_ACCESS_KEY;
238 module->hw->WDOGLOAD.reg = load_value;
239 module->hw->WDOGLOCK.reg = WDT_WDOGLOCK_ENABLE_STATUS;
240 } else {
241 module->hw->WDOGLOAD.reg = load_value;
242 }
243 }
244
245 return STATUS_OK;
246 }
247
248 /**
249 * \brief Get the current count value of the running Watchdog Timer.
250 *
251 * Get the current count value of the running Watchdog Timer.
252 *
253 * \param[in] module Pointer to the software instance struct
254 * \param[in,out] count_value Pointer to store the current count value
255 *
256 */
wdt_get_current_count(struct wdt_module * const module,uint32_t * count_value)257 void wdt_get_current_count(struct wdt_module *const module, \
258 uint32_t * count_value)
259 {
260 *count_value = module->hw->WDOGVALUE.reg;
261 }
262
263 /**
264 * \brief Registers a callback
265 *
266 * Registers a callback function which is implemented by the user.
267 *
268 * \note The callback must be enabled by \ref wdt_enable_callback,
269 * in order for the interrupt handler to call it when the conditions for
270 * the callback type are met.
271 *
272 * \param[in] module Pointer to WDT software instance struct
273 * \param[in] callback_func Pointer to callback function
274 * \param[in] callback_type Callback type given by an enum
275 *
276 */
wdt_register_callback(struct wdt_module * const module,wdt_callback_t callback_func,enum wdt_callback callback_type)277 void wdt_register_callback(struct wdt_module *const module,
278 wdt_callback_t callback_func,
279 enum wdt_callback callback_type)
280 {
281 /* Sanity check arguments */
282 Assert(module);
283 Assert(callback_func);
284
285 /* Register callback function */
286 module->callback[callback_type] = callback_func;
287 /* Set the bit corresponding to the callback_type */
288 module->callback_reg_mask |= (1 << callback_type);
289 }
290
291 /**
292 * \brief Unregisters a callback
293 *
294 * Unregisters a callback function which is implemented by the user.
295 *
296 * \param[in,out] module Pointer to WDT software instance struct
297 * \param[in] callback_type Callback type given by an enum
298 *
299 */
wdt_unregister_callback(struct wdt_module * module,enum wdt_callback callback_type)300 void wdt_unregister_callback(struct wdt_module *module,
301 enum wdt_callback callback_type)
302 {
303 /* Sanity check arguments */
304 Assert(module);
305
306 /* Unregister callback function */
307 module->callback[callback_type] = NULL;
308 /* Clear the bit corresponding to the callback_type */
309 module->callback_reg_mask &= ~(1 << callback_type);
310 }
311
312 /**
313 * \brief Enables callback
314 *
315 * Enables the callback function registered by the \ref usart_register_callback.
316 * The callback function will be called from the interrupt handler when the
317 * conditions for the callback type are met.
318 *
319 * \param[in] module Pointer to WDT software instance struct
320 * \param[in] callback_type Callback type given by an enum
321 */
wdt_enable_callback(struct wdt_module * const module,enum wdt_callback callback_type)322 void wdt_enable_callback(struct wdt_module *const module,
323 enum wdt_callback callback_type)
324 {
325 /* Sanity check arguments */
326 Assert(module);
327
328 /* Enable callback */
329 module->callback_enable_mask |= (1 << callback_type);
330 }
331
332 /**
333 * \brief Disable callback
334 *
335 * Disables the callback function registered by the \ref usart_register_callback,
336 * and the callback will not be called from the interrupt routine.
337 *
338 * \param[in] module Pointer to WDT software instance struct
339 * \param[in] callback_type Callback type given by an enum
340 */
wdt_disable_callback(struct wdt_module * const module,enum wdt_callback callback_type)341 void wdt_disable_callback(struct wdt_module *const module,
342 enum wdt_callback callback_type)
343 {
344 /* Sanity check arguments */
345 Assert(module);
346
347 /* Disable callback */
348 module->callback_enable_mask &= ~(1 << callback_type);
349 }