18
18
#include <linux/module.h>
19
19
#include <linux/of.h>
20
20
#include <linux/platform_device.h>
21
+ #include <linux/pm_wakeirq.h>
21
22
#include <linux/watchdog.h>
22
23
23
24
#define DEFAULT_TIMEOUT 10
28
29
#define IWDG_RLR 0x08 /* ReLoad Register */
29
30
#define IWDG_SR 0x0C /* Status Register */
30
31
#define IWDG_WINR 0x10 /* Windows Register */
32
+ #define IWDG_EWCR 0x14 /* Early Wake-up Register */
31
33
32
34
/* IWDG_KR register bit mask */
33
35
#define KR_KEY_RELOAD 0xAAAA /* reload counter enable */
47
49
#define SR_PVU BIT(0) /* Watchdog prescaler value update */
48
50
#define SR_RVU BIT(1) /* Watchdog counter reload value update */
49
51
52
+ #define EWCR_EWIT GENMASK(11, 0) /* Watchdog counter window value */
53
+ #define EWCR_EWIC BIT(14) /* Watchdog early interrupt acknowledge */
54
+ #define EWCR_EWIE BIT(15) /* Watchdog early interrupt enable */
55
+
50
56
/* set timeout to 100000 us */
51
57
#define TIMEOUT_US 100000
52
58
#define SLEEP_US 1000
53
59
54
60
struct stm32_iwdg_data {
55
61
bool has_pclk ;
62
+ bool has_early_wakeup ;
56
63
u32 max_prescaler ;
57
64
};
58
65
59
66
static const struct stm32_iwdg_data stm32_iwdg_data = {
60
67
.has_pclk = false,
68
+ .has_early_wakeup = false,
61
69
.max_prescaler = 256 ,
62
70
};
63
71
64
72
static const struct stm32_iwdg_data stm32mp1_iwdg_data = {
65
73
.has_pclk = true,
74
+ .has_early_wakeup = true,
66
75
.max_prescaler = 1024 ,
67
76
};
68
77
@@ -88,27 +97,35 @@ static inline void reg_write(void __iomem *base, u32 reg, u32 val)
88
97
static int stm32_iwdg_start (struct watchdog_device * wdd )
89
98
{
90
99
struct stm32_iwdg * wdt = watchdog_get_drvdata (wdd );
91
- u32 tout , presc , iwdg_rlr , iwdg_pr , iwdg_sr ;
100
+ u32 tout , ptot , presc , iwdg_rlr , iwdg_ewcr , iwdg_pr , iwdg_sr ;
92
101
int ret ;
93
102
94
103
dev_dbg (wdd -> parent , "%s\n" , __func__ );
95
104
105
+ if (!wdd -> pretimeout )
106
+ wdd -> pretimeout = 3 * wdd -> timeout / 4 ;
107
+
96
108
tout = clamp_t (unsigned int , wdd -> timeout ,
97
109
wdd -> min_timeout , wdd -> max_hw_heartbeat_ms / 1000 );
110
+ ptot = clamp_t (unsigned int , tout - wdd -> pretimeout ,
111
+ wdd -> min_timeout , tout );
98
112
99
113
presc = DIV_ROUND_UP (tout * wdt -> rate , RLR_MAX + 1 );
100
114
101
115
/* The prescaler is align on power of 2 and start at 2 ^ PR_SHIFT. */
102
116
presc = roundup_pow_of_two (presc );
103
117
iwdg_pr = presc <= 1 << PR_SHIFT ? 0 : ilog2 (presc ) - PR_SHIFT ;
104
118
iwdg_rlr = ((tout * wdt -> rate ) / presc ) - 1 ;
119
+ iwdg_ewcr = ((ptot * wdt -> rate ) / presc ) - 1 ;
105
120
106
121
/* enable write access */
107
122
reg_write (wdt -> regs , IWDG_KR , KR_KEY_EWA );
108
123
109
124
/* set prescaler & reload registers */
110
125
reg_write (wdt -> regs , IWDG_PR , iwdg_pr );
111
126
reg_write (wdt -> regs , IWDG_RLR , iwdg_rlr );
127
+ if (wdt -> data -> has_early_wakeup )
128
+ reg_write (wdt -> regs , IWDG_EWCR , iwdg_ewcr | EWCR_EWIE );
112
129
reg_write (wdt -> regs , IWDG_KR , KR_KEY_ENABLE );
113
130
114
131
/* wait for the registers to be updated (max 100ms) */
@@ -151,6 +168,34 @@ static int stm32_iwdg_set_timeout(struct watchdog_device *wdd,
151
168
return 0 ;
152
169
}
153
170
171
+ static int stm32_iwdg_set_pretimeout (struct watchdog_device * wdd ,
172
+ unsigned int pretimeout )
173
+ {
174
+ dev_dbg (wdd -> parent , "%s pretimeout: %d sec\n" , __func__ , pretimeout );
175
+
176
+ wdd -> pretimeout = pretimeout ;
177
+
178
+ if (watchdog_active (wdd ))
179
+ return stm32_iwdg_start (wdd );
180
+
181
+ return 0 ;
182
+ }
183
+
184
+ static irqreturn_t stm32_iwdg_isr (int irq , void * wdog_arg )
185
+ {
186
+ struct watchdog_device * wdd = wdog_arg ;
187
+ struct stm32_iwdg * wdt = watchdog_get_drvdata (wdd );
188
+ u32 reg ;
189
+
190
+ reg = reg_read (wdt -> regs , IWDG_EWCR );
191
+ reg |= EWCR_EWIC ;
192
+ reg_write (wdt -> regs , IWDG_EWCR , reg );
193
+
194
+ watchdog_notify_pretimeout (wdd );
195
+
196
+ return IRQ_HANDLED ;
197
+ }
198
+
154
199
static void stm32_clk_disable_unprepare (void * data )
155
200
{
156
201
clk_disable_unprepare (data );
@@ -207,11 +252,20 @@ static const struct watchdog_info stm32_iwdg_info = {
207
252
.identity = "STM32 Independent Watchdog" ,
208
253
};
209
254
255
+ static const struct watchdog_info stm32_iwdg_preinfo = {
256
+ .options = WDIOF_SETTIMEOUT |
257
+ WDIOF_MAGICCLOSE |
258
+ WDIOF_KEEPALIVEPING |
259
+ WDIOF_PRETIMEOUT ,
260
+ .identity = "STM32 Independent Watchdog" ,
261
+ };
262
+
210
263
static const struct watchdog_ops stm32_iwdg_ops = {
211
264
.owner = THIS_MODULE ,
212
265
.start = stm32_iwdg_start ,
213
266
.ping = stm32_iwdg_ping ,
214
267
.set_timeout = stm32_iwdg_set_timeout ,
268
+ .set_pretimeout = stm32_iwdg_set_pretimeout ,
215
269
};
216
270
217
271
static const struct of_device_id stm32_iwdg_of_match [] = {
@@ -221,6 +275,40 @@ static const struct of_device_id stm32_iwdg_of_match[] = {
221
275
};
222
276
MODULE_DEVICE_TABLE (of , stm32_iwdg_of_match );
223
277
278
+ static int stm32_iwdg_irq_init (struct platform_device * pdev ,
279
+ struct stm32_iwdg * wdt )
280
+ {
281
+ struct device_node * np = pdev -> dev .of_node ;
282
+ struct watchdog_device * wdd = & wdt -> wdd ;
283
+ struct device * dev = & pdev -> dev ;
284
+ int irq , ret ;
285
+
286
+ if (!wdt -> data -> has_early_wakeup )
287
+ return 0 ;
288
+
289
+ irq = platform_get_irq (pdev , 0 );
290
+ if (irq <= 0 )
291
+ return 0 ;
292
+
293
+ if (of_property_read_bool (np , "wakeup-source" )) {
294
+ ret = device_init_wakeup (dev , true);
295
+ if (ret )
296
+ return ret ;
297
+
298
+ ret = dev_pm_set_wake_irq (dev , irq );
299
+ if (ret )
300
+ return ret ;
301
+ }
302
+
303
+ ret = devm_request_irq (dev , irq , stm32_iwdg_isr , 0 ,
304
+ dev_name (dev ), wdd );
305
+ if (ret )
306
+ return ret ;
307
+
308
+ wdd -> info = & stm32_iwdg_preinfo ;
309
+ return 0 ;
310
+ }
311
+
224
312
static int stm32_iwdg_probe (struct platform_device * pdev )
225
313
{
226
314
struct device * dev = & pdev -> dev ;
@@ -255,6 +343,11 @@ static int stm32_iwdg_probe(struct platform_device *pdev)
255
343
wdd -> max_hw_heartbeat_ms = ((RLR_MAX + 1 ) * wdt -> data -> max_prescaler *
256
344
1000 ) / wdt -> rate ;
257
345
346
+ /* Initialize IRQ, this might override wdd->info, hence it is here. */
347
+ ret = stm32_iwdg_irq_init (pdev , wdt );
348
+ if (ret )
349
+ return ret ;
350
+
258
351
watchdog_set_drvdata (wdd , wdt );
259
352
watchdog_set_nowayout (wdd , WATCHDOG_NOWAYOUT );
260
353
watchdog_init_timeout (wdd , 0 , dev );
0 commit comments