blob: c5b4f8a9f665aefe5023773eb56987be7cbd9230 [file] [log] [blame]
Michael Wallefa842012021-11-15 23:45:43 +01001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Watchdog driver for the sl28cpld
4 *
5 * Copyright (c) 2021 Michael Walle <michael@walle.cc>
6 */
7
Michael Wallefa842012021-11-15 23:45:43 +01008#include <dm.h>
9#include <wdt.h>
10#include <sl28cpld.h>
11#include <div64.h>
12
13#define SL28CPLD_WDT_CTRL 0x00
14#define WDT_CTRL_EN0 BIT(0)
15#define WDT_CTRL_EN1 BIT(1)
16#define WDT_CTRL_EN_MASK GENMASK(1, 0)
17#define WDT_CTRL_LOCK BIT(2)
18#define WDT_CTRL_ASSERT_SYS_RESET BIT(6)
19#define WDT_CTRL_ASSERT_WDT_TIMEOUT BIT(7)
20#define SL28CPLD_WDT_TIMEOUT 0x01
21#define SL28CPLD_WDT_KICK 0x02
22#define WDT_KICK_VALUE 0x6b
23
24static int sl28cpld_wdt_reset(struct udevice *dev)
25{
26 return sl28cpld_write(dev, SL28CPLD_WDT_KICK, WDT_KICK_VALUE);
27}
28
29static int sl28cpld_wdt_start(struct udevice *dev, u64 timeout, ulong flags)
30{
31 int ret, val;
32
33 val = sl28cpld_read(dev, SL28CPLD_WDT_CTRL);
34 if (val < 0)
35 return val;
36
37 /* (1) disable watchdog */
38 val &= ~WDT_CTRL_EN_MASK;
39 ret = sl28cpld_write(dev, SL28CPLD_WDT_CTRL, val);
40 if (ret)
41 return ret;
42
43 /* (2) set timeout */
44 ret = sl28cpld_write(dev, SL28CPLD_WDT_TIMEOUT, lldiv(timeout, 1000));
45 if (ret)
46 return ret;
47
48 /* (3) kick it, will reset timer to the timeout value */
49 ret = sl28cpld_wdt_reset(dev);
50 if (ret)
51 return ret;
52
53 /* (4) enable either recovery or normal one */
54 if (flags & BIT(0))
55 val |= WDT_CTRL_EN1;
56 else
57 val |= WDT_CTRL_EN0;
58
59 if (flags & BIT(1))
60 val |= WDT_CTRL_LOCK;
61
62 if (flags & BIT(2))
63 val &= ~WDT_CTRL_ASSERT_SYS_RESET;
64 else
65 val |= WDT_CTRL_ASSERT_SYS_RESET;
66
67 if (flags & BIT(3))
68 val |= WDT_CTRL_ASSERT_WDT_TIMEOUT;
69 else
70 val &= ~WDT_CTRL_ASSERT_WDT_TIMEOUT;
71
72 return sl28cpld_write(dev, SL28CPLD_WDT_CTRL, val);
73}
74
75static int sl28cpld_wdt_stop(struct udevice *dev)
76{
77 int val;
78
79 val = sl28cpld_read(dev, SL28CPLD_WDT_CTRL);
80 if (val < 0)
81 return val;
82
83 return sl28cpld_write(dev, SL28CPLD_WDT_CTRL, val & ~WDT_CTRL_EN_MASK);
84}
85
86static int sl28cpld_wdt_expire_now(struct udevice *dev, ulong flags)
87{
88 return sl28cpld_wdt_start(dev, 0, flags);
89}
90
91static const struct wdt_ops sl28cpld_wdt_ops = {
92 .start = sl28cpld_wdt_start,
93 .reset = sl28cpld_wdt_reset,
94 .stop = sl28cpld_wdt_stop,
95 .expire_now = sl28cpld_wdt_expire_now,
96};
97
98static const struct udevice_id sl28cpld_wdt_ids[] = {
99 { .compatible = "kontron,sl28cpld-wdt", },
100 {}
101};
102
103U_BOOT_DRIVER(sl28cpld_wdt) = {
104 .name = "sl28cpld-wdt",
105 .id = UCLASS_WDT,
106 .of_match = sl28cpld_wdt_ids,
107 .ops = &sl28cpld_wdt_ops,
108};