1// 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}; 110