|  | /* | 
|  | * 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 <watchdog.h> | 
|  | #include <soc.h> | 
|  | #include <errno.h> | 
|  |  | 
|  | #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); |