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