1 /*
2 * Copyright (C) 2020, NXP
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #define DT_DRV_COMPAT nxp_imx_wdog
8
9 #include <zephyr/drivers/watchdog.h>
10 #include <zephyr/sys_clock.h>
11 #include <fsl_wdog.h>
12
13 #define LOG_LEVEL CONFIG_WDT_LOG_LEVEL
14 #include <zephyr/logging/log.h>
15 #include <zephyr/irq.h>
16 LOG_MODULE_REGISTER(wdt_mcux_wdog);
17
18 #define WDOG_TMOUT_SEC(x) (((x * 2) / MSEC_PER_SEC) - 1)
19
20 struct mcux_wdog_config {
21 WDOG_Type *base;
22 void (*irq_config_func)(const struct device *dev);
23 };
24
25 struct mcux_wdog_data {
26 wdt_callback_t callback;
27 wdog_config_t wdog_config;
28 bool timeout_valid;
29 };
30
mcux_wdog_setup(const struct device * dev,uint8_t options)31 static int mcux_wdog_setup(const struct device *dev, uint8_t options)
32 {
33 const struct mcux_wdog_config *config = dev->config;
34 struct mcux_wdog_data *data = dev->data;
35 WDOG_Type *base = config->base;
36
37 if (!data->timeout_valid) {
38 LOG_ERR("No valid timeouts installed");
39 return -EINVAL;
40 }
41
42 data->wdog_config.workMode.enableStop =
43 (options & WDT_OPT_PAUSE_IN_SLEEP) == 0U;
44
45 data->wdog_config.workMode.enableDebug =
46 (options & WDT_OPT_PAUSE_HALTED_BY_DBG) == 0U;
47
48 WDOG_Init(base, &data->wdog_config);
49 LOG_DBG("Setup the watchdog");
50
51 return 0;
52 }
53
mcux_wdog_disable(const struct device * dev)54 static int mcux_wdog_disable(const struct device *dev)
55 {
56 const struct mcux_wdog_config *config = dev->config;
57 struct mcux_wdog_data *data = dev->data;
58 WDOG_Type *base = config->base;
59
60 WDOG_Deinit(base);
61 data->timeout_valid = false;
62 LOG_DBG("Disabled the watchdog");
63
64 return 0;
65 }
66
mcux_wdog_install_timeout(const struct device * dev,const struct wdt_timeout_cfg * cfg)67 static int mcux_wdog_install_timeout(const struct device *dev,
68 const struct wdt_timeout_cfg *cfg)
69 {
70 struct mcux_wdog_data *data = dev->data;
71
72 if (data->timeout_valid) {
73 LOG_ERR("No more timeouts can be installed");
74 return -ENOMEM;
75 }
76
77 WDOG_GetDefaultConfig(&data->wdog_config);
78 data->wdog_config.interruptTimeValue = 0U;
79
80 if (cfg->window.max < (MSEC_PER_SEC / 2)) {
81 LOG_ERR("Invalid window max, shortest window is 500ms");
82 return -EINVAL;
83 }
84
85 data->wdog_config.timeoutValue =
86 WDOG_TMOUT_SEC(cfg->window.max);
87
88 if (cfg->window.min) {
89 LOG_ERR("Invalid window.min, Do not support window model");
90 return -EINVAL;
91 }
92 if (data->wdog_config.timeoutValue > 128) {
93 LOG_ERR("Invalid timeoutValue, valid (0.5s - 128.0s)");
94 return -EINVAL;
95 }
96
97 data->wdog_config.enableInterrupt = cfg->callback != NULL;
98 data->callback = cfg->callback;
99 data->timeout_valid = true;
100
101 return 0;
102 }
103
mcux_wdog_feed(const struct device * dev,int channel_id)104 static int mcux_wdog_feed(const struct device *dev, int channel_id)
105 {
106 const struct mcux_wdog_config *config = dev->config;
107 WDOG_Type *base = config->base;
108
109 if (channel_id != 0) {
110 LOG_ERR("Invalid channel id");
111 return -EINVAL;
112 }
113
114 WDOG_Refresh(base);
115 LOG_DBG("Fed the watchdog");
116
117 return 0;
118 }
119
mcux_wdog_isr(const struct device * dev)120 static void mcux_wdog_isr(const struct device *dev)
121 {
122 const struct mcux_wdog_config *config = dev->config;
123 struct mcux_wdog_data *data = dev->data;
124 WDOG_Type *base = config->base;
125 uint32_t flags;
126
127 flags = WDOG_GetStatusFlags(base);
128 WDOG_ClearInterruptStatus(base, flags);
129
130 if (data->callback) {
131 data->callback(dev, 0);
132 }
133 }
134
mcux_wdog_init(const struct device * dev)135 static int mcux_wdog_init(const struct device *dev)
136 {
137 const struct mcux_wdog_config *config = dev->config;
138
139 config->irq_config_func(dev);
140
141 return 0;
142 }
143
144 static const struct wdt_driver_api mcux_wdog_api = {
145 .setup = mcux_wdog_setup,
146 .disable = mcux_wdog_disable,
147 .install_timeout = mcux_wdog_install_timeout,
148 .feed = mcux_wdog_feed,
149 };
150
151 static void mcux_wdog_config_func(const struct device *dev);
152
153 static const struct mcux_wdog_config mcux_wdog_config = {
154 .base = (WDOG_Type *) DT_INST_REG_ADDR(0),
155 .irq_config_func = mcux_wdog_config_func,
156 };
157
158 static struct mcux_wdog_data mcux_wdog_data;
159
160 DEVICE_DT_INST_DEFINE(0,
161 &mcux_wdog_init,
162 NULL,
163 &mcux_wdog_data, &mcux_wdog_config,
164 POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEVICE,
165 &mcux_wdog_api);
166
mcux_wdog_config_func(const struct device * dev)167 static void mcux_wdog_config_func(const struct device *dev)
168 {
169 IRQ_CONNECT(DT_INST_IRQN(0),
170 DT_INST_IRQ(0, priority),
171 mcux_wdog_isr, DEVICE_DT_INST_GET(0), 0);
172
173 irq_enable(DT_INST_IRQN(0));
174 }
175