1 /*
2  * Copyright (c) 2021 ITE Corporation. All Rights Reserved.
3  * SPDX-License-Identifier: Apache-2.0
4  */
5 
6 #define DT_DRV_COMPAT ite_it8xxx2_watchdog
7 
8 #include <drivers/watchdog.h>
9 #include <errno.h>
10 #include <soc.h>
11 
12 #include <logging/log.h>
13 #define LOG_LEVEL CONFIG_WDT_LOG_LEVEL
14 LOG_MODULE_REGISTER(wdt_ite_it8xxx2);
15 
16 #define IT8XXX2_WATCHDOG_MAGIC_BYTE			0x5c
17 #define WARNING_TIMER_PERIOD_MS_TO_1024HZ_COUNT(ms)	((ms) * 1024 / 1000)
18 
19 /* enter critical period or not */
20 static int wdt_warning_fired;
21 
22 /* device config */
23 struct wdt_it8xxx2_config {
24 	/* wdt register base address */
25 	uintptr_t base;
26 };
27 
28 /* driver data */
29 struct wdt_it8xxx2_data {
30 	/* timeout callback used to handle watchdog event */
31 	wdt_callback_t callback;
32 	/* indicate whether a watchdog timeout is installed */
33 	bool timeout_installed;
34 	/* watchdog feed timeout in milliseconds */
35 	uint32_t timeout;
36 };
37 
38 /* driver convenience defines */
39 #define DRV_CONFIG(dev) ((const struct wdt_it8xxx2_config *)(dev)->config)
40 #define DRV_DATA(dev) ((struct wdt_it8xxx2_data *)(dev)->data)
41 #define DRV_REG(dev) (struct wdt_it8xxx2_regs *)(DRV_CONFIG(dev)->base)
42 
wdt_it8xxx2_install_timeout(const struct device * dev,const struct wdt_timeout_cfg * config)43 static int wdt_it8xxx2_install_timeout(const struct device *dev,
44 					  const struct wdt_timeout_cfg *config)
45 {
46 	struct wdt_it8xxx2_data *data = DRV_DATA(dev);
47 	struct wdt_it8xxx2_regs *const inst = DRV_REG(dev);
48 
49 	/* if watchdog is already running */
50 	if ((inst->ETWCFG) & IT8XXX2_WDT_LEWDCNTL) {
51 		return -EBUSY;
52 	}
53 
54 	/* no window watchdog support */
55 	if (config->window.min != 0) {
56 		data->timeout_installed = false;
57 		return -EINVAL;
58 	}
59 
60 	/* save watchdog timeout */
61 	data->timeout = config->window.max;
62 
63 	/* install user timeout isr */
64 	data->callback = config->callback;
65 
66 	/* mark installed */
67 	data->timeout_installed = true;
68 
69 	return 0;
70 }
71 
wdt_it8xxx2_setup(const struct device * dev,uint8_t options)72 static int wdt_it8xxx2_setup(const struct device *dev, uint8_t options)
73 {
74 	struct wdt_it8xxx2_data *data = DRV_DATA(dev);
75 	struct wdt_it8xxx2_regs *const inst = DRV_REG(dev);
76 	uint16_t cnt0 = WARNING_TIMER_PERIOD_MS_TO_1024HZ_COUNT(data->timeout);
77 	uint16_t cnt1 = WARNING_TIMER_PERIOD_MS_TO_1024HZ_COUNT((data->timeout
78 			+ CONFIG_WDT_ITE_WARNING_LEADING_TIME_MS));
79 
80 	/* disable pre-warning timer1 interrupt */
81 	irq_disable(DT_INST_IRQN(0));
82 
83 	if (!data->timeout_installed) {
84 		LOG_ERR("No valid WDT timeout installed");
85 		return -EINVAL;
86 	}
87 
88 	if ((inst->ETWCFG) & IT8XXX2_WDT_LEWDCNTL) {
89 		LOG_ERR("WDT is already running");
90 		return -EBUSY;
91 	}
92 
93 	if ((options & WDT_OPT_PAUSE_IN_SLEEP) != 0) {
94 		LOG_ERR("WDT_OPT_PAUSE_IN_SLEEP is not supported");
95 		return -ENOTSUP;
96 	}
97 
98 	if ((options & WDT_OPT_PAUSE_HALTED_BY_DBG) != 0) {
99 		LOG_ERR("WDT_OPT_PAUSE_HALTED_BY_DBG is not supported");
100 		return -ENOTSUP;
101 	}
102 
103 	/* pre-warning timer1 is 16-bit counter down timer */
104 	inst->ET1CNTLHR = (cnt0 >> 8) & 0xff;
105 	inst->ET1CNTLLR = cnt0 & 0xff;
106 
107 	/* clear pre-warning timer1 interrupt status */
108 	ite_intc_isr_clear(DT_INST_IRQN(0));
109 
110 	/* enable pre-warning timer1 interrupt */
111 	irq_enable(DT_INST_IRQN(0));
112 
113 	/* set watchdog timer count */
114 	inst->EWDCNTHR = (cnt1 >> 8) & 0xff;
115 	inst->EWDCNTLR = cnt1 & 0xff;
116 
117 	/* allow to write timer1 count register */
118 	inst->ETWCFG &= ~IT8XXX2_WDT_LET1CNTL;
119 
120 	/*
121 	 * bit5 = 1: enable key match function to touch watchdog
122 	 * bit4 = 1: select watchdog clock source from prescaler
123 	 * bit3 = 1: lock watchdog count register
124 	 * bit1 = 1: lock timer1 prescaler register
125 	 * bit0 = 1: lock watchdog and timer1 config register
126 	 */
127 	inst->ETWCFG = (IT8XXX2_WDT_EWDKEYEN |
128 			IT8XXX2_WDT_EWDSRC |
129 			IT8XXX2_WDT_LEWDCNTL |
130 			IT8XXX2_WDT_LET1PS |
131 			IT8XXX2_WDT_LETWCFG);
132 
133 	LOG_DBG("WDT Setup and enabled");
134 
135 	return 0;
136 }
137 
138 /*
139  * reload the WDT and pre-warning timer1 counter
140  *
141  * @param dev Pointer to the device structure for the driver instance.
142  * @param channel_id Index of the fed channel, and we only support
143  *                   channel_id = 0 now.
144  */
wdt_it8xxx2_feed(const struct device * dev,int channel_id)145 static int wdt_it8xxx2_feed(const struct device *dev, int channel_id)
146 {
147 	struct wdt_it8xxx2_data *data = DRV_DATA(dev);
148 	struct wdt_it8xxx2_regs *const inst = DRV_REG(dev);
149 	uint16_t cnt0 = WARNING_TIMER_PERIOD_MS_TO_1024HZ_COUNT(data->timeout);
150 
151 	ARG_UNUSED(channel_id);
152 
153 	/* reset pre-warning timer1 */
154 	inst->ETWCTRL |= IT8XXX2_WDT_ET1RST;
155 
156 	/* restart watchdog timer */
157 	inst->EWDKEYR = IT8XXX2_WATCHDOG_MAGIC_BYTE;
158 
159 	/* reset pre-warning timer1 to default if time is touched */
160 	if (wdt_warning_fired) {
161 		wdt_warning_fired = 0;
162 
163 		/* pre-warning timer1 is 16-bit counter down timer */
164 		inst->ET1CNTLHR = (cnt0 >> 8) & 0xff;
165 		inst->ET1CNTLLR = cnt0 & 0xff;
166 
167 		/* clear timer1 interrupt status */
168 		ite_intc_isr_clear(DT_INST_IRQN(0));
169 
170 		/* enable timer1 interrupt */
171 		irq_enable(DT_INST_IRQN(0));
172 	}
173 
174 	LOG_DBG("WDT Kicking");
175 
176 	return 0;
177 }
178 
wdt_it8xxx2_disable(const struct device * dev)179 static int wdt_it8xxx2_disable(const struct device *dev)
180 {
181 	struct wdt_it8xxx2_data *data = DRV_DATA(dev);
182 	struct wdt_it8xxx2_regs *const inst = DRV_REG(dev);
183 
184 	/* stop watchdog timer counting */
185 	inst->ETWCTRL |= IT8XXX2_WDT_EWDSCEN;
186 
187 	/* disable pre-warning timer1 interrupt */
188 	irq_disable(DT_INST_IRQN(0));
189 
190 	/* mark uninstalled */
191 	data->timeout_installed = false;
192 
193 	LOG_DBG("WDT Disabled");
194 
195 	return 0;
196 }
197 
wdt_it8xxx2_isr(const struct device * dev)198 static void wdt_it8xxx2_isr(const struct device *dev)
199 {
200 	struct wdt_it8xxx2_data *data = DRV_DATA(dev);
201 	struct wdt_it8xxx2_regs *const inst = DRV_REG(dev);
202 
203 	/* clear pre-warning timer1 interrupt status */
204 	ite_intc_isr_clear(DT_INST_IRQN(0));
205 
206 	/* reset pre-warning timer1 */
207 	inst->ETWCTRL |= IT8XXX2_WDT_ET1RST;
208 
209 	/* callback function, ex. print warning message */
210 	if (data->callback) {
211 		data->callback(dev, 0);
212 	}
213 
214 	/*
215 	 * Once warning timer triggered: if watchdog timer isn't reloaded,
216 	 * then we will reduce interval of warning timer to 30ms to print
217 	 * more warning messages before watchdog reset.
218 	 */
219 	if (!wdt_warning_fired++) {
220 		uint16_t cnt0 = WARNING_TIMER_PERIOD_MS_TO_1024HZ_COUNT(30);
221 
222 		/* pre-warning timer1 is 16-bit counter down timer */
223 		inst->ET1CNTLHR = (cnt0 >> 8) & 0xff;
224 		inst->ET1CNTLLR = cnt0 & 0xff;
225 
226 		/* clear pre-warning timer1 interrupt status */
227 		ite_intc_isr_clear(DT_INST_IRQN(0));
228 	}
229 
230 	LOG_DBG("WDT ISR");
231 }
232 
233 static const struct wdt_driver_api wdt_it8xxx2_api = {
234 	.setup = wdt_it8xxx2_setup,
235 	.disable = wdt_it8xxx2_disable,
236 	.install_timeout = wdt_it8xxx2_install_timeout,
237 	.feed = wdt_it8xxx2_feed,
238 };
239 
wdt_it8xxx2_init(const struct device * dev)240 static int wdt_it8xxx2_init(const struct device *dev)
241 {
242 	struct wdt_it8xxx2_regs *const inst = DRV_REG(dev);
243 
244 	if (IS_ENABLED(CONFIG_WDT_DISABLE_AT_BOOT)) {
245 		wdt_it8xxx2_disable(dev);
246 	}
247 
248 	/* unlock access to watchdog registers */
249 	inst->ETWCFG = 0x00;
250 
251 	/* set WDT and timer1 to use 1.024kHz clock */
252 	inst->ET1PSR = IT8XXX2_WDT_ETPS_1P024_KHZ;
253 
254 	/* set WDT key match enabled and WDT clock to use ET1PSR */
255 	inst->ETWCFG = (IT8XXX2_WDT_EWDKEYEN |
256 			IT8XXX2_WDT_EWDSRC);
257 
258 	/* watchdog can be stopped */
259 	inst->ETWCTRL |= IT8XXX2_WDT_EWDSCMS;
260 
261 	IRQ_CONNECT(DT_INST_IRQN(0), 0, wdt_it8xxx2_isr,
262 		    DEVICE_DT_INST_GET(0), 0);
263 	return 0;
264 }
265 
266 static const struct wdt_it8xxx2_config wdt_it8xxx2_cfg_0 = {
267 	.base = DT_INST_REG_ADDR(0),
268 };
269 
270 static struct wdt_it8xxx2_data wdt_it8xxx2_dev_data;
271 
272 DEVICE_DT_INST_DEFINE(0, wdt_it8xxx2_init, NULL,
273 			&wdt_it8xxx2_dev_data, &wdt_it8xxx2_cfg_0,
274 			PRE_KERNEL_1, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT,
275 			&wdt_it8xxx2_api);
276