summaryrefslogtreecommitdiffstats
path: root/drivers/watchdog
diff options
context:
space:
mode:
authorAlexandre Belloni <alexandre.belloni@free-electrons.com>2017-03-02 12:31:11 -0500
committerWim Van Sebroeck <wim@iguana.be>2017-05-18 12:51:21 -0400
commit015b528644a84b0018d3286ecd6ea5f82dce0180 (patch)
treea504da6ef8df476c70af11340ec94631421dc8c1 /drivers/watchdog
parentd8f1deaa5256aba3296025e103e8abb96f3e6479 (diff)
watchdog: sama5d4: fix WDDIS handling
The datasheet states: "When setting the WDDIS bit, and while it is set, the fields WDV and WDD must not be modified." Because the whole configuration is already cached inside .mr, wait for the user to enable the watchdog to configure it so it is enabled and configured at the same time (what the IP is actually expecting). When the watchdog is already enabled, it is not an issue to reconfigure it. Signed-off-by: Alexandre Belloni <alexandre.belloni@free-electrons.com> Acked-by: Wenyou.Yang <wenyou.yang@microchip.com> Signed-off-by: Guenter Roeck <linux@roeck-us.net> Signed-off-by: Wim Van Sebroeck <wim@iguana.be>
Diffstat (limited to 'drivers/watchdog')
-rw-r--r--drivers/watchdog/sama5d4_wdt.c48
1 files changed, 30 insertions, 18 deletions
diff --git a/drivers/watchdog/sama5d4_wdt.c b/drivers/watchdog/sama5d4_wdt.c
index f709962018ac..5cee20caca78 100644
--- a/drivers/watchdog/sama5d4_wdt.c
+++ b/drivers/watchdog/sama5d4_wdt.c
@@ -44,6 +44,8 @@ MODULE_PARM_DESC(nowayout,
44 "Watchdog cannot be stopped once started (default=" 44 "Watchdog cannot be stopped once started (default="
45 __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); 45 __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
46 46
47#define wdt_enabled (!(wdt->mr & AT91_WDT_WDDIS))
48
47#define wdt_read(wdt, field) \ 49#define wdt_read(wdt, field) \
48 readl_relaxed((wdt)->reg_base + (field)) 50 readl_relaxed((wdt)->reg_base + (field))
49 51
@@ -89,7 +91,16 @@ static int sama5d4_wdt_set_timeout(struct watchdog_device *wdd,
89 wdt->mr &= ~AT91_WDT_WDD; 91 wdt->mr &= ~AT91_WDT_WDD;
90 wdt->mr |= AT91_WDT_SET_WDV(value); 92 wdt->mr |= AT91_WDT_SET_WDV(value);
91 wdt->mr |= AT91_WDT_SET_WDD(value); 93 wdt->mr |= AT91_WDT_SET_WDD(value);
92 wdt_write(wdt, AT91_WDT_MR, wdt->mr); 94
95 /*
96 * WDDIS has to be 0 when updating WDD/WDV. The datasheet states: When
97 * setting the WDDIS bit, and while it is set, the fields WDV and WDD
98 * must not be modified.
99 * If the watchdog is enabled, then the timeout can be updated. Else,
100 * wait that the user enables it.
101 */
102 if (wdt_enabled)
103 wdt_write(wdt, AT91_WDT_MR, wdt->mr & ~AT91_WDT_WDDIS);
93 104
94 wdd->timeout = timeout; 105 wdd->timeout = timeout;
95 106
@@ -145,23 +156,20 @@ static int of_sama5d4_wdt_init(struct device_node *np, struct sama5d4_wdt *wdt)
145 156
146static int sama5d4_wdt_init(struct sama5d4_wdt *wdt) 157static int sama5d4_wdt_init(struct sama5d4_wdt *wdt)
147{ 158{
148 struct watchdog_device *wdd = &wdt->wdd;
149 u32 value = WDT_SEC2TICKS(wdd->timeout);
150 u32 reg; 159 u32 reg;
151
152 /* 160 /*
153 * Because the fields WDV and WDD must not be modified when the WDDIS 161 * When booting and resuming, the bootloader may have changed the
154 * bit is set, so clear the WDDIS bit before writing the WDT_MR. 162 * watchdog configuration.
163 * If the watchdog is already running, we can safely update it.
164 * Else, we have to disable it properly.
155 */ 165 */
156 reg = wdt_read(wdt, AT91_WDT_MR); 166 if (wdt_enabled) {
157 reg &= ~AT91_WDT_WDDIS; 167 wdt_write(wdt, AT91_WDT_MR, wdt->mr);
158 wdt_write(wdt, AT91_WDT_MR, reg); 168 } else {
159 169 reg = wdt_read(wdt, AT91_WDT_MR);
160 wdt->mr |= AT91_WDT_SET_WDD(value); 170 if (!(reg & AT91_WDT_WDDIS))
161 wdt->mr |= AT91_WDT_SET_WDV(value); 171 wdt_write(wdt, AT91_WDT_MR, reg | AT91_WDT_WDDIS);
162 172 }
163 wdt_write(wdt, AT91_WDT_MR, wdt->mr);
164
165 return 0; 173 return 0;
166} 174}
167 175
@@ -172,6 +180,7 @@ static int sama5d4_wdt_probe(struct platform_device *pdev)
172 struct resource *res; 180 struct resource *res;
173 void __iomem *regs; 181 void __iomem *regs;
174 u32 irq = 0; 182 u32 irq = 0;
183 u32 timeout;
175 int ret; 184 int ret;
176 185
177 wdt = devm_kzalloc(&pdev->dev, sizeof(*wdt), GFP_KERNEL); 186 wdt = devm_kzalloc(&pdev->dev, sizeof(*wdt), GFP_KERNEL);
@@ -221,6 +230,11 @@ static int sama5d4_wdt_probe(struct platform_device *pdev)
221 return ret; 230 return ret;
222 } 231 }
223 232
233 timeout = WDT_SEC2TICKS(wdd->timeout);
234
235 wdt->mr |= AT91_WDT_SET_WDD(timeout);
236 wdt->mr |= AT91_WDT_SET_WDV(timeout);
237
224 ret = sama5d4_wdt_init(wdt); 238 ret = sama5d4_wdt_init(wdt);
225 if (ret) 239 if (ret)
226 return ret; 240 return ret;
@@ -263,9 +277,7 @@ static int sama5d4_wdt_resume(struct device *dev)
263{ 277{
264 struct sama5d4_wdt *wdt = dev_get_drvdata(dev); 278 struct sama5d4_wdt *wdt = dev_get_drvdata(dev);
265 279
266 wdt_write(wdt, AT91_WDT_MR, wdt->mr & ~AT91_WDT_WDDIS); 280 sama5d4_wdt_init(wdt);
267 if (wdt->mr & AT91_WDT_WDDIS)
268 wdt_write(wdt, AT91_WDT_MR, wdt->mr);
269 281
270 return 0; 282 return 0;
271} 283}