1 /*
2  * SPDX-FileCopyrightText: 2021 Espressif Systems (Shanghai) CO LTD
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 #include <string.h>
7 
8 #include "soc/soc_caps.h"
9 
10 #include "hal/xt_wdt_hal.h"
11 #include "hal/xt_wdt_ll.h"
12 #include "hal/assert.h"
13 
14 #define DIV_COMP_N_MAX 8
15 
xt_wdt_hal_calculate(uint32_t rtc_clk_frequency_khz)16 static uint32_t xt_wdt_hal_calculate(uint32_t rtc_clk_frequency_khz)
17 {
18     uint32_t xtal32k_clk_factor = 0;
19     uint8_t divisor_comps[DIV_COMP_N_MAX];
20 
21     /*  From the TRM:
22 
23         Define the frequency of RTC_CLK as f_rtc_clk (unit: kHz), and the eight divisor components as
24         x0, x1, x2, x3, x4, x5, x6, and x7, respectively. S = x0 + x1 + x2 + x3 + x4 + x5 + x6 + x7.
25         The following conditions should be fulfilled:
26         S = f_rtc_clk * (4/32)
27         M + 1 >= xn >= M(0 <= n <= 7)
28         M = f_rtc_clk/32/2
29         xn should be an integer. M and S are rounded up or down. Each divisor component (x0 ~x7) is 4-bit long, and
30         corresponds to the value of RTC_CNTL_XTAL32K_CLK_FACTOR (32-bit) in order.
31     */
32 
33     uint8_t M = ((rtc_clk_frequency_khz / 32) / 2);
34     uint32_t S = ((4 * rtc_clk_frequency_khz) / 32);
35 
36     memset(divisor_comps, M, DIV_COMP_N_MAX);
37 
38     /* Calculate how far we are away from satisfying S = SUM(x_n) */
39     uint8_t off = S - DIV_COMP_N_MAX * M;
40 
41     /* Offset should never be this big */
42     HAL_ASSERT(off <= DIV_COMP_N_MAX);
43 
44     for (int i = 0; i < DIV_COMP_N_MAX; i++) {
45         if (off) {
46             divisor_comps[i]++;
47             off--;
48         }
49         /* Sum up all divisors */
50         xtal32k_clk_factor |=  (divisor_comps[i] << 4 * i);
51     }
52 
53     return xtal32k_clk_factor;
54 }
55 
xt_wdt_hal_init(xt_wdt_hal_context_t * hal,const xt_wdt_hal_config_t * config)56 void xt_wdt_hal_init(xt_wdt_hal_context_t *hal, const xt_wdt_hal_config_t *config)
57 {
58     hal->dev = &RTCCNTL;
59 
60     xt_wdt_ll_enable(hal->dev, false);
61     xt_wdt_ll_set_timeout(hal->dev, config->timeout);
62 }
63 
xt_wdt_hal_enable_backup_clk(xt_wdt_hal_context_t * hal,uint32_t rtc_clk_frequency_khz)64 uint32_t xt_wdt_hal_enable_backup_clk(xt_wdt_hal_context_t *hal, uint32_t rtc_clk_frequency_khz)
65 {
66     uint32_t xtal32k_clk_factor = xt_wdt_hal_calculate(rtc_clk_frequency_khz);
67 
68     xt_wdt_ll_set_backup_clk_factor(hal->dev, xtal32k_clk_factor);
69     xt_wdt_ll_auto_backup_enable(hal->dev, true);
70 
71     return xtal32k_clk_factor;
72 }
73 
xt_wdt_hal_enable(xt_wdt_hal_context_t * hal,bool enable)74 void xt_wdt_hal_enable(xt_wdt_hal_context_t *hal, bool enable)
75 {
76     xt_wdt_ll_enable(hal->dev, enable);
77     xt_wdt_ll_intr_enable(hal->dev, enable);
78 }
79