| /* |
| * Copyright (C) 2017 C-SKY Microsystems Co., Ltd. All rights reserved. |
| * |
| * 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. |
| */ |
| |
| /****************************************************************************** |
| * @file dw_wdt.c |
| * @brief CSI Source File for WDT Driver |
| * @version V1.0 |
| * @date 02. June 2017 |
| ******************************************************************************/ |
| #include <stdio.h> |
| #include "drv_wdt.h" |
| #include "dw_wdt.h" |
| #include "soc.h" |
| #include "csi_core.h" |
| |
| #define ERR_WDT(errno) (CSI_DRV_ERRNO_WDT_BASE | errno) |
| |
| static uint32_t timeout_ms[16] = {4, 7, 13, 26, 52, 105, 210, 419, 839, 1678, 3355, 6711, |
| 13422, 26844, 53687, 107374 |
| }; |
| |
| #define WDT_NULL_PARAM_CHK(para) \ |
| do { \ |
| if (para == NULL) { \ |
| return ERR_WDT(EDRV_PARAMETER); \ |
| } \ |
| } while (0) |
| |
| typedef struct { |
| uint32_t base; |
| uint32_t irq; |
| wdt_event_cb_t cb_event; |
| } dw_wdt_priv_t; |
| |
| extern int32_t target_get_wdt_count(void); |
| extern int32_t target_get_wdt(int32_t idx, uint32_t *base, uint32_t *irq); |
| |
| static dw_wdt_priv_t wdt_instance[CONFIG_WDT_NUM]; |
| |
| /* Driver Capabilities */ |
| static const wdt_capabilities_t wdt_capabilities = { |
| .interrupt = 1, ///< supports interrupt |
| }; |
| |
| static inline void dw_wdt_enable(dw_wdt_reg_t *addr) |
| { |
| uint32_t value = addr->WDT_CR; |
| value |= 1 << 0; |
| addr->WDT_CR = value; |
| } |
| |
| static inline void dw_wdt_disable(dw_wdt_reg_t *addr) |
| { |
| uint32_t value = addr->WDT_CR; |
| value &= ~(1 << 0); |
| addr->WDT_CR = value; |
| } |
| |
| |
| void dw_wdt_irqhandler(int32_t idx) |
| { |
| dw_wdt_priv_t *wdt_priv = &wdt_instance[idx]; |
| dw_wdt_reg_t *addr = (dw_wdt_reg_t *)(wdt_priv->base); |
| |
| addr->WDT_EOI; |
| |
| if (wdt_priv->cb_event) { |
| wdt_priv->cb_event(WDT_EVENT_TIMEOUT); |
| } |
| } |
| |
| /** |
| \brief get wdt instance count. |
| \return wdt instance count |
| */ |
| int32_t csi_wdt_get_instance_count(void) |
| { |
| return target_get_wdt_count(); |
| } |
| |
| /** |
| \brief Initialize WDT Interface. 1. Initializes the resources needed for the WDT interface 2.registers event callback function |
| \param[in] idx must not exceed return value of csi_wdt_get_instance_count() |
| \param[in] cb_event Pointer to \ref wdt_event_cb_t |
| \return pointer to wdt instance |
| */ |
| wdt_handle_t csi_wdt_initialize(int32_t idx, wdt_event_cb_t cb_event) |
| { |
| if (idx < 0 || idx >= CONFIG_WDT_NUM) { |
| return NULL; |
| } |
| |
| uint32_t base = 0u; |
| uint32_t irq = 0u; |
| |
| int32_t real_idx = target_get_wdt(idx, &base, &irq); |
| |
| if (real_idx != idx) { |
| return NULL; |
| } |
| |
| dw_wdt_priv_t *wdt_priv = &wdt_instance[idx]; |
| wdt_priv->base = base; |
| wdt_priv->irq = irq; |
| |
| wdt_priv->cb_event = cb_event; |
| drv_nvic_enable_irq(wdt_priv->irq); |
| |
| return (wdt_handle_t)wdt_priv; |
| } |
| |
| /** |
| \brief De-initialize WDT Interface. stops operation and releases the software resources used by the interface |
| \param[in] instance wdt instance to operate. |
| \return \ref execution_status |
| */ |
| int32_t csi_wdt_uninitialize(wdt_handle_t handle) |
| { |
| WDT_NULL_PARAM_CHK(handle); |
| |
| dw_wdt_priv_t *wdt_priv = handle; |
| |
| wdt_priv->cb_event = NULL; |
| drv_nvic_disable_irq(wdt_priv->irq); |
| return 0; |
| } |
| /** |
| \brief Get driver capabilities. |
| \param[in] wdt instance to operate. |
| \return \ref wdt_capabilities_t |
| */ |
| wdt_capabilities_t csi_wdt_get_capabilities(wdt_handle_t handle) |
| { |
| return wdt_capabilities; |
| } |
| |
| /** |
| \brief Set the WDT value. value = (2^t*0xffff * 10^6 /freq)/10^3(t: 0 ~ 15). |
| \param[in] handle wdt handle to operate. |
| \param[in] value the timeout value(ms) \ref:timeout_ms[] |
| \return \ref execution_status |
| */ |
| int32_t csi_wdt_set_timeout(wdt_handle_t handle, uint32_t value) |
| { |
| WDT_NULL_PARAM_CHK(handle); |
| uint32_t i = 0u; |
| |
| for (i = 0; i <= 15 ; i++) { |
| if (timeout_ms[i] == value) { |
| break; |
| } |
| |
| if (i == 15) { |
| return ERR_WDT(EDRV_PARAMETER); |
| } |
| } |
| |
| dw_wdt_priv_t *wdt_priv = handle; |
| dw_wdt_reg_t *addr = (dw_wdt_reg_t *)(wdt_priv->base); |
| |
| uint32_t config = addr->WDT_CR; |
| uint32_t en_stat = 0; /*origin wdt enable status*/ |
| |
| if ((config & 0x1) != 0) { |
| en_stat = 1; |
| } |
| |
| config = 0; |
| addr->WDT_CR = config; |
| |
| /*before configuration, must disable wdt first*/ |
| dw_wdt_disable(addr); |
| i += i << 4; |
| addr->WDT_TORR = i; |
| |
| if (en_stat == 1) { |
| dw_wdt_enable(addr); |
| csi_wdt_restart(handle); |
| } |
| |
| return 0; |
| } |
| |
| /** |
| \brief Start the WDT. |
| \param[in] handle wdt handle to operate. |
| \return \ref execution_status |
| */ |
| int32_t csi_wdt_start(wdt_handle_t handle) |
| { |
| WDT_NULL_PARAM_CHK(handle); |
| |
| dw_wdt_priv_t *wdt_priv = handle; |
| dw_wdt_reg_t *addr = (dw_wdt_reg_t *)(wdt_priv->base); |
| |
| dw_wdt_enable(addr); |
| csi_wdt_restart(handle); |
| return 0; |
| } |
| |
| /** |
| \brief Stop the WDT. |
| \param[in] handle wdt handle to operate. |
| \return \ref execution_status |
| */ |
| int32_t csi_wdt_stop(wdt_handle_t handle) |
| { |
| WDT_NULL_PARAM_CHK(handle); |
| |
| return ERR_WDT(EDRV_UNSUPPORTED); |
| } |
| |
| /** |
| \brief Restart the WDT. |
| \param[in] handle wdt handle to operate. |
| \return \ref execution_status |
| */ |
| int32_t csi_wdt_restart(wdt_handle_t handle) |
| { |
| WDT_NULL_PARAM_CHK(handle); |
| |
| dw_wdt_priv_t *wdt_priv = handle; |
| dw_wdt_reg_t *addr = (dw_wdt_reg_t *)(wdt_priv->base); |
| |
| addr->WDT_CRR = DW_WDT_CRR_RESET; |
| |
| return 0; |
| } |
| |
| /** |
| \brief Read the WDT Current value. |
| \param[in] handle wdt handle to operate. |
| \param[in] value Pointer to the Value. |
| \return \ref execution_status |
| */ |
| int32_t csi_wdt_read_current_value(wdt_handle_t handle, uint32_t *value) |
| { |
| WDT_NULL_PARAM_CHK(handle); |
| |
| dw_wdt_priv_t *wdt_priv = handle; |
| dw_wdt_reg_t *addr = (dw_wdt_reg_t *)(wdt_priv->base); |
| |
| *value = addr->WDT_CCVR; |
| return 0; |
| } |
| |