1818#include <linux/module.h>
1919#include <linux/of.h>
2020#include <linux/platform_device.h>
21+ #include <linux/pm_wakeirq.h>
2122#include <linux/watchdog.h>
2223
2324#define DEFAULT_TIMEOUT 10
2829#define IWDG_RLR 0x08 /* ReLoad Register */
2930#define IWDG_SR 0x0C /* Status Register */
3031#define IWDG_WINR 0x10 /* Windows Register */
32+ #define IWDG_EWCR 0x14 /* Early Wake-up Register */
3133
3234/* IWDG_KR register bit mask */
3335#define KR_KEY_RELOAD 0xAAAA /* reload counter enable */
4749#define SR_PVU BIT(0) /* Watchdog prescaler value update */
4850#define SR_RVU BIT(1) /* Watchdog counter reload value update */
4951
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+
5056/* set timeout to 100000 us */
5157#define TIMEOUT_US 100000
5258#define SLEEP_US 1000
5359
5460struct stm32_iwdg_data {
5561 bool has_pclk ;
62+ bool has_early_wakeup ;
5663 u32 max_prescaler ;
5764};
5865
5966static const struct stm32_iwdg_data stm32_iwdg_data = {
6067 .has_pclk = false,
68+ .has_early_wakeup = false,
6169 .max_prescaler = 256 ,
6270};
6371
6472static const struct stm32_iwdg_data stm32mp1_iwdg_data = {
6573 .has_pclk = true,
74+ .has_early_wakeup = true,
6675 .max_prescaler = 1024 ,
6776};
6877
@@ -88,27 +97,35 @@ static inline void reg_write(void __iomem *base, u32 reg, u32 val)
8897static int stm32_iwdg_start (struct watchdog_device * wdd )
8998{
9099 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 ;
92101 int ret ;
93102
94103 dev_dbg (wdd -> parent , "%s\n" , __func__ );
95104
105+ if (!wdd -> pretimeout )
106+ wdd -> pretimeout = 3 * wdd -> timeout / 4 ;
107+
96108 tout = clamp_t (unsigned int , wdd -> timeout ,
97109 wdd -> min_timeout , wdd -> max_hw_heartbeat_ms / 1000 );
110+ ptot = clamp_t (unsigned int , tout - wdd -> pretimeout ,
111+ wdd -> min_timeout , tout );
98112
99113 presc = DIV_ROUND_UP (tout * wdt -> rate , RLR_MAX + 1 );
100114
101115 /* The prescaler is align on power of 2 and start at 2 ^ PR_SHIFT. */
102116 presc = roundup_pow_of_two (presc );
103117 iwdg_pr = presc <= 1 << PR_SHIFT ? 0 : ilog2 (presc ) - PR_SHIFT ;
104118 iwdg_rlr = ((tout * wdt -> rate ) / presc ) - 1 ;
119+ iwdg_ewcr = ((ptot * wdt -> rate ) / presc ) - 1 ;
105120
106121 /* enable write access */
107122 reg_write (wdt -> regs , IWDG_KR , KR_KEY_EWA );
108123
109124 /* set prescaler & reload registers */
110125 reg_write (wdt -> regs , IWDG_PR , iwdg_pr );
111126 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 );
112129 reg_write (wdt -> regs , IWDG_KR , KR_KEY_ENABLE );
113130
114131 /* wait for the registers to be updated (max 100ms) */
@@ -151,6 +168,34 @@ static int stm32_iwdg_set_timeout(struct watchdog_device *wdd,
151168 return 0 ;
152169}
153170
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+
154199static void stm32_clk_disable_unprepare (void * data )
155200{
156201 clk_disable_unprepare (data );
@@ -207,11 +252,20 @@ static const struct watchdog_info stm32_iwdg_info = {
207252 .identity = "STM32 Independent Watchdog" ,
208253};
209254
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+
210263static const struct watchdog_ops stm32_iwdg_ops = {
211264 .owner = THIS_MODULE ,
212265 .start = stm32_iwdg_start ,
213266 .ping = stm32_iwdg_ping ,
214267 .set_timeout = stm32_iwdg_set_timeout ,
268+ .set_pretimeout = stm32_iwdg_set_pretimeout ,
215269};
216270
217271static const struct of_device_id stm32_iwdg_of_match [] = {
@@ -221,6 +275,40 @@ static const struct of_device_id stm32_iwdg_of_match[] = {
221275};
222276MODULE_DEVICE_TABLE (of , stm32_iwdg_of_match );
223277
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+
224312static int stm32_iwdg_probe (struct platform_device * pdev )
225313{
226314 struct device * dev = & pdev -> dev ;
@@ -255,6 +343,11 @@ static int stm32_iwdg_probe(struct platform_device *pdev)
255343 wdd -> max_hw_heartbeat_ms = ((RLR_MAX + 1 ) * wdt -> data -> max_prescaler *
256344 1000 ) / wdt -> rate ;
257345
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+
258351 watchdog_set_drvdata (wdd , wdt );
259352 watchdog_set_nowayout (wdd , WATCHDOG_NOWAYOUT );
260353 watchdog_init_timeout (wdd , 0 , dev );
0 commit comments