/* * Copyright (c) 2016 Open-RnD Sp. z o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @brief Driver for Independent Watchdog (IWDG) for STM32 MCUs * * Based on reference manual: * STM32F101xx, STM32F102xx, STM32F103xx, STM32F105xx and STM32F107xx * advanced ARM ® -based 32-bit MCUs * * Chapter 19: Independent watchdog (IWDG) * */ #include #include #include #include "iwdg_stm32.h" #define AS_IWDG(__base_addr) \ (struct iwdg_stm32 *)(__base_addr) static void iwdg_stm32_enable(struct device *dev) { volatile struct iwdg_stm32 *iwdg = AS_IWDG(IWDG_BASE); ARG_UNUSED(dev); iwdg->kr.bit.key = STM32_IWDG_KR_START; } static void iwdg_stm32_disable(struct device *dev) { /* watchdog cannot be stopped once started */ ARG_UNUSED(dev); } static int iwdg_stm32_set_config(struct device *dev, struct wdt_config *config) { ARG_UNUSED(dev); ARG_UNUSED(config); /* no configuration */ return -ENOTSUP; } static void iwdg_stm32_get_config(struct device *dev, struct wdt_config *config) { ARG_UNUSED(dev); ARG_UNUSED(config); } static void iwdg_stm32_reload(struct device *dev) { volatile struct iwdg_stm32 *iwdg = AS_IWDG(IWDG_BASE); ARG_UNUSED(dev); iwdg->kr.bit.key = STM32_IWDG_KR_RELOAD; } static const struct wdt_driver_api iwdg_stm32_api = { .enable = iwdg_stm32_enable, .disable = iwdg_stm32_disable, .get_config = iwdg_stm32_get_config, .set_config = iwdg_stm32_set_config, .reload = iwdg_stm32_reload, }; static inline int __iwdg_stm32_prescaler(int setting) { int v; int i = 0; /* prescaler range 4 - 256 */ for (v = 4; v < 256; v *= 2, i++) { if (v == setting) return i; } return i; } static int iwdg_stm32_init(struct device *dev) { volatile struct iwdg_stm32 *iwdg = AS_IWDG(IWDG_BASE); /* clock setup is not required, once the watchdog is enabled * LSI oscillator will be forced on and fed to IWD after * stabilization period */ /* unlock access to configuration registers */ iwdg->kr.bit.key = STM32_IWDG_KR_UNLOCK; iwdg->pr.bit.pr = __iwdg_stm32_prescaler(CONFIG_IWDG_STM32_PRESCALER); iwdg->rlr.bit.rl = CONFIG_IWDG_STM32_RELOAD_COUNTER; #ifdef CONFIG_IWDG_STM32_START_AT_BOOT iwdg_stm32_enable(dev); #endif return 0; } DEVICE_AND_API_INIT(iwdg_stm32, CONFIG_IWDG_STM32_DEVICE_NAME, iwdg_stm32_init, NULL, NULL, PRE_KERNEL_1, CONFIG_KERNEL_INIT_PRIORITY_DEVICE, &iwdg_stm32_api);