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