1 /*
2 * Copyright (c) 2021 Pavlo Hamov <pasha.gamov@gmail.com>
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #define DT_DRV_COMPAT ti_cc32xx_watchdog
8
9 #include <drivers/watchdog.h>
10 #include <soc.h>
11 #include <errno.h>
12
13 /* Driverlib includes */
14 #include <inc/hw_types.h>
15 #include <inc/hw_wdt.h>
16 #include <driverlib/pin.h>
17 #include <driverlib/rom.h>
18 #include <driverlib/rom_map.h>
19 #include <driverlib/prcm.h>
20 #include <driverlib/wdt.h>
21
22 #define MAX_RELOAD_VALUE 0xFFFFFFFF
23
24 #define LOG_LEVEL CONFIG_WDT_LOG_LEVEL
25 #include <logging/log.h>
26 #include <logging/log_ctrl.h>
27 LOG_MODULE_REGISTER(wdt_cc32xx);
28
29 struct wdt_cc32xx_data {
30 int reload;
31 wdt_callback_t cb;
32 uint8_t flags;
33 };
34
35 struct wdt_cc32xx_cfg {
36 const unsigned long reg;
37 void (*irq_cfg_func)(void);
38 };
39
wdt_cc32xx_msToTicks(uint32_t ms)40 static uint32_t wdt_cc32xx_msToTicks(uint32_t ms)
41 {
42 static const uint32_t ratio = CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC / 1000;
43 static const uint32_t maxMs = MAX_RELOAD_VALUE / ratio;
44
45 if (ms > maxMs) {
46 return maxMs;
47 }
48
49 return ms * ratio;
50 }
51
wdt_cc32xx_enable(const struct device * dev)52 static int wdt_cc32xx_enable(const struct device *dev)
53 {
54 struct wdt_cc32xx_data *data = dev->data;
55 const struct wdt_cc32xx_cfg *config = dev->config;
56 const uint32_t reload = wdt_cc32xx_msToTicks(data->reload);
57
58 MAP_WatchdogIntClear(config->reg);
59 MAP_WatchdogReloadSet(config->reg, reload);
60 MAP_WatchdogEnable(config->reg);
61 LOG_DBG("Enabled");
62 return 0;
63 }
64
wdt_cc32xx_setup(const struct device * dev,uint8_t options)65 static int wdt_cc32xx_setup(const struct device *dev, uint8_t options)
66 {
67 const struct wdt_cc32xx_cfg *config = dev->config;
68 int rv;
69
70 if (options & WDT_OPT_PAUSE_IN_SLEEP) {
71 return -ENOTSUP;
72 }
73
74 MAP_WatchdogUnlock(config->reg);
75 if (options & WDT_OPT_PAUSE_HALTED_BY_DBG) {
76 MAP_WatchdogStallEnable(config->reg);
77 } else {
78 MAP_WatchdogStallDisable(config->reg);
79 }
80 rv = wdt_cc32xx_enable(dev);
81 MAP_WatchdogLock(config->reg);
82 return rv;
83 }
84
wdt_cc32xx_disable(const struct device * dev)85 static int wdt_cc32xx_disable(const struct device *dev)
86 {
87 return -ENOTSUP;
88 }
89
wdt_cc32xx_install_timeout(const struct device * dev,const struct wdt_timeout_cfg * cfg)90 static int wdt_cc32xx_install_timeout(const struct device *dev,
91 const struct wdt_timeout_cfg *cfg)
92 {
93 struct wdt_cc32xx_data *data = dev->data;
94
95 if (COND_CODE_1(CONFIG_WDT_MULTISTAGE, (cfg->next), (0))) {
96 return -ENOTSUP;
97 }
98
99 data->reload = cfg->window.max;
100 data->cb = cfg->callback;
101 data->flags = cfg->flags;
102 LOG_DBG("Reload time %d", data->reload);
103 return 0;
104 }
105
wdt_cc32xx_feed(const struct device * dev,int channel_id)106 static int wdt_cc32xx_feed(const struct device *dev, int channel_id)
107 {
108 struct wdt_cc32xx_data *data = dev->data;
109 const struct wdt_cc32xx_cfg *config = dev->config;
110 const uint32_t reload = wdt_cc32xx_msToTicks(data->reload);
111 bool inIsr = k_is_in_isr();
112
113 if (!inIsr) {
114 MAP_WatchdogUnlock(config->reg);
115 }
116 MAP_WatchdogIntClear(config->reg);
117 MAP_WatchdogReloadSet(config->reg, reload);
118 if (!inIsr) {
119 MAP_WatchdogLock(config->reg);
120 }
121 LOG_DBG("Feed");
122 return 0;
123 }
124
wdt_cc32xx_isr(const struct device * dev)125 static void wdt_cc32xx_isr(const struct device *dev)
126 {
127 struct wdt_cc32xx_data *data = dev->data;
128
129 LOG_DBG("ISR");
130 if (data->cb) {
131 data->cb(dev, 0);
132 }
133 if (data->flags != WDT_FLAG_RESET_NONE) {
134 LOG_PANIC();
135 MAP_PRCMMCUReset(data->flags & WDT_FLAG_RESET_SOC);
136 while (1) {
137 }
138 }
139 }
140
wdt_cc32xx_init(const struct device * dev)141 static int wdt_cc32xx_init(const struct device *dev)
142 {
143 const struct wdt_cc32xx_cfg *config = dev->config;
144 int rv;
145
146 LOG_DBG("init");
147 config->irq_cfg_func();
148
149 MAP_PRCMPeripheralClkEnable(PRCM_WDT, PRCM_RUN_MODE_CLK | PRCM_SLP_MODE_CLK);
150 while (!MAP_PRCMPeripheralStatusGet(PRCM_WDT)) {
151 }
152
153 if (IS_ENABLED(CONFIG_WDT_DISABLE_AT_BOOT)) {
154 return 0;
155 }
156
157 MAP_WatchdogUnlock(config->reg);
158 rv = wdt_cc32xx_enable(dev);
159 MAP_WatchdogLock(config->reg);
160 return rv;
161 }
162
163 static const struct wdt_driver_api wdt_cc32xx_api = {
164 .setup = wdt_cc32xx_setup,
165 .disable = wdt_cc32xx_disable,
166 .install_timeout = wdt_cc32xx_install_timeout,
167 .feed = wdt_cc32xx_feed,
168 };
169
170 #define cc32xx_WDT_INIT(index) \
171 \
172 static void wdt_cc32xx_irq_cfg_##index(void) \
173 { \
174 IRQ_CONNECT(DT_INST_IRQN(index), \
175 DT_INST_IRQ(index, priority), \
176 wdt_cc32xx_isr, DEVICE_DT_INST_GET(index), 0); \
177 irq_enable(DT_INST_IRQN(index)); \
178 } \
179 \
180 static struct wdt_cc32xx_data wdt_cc32xx_data_##index = { \
181 .reload = CONFIG_WDT_CC32XX_INITIAL_TIMEOUT, \
182 .cb = NULL, \
183 .flags = 0, \
184 }; \
185 \
186 static struct wdt_cc32xx_cfg wdt_cc32xx_cfg_##index = { \
187 .reg = (unsigned long)DT_INST_REG_ADDR(index), \
188 .irq_cfg_func = wdt_cc32xx_irq_cfg_##index, \
189 }; \
190 \
191 DEVICE_DT_INST_DEFINE(index, \
192 &wdt_cc32xx_init, NULL, \
193 &wdt_cc32xx_data_##index, &wdt_cc32xx_cfg_##index, \
194 POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, \
195 &wdt_cc32xx_api);
196
197 DT_INST_FOREACH_STATUS_OKAY(cc32xx_WDT_INIT)
198