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